GP-3566: Adjusted MachoLoader and DyldCacheLoader options

This commit is contained in:
Ryan Kurtz
2023-06-22 07:42:43 -04:00
parent dea22bc2ba
commit 309be1eb05
18 changed files with 206 additions and 150 deletions
@@ -63,13 +63,13 @@ public class DataInCodeCommand extends LinkEditDataCommand {
} }
@Override @Override
public void markup(Program program, MachHeader header, Address addr, TaskMonitor monitor, public void markup(Program program, MachHeader header, Address addr, String source,
MessageLog log) throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
if (addr == null || datasize == 0) { if (addr == null || datasize == 0) {
return; return;
} }
super.markup(program, header, addr, monitor, log); super.markup(program, header, addr, source, monitor, log);
try { try {
for (DataInCodeEntry entry : entries) { for (DataInCodeEntry entry : entries) {
@@ -64,14 +64,14 @@ public class DyldChainedFixupsCommand extends LinkEditDataCommand {
} }
@Override @Override
public void markup(Program program, MachHeader header, Address addr, TaskMonitor monitor, public void markup(Program program, MachHeader header, Address addr, String source,
MessageLog log) throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
if (addr == null || datasize == 0) { if (addr == null || datasize == 0) {
return; return;
} }
super.markup(program, header, addr, monitor, log); super.markup(program, header, addr, source, monitor, log);
try { try {
DataUtilities.createData(program, addr, chainHeader.toDataType(), -1, DataUtilities.createData(program, addr, chainHeader.toDataType(), -1,
@@ -80,13 +80,13 @@ public class FunctionStartsCommand extends LinkEditDataCommand {
} }
@Override @Override
public void markup(Program program, MachHeader header, Address addr, TaskMonitor monitor, public void markup(Program program, MachHeader header, Address addr, String source,
MessageLog log) throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
if (addr == null || datasize == 0) { if (addr == null || datasize == 0) {
return; return;
} }
super.markup(program, header, addr, monitor, log); super.markup(program, header, addr, source, monitor, log);
SegmentCommand textSegment = header.getSegment(SegmentNames.SEG_TEXT); SegmentCommand textSegment = header.getSegment(SegmentNames.SEG_TEXT);
if (textSegment == null) { if (textSegment == null) {
@@ -83,13 +83,16 @@ public class LinkEditDataCommand extends LoadCommand {
} }
@Override @Override
public void markup(Program program, MachHeader header, Address addr, TaskMonitor monitor, public void markup(Program program, MachHeader header, Address addr, String source,
MessageLog log) throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
if (addr == null || datasize == 0) { if (addr == null || datasize == 0) {
return; return;
} }
String lcName = LoadCommandTypes.getLoadCommandName(getCommandType()); String name = LoadCommandTypes.getLoadCommandName(getCommandType());
program.getListing().setComment(addr, CodeUnit.PLATE_COMMENT, lcName); if (source != null) {
name += " - " + source;
}
program.getListing().setComment(addr, CodeUnit.PLATE_COMMENT, name);
} }
@Override @Override
@@ -103,12 +103,13 @@ public abstract class LoadCommand implements StructConverter {
* @param program The {@link Program} to mark up * @param program The {@link Program} to mark up
* @param header The Mach-O header * @param header The Mach-O header
* @param addr The {@link Address} of the start of load command data (could be null if no data) * @param addr The {@link Address} of the start of load command data (could be null if no data)
* @param source A name that represents where the header came from (could be null)
* @param monitor A cancellable task monitor * @param monitor A cancellable task monitor
* @param log The log * @param log The log
* @throws CancelledException if the user cancelled the operation * @throws CancelledException if the user cancelled the operation
*/ */
public void markup(Program program, MachHeader header, Address addr, TaskMonitor monitor, public void markup(Program program, MachHeader header, Address addr, String source,
MessageLog log) throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
// Default is no markup // Default is no markup
return; return;
} }
@@ -167,7 +167,7 @@ public class SymbolTableCommand extends LoadCommand {
@Override @Override
public void markup(Program program, MachHeader header, Address symbolTableAddr, public void markup(Program program, MachHeader header, Address symbolTableAddr,
TaskMonitor monitor, MessageLog log) throws CancelledException { String source, TaskMonitor monitor, MessageLog log) throws CancelledException {
if (symbolTableAddr == null) { if (symbolTableAddr == null) {
return; return;
} }
@@ -175,9 +175,12 @@ public class SymbolTableCommand extends LoadCommand {
Listing listing = program.getListing(); Listing listing = program.getListing();
ReferenceManager referenceManager = program.getReferenceManager(); ReferenceManager referenceManager = program.getReferenceManager();
String lcName = LoadCommandTypes.getLoadCommandName(getCommandType()); String name = LoadCommandTypes.getLoadCommandName(getCommandType());
if (source != null) {
name += " - " + source;
}
try { try {
listing.setComment(symbolTableAddr, CodeUnit.PLATE_COMMENT, lcName); listing.setComment(symbolTableAddr, CodeUnit.PLATE_COMMENT, name);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
NList nlist = symbols.get(i); NList nlist = symbols.get(i);
DataType dt = nlist.toDataType(); DataType dt = nlist.toDataType();
@@ -197,7 +200,7 @@ public class SymbolTableCommand extends LoadCommand {
} }
catch (Exception e) { catch (Exception e) {
log.appendMsg(SymbolTableCommand.class.getSimpleName(), log.appendMsg(SymbolTableCommand.class.getSimpleName(),
"Failed to markup %s.".formatted(lcName)); "Failed to markup %s.".formatted(name));
} }
} }
@@ -40,7 +40,6 @@ public class DyldChainedFixups {
private MachHeader machoHeader; private MachHeader machoHeader;
private Program program; private Program program;
private boolean shouldAddChainedFixupsRelocations;
private MessageLog log; private MessageLog log;
private TaskMonitor monitor; private TaskMonitor monitor;
private Memory memory; private Memory memory;
@@ -51,16 +50,13 @@ public class DyldChainedFixups {
* *
* @param program The {@link Program} * @param program The {@link Program}
* @param header The Mach-O header * @param header The Mach-O header
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false
* @param log The log * @param log The log
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
*/ */
public DyldChainedFixups(Program program, MachHeader header, public DyldChainedFixups(Program program, MachHeader header, MessageLog log,
boolean shouldAddChainedFixupsRelocations, MessageLog log, TaskMonitor monitor) { TaskMonitor monitor) {
this.program = program; this.program = program;
this.machoHeader = header; this.machoHeader = header;
this.shouldAddChainedFixupsRelocations = shouldAddChainedFixupsRelocations;
this.log = log; this.log = log;
this.monitor = monitor; this.monitor = monitor;
this.memory = program.getMemory(); this.memory = program.getMemory();
@@ -306,13 +302,11 @@ public class DyldChainedFixups {
byteLength = result.byteLength(); byteLength = result.byteLength();
} }
finally { finally {
if (shouldAddChainedFixupsRelocations) { program.getRelocationTable()
program.getRelocationTable() .add(chainLoc, status,
.add(chainLoc, status, (start ? 0x8000 : 0x4000) | (isAuthenticated ? 4 : 0) |
(start ? 0x8000 : 0x4000) | (isAuthenticated ? 4 : 0) | (isBound ? 2 : 0) | 1,
(isBound ? 2 : 0) | 1, new long[] { newChainValue }, byteLength, symName);
new long[] { newChainValue }, byteLength, symName);
}
} }
} }
// delay creating data until after memory has been changed // delay creating data until after memory has been changed
@@ -359,19 +359,19 @@ public class DyldCacheHeader implements StructConverter {
/** /**
* Parses the structures referenced by this {@link DyldCacheHeader} from a file. * Parses the structures referenced by this {@link DyldCacheHeader} from a file.
* *
* @param parseSymbols True if symbols should be parsed (could be very slow); otherwise, false * @param parseLocalSymbols True if local symbols should be parsed; otherwise, false
* @param log The log * @param log The log
* @param monitor A cancellable task monitor * @param monitor A cancellable task monitor
* @throws CancelledException if the user cancelled the operation * @throws CancelledException if the user cancelled the operation
*/ */
public void parseFromFile(boolean parseSymbols, MessageLog log, TaskMonitor monitor) public void parseFromFile(boolean parseLocalSymbols, MessageLog log, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
if (headerType >= 1) { if (headerType >= 1) {
parseMappingInfo(log, monitor); parseMappingInfo(log, monitor);
parseImageInfo(log, monitor); parseImageInfo(log, monitor);
} }
if (headerType >= 3) { if (headerType >= 3) {
if (parseSymbols) { if (parseLocalSymbols) {
parseLocalSymbolsInfo(log, monitor); parseLocalSymbolsInfo(log, monitor);
} }
} }
@@ -454,13 +454,14 @@ public class DyldCacheHeader implements StructConverter {
* Marks up this {@link DyldCacheHeader} with data structures and comments. * Marks up this {@link DyldCacheHeader} with data structures and comments.
* *
* @param program The {@link Program} to mark up * @param program The {@link Program} to mark up
* @param markupLocalSymbols True if the local symbols should be marked up; otherwise, false
* @param space The {@link Program}'s {@link AddressSpace} * @param space The {@link Program}'s {@link AddressSpace}
* @param monitor A cancellable task monitor * @param monitor A cancellable task monitor
* @param log The log * @param log The log
* @throws CancelledException if the user cancelled the operation * @throws CancelledException if the user cancelled the operation
*/ */
public void markup(Program program, AddressSpace space, TaskMonitor monitor, MessageLog log) public void markup(Program program, boolean markupLocalSymbols, AddressSpace space,
throws CancelledException { TaskMonitor monitor, MessageLog log) throws CancelledException {
if (headerType >= 1) { if (headerType >= 1) {
markupHeader(program, space, monitor, log); markupHeader(program, space, monitor, log);
markupMappingInfo(program, space, monitor, log); markupMappingInfo(program, space, monitor, log);
@@ -471,7 +472,9 @@ public class DyldCacheHeader implements StructConverter {
markupSlideInfo(program, space, monitor, log); markupSlideInfo(program, space, monitor, log);
} }
if (headerType >= 3) { if (headerType >= 3) {
markupLocalSymbolsInfo(program, space, monitor, log); if (markupLocalSymbols) {
markupLocalSymbolsInfo(program, space, monitor, log);
}
} }
if (headerType >= 6) { if (headerType >= 6) {
markupBranchPools(program, space, monitor, log); markupBranchPools(program, space, monitor, log);
@@ -107,9 +107,7 @@ public class DyldCacheLocalSymbolsInfo implements StructConverter {
public void markup(Program program, Address localSymbolsInfoAddr, TaskMonitor monitor, public void markup(Program program, Address localSymbolsInfoAddr, TaskMonitor monitor,
MessageLog log) throws CancelledException { MessageLog log) throws CancelledException {
markupLocalSymbols(program, localSymbolsInfoAddr, monitor, log); markupLocalSymbols(program, localSymbolsInfoAddr, monitor, log);
markupNList(program, localSymbolsInfoAddr, monitor, log);
// TODO: This is slow and not too useful. Add an option for it.
//markupNList(program, localSymbolsInfoAddr, monitor, log);
} }
/** /**
@@ -36,19 +36,43 @@ public class DyldCacheLoader extends AbstractProgramWrapperLoader {
public final static String DYLD_CACHE_NAME = "DYLD Cache"; public final static String DYLD_CACHE_NAME = "DYLD Cache";
/** Loader option to process symbols*/ /** Loader option to process symbols */
static final String PROCESS_SYMBOLS_OPTION_NAME = "Process symbols"; static final String PROCESS_LOCAL_SYMBOLS_OPTION_NAME = "Process local symbols";
/** Default value for loader option to process symbols */ /** Default value for loader option to process symbols */
static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true; static final boolean PROCESS_LOCAL_SYMBOLS_OPTION_DEFAULT = true;
/** Loader option to add relocation entries for chained fixups */ /** Loader option to process exports */
static final String PROCESS_EXPORTS_OPTION_NAME = "Process exports";
/** Default value for loader option to process exports */
static final boolean PROCESS_EXPORTS_OPTION_DEFAULT = true;
/** Loader option to mark up symbols */
static final String MARKUP_LOCAL_SYMBOLS_OPTION_NAME = "Markup local symbol nlists (slow)";
/** Default value for loader option to mark up symbols */
static final boolean MARKUP_LOCAL_SYMBOLS_OPTION_DEFAULT = false;
/** Loader option to process chained fixups */
static final String PROCESS_CHAINED_FIXUPS_OPTION_NAME = "Process chained fixups";
/** Default value for loader option to process chained fixups */
static final boolean PROCESS_CHAINED_FIXUPS_OPTION_DEFAULT = true;
/** Loader option to add chained fixups to relocation table */
static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME = static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME =
"Add relocation entries for chained fixups"; "Add chained fixups to relocation table";
/** Default value for loader option to add chained fixups relocation entries */ /** Default value for loader option to add chained fixups to relocation table */
static final boolean ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT = false; static final boolean ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT = false;
/** Loader option to mark up Mach-O load command data */
static final String MARKUP_MACHO_LC_DATA_OPTION_NAME = "Markup Mach-O load command data (slow)";
/** Default value for loader option to mark up Mach-O load command data */
static final boolean MARKUP_MACHO_LC_DATA_OPTION_DEFAULT = false;
@Override @Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException { public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>(); List<LoadSpec> loadSpecs = new ArrayList<>();
@@ -87,8 +111,7 @@ public class DyldCacheLoader extends AbstractProgramWrapperLoader {
try { try {
DyldCacheProgramBuilder.buildProgram(program, provider, DyldCacheProgramBuilder.buildProgram(program, provider,
MemoryBlockUtils.createFileBytes(program, provider, monitor), MemoryBlockUtils.createFileBytes(program, provider, monitor),
shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options), log, getDyldCacheOptions(options), log, monitor);
monitor);
} }
catch (CancelledException e) { catch (CancelledException e) {
return; return;
@@ -104,23 +127,44 @@ public class DyldCacheLoader extends AbstractProgramWrapperLoader {
List<Option> list = List<Option> list =
super.getDefaultOptions(provider, loadSpec, domainObject, loadIntoProgram); super.getDefaultOptions(provider, loadSpec, domainObject, loadIntoProgram);
if (!loadIntoProgram) { if (!loadIntoProgram) {
list.add(new Option(PROCESS_SYMBOLS_OPTION_NAME, PROCESS_SYMBOLS_OPTION_DEFAULT, list.add(
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-processSymbols")); new Option(PROCESS_LOCAL_SYMBOLS_OPTION_NAME, PROCESS_LOCAL_SYMBOLS_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-processLocalSymbols"));
list.add(
new Option(MARKUP_LOCAL_SYMBOLS_OPTION_NAME, MARKUP_LOCAL_SYMBOLS_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-markupLocalSymbols"));
list.add(
new Option(PROCESS_EXPORTS_OPTION_NAME, PROCESS_EXPORTS_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-processExports"));
list.add(new Option(PROCESS_CHAINED_FIXUPS_OPTION_NAME,
PROCESS_CHAINED_FIXUPS_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-processChainedFixups"));
list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class, ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations")); Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations"));
list.add(new Option(MARKUP_MACHO_LC_DATA_OPTION_NAME,
MARKUP_MACHO_LC_DATA_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-markupMachoLoadCommandData"));
} }
return list; return list;
} }
private boolean shouldProcessSymbols(List<Option> options) { private DyldCacheOptions getDyldCacheOptions(List<Option> options) {
return OptionUtils.getOption(PROCESS_SYMBOLS_OPTION_NAME, options, boolean processLocalSymbols = OptionUtils.getOption(PROCESS_LOCAL_SYMBOLS_OPTION_NAME,
PROCESS_SYMBOLS_OPTION_DEFAULT); options, PROCESS_LOCAL_SYMBOLS_OPTION_DEFAULT);
} boolean markupLocalSymbols = OptionUtils.getOption(MARKUP_LOCAL_SYMBOLS_OPTION_NAME,
options, MARKUP_LOCAL_SYMBOLS_OPTION_DEFAULT);
private boolean shouldAddChainedFixupsRelocations(List<Option> options) { boolean processExports = OptionUtils.getOption(PROCESS_EXPORTS_OPTION_NAME,
return OptionUtils.getOption(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, options, options, PROCESS_EXPORTS_OPTION_DEFAULT);
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT); boolean processChainedFixups = OptionUtils.getOption(PROCESS_CHAINED_FIXUPS_OPTION_NAME,
options, PROCESS_CHAINED_FIXUPS_OPTION_DEFAULT);
boolean addChainedFixupsRelocations =
OptionUtils.getOption(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, options,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT);
boolean markupMachoLoadCommandData = OptionUtils.getOption(MARKUP_MACHO_LC_DATA_OPTION_NAME,
options, MARKUP_MACHO_LC_DATA_OPTION_DEFAULT);
return new DyldCacheOptions(processLocalSymbols, markupLocalSymbols, processExports,
processChainedFixups, addChainedFixupsRelocations, markupMachoLoadCommandData);
} }
@Override @Override
@@ -0,0 +1,33 @@
/* ###
* 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.
*/
package ghidra.app.util.opinion;
/**
* Options from the {@link DyldCacheLoader}
*
* @param processLocalSymbols True if local symbols should be processes; otherwise, false
* @param markupLocalSymbols True if local symbols should be marked up; otherwise, false
* @param processExports True if exported symbols should be processed; otherwise, false
* @param processChainedFixups True if chained fixups should be processed; otherwise, false
* @param addChainedFixupsRelocations True if chained fixups should be added to the relocation
* table; otherwise false
* @param markupMachoLoadCommandData True if individual Mach-O load command data blocks should be
* marked up; otherwise, false
*/
public record DyldCacheOptions(boolean processLocalSymbols, boolean markupLocalSymbols,
boolean processExports, boolean processChainedFixups, boolean addChainedFixupsRelocations,
boolean markupMachoLoadCommandData) {
}
@@ -44,7 +44,7 @@ import ghidra.util.task.TaskMonitor;
*/ */
public class DyldCacheProgramBuilder extends MachoProgramBuilder { public class DyldCacheProgramBuilder extends MachoProgramBuilder {
private boolean shouldProcessSymbols; private DyldCacheOptions options;
/** /**
* Creates a new {@link DyldCacheProgramBuilder} based on the given information. * Creates a new {@link DyldCacheProgramBuilder} based on the given information.
@@ -52,18 +52,15 @@ 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 DYLD Cache's bytes came from * @param fileBytes Where the DYLD Cache's bytes came from
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @param options Options from the {@link DyldCacheLoader}
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false
* imported and combined into 1 program; otherwise, false
* @param log The log * @param log The log
* @param monitor A cancelable task monitor * @param monitor A cancelable task monitor
*/ */
protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes, protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations, MessageLog log, DyldCacheOptions options, MessageLog log,
TaskMonitor monitor) { TaskMonitor monitor) {
super(program, provider, fileBytes, shouldAddChainedFixupsRelocations, log, monitor); super(program, provider, fileBytes, log, monitor);
this.shouldProcessSymbols = shouldProcessSymbols; this.options = options;
} }
/** /**
@@ -72,19 +69,15 @@ 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 fileBytes Where the Mach-O's bytes came from
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @param options Options from the {@link DyldCacheLoader}
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false
* @param log The log * @param log The log
* @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, FileBytes fileBytes, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations, MessageLog log, DyldCacheOptions options, MessageLog log, TaskMonitor monitor) throws Exception {
TaskMonitor monitor) throws Exception {
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program, DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
provider, fileBytes, shouldProcessSymbols, shouldAddChainedFixupsRelocations, log, provider, fileBytes, options, log, monitor);
monitor);
dyldCacheProgramBuilder.build(); dyldCacheProgramBuilder.build();
} }
@@ -92,7 +85,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
protected void build() throws Exception { protected void build() throws Exception {
try (SplitDyldCache splitDyldCache = try (SplitDyldCache splitDyldCache =
new SplitDyldCache(provider, shouldProcessSymbols, log, monitor)) { new SplitDyldCache(provider, options.processLocalSymbols(), log, monitor)) {
// Set image base // Set image base
setDyldCacheImageBase(splitDyldCache.getDyldCacheHeader(0)); setDyldCacheImageBase(splitDyldCache.getDyldCacheHeader(0));
@@ -197,7 +190,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
monitor.setMessage("Marking up DYLD headers..."); monitor.setMessage("Marking up DYLD headers...");
monitor.initialize(1); monitor.initialize(1);
dyldCacheHeader.parseFromMemory(program, space, log, monitor); dyldCacheHeader.parseFromMemory(program, space, log, monitor);
dyldCacheHeader.markup(program, space, monitor, log); dyldCacheHeader.markup(program, options.markupLocalSymbols(), space, monitor, log);
monitor.incrementProgress(1); monitor.incrementProgress(1);
} }
@@ -233,7 +226,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* @throws Exception if there was a problem creating the local symbols * @throws Exception if there was a problem creating the local symbols
*/ */
private void createLocalSymbols(DyldCacheHeader dyldCacheHeader) throws Exception { private void createLocalSymbols(DyldCacheHeader dyldCacheHeader) throws Exception {
if (!shouldProcessSymbols) { if (!options.processLocalSymbols()) {
return; return;
} }
DyldCacheLocalSymbolsInfo localSymbolsInfo = dyldCacheHeader.getLocalSymbolsInfo(); DyldCacheLocalSymbolsInfo localSymbolsInfo = dyldCacheHeader.getLocalSymbolsInfo();
@@ -269,13 +262,17 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
*/ */
private void fixPageChains(DyldCacheHeader dyldCacheHeader) private void fixPageChains(DyldCacheHeader dyldCacheHeader)
throws MemoryAccessException, CancelledException { throws MemoryAccessException, CancelledException {
if (!options.processChainedFixups()) {
return;
}
// locate slide Info // locate slide Info
List<DyldCacheSlideInfoCommon> slideInfos = dyldCacheHeader.getSlideInfos(); List<DyldCacheSlideInfoCommon> slideInfos = dyldCacheHeader.getSlideInfos();
for (DyldCacheSlideInfoCommon info : slideInfos) { for (DyldCacheSlideInfoCommon info : slideInfos) {
int version = info.getVersion(); int version = info.getVersion();
log.appendMsg("Fixing page chains version: " + version); log.appendMsg("Fixing page chains version: " + version);
info.fixPageChains(program, dyldCacheHeader, shouldAddChainedFixupsRelocations, log, info.fixPageChains(program, dyldCacheHeader, options.addChainedFixupsRelocations(), log,
monitor); monitor);
} }
} }
@@ -312,21 +309,23 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
} }
// Create Exports // Create Exports
monitor.setMessage("Creating DYLIB exports...");
monitor.initialize(infoSet.size());
boolean exportsCreated = false; boolean exportsCreated = false;
for (DyldCacheMachoInfo info : infoSet) { if (options.processExports()) {
info.createExports(); monitor.setMessage("Creating DYLIB exports...");
monitor.checkCancelled(); monitor.initialize(infoSet.size());
monitor.incrementProgress(1); for (DyldCacheMachoInfo info : infoSet) {
exportsCreated = info.createExports();
monitor.checkCancelled();
monitor.incrementProgress(1);
}
} }
// Create DyldCache Mach-O symbols if local symbols are not present // Create DyldCache Mach-O symbols if local symbols are not present
if (shouldProcessSymbols && !localSymbolsPresent) { if (options.processLocalSymbols() && !localSymbolsPresent) {
monitor.setMessage("Creating DYLIB symbols..."); monitor.setMessage("Creating DYLIB symbols...");
monitor.initialize(infoSet.size()); monitor.initialize(infoSet.size());
for (DyldCacheMachoInfo info : infoSet) { for (DyldCacheMachoInfo info : infoSet) {
info.createSymbols(exportsCreated); info.createSymbols(options.processExports() && !exportsCreated);
monitor.checkCancelled(); monitor.checkCancelled();
monitor.incrementProgress(1); monitor.incrementProgress(1);
} }
@@ -341,6 +340,17 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
monitor.incrementProgress(1); monitor.incrementProgress(1);
} }
// Markup DyldCache Mach-O headers
if (options.markupMachoLoadCommandData()) {
monitor.setMessage("Marking up DYLIB load command data...");
monitor.initialize(infoSet.size());
for (DyldCacheMachoInfo info : infoSet) {
info.markupLoadCommandData();
monitor.checkCancelled();
monitor.incrementProgress(1);
}
}
// 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(infoSet.size()); monitor.initialize(infoSet.size());
@@ -441,9 +451,16 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
if (!name.isEmpty()) { if (!name.isEmpty()) {
listing.setComment(headerAddr, CodeUnit.PLATE_COMMENT, path); listing.setComment(headerAddr, CodeUnit.PLATE_COMMENT, path);
} }
}
// TODO: This can be slow. Add an option for it. /**
//DyldCacheProgramBuilder.this.markupLoadCommandData(header); * Marks up the Mach-O load command data.
*
* @throws Exception If there was a problem marking up the Mach-O's load command data
* @see DyldCacheProgramBuilder#markupLoadCommandData(MachHeader, String)
*/
public void markupLoadCommandData() throws Exception {
DyldCacheProgramBuilder.this.markupLoadCommandData(header, name);
} }
/** /**
@@ -111,20 +111,21 @@ public class DyldCacheUtils {
* Creates a new {@link SplitDyldCache} * Creates a new {@link SplitDyldCache}
* *
* @param baseProvider The {@link ByteProvider} of the "base" DYLD Cache file * @param baseProvider The {@link ByteProvider} of the "base" DYLD Cache file
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @param shouldProcessLocalSymbols True if local symbols should be processed; otherwise,
* false
* @param log The log * @param log The log
* @param monitor A cancelable task monitor * @param monitor A cancelable task monitor
* @throws IOException If there was an IO-related issue with processing the split DYLD Cache * @throws IOException If there was an IO-related issue with processing the split DYLD Cache
* @throws CancelledException If the user canceled the operation * @throws CancelledException If the user canceled the operation
*/ */
public SplitDyldCache(ByteProvider baseProvider, boolean shouldProcessSymbols, public SplitDyldCache(ByteProvider baseProvider, boolean shouldProcessLocalSymbols,
MessageLog log, TaskMonitor monitor) throws IOException, CancelledException { MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
// Setup "base" DYLD Cache // Setup "base" DYLD Cache
monitor.setMessage("Parsing " + baseProvider.getName() + " headers..."); monitor.setMessage("Parsing " + baseProvider.getName() + " headers...");
providers.add(baseProvider); providers.add(baseProvider);
DyldCacheHeader baseHeader = new DyldCacheHeader(new BinaryReader(baseProvider, true)); DyldCacheHeader baseHeader = new DyldCacheHeader(new BinaryReader(baseProvider, true));
baseHeader.parseFromFile(shouldProcessSymbols, log, monitor); baseHeader.parseFromFile(shouldProcessLocalSymbols, log, monitor);
headers.add(baseHeader); headers.add(baseHeader);
names.add(baseProvider.getName()); names.add(baseProvider.getName());
@@ -145,7 +146,7 @@ public class DyldCacheUtils {
providers.add(splitProvider); providers.add(splitProvider);
DyldCacheHeader splitHeader = DyldCacheHeader splitHeader =
new DyldCacheHeader(new BinaryReader(splitProvider, true)); new DyldCacheHeader(new BinaryReader(splitProvider, true));
splitHeader.parseFromFile(shouldProcessSymbols, log, monitor); splitHeader.parseFromFile(shouldProcessLocalSymbols, log, monitor);
headers.add(splitHeader); headers.add(splitHeader);
names.add(splitFSRL.getName()); names.add(splitFSRL.getName());
uuidToFileMap.put(splitHeader.getUUID(), splitFSRL); uuidToFileMap.put(splitHeader.getUUID(), splitFSRL);
@@ -20,13 +20,13 @@ import java.io.IOException;
import java.nio.file.AccessMode; import java.nio.file.AccessMode;
import java.util.*; import java.util.*;
import ghidra.app.util.*; import ghidra.app.util.MemoryBlockUtils;
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.*;
import ghidra.app.util.bin.format.ubi.*; import ghidra.app.util.bin.format.ubi.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.formats.gfilesystem.FileSystemService; import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.framework.model.DomainObject;
import ghidra.program.database.mem.FileBytes; 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;
@@ -41,13 +41,6 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
public final static String MACH_O_NAME = "Mac OS X Mach-O"; public final static String MACH_O_NAME = "Mac OS X Mach-O";
private static final long MIN_BYTE_LENGTH = 4; private static final long MIN_BYTE_LENGTH = 4;
/** Loader option to add relocation entries for chained fixups */
static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME =
"Add relocation entries for chained fixups";
/** Default value for loader option add chained fixups relocation entries */
static final boolean ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT = true;
@Override @Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException { public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>(); List<LoadSpec> loadSpecs = new ArrayList<>();
@@ -91,12 +84,10 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
// 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.
if (MachoPrelinkUtils.isMachoPrelink(provider, monitor)) { if (MachoPrelinkUtils.isMachoPrelink(provider, monitor)) {
MachoPrelinkProgramBuilder.buildProgram(program, provider, fileBytes, MachoPrelinkProgramBuilder.buildProgram(program, provider, fileBytes, log, monitor);
shouldAddChainedFixupsRelocations(options), log, monitor);
} }
else { else {
MachoProgramBuilder.buildProgram(program, provider, fileBytes, MachoProgramBuilder.buildProgram(program, provider, fileBytes, log, monitor);
shouldAddChainedFixupsRelocations(options), log, monitor);
} }
} }
catch (CancelledException e) { catch (CancelledException e) {
@@ -115,24 +106,6 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
return MACH_O_NAME; return MACH_O_NAME;
} }
@Override
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean loadIntoProgram) {
List<Option> list =
super.getDefaultOptions(provider, loadSpec, domainObject, loadIntoProgram);
if (!loadIntoProgram) {
list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations"));
}
return list;
}
private boolean shouldAddChainedFixupsRelocations(List<Option> options) {
return OptionUtils.getOption(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, options,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT);
}
/** /**
* Overrides the default implementation to account for Universal Binary (UBI) files. * Overrides the default implementation to account for Universal Binary (UBI) files.
* These must be specially parsed to find the internal file matching the current architecture. * These must be specially parsed to find the internal file matching the current architecture.
@@ -46,16 +46,13 @@ 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 fileBytes Where the Mach-O's bytes came from.
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false.
* @param log The log. * @param log The log.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
* @throws Exception if a problem occurs. * @throws Exception if a problem occurs.
*/ */
protected MachoPrelinkProgramBuilder(Program program, ByteProvider provider, protected MachoPrelinkProgramBuilder(Program program, ByteProvider provider,
FileBytes fileBytes, boolean shouldAddChainedFixupsRelocations, MessageLog log, FileBytes fileBytes, MessageLog log, TaskMonitor monitor) throws Exception {
TaskMonitor monitor) throws Exception { super(program, provider, fileBytes, log, monitor);
super(program, provider, fileBytes, shouldAddChainedFixupsRelocations, log, monitor);
} }
/** /**
@@ -64,17 +61,14 @@ 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 fileBytes Where the Mach-O's bytes came from.
* @param addChainedFixupsRelocations True if relocations should be added for chained fixups;
* otherwise, false.
* @param log The log. * @param log The log.
* @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, FileBytes fileBytes, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean addChainedFixupsRelocations, MessageLog log, TaskMonitor monitor) MessageLog log, TaskMonitor monitor) throws Exception {
throws Exception {
MachoPrelinkProgramBuilder machoPrelinkProgramBuilder = new MachoPrelinkProgramBuilder( MachoPrelinkProgramBuilder machoPrelinkProgramBuilder = new MachoPrelinkProgramBuilder(
program, provider, fileBytes, addChainedFixupsRelocations, log, monitor); program, provider, fileBytes, log, monitor);
machoPrelinkProgramBuilder.build(); machoPrelinkProgramBuilder.build();
} }
@@ -63,7 +63,6 @@ public class MachoProgramBuilder {
protected Program program; protected Program program;
protected ByteProvider provider; protected ByteProvider provider;
protected FileBytes fileBytes; protected FileBytes fileBytes;
protected boolean shouldAddChainedFixupsRelocations;
protected MessageLog log; protected MessageLog log;
protected TaskMonitor monitor; protected TaskMonitor monitor;
protected Memory memory; protected Memory memory;
@@ -76,17 +75,14 @@ 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 fileBytes Where the Mach-O's bytes came from.
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false.
* @param log The log. * @param log The log.
* @param monitor A cancelable task monitor. * @param monitor A cancelable task monitor.
*/ */
protected MachoProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes, protected MachoProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldAddChainedFixupsRelocations, MessageLog log, TaskMonitor monitor) { MessageLog log, TaskMonitor monitor) {
this.program = program; this.program = program;
this.provider = provider; this.provider = provider;
this.fileBytes = fileBytes; this.fileBytes = fileBytes;
this.shouldAddChainedFixupsRelocations = shouldAddChainedFixupsRelocations;
this.log = log; this.log = log;
this.monitor = monitor; this.monitor = monitor;
this.memory = program.getMemory(); this.memory = program.getMemory();
@@ -100,17 +96,14 @@ 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 fileBytes Where the Mach-O's bytes came from.
* @param addChainedFixupsRelocations True if relocations should be added for chained fixups;
* otherwise, false.
* @param log The log. * @param log The log.
* @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, FileBytes fileBytes, public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean addChainedFixupsRelocations, MessageLog log, TaskMonitor monitor) MessageLog log, TaskMonitor monitor) throws Exception {
throws Exception {
MachoProgramBuilder machoProgramBuilder = new MachoProgramBuilder(program, provider, MachoProgramBuilder machoProgramBuilder = new MachoProgramBuilder(program, provider,
fileBytes, addChainedFixupsRelocations, log, monitor); fileBytes, log, monitor);
machoProgramBuilder.build(); machoProgramBuilder.build();
} }
@@ -146,7 +139,7 @@ public class MachoProgramBuilder {
// Markup structures // Markup structures
markupHeaders(machoHeader, setupHeaderAddr(machoHeader.getAllSegments())); markupHeaders(machoHeader, setupHeaderAddr(machoHeader.getAllSegments()));
markupSections(); markupSections();
markupLoadCommandData(machoHeader); markupLoadCommandData(machoHeader, null);
markupChainedFixups(machoHeader, chainedFixups); markupChainedFixups(machoHeader, chainedFixups);
markupProgramVars(); markupProgramVars();
@@ -763,8 +756,7 @@ public class MachoProgramBuilder {
} }
public List<Address> processChainedFixups(MachHeader header) throws Exception { public List<Address> processChainedFixups(MachHeader header) throws Exception {
DyldChainedFixups dyldChainedFixups = DyldChainedFixups dyldChainedFixups = new DyldChainedFixups(program, header, log, monitor);
new DyldChainedFixups(program, header, shouldAddChainedFixupsRelocations, log, monitor);
return dyldChainedFixups.processChainedFixups(); return dyldChainedFixups.processChainedFixups();
} }
@@ -1250,13 +1242,14 @@ public class MachoProgramBuilder {
* Marks up {@link LoadCommand} dadta * Marks up {@link LoadCommand} dadta
* *
* @param header The Mach-O header * @param header The Mach-O header
* @param source A name that represents where the header came from (could be null)
* @throws Exception If there was a problem performing the markup * @throws Exception If there was a problem performing the markup
*/ */
protected void markupLoadCommandData(MachHeader header) throws Exception { protected void markupLoadCommandData(MachHeader header, String source) throws Exception {
for (LoadCommand cmd : header.getLoadCommands()) { for (LoadCommand cmd : header.getLoadCommands()) {
Address dataAddr = cmd.getDataAddress(header, space); Address dataAddr = cmd.getDataAddress(header, space);
if (dataAddr != null) { if (dataAddr != null) {
cmd.markup(program, header, dataAddr, monitor, log); cmd.markup(program, header, dataAddr, source, monitor, log);
} }
} }
} }
@@ -181,7 +181,7 @@ public class MachoPrelinkFileSystem extends GFileSystemBase implements GFileSyst
provider.length() - offset, monitor); provider.length() - offset, monitor);
ByteProvider providerWrapper = ByteProvider providerWrapper =
new ByteProviderWrapper(provider, offset, provider.length() - offset); new ByteProviderWrapper(provider, offset, provider.length() - offset);
MachoProgramBuilder.buildProgram(program, providerWrapper, fileBytes, false, MachoProgramBuilder.buildProgram(program, providerWrapper, fileBytes,
new MessageLog(), monitor); new MessageLog(), monitor);
AbstractProgramLoader.setProgramProperties(program, providerWrapper, AbstractProgramLoader.setProgramProperties(program, providerWrapper,
@@ -626,7 +626,6 @@ The Headless Analyzer uses the command-line parameters discussed below. See <a h
<LI><typewriter>-loader-loadSystemLibraries &lt;true|false&gt;</typewriter></LI> <LI><typewriter>-loader-loadSystemLibraries &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-libraryLoadDepth &lt;depth&gt;</typewriter></LI> <LI><typewriter>-loader-libraryLoadDepth &lt;depth&gt;</typewriter></LI>
<LI><typewriter>-loader-libraryDestinationFolder &lt;project path&gt;</typewriter></LI> <LI><typewriter>-loader-libraryDestinationFolder &lt;project path&gt;</typewriter></LI>
<LI><typewriter>-loader-addChainedFixupsRelocations &lt;true|false&gt;</typewriter></LI>
</UL> </UL>
</UL> </UL>
<br> <br>