GP-4103: Fixing issue with loading Mach-O Rust binaries

This commit is contained in:
Ryan Kurtz 2023-12-13 07:24:43 -05:00
parent 53275c92f8
commit 9dd1a3fb10
8 changed files with 61 additions and 49 deletions

View file

@ -21,7 +21,8 @@ public class RustConstants {
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 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_WINDOWS = "windows";
public static final String RUST_COMPILER = "rustc";
}

View file

@ -44,7 +44,7 @@ public class RustStringAnalyzer extends AbstractAnalyzer {
@Override
public boolean canAnalyze(Program program) {
String name = program.getCompiler();
return name.contains("rustc");
return name.contains(RustConstants.RUST_COMPILER);
}
@Override
@ -98,9 +98,9 @@ public class RustStringAnalyzer extends AbstractAnalyzer {
/**
* Get the number of bytes to the next reference, or the max length
* @param program
* @param address
* @param maxLen
* @param program The {@link Program}
* @param address The {@link Address}
* @param maxLen The maximum length
* @return maximum length to create the string
*/
private static int getMaxStringLength(Program program, Address address, int maxLen) {

View file

@ -25,6 +25,7 @@ import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.framework.Application;
import ghidra.framework.store.LockException;
import ghidra.program.database.SpecExtension;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg;
@ -36,50 +37,51 @@ import ghidra.xml.XmlParseException;
*/
public class RustUtilities {
/**
* Checks if a given {@link Program} was written in Rust
* Checks if a given {@link MemoryBlock} contains a Rust signature
*
* @param program The {@link Program} to check
* @param blockName The name of the {@link MemoryBlock} to scan for Rust signatures
* @return True if the given {@link Program} was written in Rust; otherwise, false
* @param block The {@link MemoryBlock} to scan for Rust signatures
* @return True if the given {@link MemoryBlock} is not null and contains a Rust signature;
* otherwise, false
* @throws IOException if there was an IO-related error
*/
public static boolean isRust(Program program, String blockName) throws IOException {
MemoryBlock[] blocks = program.getMemory().getBlocks();
for (MemoryBlock block : blocks) {
if (block.getName().equals(blockName)) {
byte[] bytes = block.getData().readAllBytes();
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_1)) {
return true;
}
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_2)) {
return true;
}
}
public static boolean isRust(MemoryBlock block) throws IOException {
if (block == null) {
return false;
}
byte[] bytes = block.getData().readAllBytes();
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_1)) {
return true;
}
if (containsBytes(bytes, RustConstants.RUST_SIGNATURE_2)) {
return true;
}
return false;
}
public static int addExtensions(Program program, TaskMonitor monitor, String subPath)
throws IOException {
var processor = program.getLanguageCompilerSpecPair().getLanguage().getProcessor();
Processor processor = program.getLanguageCompilerSpecPair().getLanguage().getProcessor();
ResourceFile module = Application.getModuleDataSubDirectory(processor.toString(),
RustConstants.RUST_EXTENSIONS_PATH + subPath);
int extensionCount = 0;
ResourceFile[] files = module.listFiles();
for (ResourceFile file : files) {
InputStream stream = file.getInputStream();
byte[] bytes = stream.readAllBytes();
String xml = new String(bytes);
if (files != null) {
for (ResourceFile file : files) {
InputStream stream = file.getInputStream();
byte[] bytes = stream.readAllBytes();
String xml = new String(bytes);
try {
SpecExtension extension = new SpecExtension(program);
extension.addReplaceCompilerSpecExtension(xml, monitor);
extensionCount += 1;
}
catch (SleighException | SAXException | XmlParseException | LockException e) {
Msg.error(program, "Failed to load load cspec extensions");
try {
SpecExtension extension = new SpecExtension(program);
extension.addReplaceCompilerSpecExtension(xml, monitor);
extensionCount++;
}
catch (SleighException | SAXException | XmlParseException | LockException e) {
Msg.error(RustUtilities.class,
"Failed to load Rust cspec extension: " + file.getAbsolutePath(), e);
}
}
}

View file

@ -15,6 +15,7 @@
*/
package ghidra.app.plugin.core.analysis.rust.demangler;
import ghidra.app.plugin.core.analysis.rust.RustConstants;
import ghidra.app.util.demangler.*;
import ghidra.program.model.listing.Program;
@ -35,7 +36,7 @@ public class RustDemangler implements Demangler {
@Override
public boolean canDemangle(Program program) {
String name = program.getCompiler();
return name != null && name.contains("rustc");
return name != null && name.contains(RustConstants.RUST_COMPILER);
}
@Override

View file

@ -18,6 +18,7 @@ package ghidra.app.plugin.core.datamgr.util;
import java.util.*;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.analysis.rust.RustConstants;
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
import ghidra.app.util.opinion.*;
import ghidra.framework.Application;
@ -144,7 +145,7 @@ public class DataTypeArchiveUtility {
list.add("generic_clib");
}
if (program.getCompiler().contains("rustc")) {
if (program.getCompiler().contains(RustConstants.RUST_COMPILER)) {
list.add("rust-common");
}

View file

@ -2443,15 +2443,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
private void setCompiler(TaskMonitor monitor) {
// Check for Rust
try {
if (RustUtilities.isRust(program, ElfSectionHeaderConstants.dot_rodata)) {
if (RustUtilities.isRust(memory.getBlock(ElfSectionHeaderConstants.dot_rodata))) {
program.setCompiler(RustConstants.RUST_COMPILER);
int extensionCount = RustUtilities.addExtensions(program, monitor,
RustConstants.RUST_EXTENSIONS_UNIX);
log.appendMsg("Installed " + extensionCount + " Rust cspec extensions");
program.setCompiler("rustc");
}
}
catch (IOException e) {
log.appendException(e);
log.appendMsg("Rust error: " + e.getMessage());
}
}

View file

@ -1694,16 +1694,23 @@ public class MachoProgramBuilder {
protected void setCompiler() {
// Check for Rust
try {
if (RustUtilities.isRust(program,
SegmentNames.SEG_TEXT + "." + SectionNames.TEXT_CONST)) {
SegmentCommand segment = machoHeader.getSegment(SegmentNames.SEG_TEXT);
if (segment == null) {
return;
}
Section section = segment.getSectionByName(SectionNames.TEXT_CONST);
if (section == null) {
return;
}
if (RustUtilities.isRust(memory.getBlock(space.getAddress(section.getAddress())))) {
program.setCompiler(RustConstants.RUST_COMPILER);
int extensionCount = RustUtilities.addExtensions(program, monitor,
RustConstants.RUST_EXTENSIONS_UNIX);
log.appendMsg("Installed " + extensionCount + " Rust cspec extensions");
program.setCompiler("rustc");
}
}
catch (IOException e) {
log.appendException(e);
log.appendMsg("Rust error: " + e.getMessage());
}
}

View file

@ -902,7 +902,7 @@ public class PeLoader extends AbstractPeDebugLoader {
BorlandCpp("borland:c++", "borlandcpp"),
BorlandUnk("borland:unknown", "borlandcpp"),
CLI("cli", "cli"),
Rustc("rustc", "rustc"),
Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER),
GOLANG("golang", "golang"),
Unknown("unknown", "unknown"),
@ -958,16 +958,16 @@ public class PeLoader extends AbstractPeDebugLoader {
DOSHeader dh = pe.getDOSHeader();
// Check for Rust. Program object is required, which may be null.
try {
if (program != null && RustUtilities.isRust(program, ".rdata")) {
if (program != null && RustUtilities.isRust(program.getMemory().getBlock(".rdata"))) {
try {
int extensionCount = RustUtilities.addExtensions(program, monitor,
RustConstants.RUST_EXTENSIONS_WINDOWS);
log.appendMsg("Installed " + extensionCount + " Rust cspec extensions");
return CompilerEnum.Rustc;
}
}
catch (IOException e) {
log.appendException(e);
catch (IOException e) {
log.appendMsg("Rust error: " + e.getMessage());
}
return CompilerEnum.Rustc;
}
// Check for managed code (.NET)