mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-5515: Faster Rust signature search
This commit is contained in:
parent
cdd68cc791
commit
cb949f275a
5 changed files with 52 additions and 41 deletions
|
@ -15,15 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.analysis.rust;
|
package ghidra.app.plugin.core.analysis.rust;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.CategoryPath;
|
||||||
|
|
||||||
public class RustConstants {
|
public class RustConstants {
|
||||||
public static final CategoryPath RUST_CATEGORYPATH = new CategoryPath("/rust");
|
public static final CategoryPath RUST_CATEGORYPATH = new CategoryPath("/rust");
|
||||||
public static final byte[] RUST_SIGNATURE_1 = "RUST_BACKTRACE".getBytes();
|
|
||||||
public static final byte[] RUST_SIGNATURE_2 = "/rustc/".getBytes();
|
|
||||||
public static final byte[] RUST_SIGNATURE_3 = "RUST_MIN_STACK".getBytes();
|
|
||||||
public static final String RUST_EXTENSIONS_PATH = "extensions/rust/";
|
public static final String RUST_EXTENSIONS_PATH = "extensions/rust/";
|
||||||
public static final String RUST_EXTENSIONS_UNIX = "unix";
|
public static final String RUST_EXTENSIONS_UNIX = "unix";
|
||||||
public static final String RUST_EXTENSIONS_WINDOWS = "windows";
|
public static final String RUST_EXTENSIONS_WINDOWS = "windows";
|
||||||
public static final String RUST_COMPILER = "rustc";
|
public static final String RUST_COMPILER = "rustc";
|
||||||
|
|
||||||
|
public static final List<byte[]> RUST_SIGNATURES = List.of(
|
||||||
|
"RUST_BACKTRACE".getBytes(),
|
||||||
|
"RUST_MIN_STACK".getBytes(),
|
||||||
|
"/rustc/".getBytes()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.plugin.core.analysis.rust;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
@ -25,10 +26,14 @@ import ghidra.app.plugin.processors.sleigh.SleighException;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.SpecExtension;
|
import ghidra.program.database.SpecExtension;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.lang.Processor;
|
import ghidra.program.model.lang.Processor;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.bytesearch.*;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.xml.XmlParseException;
|
import ghidra.xml.XmlParseException;
|
||||||
|
|
||||||
|
@ -36,6 +41,7 @@ import ghidra.xml.XmlParseException;
|
||||||
* Rust utility functions
|
* Rust utility functions
|
||||||
*/
|
*/
|
||||||
public class RustUtilities {
|
public class RustUtilities {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a given {@link MemoryBlock} contains a Rust signature
|
* Checks if a given {@link MemoryBlock} contains a Rust signature
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -43,26 +49,38 @@ public class RustUtilities {
|
||||||
* If the program is determined to be rust, then the compiler property is set to
|
* If the program is determined to be rust, then the compiler property is set to
|
||||||
* {@link RustConstants#RUST_COMPILER}.
|
* {@link RustConstants#RUST_COMPILER}.
|
||||||
*
|
*
|
||||||
|
* @param program The {@link Program}
|
||||||
* @param block The {@link MemoryBlock} to scan for Rust signatures
|
* @param block The {@link MemoryBlock} to scan for Rust signatures
|
||||||
|
* @param monitor The monitor
|
||||||
* @return True if the given {@link MemoryBlock} is not null and contains a Rust signature;
|
* @return True if the given {@link MemoryBlock} is not null and contains a Rust signature;
|
||||||
* otherwise, false
|
* otherwise, false
|
||||||
* @throws IOException if there was an IO-related error
|
* @throws IOException if there was an IO-related error
|
||||||
|
* @throws CancelledException if the user cancelled the operation
|
||||||
*/
|
*/
|
||||||
public static boolean isRust(MemoryBlock block) throws IOException {
|
public static boolean isRust(Program program, MemoryBlock block, TaskMonitor monitor)
|
||||||
|
throws IOException, CancelledException {
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
byte[] bytes = block.getData().readAllBytes();
|
|
||||||
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_1)) {
|
// Use a MemoryBytePatternSearch for more efficient byte searching over a list of potential
|
||||||
return true;
|
// byte signatures. The below action sets our supplied boolean to true on a match, which we
|
||||||
|
// can later query and use as a return value for this method.
|
||||||
|
GenericMatchAction<AtomicBoolean> action =
|
||||||
|
new GenericMatchAction<AtomicBoolean>(new AtomicBoolean()) {
|
||||||
|
@Override
|
||||||
|
public void apply(Program prog, Address addr, Match match) {
|
||||||
|
getMatchValue().set(true);
|
||||||
}
|
}
|
||||||
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_2)) {
|
};
|
||||||
return true;
|
MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Rust signatures");
|
||||||
|
for (byte[] sig : RustConstants.RUST_SIGNATURES) {
|
||||||
|
searcher.addPattern(new GenericByteSequencePattern<AtomicBoolean>(sig, action));
|
||||||
}
|
}
|
||||||
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_3)) {
|
|
||||||
return true;
|
searcher.search(program, new AddressSet(block.getAddressRange()), monitor);
|
||||||
}
|
|
||||||
return false;
|
return action.getMatchValue().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,22 +124,4 @@ public class RustUtilities {
|
||||||
|
|
||||||
return extensionCount;
|
return extensionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean containsBytes(byte[] data, byte[] bytes) {
|
|
||||||
for (int i = 0; i < data.length - bytes.length; i++) {
|
|
||||||
boolean isMatch = true;
|
|
||||||
for (int j = 0; j < bytes.length; j++) {
|
|
||||||
if (Byte.compare(data[i + j], bytes[j]) != 0) {
|
|
||||||
isMatch = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMatch) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2464,10 +2464,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCompiler(TaskMonitor monitor) {
|
private void setCompiler(TaskMonitor monitor) throws CancelledException {
|
||||||
// Check for Rust
|
// Check for Rust
|
||||||
try {
|
try {
|
||||||
if (RustUtilities.isRust(memory.getBlock(ElfSectionHeaderConstants.dot_rodata))) {
|
if (RustUtilities.isRust(program, memory.getBlock(ElfSectionHeaderConstants.dot_rodata),
|
||||||
|
monitor)) {
|
||||||
program.setCompiler(RustConstants.RUST_COMPILER);
|
program.setCompiler(RustConstants.RUST_COMPILER);
|
||||||
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
||||||
RustConstants.RUST_EXTENSIONS_UNIX);
|
RustConstants.RUST_EXTENSIONS_UNIX);
|
||||||
|
|
|
@ -1805,7 +1805,7 @@ public class MachoProgramBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setCompiler() {
|
protected void setCompiler() throws CancelledException {
|
||||||
// Check for Rust
|
// Check for Rust
|
||||||
try {
|
try {
|
||||||
SegmentCommand segment = machoHeader.getSegment(SegmentNames.SEG_TEXT);
|
SegmentCommand segment = machoHeader.getSegment(SegmentNames.SEG_TEXT);
|
||||||
|
@ -1816,7 +1816,8 @@ public class MachoProgramBuilder {
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (RustUtilities.isRust(memory.getBlock(space.getAddress(section.getAddress())))) {
|
if (RustUtilities.isRust(program,
|
||||||
|
memory.getBlock(space.getAddress(section.getAddress())), monitor)) {
|
||||||
program.setCompiler(RustConstants.RUST_COMPILER);
|
program.setCompiler(RustConstants.RUST_COMPILER);
|
||||||
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
||||||
RustConstants.RUST_EXTENSIONS_UNIX);
|
RustConstants.RUST_EXTENSIONS_UNIX);
|
||||||
|
|
|
@ -975,17 +975,21 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||||
DOSHeader dh = pe.getDOSHeader();
|
DOSHeader dh = pe.getDOSHeader();
|
||||||
|
|
||||||
// Check for Rust. Program object is required, which may be null.
|
// Check for Rust. Program object is required, which may be null.
|
||||||
if (program != null && RustUtilities.isRust(program.getMemory().getBlock(".rdata"))) {
|
|
||||||
try {
|
try {
|
||||||
|
if (program != null && RustUtilities.isRust(program,
|
||||||
|
program.getMemory().getBlock(".rdata"), monitor)) {
|
||||||
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
int extensionCount = RustUtilities.addExtensions(program, monitor,
|
||||||
RustConstants.RUST_EXTENSIONS_WINDOWS);
|
RustConstants.RUST_EXTENSIONS_WINDOWS);
|
||||||
log.appendMsg("Installed " + extensionCount + " Rust cspec extensions");
|
log.appendMsg("Installed " + extensionCount + " Rust cspec extensions");
|
||||||
}
|
}
|
||||||
|
return CompilerEnum.Rustc;
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
// Move on
|
||||||
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log.appendMsg("Rust error: " + e.getMessage());
|
log.appendMsg("Rust error: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return CompilerEnum.Rustc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for Swift
|
// Check for Swift
|
||||||
List<String> sectionNames =
|
List<String> sectionNames =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue