GT-2845: updated Mach-O, DYLD, Prelink loaders to utilize FilesBytes.

This commit is contained in:
Ryan Kurtz
2019-07-02 14:59:41 -04:00
parent 12af9291c9
commit 7e5252f6c7
7 changed files with 108 additions and 118 deletions
@@ -330,7 +330,7 @@ public class BinaryLoader extends AbstractProgramLoader {
block.setWrite(isOverlay ? false : true); block.setWrite(isOverlay ? false : true);
block.setExecute(isOverlay ? false : true); block.setExecute(isOverlay ? false : true);
block.setSourceName("Binary Loader"); block.setSourceName("Binary Loader");
MemoryBlockUtil.adjustFragment(prog.getListing(), block.getStart(), blockName); MemoryBlockUtils.adjustFragment(prog, block.getStart(), blockName);
} }
catch (LockException | MemoryConflictException e) { catch (LockException | MemoryConflictException e) {
Msg.error(this, "Unexpected exception creating memory block", e); Msg.error(this, "Unexpected exception creating memory block", e);
@@ -18,6 +18,7 @@ package ghidra.app.util.opinion;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.Option; import ghidra.app.util.Option;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
@@ -44,8 +45,7 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true; static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true;
/** Loader option to create memory blocks for DYLIB sections */ /** Loader option to create memory blocks for DYLIB sections */
static final String CREATE_DYLIB_SECTIONS_OPTION_NAME = static final String CREATE_DYLIB_SECTIONS_OPTION_NAME = "Create DYLIB section memory blocks";
"Create DYLIB section memory blocks (slow!)";
/** Default value for loader option to create memory blocks for DYLIB sections */ /** Default value for loader option to create memory blocks for DYLIB sections */
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false; static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false;
@@ -85,8 +85,9 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
throws IOException { throws IOException {
try { try {
DyldCacheProgramBuilder.buildProgram(program, provider, shouldProcessSymbols(options), DyldCacheProgramBuilder.buildProgram(program, provider,
shouldCreateDylibSections(options), log, handler, monitor); MemoryBlockUtils.createFileBytes(program, provider), shouldProcessSymbols(options),
shouldCreateDylibSections(options), log, monitor);
} }
catch (CancelledException e) { catch (CancelledException e) {
return; return;
@@ -19,13 +19,16 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException; import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader; import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.NList; import ghidra.app.util.bin.format.macho.commands.NList;
import ghidra.app.util.bin.format.macho.dyld.*; import ghidra.app.util.bin.format.macho.dyld.*;
import ghidra.app.util.importer.*; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.importer.MessageLogContinuesFactory;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -47,17 +50,17 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* *
* @param program The {@link Program} to build up * @param program The {@link Program} to build up
* @param provider The {@link ByteProvider} that contains the DYLD Cache bytes * @param provider The {@link ByteProvider} that contains the DYLD Cache bytes
* @param fileBytes Where the Mach-O's bytes came from
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections; * @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
* otherwise, false * otherwise, false
* @param log The log * @param log The log
* @param memoryConflictHandler How to handle memory conflicts that may occur
* @param monitor A cancelable task monitor * @param monitor A cancelable task monitor
*/ */
protected DyldCacheProgramBuilder(Program program, ByteProvider provider, protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log, boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) { TaskMonitor monitor) {
super(program, provider, log, memoryConflictHandler, monitor); super(program, provider, fileBytes, log, monitor);
this.shouldProcessSymbols = shouldProcessSymbols; this.shouldProcessSymbols = shouldProcessSymbols;
this.shouldCreateDylibSections = shouldCreateDylibSections; this.shouldCreateDylibSections = shouldCreateDylibSections;
} }
@@ -67,20 +70,19 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* *
* @param program The {@link Program} to build up * @param program The {@link Program} to build up
* @param provider The {@link ByteProvider} that contains the DYLD Cache's bytes * @param provider The {@link ByteProvider} that contains the DYLD Cache's bytes
* @param fileBytes Where the Mach-O's bytes came from
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections; * @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
* otherwise, false * otherwise, false
* @param log The log * @param log The log
* @param memoryConflictHandler How to handle memory conflicts that may occur
* @param monitor A cancelable task monitor * @param monitor A cancelable task monitor
* @throws Exception if a problem occurs * @throws Exception if a problem occurs
*/ */
public static void buildProgram(Program program, ByteProvider provider, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log, boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) throws Exception { TaskMonitor monitor) throws Exception {
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program, DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
provider, shouldProcessSymbols, shouldCreateDylibSections, log, memoryConflictHandler, provider, fileBytes, shouldProcessSymbols, shouldCreateDylibSections, log, monitor);
monitor);
dyldCacheProgramBuilder.build(); dyldCacheProgramBuilder.build();
} }
@@ -93,20 +95,12 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
dyldCacheHeader.parseFromFile(shouldProcessSymbols, log, monitor); dyldCacheHeader.parseFromFile(shouldProcessSymbols, log, monitor);
monitor.incrementProgress(1); monitor.incrementProgress(1);
try { setDyldCacheImageBase();
setDyldCacheImageBase(); processDyldCacheMemoryBlocks();
processDyldCacheMemoryBlocks(); markupHeaders();
markupHeaders(); markupBranchIslands();
markupBranchIslands(); createSymbols();
createSymbols(); processDylibs();
processDylibs();
}
finally {
if (mbu != null) {
mbu.dispose();
mbu = null;
}
}
} }
/** /**
@@ -135,9 +129,9 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
for (DyldCacheMappingInfo mappingInfo : mappingInfos) { for (DyldCacheMappingInfo mappingInfo : mappingInfos) {
long offset = mappingInfo.getFileOffset(); long offset = mappingInfo.getFileOffset();
long size = mappingInfo.getSize(); long size = mappingInfo.getSize();
mbu.createInitializedBlock("DYLD", space.getAddress(mappingInfo.getAddress()), MemoryBlockUtils.createInitializedBlock(program, false, "DYLD",
provider.getInputStream(offset), size, "", "", mappingInfo.isRead(), space.getAddress(mappingInfo.getAddress()), fileBytes, offset, size, "", "",
mappingInfo.isWrite(), mappingInfo.isExecute(), monitor); mappingInfo.isRead(), mappingInfo.isWrite(), mappingInfo.isExecute(), log);
if (offset + size > endOfMappedOffset) { if (offset + size > endOfMappedOffset) {
endOfMappedOffset = offset + size; endOfMappedOffset = offset + size;
} }
@@ -147,9 +141,10 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
if (endOfMappedOffset < provider.length()) { if (endOfMappedOffset < provider.length()) {
monitor.setMessage("Processing DYLD unmapped memory block..."); monitor.setMessage("Processing DYLD unmapped memory block...");
mbu.createOverlayBlock("FILE", AddressSpace.OTHER_SPACE.getAddress(endOfMappedOffset), MemoryBlockUtils.createInitializedBlock(program, true, "FILE",
provider.getInputStream(endOfMappedOffset), provider.length() - endOfMappedOffset, AddressSpace.OTHER_SPACE.getAddress(endOfMappedOffset), fileBytes,
"Useful bytes that don't get mapped into memory", "", false, false, false, monitor); endOfMappedOffset, provider.length() - endOfMappedOffset,
"Useful bytes that don't get mapped into memory", "", false, false, false, log);
} }
} }
@@ -228,10 +223,9 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
// easier // easier
monitor.setMessage("Parsing DYLIB's..."); monitor.setMessage("Parsing DYLIB's...");
monitor.initialize(dyldCacheHeader.getImageInfos().size()); monitor.initialize(dyldCacheHeader.getImageInfos().size());
TreeSet<DyldCacheMachoInfo> dyldCacheMachoInfoSet = List<DyldCacheMachoInfo> infoList = new ArrayList<>(dyldCacheHeader.getImageInfos().size());
new TreeSet<>((a, b) -> a.headerAddr.compareTo(b.headerAddr));
for (DyldCacheImageInfo dyldCacheImageInfo : dyldCacheHeader.getImageInfos()) { for (DyldCacheImageInfo dyldCacheImageInfo : dyldCacheHeader.getImageInfos()) {
dyldCacheMachoInfoSet.add(new DyldCacheMachoInfo(provider, infoList.add(new DyldCacheMachoInfo(provider,
dyldCacheImageInfo.getAddress() - dyldCacheHeader.getBaseAddress(), dyldCacheImageInfo.getAddress() - dyldCacheHeader.getBaseAddress(),
space.getAddress(dyldCacheImageInfo.getAddress()), dyldCacheImageInfo.getPath())); space.getAddress(dyldCacheImageInfo.getAddress()), dyldCacheImageInfo.getPath()));
monitor.checkCanceled(); monitor.checkCanceled();
@@ -240,8 +234,8 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
// Markup DyldCache Mach-O headers // Markup DyldCache Mach-O headers
monitor.setMessage("Marking up DYLIB headers..."); monitor.setMessage("Marking up DYLIB headers...");
monitor.initialize(dyldCacheMachoInfoSet.size()); monitor.initialize(infoList.size());
for (DyldCacheMachoInfo info : dyldCacheMachoInfoSet) { for (DyldCacheMachoInfo info : infoList) {
info.markupHeaders(); info.markupHeaders();
monitor.checkCanceled(); monitor.checkCanceled();
monitor.incrementProgress(1); monitor.incrementProgress(1);
@@ -249,8 +243,8 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
// Add DyldCache Mach-O's to program tree // Add DyldCache Mach-O's to program tree
monitor.setMessage("Adding DYLIB's to program tree..."); monitor.setMessage("Adding DYLIB's to program tree...");
monitor.initialize(dyldCacheMachoInfoSet.size()); monitor.initialize(infoList.size());
Iterator<DyldCacheMachoInfo> iter = dyldCacheMachoInfoSet.iterator(); Iterator<DyldCacheMachoInfo> iter = infoList.iterator();
if (iter.hasNext()) { if (iter.hasNext()) {
DyldCacheMachoInfo curr = iter.next(); DyldCacheMachoInfo curr = iter.next();
do { do {
@@ -263,13 +257,11 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
while (iter.hasNext()); while (iter.hasNext());
} }
// Process DyldCache DYLIB memory blocks. Need to do it in descending (reverse) order or // Process DyldCache DYLIB memory blocks.
// the memory block splitting will be way too slow.
monitor.setMessage("Processing DYLIB memory blocks..."); monitor.setMessage("Processing DYLIB memory blocks...");
monitor.initialize(dyldCacheMachoInfoSet.size()); monitor.initialize(infoList.size());
Iterator<DyldCacheMachoInfo> descendingIter = dyldCacheMachoInfoSet.descendingIterator(); for (DyldCacheMachoInfo info : infoList) {
while (descendingIter.hasNext()) { info.processMemoryBlocks();
descendingIter.next().processMemoryBlocks();
monitor.checkCanceled(); monitor.checkCanceled();
monitor.incrementProgress(1); monitor.incrementProgress(1);
} }
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.*; import java.util.*;
import generic.continues.RethrowContinuesFactory; import generic.continues.RethrowContinuesFactory;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.Option; import ghidra.app.util.Option;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.*;
@@ -28,6 +29,7 @@ import ghidra.app.util.bin.format.ubi.*;
import ghidra.app.util.importer.MemoryConflictHandler; import ghidra.app.util.importer.MemoryConflictHandler;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.DomainFolder; import ghidra.framework.model.DomainFolder;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.LittleEndianDataConverter; import ghidra.util.LittleEndianDataConverter;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@@ -81,15 +83,18 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
throws IOException { throws IOException {
try { try {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider);
// A Mach-O file may contain PRELINK information. If so, we use a special // A Mach-O file may contain PRELINK information. If so, we use a special
// program builder that knows how to deal with it. // program builder that knows how to deal with it.
List<PrelinkMap> prelinkList = MachoPrelinkUtils.parsePrelinkXml(provider, monitor); List<PrelinkMap> prelinkList = MachoPrelinkUtils.parsePrelinkXml(provider, monitor);
if (!prelinkList.isEmpty()) { if (!prelinkList.isEmpty()) {
MachoPrelinkProgramBuilder.buildProgram(program, provider, prelinkList, log, handler, MachoPrelinkProgramBuilder.buildProgram(program, provider, fileBytes, prelinkList,
monitor); log, monitor);
} }
else { else {
MachoProgramBuilder.buildProgram(program, provider, log, handler, monitor); MachoProgramBuilder.buildProgram(program, provider, fileBytes, log, handler,
monitor);
} }
} }
catch (Exception e) { catch (Exception e) {
@@ -25,7 +25,9 @@ import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.Section; import ghidra.app.util.bin.format.macho.Section;
import ghidra.app.util.bin.format.macho.commands.SegmentNames; import ghidra.app.util.bin.format.macho.commands.SegmentNames;
import ghidra.app.util.bin.format.macho.prelink.PrelinkMap; import ghidra.app.util.bin.format.macho.prelink.PrelinkMap;
import ghidra.app.util.importer.*; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.importer.MessageLogContinuesFactory;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.Pointer64DataType; import ghidra.program.model.data.Pointer64DataType;
@@ -48,15 +50,15 @@ public class MachoPrelinkProgramBuilder extends MachoProgramBuilder {
* *
* @param program The {@link Program} to build up. * @param program The {@link Program} to build up.
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes. * @param provider The {@link ByteProvider} that contains the Mach-O's bytes.
* @param fileBytes Where the Mach-O's bytes came from.
* @param prelinkList Parsed {@link PrelinkMap PRELINK} information. * @param prelinkList Parsed {@link PrelinkMap PRELINK} information.
* @param log The log. * @param log The log.
* @param memoryConflictHandler How to handle memory conflicts that may occur.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
*/ */
protected MachoPrelinkProgramBuilder(Program program, ByteProvider provider, protected MachoPrelinkProgramBuilder(Program program, ByteProvider provider,
List<PrelinkMap> prelinkList, MessageLog log, FileBytes fileBytes, List<PrelinkMap> prelinkList, MessageLog log,
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) { TaskMonitor monitor) {
super(program, provider, log, memoryConflictHandler, monitor); super(program, provider, fileBytes, log, monitor);
this.prelinkList = prelinkList; this.prelinkList = prelinkList;
} }
@@ -65,17 +67,16 @@ public class MachoPrelinkProgramBuilder extends MachoProgramBuilder {
* *
* @param program The {@link Program} to build up. * @param program The {@link Program} to build up.
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes. * @param provider The {@link ByteProvider} that contains the Mach-O's bytes.
* @param fileBytes Where the Mach-O's bytes came from.
* @param prelinkList Parsed {@link PrelinkMap PRELINK} information. * @param prelinkList Parsed {@link PrelinkMap PRELINK} information.
* @param log The log. * @param log The log.
* @param memoryConflictHandler How to handle memory conflicts that may occur.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
* @throws Exception if a problem occurs. * @throws Exception if a problem occurs.
*/ */
public static void buildProgram(Program program, ByteProvider provider, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
List<PrelinkMap> prelinkList, MessageLog log, List<PrelinkMap> prelinkList, MessageLog log, TaskMonitor monitor) throws Exception {
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) throws Exception {
MachoPrelinkProgramBuilder machoPrelinkProgramBuilder = new MachoPrelinkProgramBuilder( MachoPrelinkProgramBuilder machoPrelinkProgramBuilder = new MachoPrelinkProgramBuilder(
program, provider, prelinkList, log, memoryConflictHandler, monitor); program, provider, fileBytes, prelinkList, log, monitor);
machoPrelinkProgramBuilder.build(); machoPrelinkProgramBuilder.build();
} }
@@ -19,7 +19,7 @@ import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.MemoryBlockUtil; import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.*;
@@ -30,6 +30,7 @@ import ghidra.app.util.bin.format.objectiveC.ObjectiveC1_Constants;
import ghidra.app.util.importer.*; import ghidra.app.util.importer.*;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.function.OverlappingFunctionException; import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Processor; import ghidra.program.model.lang.Processor;
@@ -55,32 +56,32 @@ public class MachoProgramBuilder {
protected Program program; protected Program program;
protected ByteProvider provider; protected ByteProvider provider;
protected FileBytes fileBytes;
protected MessageLog log; protected MessageLog log;
protected TaskMonitor monitor; protected TaskMonitor monitor;
protected Memory memory; protected Memory memory;
protected Listing listing; protected Listing listing;
protected AddressSpace space; protected AddressSpace space;
protected MemoryBlockUtil mbu;
/** /**
* Creates a new {@link MachoProgramBuilder} based on the given information. * Creates a new {@link MachoProgramBuilder} based on the given information.
* *
* @param program The {@link Program} to build up. * @param program The {@link Program} to build up.
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes. * @param provider The {@link ByteProvider} that contains the Mach-O's bytes.
* @param fileBytes Where the Mach-O's bytes came from.
* @param log The log. * @param log The log.
* @param memoryConflictHandler How to handle memory conflicts that may occur.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
*/ */
protected MachoProgramBuilder(Program program, ByteProvider provider, MessageLog log, protected MachoProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) { MessageLog log, TaskMonitor monitor) {
this.program = program; this.program = program;
this.provider = provider; this.provider = provider;
this.fileBytes = fileBytes;
this.log = log; this.log = log;
this.monitor = monitor; this.monitor = monitor;
this.memory = program.getMemory(); this.memory = program.getMemory();
this.listing = program.getListing(); this.listing = program.getListing();
this.space = program.getAddressFactory().getDefaultAddressSpace(); this.space = program.getAddressFactory().getDefaultAddressSpace();
this.mbu = new MemoryBlockUtil(program, memoryConflictHandler);
} }
/** /**
@@ -88,15 +89,17 @@ public class MachoProgramBuilder {
* *
* @param program The {@link Program} to build up. * @param program The {@link Program} to build up.
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes. * @param provider The {@link ByteProvider} that contains the Mach-O's bytes.
* @param fileBytes Where the Mach-O's bytes came from.
* @param log The log. * @param log The log.
* @param memoryConflictHandler How to handle memory conflicts that may occur. * @param memoryConflictHandler How to handle memory conflicts that may occur.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
* @throws Exception if a problem occurs. * @throws Exception if a problem occurs.
*/ */
public static void buildProgram(Program program, ByteProvider provider, MessageLog log, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) throws Exception { MessageLog log, MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor)
throws Exception {
MachoProgramBuilder machoProgramBuilder = MachoProgramBuilder machoProgramBuilder =
new MachoProgramBuilder(program, provider, log, memoryConflictHandler, monitor); new MachoProgramBuilder(program, provider, fileBytes, log, monitor);
machoProgramBuilder.build(); machoProgramBuilder.build();
} }
@@ -115,33 +118,25 @@ public class MachoProgramBuilder {
} }
monitor.setCancelEnabled(true); monitor.setCancelEnabled(true);
try { setImageBase();
setImageBase(); processEntryPoint();
processEntryPoint(); processMemoryBlocks(machoHeader, provider.getName(), true, true);
processMemoryBlocks(machoHeader, provider.getName(), true, true); processUnsupportedLoadCommands();
processUnsupportedLoadCommands(); processSymbolTables();
processSymbolTables(); processIndirectSymbols();
processIndirectSymbols(); setRelocatableProperty();
setRelocatableProperty(); processLibraries();
processLibraries(); processProgramDescription();
processProgramDescription(); renameObjMsgSendRtpSymbol();
renameObjMsgSendRtpSymbol(); processUndefinedSymbols();
processUndefinedSymbols(); processAbsoluteSymbols();
processAbsoluteSymbols(); processDyldInfo();
processDyldInfo(); markupHeaders(machoHeader, headerAddr);
markupHeaders(machoHeader, headerAddr); markupSections();
markupSections(); processProgramVars();
processProgramVars(); loadSectionRelocations();
loadSectionRelocations(); loadExternalRelocations();
loadExternalRelocations(); loadLocalRelocations();
loadLocalRelocations();
}
finally {
if (mbu != null) {
mbu.dispose();
mbu = null;
}
}
} }
private void setImageBase() throws Exception { private void setImageBase() throws Exception {
@@ -219,12 +214,8 @@ public class MachoProgramBuilder {
return; return;
} }
// Create memory blocks for segments. Create them in reverse order so the splitting // Create memory blocks for segments.
// is more efficient. for (SegmentCommand segment : header.getAllSegments()) {
List<SegmentCommand> segments = header.getAllSegments();
segments.sort((SegmentCommand a, SegmentCommand b) -> Long.compare(b.getVMaddress(),
a.getVMaddress()));
for (SegmentCommand segment : segments) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
break; break;
} }
@@ -256,12 +247,9 @@ public class MachoProgramBuilder {
} }
// Create memory blocks for sections. They will be in the segments we just created, so the // Create memory blocks for sections. They will be in the segments we just created, so the
// segment blocks will be split and possibly replaced. Create them in reverse order so // segment blocks will be split and possibly replaced.
// the splitting is more efficient.
if (processSections) { if (processSections) {
List<Section> sections = header.getAllSections(); for (Section section : header.getAllSections()) {
sections.sort((Section a, Section b) -> Long.compare(b.getAddress(), a.getAddress()));
for (Section section : sections) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
break; break;
} }
@@ -331,12 +319,12 @@ public class MachoProgramBuilder {
if (intersectingBlocks.isEmpty()) { if (intersectingBlocks.isEmpty()) {
if (zeroFill) { if (zeroFill) {
// Treat zero-fill blocks as uninitialized to save space // Treat zero-fill blocks as uninitialized to save space
return mbu.createUninitializedBlock(false, name, start, dataLength, comment, source, return MemoryBlockUtils.createUninitializedBlock(program, false, name, start,
r, w, x); dataLength, comment, source, r, w, x, log);
} }
return mbu.createInitializedBlock(name, start, provider.getInputStream(dataOffset), return MemoryBlockUtils.createInitializedBlock(program, false, name, start, fileBytes,
dataLength, comment, source, r, w, x, monitor); dataOffset, dataLength, comment, source, r, w, x, log);
} }
// Split the starting block (if necessary). Splitting is not necessary if the start of our // Split the starting block (if necessary). Splitting is not necessary if the start of our
@@ -363,9 +351,7 @@ public class MachoProgramBuilder {
for (MemoryBlock block : memory.getBlocks()) { for (MemoryBlock block : memory.getBlocks()) {
if (range.intersects(block.getStart(), block.getEnd())) { if (range.intersects(block.getStart(), block.getEnd())) {
block.setName(name); block.setName(name);
block.setRead(r); block.setPermissions(r, w, x);
block.setWrite(w);
block.setExecute(x);
block.setSourceName(source); block.setSourceName(source);
block.setComment(comment); block.setComment(comment);
} }
@@ -23,6 +23,7 @@ import org.apache.commons.collections4.BidiMap;
import org.jdom.JDOMException; import org.jdom.JDOMException;
import generic.continues.RethrowContinuesFactory; import generic.continues.RethrowContinuesFactory;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.*;
import ghidra.app.util.bin.format.macho.commands.*; import ghidra.app.util.bin.format.macho.commands.*;
@@ -37,6 +38,7 @@ import ghidra.formats.gfilesystem.factory.GFileSystemBaseFactory;
import ghidra.framework.store.local.LocalFileSystem; import ghidra.framework.store.local.LocalFileSystem;
import ghidra.macosx.MacosxLanguageHelper; import ghidra.macosx.MacosxLanguageHelper;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.lang.LanguageCompilerSpecPair; import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.lang.LanguageService; import ghidra.program.model.lang.LanguageService;
@@ -185,9 +187,12 @@ public class PrelinkFileSystem extends GFileSystemBase implements GFileSystemPro
int id = program.startTransaction(getName()); int id = program.startTransaction(getName());
boolean success = false; boolean success = false;
try { try {
MachoProgramBuilder.buildProgram(program, FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, offset,
new ByteProviderWrapper(provider, offset, provider.length() - offset), provider.length() - offset);
new MessageLog(), MemoryConflictHandler.NEVER_OVERWRITE, monitor); ByteProvider providerWrapper =
new ByteProviderWrapper(provider, offset, provider.length() - offset);
MachoProgramBuilder.buildProgram(program, providerWrapper, fileBytes, new MessageLog(),
MemoryConflictHandler.NEVER_OVERWRITE, monitor);
program.setExecutableFormat(MachoLoader.MACH_O_NAME); program.setExecutableFormat(MachoLoader.MACH_O_NAME);
program.setExecutablePath(file.getPath()); program.setExecutablePath(file.getPath());