Skip to content

Commit

Permalink
GP-4103: Fixing issue with loading Mach-O Rust binaries
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanmkurtz committed Dec 13, 2023
1 parent 53275c9 commit 9dd1a3f
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public RustStringAnalyzer() {
@Override
public boolean canAnalyze(Program program) {
String name = program.getCompiler();
return name.contains("rustc");
return name.contains(RustConstants.RUST_COMPILER);
}

@Override
Expand Down Expand Up @@ -98,9 +98,9 @@ private static void recurseString(Program program, Address start, int maxLen) {

/**
* 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
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;
Expand All @@ -36,50 +37,51 @@
*/
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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -35,7 +36,7 @@ public DemanglerOptions createDefaultOptions() {
@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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;
Expand Down Expand Up @@ -144,7 +145,7 @@ else if (size == 64) {
list.add("generic_clib");
}

if (program.getCompiler().contains("rustc")) {
if (program.getCompiler().contains(RustConstants.RUST_COMPILER)) {
list.add("rust-common");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2443,15 +2443,15 @@ private void markupElfInfoProducers(TaskMonitor monitor) throws CancelledExcepti
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());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1694,16 +1694,23 @@ protected void setProgramDescription() {
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());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ public enum CompilerEnum {
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"),

Expand Down Expand Up @@ -958,16 +958,16 @@ public static CompilerEnum getOpinion(PortableExecutable pe, ByteProvider provid
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)
Expand Down

0 comments on commit 9dd1a3f

Please sign in to comment.