mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Candidate release of source code.
This commit is contained in:
parent
db81e6b3b0
commit
79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
|
@ -0,0 +1,182 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//Finds undefined functions by searching for common
|
||||
//byte patterns used by compilers for function entry points.
|
||||
//
|
||||
//Only Intel GCC, Windows, and PowerPC are currently
|
||||
//handled.
|
||||
//
|
||||
//Please feel free to change this script and add
|
||||
//different byte patterns.
|
||||
//
|
||||
//When the byte pattern is found, the instructions
|
||||
//will be disassembled and a function will be created.
|
||||
//
|
||||
//Please note: this will NOT find all undefined functions!
|
||||
//@category Functions
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.CompilerSpecID;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
|
||||
public class FindUndefinedFunctionsScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
PatternMatcher[] expectedPatterns = getPatterns();
|
||||
|
||||
boolean doIT =
|
||||
askYesNo("Find and Create Functions?", "Would you like find and create functions?");
|
||||
if (!doIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (PatternMatcher expectedPattern : expectedPatterns) {
|
||||
Address address = currentProgram.getMinAddress();
|
||||
while (true) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Data nextUndefined =
|
||||
currentProgram.getListing().getUndefinedDataAfter(address, monitor);
|
||||
if (nextUndefined == null) {
|
||||
break;
|
||||
}
|
||||
Address undefinedAddress = nextUndefined.getMinAddress();
|
||||
|
||||
MemoryBlock block = currentProgram.getMemory().getBlock(undefinedAddress);
|
||||
if (!block.isExecute()) {
|
||||
address = undefinedAddress;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expectedPattern.isMatch(undefinedAddress)) {
|
||||
disassemble(undefinedAddress);
|
||||
createFunction(undefinedAddress, null);
|
||||
address = undefinedAddress.add(1);
|
||||
}
|
||||
else {
|
||||
address = undefinedAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PatternMatcher[] getPatterns() {
|
||||
if (currentProgram == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Processor processor = currentProgram.getLanguage().getProcessor();
|
||||
|
||||
if (processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
||||
CompilerSpecID compilerSpecID = currentProgram.getCompilerSpec().getCompilerSpecID();
|
||||
if (compilerSpecID.equals(new CompilerSpecID("windows"))) {
|
||||
return new PatternMatcher[] { new PatternMatcher(new byte[] { (byte) 0x55,
|
||||
(byte) 0x8b, (byte) 0xec }, false), };
|
||||
}
|
||||
if (compilerSpecID.equals(new CompilerSpecID("gcc"))) {
|
||||
return new PatternMatcher[] { new PatternMatcher(new byte[] { (byte) 0x55,
|
||||
(byte) 0x89, (byte) 0xe5 }, false), };
|
||||
}
|
||||
}
|
||||
|
||||
// Endianness OK here?
|
||||
if (processor.equals(Processor.findOrPossiblyCreateProcessor("PowerPC"))) {
|
||||
return new PatternMatcher[] { new PatternMatcher(new byte[] { (byte) 0x7c, (byte) 0x08,
|
||||
(byte) 0x02, (byte) 0xa6 }, false),//
|
||||
};
|
||||
}
|
||||
if (processor.equals(Processor.findOrPossiblyCreateProcessor("ARM"))) {
|
||||
return new PatternMatcher[] {
|
||||
//new PatternMatcher(new byte[]{(byte)0x00,(byte)0x00,(byte)0x50,(byte)0xe3}, true),//only check 'cmp' at function entry
|
||||
//new PatternMatcher(new byte[]{(byte)0x00,(byte)0x00,(byte)0x51,(byte)0xe3}, true),//only check 'cmp' at function entry
|
||||
//new PatternMatcher(new byte[]{(byte)0x00,(byte)0x00,(byte)0x53,(byte)0xe3}, true),//only check 'cmp' at function entry
|
||||
new PatternMatcher(
|
||||
new byte[] { (byte) 0xf0, (byte) 0x40, (byte) 0x2d, (byte) 0xe9 }, false),//stmdb sp!{r4 r5 r6 r7 lr}
|
||||
new PatternMatcher(
|
||||
new byte[] { (byte) 0xb0, (byte) 0x40, (byte) 0x2d, (byte) 0xe9 }, false),//stmdb sp!{r4 r5 r7 lr}
|
||||
new PatternMatcher(
|
||||
new byte[] { (byte) 0x90, (byte) 0x40, (byte) 0x2d, (byte) 0xe9 }, false),//stmdb sp!{r4 r7 lr}
|
||||
new PatternMatcher(
|
||||
new byte[] { (byte) 0x80, (byte) 0x40, (byte) 0x2d, (byte) 0xe9 }, false),//stmdb sp!{r7 lr}
|
||||
};
|
||||
}
|
||||
throw new RuntimeException("Unsupported language.");
|
||||
}
|
||||
|
||||
private class PatternMatcher {
|
||||
byte[] expectedBytes;
|
||||
boolean requiresEntyPoint;
|
||||
|
||||
PatternMatcher(byte[] expectedBytes, boolean requiresEntryPoint) {
|
||||
this.expectedBytes = expectedBytes;
|
||||
this.requiresEntyPoint = requiresEntryPoint;
|
||||
}
|
||||
|
||||
boolean isMatch(Address undefinedAddress) throws MemoryAccessException {
|
||||
byte[] actualBytes = new byte[expectedBytes.length];
|
||||
currentProgram.getMemory().getBytes(undefinedAddress, actualBytes);
|
||||
|
||||
if (equals(expectedBytes, actualBytes)) {
|
||||
if (requiresEntyPoint) {
|
||||
// return currentProgram.getSymbolTable().isExternalEntryPoint(undefinedAddress);
|
||||
Symbol primarySymbol =
|
||||
currentProgram.getSymbolTable().getPrimarySymbol(undefinedAddress);
|
||||
return (primarySymbol != null) &&
|
||||
(primarySymbol.getSource() == SourceType.IMPORTED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equals(byte[] expected, byte[] actual) {
|
||||
if (expected.length != actual.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
if (expected[i] != actual[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// private String toString(byte [][] bytes) {
|
||||
// StringBuffer buffer = new StringBuffer();
|
||||
// for (byte [] array : bytes) {
|
||||
// buffer.append('[');
|
||||
// for (byte b : array) {
|
||||
// buffer.append(toHexString(b, true, true));
|
||||
// buffer.append(',');
|
||||
// }
|
||||
// buffer.deleteCharAt(buffer.length()-1);
|
||||
// buffer.append(']');
|
||||
// buffer.append('\n');
|
||||
// }
|
||||
// return buffer.toString();
|
||||
// }
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue