mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-29 15:41:45 +00:00
Merge branch 'GT-2343_ryanmkurtz_DYLD-loader'
This commit is contained in:
commit
67198eb40f
@ -435,21 +435,25 @@ public class BinaryReader {
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public String readAsciiString(long index) throws IOException {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
while (true) {
|
||||
if (index == provider.length()) {
|
||||
// reached the end of the bytes and found no non-ascii data
|
||||
break;
|
||||
}
|
||||
byte b = provider.readByte(index++);
|
||||
if ((b >= 32) && (b <= 126)) {
|
||||
buffer.append((char) b);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
final int BUF_LEN = 1024;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
boolean done = false;
|
||||
while (!done && index < provider.length()) {
|
||||
long numToRead = Math.min(BUF_LEN, provider.length() - index);
|
||||
for (byte b : provider.readBytes(index, numToRead)) {
|
||||
if ((b >= 32) && (b <= 126)) {
|
||||
builder.append((char) b);
|
||||
}
|
||||
else {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
index += numToRead;
|
||||
}
|
||||
return buffer.toString().trim();
|
||||
|
||||
|
||||
return builder.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,8 +38,8 @@ public class NList implements StructConverter {
|
||||
private String string;
|
||||
private boolean is32bit;
|
||||
|
||||
static NList createNList(FactoryBundledWithBinaryReader reader,
|
||||
boolean is32bit, int stringTableOffset) throws IOException {
|
||||
public static NList createNList(FactoryBundledWithBinaryReader reader,
|
||||
boolean is32bit, long stringTableOffset) throws IOException {
|
||||
NList nList = (NList) reader.getFactory().create(NList.class);
|
||||
nList.initNList(reader, is32bit, stringTableOffset);
|
||||
return nList;
|
||||
@ -50,7 +50,8 @@ public class NList implements StructConverter {
|
||||
*/
|
||||
public NList() {}
|
||||
|
||||
private void initNList(FactoryBundledWithBinaryReader reader, boolean is32bit, int stringTableOffset) throws IOException {
|
||||
private void initNList(FactoryBundledWithBinaryReader reader, boolean is32bit,
|
||||
long stringTableOffset) throws IOException {
|
||||
this.is32bit = is32bit;
|
||||
|
||||
n_strx = reader.readNextInt();
|
||||
@ -64,9 +65,9 @@ public class NList implements StructConverter {
|
||||
n_value = reader.readNextLong();
|
||||
}
|
||||
try {
|
||||
string = reader.readAsciiString((stringTableOffset + n_strx) & 0xffffffffL);
|
||||
string = reader.readAsciiString(stringTableOffset + n_strx);
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (Exception e) {
|
||||
string = "";
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +59,8 @@ public class SubClientCommand extends LoadCommand {
|
||||
* Returns the client name.
|
||||
* @return the client name
|
||||
*/
|
||||
public String getClientName() {
|
||||
return client.getString();
|
||||
public LoadCommandString getClientName() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,8 +55,8 @@ public class SubFrameworkCommand extends LoadCommand {
|
||||
umbrella = LoadCommandString.createLoadCommandString(reader, this);
|
||||
}
|
||||
|
||||
public String getUmbrellaFrameworkName() {
|
||||
return umbrella.getString();
|
||||
public LoadCommandString getUmbrellaFrameworkName() {
|
||||
return umbrella;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,8 +55,8 @@ public class SubLibraryCommand extends LoadCommand {
|
||||
sub_library = LoadCommandString.createLoadCommandString(reader, this);
|
||||
}
|
||||
|
||||
public String getSubLibraryName() {
|
||||
return sub_library.getString();
|
||||
public LoadCommandString getSubLibraryName() {
|
||||
return sub_library;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,8 +55,8 @@ public class SubUmbrellaCommand extends LoadCommand {
|
||||
sub_umbrella = LoadCommandString.createLoadCommandString(reader, this);
|
||||
}
|
||||
|
||||
public String getSubUmbrellaFrameworkName() {
|
||||
return sub_umbrella.getString();
|
||||
public LoadCommandString getSubUmbrellaFrameworkName() {
|
||||
return sub_umbrella;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.file.formats.ios.dyldcache;
|
||||
package ghidra.app.util.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -0,0 +1,363 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_accelerate_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheAccelerateInfo implements StructConverter {
|
||||
|
||||
private int version;
|
||||
private int imageExtrasCount;
|
||||
private int imagesExtrasOffset;
|
||||
private int bottomUpListOffset;
|
||||
private int dylibTrieOffset;
|
||||
private int dylibTrieSize;
|
||||
private int initializersOffset;
|
||||
private int initializersCount;
|
||||
private int dofSectionsOffset;
|
||||
private int dofSectionsCount;
|
||||
private int reExportListOffset;
|
||||
private int reExportCount;
|
||||
private int depListOffset;
|
||||
private int depListCount;
|
||||
private int rangeTableOffset;
|
||||
private int rangeTableCount;
|
||||
private long dyldSectionAddr;
|
||||
|
||||
private BinaryReader reader;
|
||||
private List<DyldCacheImageInfoExtra> imageInfoExtraList;
|
||||
private List<DyldCacheAcceleratorInitializer> acceleratorInitializerList;
|
||||
private List<DyldCacheAcceleratorDof> acceleratorDofList;
|
||||
private List<DyldCacheRangeEntry> rangeEntryList;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheAccelerateInfo}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD accelerate info
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD accelerate info
|
||||
*/
|
||||
public DyldCacheAccelerateInfo(BinaryReader reader) throws IOException {
|
||||
this.reader = reader;
|
||||
|
||||
version = reader.readNextInt();
|
||||
imageExtrasCount = reader.readNextInt();
|
||||
imagesExtrasOffset = reader.readNextInt();
|
||||
bottomUpListOffset = reader.readNextInt();
|
||||
dylibTrieOffset = reader.readNextInt();
|
||||
dylibTrieSize = reader.readNextInt();
|
||||
initializersOffset = reader.readNextInt();
|
||||
initializersCount = reader.readNextInt();
|
||||
dofSectionsOffset = reader.readNextInt();
|
||||
dofSectionsCount = reader.readNextInt();
|
||||
reExportListOffset = reader.readNextInt();
|
||||
reExportCount = reader.readNextInt();
|
||||
depListOffset = reader.readNextInt();
|
||||
depListCount = reader.readNextInt();
|
||||
rangeTableOffset = reader.readNextInt();
|
||||
rangeTableCount = reader.readNextInt();
|
||||
dyldSectionAddr = reader.readNextLong();
|
||||
|
||||
imageInfoExtraList = new ArrayList<>(imageExtrasCount);
|
||||
acceleratorInitializerList = new ArrayList<>(initializersCount);
|
||||
acceleratorDofList = new ArrayList<>(dofSectionsCount);
|
||||
rangeEntryList = new ArrayList<>(rangeTableCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the structures referenced by this {@link DyldCacheAccelerateInfo}.
|
||||
*
|
||||
* @param program The {@link Program} to parse.
|
||||
* @param accelerateInfoAddr The {@link Address} of the {@link DyldCacheAccelerateInfo}
|
||||
* @param log The log
|
||||
* @param monitor A cancellable task monitor
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void parse(Program program, Address accelerateInfoAddr, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
parseImageInfoExtra(program, accelerateInfoAddr, log, monitor);
|
||||
parseAcceleratorInitializer(program, accelerateInfoAddr, log, monitor);
|
||||
parseAcceleratorDof(program, accelerateInfoAddr, log, monitor);
|
||||
parseRangeEntry(program, accelerateInfoAddr, log, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up this {@link DyldCacheAccelerateInfo} with data structures and comments.
|
||||
*
|
||||
* @param program The {@link Program} to mark up
|
||||
* @param accelerateInfoAddr The {@link Address} of the {@link DyldCacheAccelerateInfo}
|
||||
* @param monitor A cancellable task monitor
|
||||
* @param log The log
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void markup(Program program, Address accelerateInfoAddr, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
markupImageInfoExtra(program, accelerateInfoAddr, monitor, log);
|
||||
markupAcceleratorInitializer(program, accelerateInfoAddr, monitor, log);
|
||||
markupAcceleratorDof(program, accelerateInfoAddr, monitor, log);
|
||||
markupReExportList(program, accelerateInfoAddr, monitor, log);
|
||||
markupDependencies(program, accelerateInfoAddr, monitor, log);
|
||||
markupRangeEntry(program, accelerateInfoAddr, monitor, log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_accelerate_info", 0);
|
||||
struct.add(DWORD, "version", "currently 1");
|
||||
struct.add(DWORD, "imageExtrasCount", "does not include aliases");
|
||||
struct.add(DWORD, "imagesExtrasOffset",
|
||||
"offset into this chunk of first dyld_cache_image_info_extra");
|
||||
struct.add(DWORD, "bottomUpListOffset",
|
||||
"offset into this chunk to start of 16-bit array of sorted image indexes");
|
||||
struct.add(DWORD, "dylibTrieOffset",
|
||||
"offset into this chunk to start of trie containing all dylib paths");
|
||||
struct.add(DWORD, "dylibTrieSize", "size of trie containing all dylib paths");
|
||||
struct.add(DWORD, "initializersOffset",
|
||||
"offset into this chunk to start of initializers list");
|
||||
struct.add(DWORD, "initializersCount", "size of initializers list");
|
||||
struct.add(DWORD, "dofSectionsOffset",
|
||||
"offset into this chunk to start of DOF (DTrace object format) sections list");
|
||||
struct.add(DWORD, "dofSectionsCount", "size of DOF (DTrace object format sections list)");
|
||||
struct.add(DWORD, "reExportListOffset",
|
||||
"offset into this chunk to start of 16-bit array of re-exports");
|
||||
struct.add(DWORD, "reExportCount", "size of re-exports");
|
||||
struct.add(DWORD, "depListOffset",
|
||||
"offset into this chunk to start of 16-bit array of dependencies (0x8000 bit set if upward)");
|
||||
struct.add(DWORD, "depListCount", "size of dependencies");
|
||||
struct.add(DWORD, "rangeTableOffset", "offset into this chunk to start of ss");
|
||||
struct.add(DWORD, "rangeTableCount", "size of dependencies");
|
||||
struct.add(QWORD, "dyldSectionAddr", "address of libdyld's __dyld section in unslid cache");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
|
||||
private void parseImageInfoExtra(Program program, Address accelerateInfoAddr, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD image image info extras...");
|
||||
monitor.initialize(imageExtrasCount);
|
||||
reader.setPointerIndex(imagesExtrasOffset);
|
||||
try {
|
||||
for (int i = 0; i < imageExtrasCount; ++i) {
|
||||
imageInfoExtraList.add(new DyldCacheImageInfoExtra(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_image_info_extra.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAcceleratorInitializer(Program program, Address accelerateInfoAddr,
|
||||
MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD accelerator initializers...");
|
||||
monitor.initialize(initializersCount);
|
||||
reader.setPointerIndex(initializersOffset);
|
||||
try {
|
||||
for (int i = 0; i < initializersCount; ++i) {
|
||||
acceleratorInitializerList.add(new DyldCacheAcceleratorInitializer(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_accelerator_initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAcceleratorDof(Program program, Address accelerateInfoAddr, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD DOF sections...");
|
||||
monitor.initialize(dofSectionsCount);
|
||||
reader.setPointerIndex(dofSectionsOffset);
|
||||
try {
|
||||
for (int i = 0; i < dofSectionsCount; ++i) {
|
||||
acceleratorDofList.add(new DyldCacheAcceleratorDof(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_accelerator_dof.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRangeEntry(Program program, Address accelerateInfoAddr, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD range entries...");
|
||||
monitor.initialize(rangeTableCount);
|
||||
reader.setPointerIndex(rangeTableOffset);
|
||||
try {
|
||||
for (int i = 0; i < rangeTableCount; ++i) {
|
||||
rangeEntryList.add(new DyldCacheRangeEntry(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_range_entry.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupImageInfoExtra(Program program, Address accelerateInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD image info extras...");
|
||||
monitor.initialize(imageInfoExtraList.size());
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(imagesExtrasOffset);
|
||||
for (DyldCacheImageInfoExtra imageInfoExtra : imageInfoExtraList) {
|
||||
Data d = DataUtilities.createData(program, addr, imageInfoExtra.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_image_info_extra.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupAcceleratorInitializer(Program program, Address accelerateInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD accelerator initializers...");
|
||||
monitor.initialize(acceleratorInitializerList.size());
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(initializersOffset);
|
||||
for (DyldCacheAcceleratorInitializer initializer : acceleratorInitializerList) {
|
||||
Data d = DataUtilities.createData(program, addr, initializer.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
Address funcAddr = program.getImageBase().add(initializer.getFunctionsOffset());
|
||||
try {
|
||||
program.getFunctionManager().createFunction(null, funcAddr,
|
||||
new AddressSet(funcAddr), SourceType.ANALYSIS);
|
||||
}
|
||||
catch (OverlappingFunctionException | InvalidInputException e) {
|
||||
// Function already created...skip
|
||||
}
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_accelerator_initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupAcceleratorDof(Program program, Address accelerateInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD DOF sections...");
|
||||
monitor.initialize(acceleratorDofList.size());
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(dofSectionsOffset);
|
||||
for (DyldCacheAcceleratorDof dof : acceleratorDofList) {
|
||||
Data d = DataUtilities.createData(program, addr, dof.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_accelerator_dof.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupReExportList(Program program, Address accelerateInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD re-exports...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(reExportListOffset);
|
||||
DataType dt = new ArrayDataType(WORD, reExportCount, WORD.getLength());
|
||||
DataUtilities.createData(program, addr, dt, -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
program.getListing().setComment(addr, CodeUnit.EOL_COMMENT, "re-exports");
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup reExportList.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupDependencies(Program program, Address accelerateInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD dependencies...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(depListOffset);
|
||||
DataType dt = new ArrayDataType(WORD, depListCount, WORD.getLength());
|
||||
DataUtilities.createData(program, addr, dt, -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
program.getListing().setComment(addr, CodeUnit.EOL_COMMENT, "dependencies");
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dependences.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupRangeEntry(Program program, Address accelerateInfoAddr, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD range entries...");
|
||||
monitor.initialize(rangeEntryList.size());
|
||||
try {
|
||||
Address addr = accelerateInfoAddr.add(rangeTableOffset);
|
||||
for (DyldCacheRangeEntry rangeEntry : rangeEntryList) {
|
||||
Data d = DataUtilities.createData(program, addr, rangeEntry.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_range_entry.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_accelerator_dof structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheAcceleratorDof implements StructConverter {
|
||||
|
||||
private long sectionAddress;
|
||||
private int sectionSize;
|
||||
private int imageIndex;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheAcceleratorDof}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD accelerator DOF
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD accelerator DOF
|
||||
*/
|
||||
public DyldCacheAcceleratorDof(BinaryReader reader) throws IOException {
|
||||
sectionAddress = reader.readNextLong();
|
||||
sectionSize = reader.readNextInt();
|
||||
imageIndex = reader.readNextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_accelerator_dof", 0);
|
||||
struct.add(QWORD, "sectionAddress", "");
|
||||
struct.add(DWORD, "sectionSize", "");
|
||||
struct.add(DWORD, "imageIndex", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_accelerator_initializer structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheAcceleratorInitializer implements StructConverter {
|
||||
|
||||
private int functionsOffset;
|
||||
private int imageIndex;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheAcceleratorInitializer}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD accelerator
|
||||
* initializer
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD accelerator
|
||||
* initializer
|
||||
*/
|
||||
public DyldCacheAcceleratorInitializer(BinaryReader reader) throws IOException {
|
||||
functionsOffset = reader.readNextInt();
|
||||
imageIndex = reader.readNextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the functions offset, which is an address offset from the start of the cache mapping.
|
||||
*
|
||||
* @return The functions offset, which is an address offset from the start of the cache
|
||||
* mapping
|
||||
*/
|
||||
public int getFunctionsOffset() {
|
||||
return functionsOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_accelerator_initializer", 0);
|
||||
struct.add(DWORD, "functionsOffset", "");
|
||||
struct.add(DWORD, "imageIndex", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.file.formats.ios.dyldcache;
|
||||
package ghidra.app.util.bin.format.macho.dyld;
|
||||
|
||||
public final class DyldCacheConstants {
|
||||
|
@ -0,0 +1,675 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_header structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheHeader implements StructConverter {
|
||||
|
||||
private byte[] magic;
|
||||
private int mappingOffset;
|
||||
private int mappingCount;
|
||||
private int imagesOffset;
|
||||
private int imagesCount;
|
||||
private long dyldBaseAddress;
|
||||
private long codeSignatureOffset;
|
||||
private long codeSignatureSize;
|
||||
private long slideInfoOffset;
|
||||
private long slideInfoSize;
|
||||
private long localSymbolsOffset;
|
||||
private long localSymbolsSize;
|
||||
private byte[] uuid;
|
||||
private long cacheType;
|
||||
private int branchPoolsOffset;
|
||||
private int branchPoolsCount;
|
||||
private long accelerateInfoAddr;
|
||||
private long accelerateInfoSize;
|
||||
private long imagesTextOffset;
|
||||
private long imagesTextCount;
|
||||
|
||||
private int headerType;
|
||||
private BinaryReader reader;
|
||||
private long baseAddress;
|
||||
private List<DyldCacheMappingInfo> mappingInfoList;
|
||||
private List<DyldCacheImageInfo> imageInfoList;
|
||||
private DyldCacheSlideInfoCommon slideInfo;
|
||||
private DyldCacheLocalSymbolsInfo localSymbolsInfo;
|
||||
private List<Long> branchPoolList;
|
||||
private DyldCacheAccelerateInfo accelerateInfo;
|
||||
private List<DyldCacheImageTextInfo> imageTextInfoList;
|
||||
private DyldArchitecture architecture;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheHeader}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD cache header
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD cache header
|
||||
*/
|
||||
public DyldCacheHeader(BinaryReader reader) throws IOException {
|
||||
this.reader = reader;
|
||||
|
||||
// ------ HEADER 1 ---------
|
||||
headerType = 1; // https://opensource.apple.com/source/dyld/dyld-95.3/launch-cache/dyld_cache_format.h.auto.html
|
||||
magic = reader.readNextByteArray(16);
|
||||
mappingOffset = reader.readNextInt();
|
||||
mappingCount = reader.readNextInt();
|
||||
imagesOffset = reader.readNextInt();
|
||||
imagesCount = reader.readNextInt();
|
||||
dyldBaseAddress = reader.readNextLong();
|
||||
|
||||
// ------ HEADER 2 ---------
|
||||
if (mappingOffset > 0x28) {
|
||||
headerType = 2; // https://opensource.apple.com/source/dyld/dyld-195.5/launch-cache/dyld_cache_format.h.auto.html
|
||||
codeSignatureOffset = reader.readNextLong();
|
||||
codeSignatureSize = reader.readNextLong();
|
||||
slideInfoOffset = reader.readNextLong();
|
||||
slideInfoSize = reader.readNextLong();
|
||||
}
|
||||
|
||||
// ------ HEADER 3 ---------
|
||||
if (mappingOffset > 0x48) {
|
||||
headerType = 3; // No header file for this version (without the following UUID), but there are images of this version
|
||||
localSymbolsOffset = reader.readNextLong();
|
||||
localSymbolsSize = reader.readNextLong();
|
||||
}
|
||||
|
||||
// ------ HEADER 4 ---------
|
||||
if (mappingOffset > 0x58) {
|
||||
headerType = 4; // https://opensource.apple.com/source/dyld/dyld-239.3/launch-cache/dyld_cache_format.h.auto.html
|
||||
uuid = reader.readNextByteArray(16);
|
||||
}
|
||||
|
||||
// ------ HEADER 5 ---------
|
||||
if (mappingOffset > 0x68) {
|
||||
headerType = 5; // https://opensource.apple.com/source/dyld/dyld-360.14/launch-cache/dyld_cache_format.h.auto.html
|
||||
cacheType = reader.readNextLong();
|
||||
}
|
||||
|
||||
// ------ HEADER 6 ---------
|
||||
if (mappingOffset > 0x70) {
|
||||
headerType = 6; // https://opensource.apple.com/source/dyld/dyld-421.1/launch-cache/dyld_cache_format.h.auto.html
|
||||
branchPoolsOffset = reader.readNextInt();
|
||||
branchPoolsCount = reader.readNextInt();
|
||||
accelerateInfoAddr = reader.readNextLong();
|
||||
accelerateInfoSize = reader.readNextLong();
|
||||
imagesTextOffset = reader.readNextLong();
|
||||
imagesTextCount = reader.readNextLong();
|
||||
}
|
||||
|
||||
baseAddress = reader.readLong(mappingOffset);
|
||||
architecture = DyldArchitecture.getArchitecture(new String(magic).trim());
|
||||
|
||||
mappingInfoList = new ArrayList<>(mappingCount);
|
||||
imageInfoList = new ArrayList<>(imagesCount);
|
||||
branchPoolList = new ArrayList<>(branchPoolsCount);
|
||||
imageTextInfoList = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 log The log
|
||||
* @param monitor A cancellable task monitor
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void parseFromFile(boolean parseSymbols, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
if (headerType >= 1) {
|
||||
parseMappingInfo(log, monitor);
|
||||
parseImageInfo(log, monitor);
|
||||
}
|
||||
if (headerType >= 2) {
|
||||
parseSlideInfo(log, monitor);
|
||||
}
|
||||
if (headerType >= 3) {
|
||||
if (parseSymbols) {
|
||||
parseLocalSymbolsInfo(log, monitor);
|
||||
}
|
||||
}
|
||||
if (headerType >= 6) {
|
||||
parseBranchPools(log, monitor);
|
||||
parseImageTextInfo(log, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the structures referenced by this {@link DyldCacheHeader} from memory.
|
||||
*
|
||||
* @param program The {@link Program} whose memory to parse
|
||||
* @param space The {@link Program}'s {@link AddressSpace}
|
||||
* @param log The log
|
||||
* @param monitor A cancellable task monitor
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void parseFromMemory(Program program, AddressSpace space, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
if (headerType >= 6) {
|
||||
parseAcceleratorInfo(program, space, log, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up this {@link DyldCacheHeader} with data structures and comments.
|
||||
*
|
||||
* @param program The {@link Program} to mark up
|
||||
* @param space The {@link Program}'s {@link AddressSpace}
|
||||
* @param monitor A cancellable task monitor
|
||||
* @param log The log
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void markup(Program program, AddressSpace space, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
if (headerType >= 1) {
|
||||
markupHeader(program, space, monitor, log);
|
||||
markupMappingInfo(program, space, monitor, log);
|
||||
markupImageInfo(program, space, monitor, log);
|
||||
}
|
||||
if (headerType >= 2) {
|
||||
markupCodeSignature(program, space, monitor, log);
|
||||
markupSlideInfo(program, space, monitor, log);
|
||||
}
|
||||
if (headerType >= 3) {
|
||||
markupLocalSymbolsInfo(program, space, monitor, log);
|
||||
}
|
||||
if (headerType >= 6) {
|
||||
markupBranchPools(program, space, monitor, log);
|
||||
markupAcceleratorInfo(program, space, monitor, log);
|
||||
markupImageTextInfo(program, space, monitor, log);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base address of the DYLD cache. This is where the cache should be loaded in
|
||||
* memory.
|
||||
*
|
||||
* @return The base address of the DYLD cache
|
||||
*/
|
||||
public long getBaseAddress() {
|
||||
return baseAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the magic bytes, which contain version information.
|
||||
*
|
||||
* @return The magic bytes
|
||||
*/
|
||||
public byte[] getMagic() {
|
||||
return magic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of {@link DyldCacheMappingInfo}s. Requires header to have been parsed.
|
||||
*
|
||||
* @return The {@link List} of {@link DyldCacheMappingInfo}s
|
||||
*/
|
||||
public List<DyldCacheMappingInfo> getMappingInfos() {
|
||||
return mappingInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file offset to first {@link DyldCacheImageInfo}.
|
||||
*
|
||||
* @return The file offset to first {@link DyldCacheImageInfo}
|
||||
*/
|
||||
public int getImagesOffset() {
|
||||
return imagesOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of {@link DyldCacheImageInfo}s.
|
||||
*
|
||||
* @return The number of {@link DyldCacheImageInfo}s
|
||||
*/
|
||||
public int getImagesCount() {
|
||||
return imagesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of {@link DyldCacheImageInfo}s. Requires header to have been parsed.
|
||||
*
|
||||
* @return The {@link List} of {@link DyldCacheImageInfo}s
|
||||
*/
|
||||
public List<DyldCacheImageInfo> getImageInfos() {
|
||||
return imageInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link DyldCacheLocalSymbolsInfo}.
|
||||
*
|
||||
* @return The {@link DyldCacheLocalSymbolsInfo}. Could be be null if it didn't parse.
|
||||
*/
|
||||
public DyldCacheLocalSymbolsInfo getLocalSymbolsInfo() {
|
||||
return localSymbolsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of branch pool address. Requires header to have been parsed.
|
||||
*
|
||||
* @return The {@link List} of branch pool address
|
||||
*/
|
||||
public List<Long> getBranchPoolAddresses() {
|
||||
return branchPoolList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets architecture information.
|
||||
*
|
||||
* @return architecture information
|
||||
*/
|
||||
public DyldArchitecture getArchitecture() {
|
||||
return architecture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_header", 0);
|
||||
if (headerType >= 1) {
|
||||
struct.add(new ArrayDataType(ASCII, 16, 1), "magic", "e.g. \"dyld_v0 i386\"");
|
||||
struct.add(DWORD, "mappingOffset", "file offset to first dyld_cache_mapping_info");
|
||||
struct.add(DWORD, "mappingCount", "number of dyld_cache_mapping_info entries");
|
||||
struct.add(DWORD, "imagesOffset", "file offset to first dyld_cache_image_info");
|
||||
struct.add(DWORD, "imagesCount", "number of dyld_cache_image_info entries");
|
||||
struct.add(QWORD, "dyldBaseAddress", "base address of dyld when cache was built");
|
||||
}
|
||||
if (headerType >= 2) {
|
||||
struct.add(QWORD, "codeSignatureOffset", "file offset of code signature blob");
|
||||
struct.add(QWORD, "codeSignatureSize",
|
||||
"size of code signature blob (zero means to end of file)");
|
||||
struct.add(QWORD, "slideInfoOffset", "file offset of kernel slid info");
|
||||
struct.add(QWORD, "slideInfoSize", "size of kernel slid info");
|
||||
}
|
||||
if (headerType >= 3) {
|
||||
struct.add(QWORD, "localSymbolsOffset",
|
||||
"file offset of where local symbols are stored");
|
||||
struct.add(QWORD, "localSymbolsSize", "size of local symbols information");
|
||||
}
|
||||
if (headerType >= 4) {
|
||||
struct.add(new ArrayDataType(BYTE, 16, 1), "uuid",
|
||||
"unique value for each shared cache file");
|
||||
}
|
||||
if (headerType >= 5) {
|
||||
struct.add(QWORD, "cacheType", "0 for development, 1 for production");
|
||||
}
|
||||
if (headerType >= 6) {
|
||||
struct.add(DWORD, "branchPoolsOffset",
|
||||
"file offset to table of uint64_t pool addresses");
|
||||
struct.add(DWORD, "branchPoolsCount", "number of uint64_t entries");
|
||||
struct.add(QWORD, "accelerateInfoAddr", "(unslid) address of optimization info");
|
||||
struct.add(QWORD, "accelerateInfoSize", "size of optimization info");
|
||||
struct.add(QWORD, "imagesTextOffset",
|
||||
"file offset to first dyld_cache_image_text_info");
|
||||
struct.add(QWORD, "imagesTextCount", "number of dyld_cache_image_text_info entries");
|
||||
}
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
|
||||
private void parseMappingInfo(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD mapping info...");
|
||||
monitor.initialize(mappingCount);
|
||||
try {
|
||||
reader.setPointerIndex(mappingOffset);
|
||||
for (int i = 0; i < mappingCount; ++i) {
|
||||
mappingInfoList.add(new DyldCacheMappingInfo(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_mapping_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseImageInfo(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD image info...");
|
||||
monitor.initialize(imagesCount);
|
||||
try {
|
||||
reader.setPointerIndex(imagesOffset);
|
||||
for (int i = 0; i < imagesCount; ++i) {
|
||||
imageInfoList.add(new DyldCacheImageInfo(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_image_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseSlideInfo(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD slide info...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
reader.setPointerIndex(slideInfoOffset);
|
||||
slideInfo = new DyldCacheSlideInfoCommon(reader);
|
||||
reader.setPointerIndex(slideInfoOffset);
|
||||
switch (slideInfo.getVersion()) {
|
||||
case 1:
|
||||
slideInfo = new DyldCacheSlideInfo1(reader);
|
||||
break;
|
||||
case 2:
|
||||
slideInfo = new DyldCacheSlideInfo2(reader);
|
||||
break;
|
||||
case 3:
|
||||
slideInfo = new DyldCacheSlideInfo3(reader);
|
||||
break;
|
||||
default:
|
||||
throw new IOException();
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_slide_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLocalSymbolsInfo(MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD local symbols info...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
reader.setPointerIndex(localSymbolsOffset);
|
||||
localSymbolsInfo = new DyldCacheLocalSymbolsInfo(reader, architecture);
|
||||
localSymbolsInfo.parse(log, monitor);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_local_symbols_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseBranchPools(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD branch pool addresses...");
|
||||
monitor.initialize(branchPoolsCount);
|
||||
try {
|
||||
reader.setPointerIndex(branchPoolsOffset);
|
||||
for (int i = 0; i < branchPoolsCount; ++i) {
|
||||
branchPoolList.add(reader.readNextLong());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(), "Failed to parse pool addresses.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseImageTextInfo(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD image text info...");
|
||||
monitor.initialize(imagesTextCount);
|
||||
try {
|
||||
reader.setPointerIndex(imagesTextOffset);
|
||||
for (int i = 0; i < imagesTextCount; ++i) {
|
||||
imageTextInfoList.add(new DyldCacheImageTextInfo(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_image_text_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAcceleratorInfo(Program program, AddressSpace space, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD accelerateor info...");
|
||||
monitor.initialize(imagesTextCount);
|
||||
try {
|
||||
Address addr = space.getAddress(accelerateInfoAddr);
|
||||
ByteProvider bytes = new MemoryByteProvider(program.getMemory(), addr);
|
||||
BinaryReader memoryReader =
|
||||
new BinaryReader(bytes, !program.getLanguage().isBigEndian());
|
||||
accelerateInfo = new DyldCacheAccelerateInfo(memoryReader);
|
||||
accelerateInfo.parse(program, addr, log, monitor);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_accelerator_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupHeader(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD header...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
DataUtilities.createData(program, program.getImageBase(), toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_header.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupMappingInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD mapping info...");
|
||||
monitor.initialize(mappingInfoList.size());
|
||||
try {
|
||||
Address addr = fileOffsetToAddr(mappingOffset, program, space);
|
||||
for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
|
||||
Data d = DataUtilities.createData(program, addr, mappingInfo.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_mapping_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupImageInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD image info...");
|
||||
monitor.initialize(imageInfoList.size());
|
||||
try {
|
||||
Address addr = fileOffsetToAddr(imagesOffset, program, space);
|
||||
for (DyldCacheImageInfo imageInfo : imageInfoList) {
|
||||
Data d = DataUtilities.createData(program, addr, imageInfo.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
program.getListing().setComment(addr, CodeUnit.EOL_COMMENT, imageInfo.getPath());
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_image_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupCodeSignature(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD code signature...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
String size = "0x" + Long.toHexString(codeSignatureSize);
|
||||
program.getListing().setComment(fileOffsetToAddr(codeSignatureOffset, program, space),
|
||||
CodeUnit.PLATE_COMMENT, "Code Signature (" + size + " bytes)");
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup code signature.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupSlideInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD slide info...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
if (slideInfo != null) {
|
||||
Address addr = fileOffsetToAddr(slideInfoOffset, program, space);
|
||||
DataUtilities.createData(program, addr, slideInfo.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_slide_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupLocalSymbolsInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD local symbols info...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
if (localSymbolsInfo != null) {
|
||||
Address addr = fileOffsetToAddr(localSymbolsOffset, program, space);
|
||||
DataUtilities.createData(program, addr, localSymbolsInfo.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
localSymbolsInfo.markup(program, addr, monitor, log);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_local_symbols_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupBranchPools(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD branch pool addresses...");
|
||||
monitor.initialize(branchPoolList.size());
|
||||
try {
|
||||
Address addr = fileOffsetToAddr(branchPoolsOffset, program, space);
|
||||
for (int i = 0; i < branchPoolList.size(); i++) {
|
||||
Data d = DataUtilities.createData(program, addr, Pointer64DataType.dataType,
|
||||
Pointer64DataType.dataType.getLength(), false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup branch pool addresses.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupAcceleratorInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD accelerator info...");
|
||||
monitor.initialize(1);
|
||||
try {
|
||||
if (accelerateInfo != null) {
|
||||
Address addr = space.getAddress(accelerateInfoAddr);
|
||||
DataUtilities.createData(program, addr, accelerateInfo.toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
accelerateInfo.markup(program, addr, monitor, log);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_accelerator_info.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupImageTextInfo(Program program, AddressSpace space, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD image text info...");
|
||||
monitor.initialize(imageTextInfoList.size());
|
||||
try {
|
||||
Address addr = fileOffsetToAddr(imagesTextOffset, program, space);
|
||||
for (DyldCacheImageTextInfo imageTextInfo : imageTextInfoList) {
|
||||
Data d = DataUtilities.createData(program, addr, imageTextInfo.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
program.getListing().setComment(addr, CodeUnit.EOL_COMMENT,
|
||||
imageTextInfo.getPath());
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_image_text_info.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the given file offset's corresponding memory address.
|
||||
*
|
||||
* @param offset The file offset
|
||||
* @param program The {@link Program}
|
||||
* @param space The {@link AddressSpace}
|
||||
* @return The given file offset's corresponding memory address. Could be null if it doesn't
|
||||
* have one.
|
||||
*/
|
||||
private Address fileOffsetToAddr(long offset, Program program, AddressSpace space) {
|
||||
|
||||
// First check the memory that was supposed to get mapped in
|
||||
for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
|
||||
if (offset >= mappingInfo.getFileOffset() &&
|
||||
offset < mappingInfo.getFileOffset() + mappingInfo.getSize()) {
|
||||
return space.getAddress(
|
||||
mappingInfo.getAddress() + (offset - mappingInfo.getFileOffset()));
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the special memory block that contains bytes that weren't supposed to get
|
||||
// mapped in to memory
|
||||
AddressSpace fileSpace = program.getAddressFactory().getAddressSpace("FILE");
|
||||
if (fileSpace != null) {
|
||||
try {
|
||||
return fileSpace.getAddress(offset);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_image_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheImageInfo implements StructConverter {
|
||||
|
||||
private long address;
|
||||
private long modTime;
|
||||
private long inode;
|
||||
private int pathFileOffset;
|
||||
private int pad;
|
||||
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheImageInfo}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD image info
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD image info
|
||||
*/
|
||||
public DyldCacheImageInfo(BinaryReader reader) throws IOException {
|
||||
address = reader.readNextLong();
|
||||
modTime = reader.readNextLong();
|
||||
inode = reader.readNextLong();
|
||||
pathFileOffset = reader.readNextInt();
|
||||
pad = reader.readNextInt();
|
||||
|
||||
path = reader.readAsciiString(pathFileOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address the start of the image.
|
||||
*
|
||||
* @return The address of the start of the image
|
||||
*/
|
||||
public long getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path of the image.
|
||||
*
|
||||
* @return The path of the image
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_image_info", 0);
|
||||
struct.add(QWORD, "address", "");
|
||||
struct.add(QWORD, "modTime", "");
|
||||
struct.add(QWORD, "inode", "");
|
||||
struct.add(DWORD, "pathFileOffset", "");
|
||||
struct.add(DWORD, "pad", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_image_info_extra structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheImageInfoExtra implements StructConverter {
|
||||
|
||||
private long exportsTrieAddr;
|
||||
private long weakBindingsAddr;
|
||||
private int exportsTrieSize;
|
||||
private int weakBindingsSize;
|
||||
private int dependentsStartArrayIndex;
|
||||
private int reExportsStartArrayIndex;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheImageInfoExtra}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD image info extra
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD image info extra
|
||||
*/
|
||||
public DyldCacheImageInfoExtra(BinaryReader reader) throws IOException {
|
||||
exportsTrieAddr = reader.readNextLong();
|
||||
weakBindingsAddr = reader.readNextLong();
|
||||
exportsTrieSize = reader.readNextInt();
|
||||
weakBindingsSize = reader.readNextInt();
|
||||
dependentsStartArrayIndex = reader.readNextInt();
|
||||
reExportsStartArrayIndex = reader.readNextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_image_info_extra", 0);
|
||||
struct.add(QWORD, "exportsTrieAddr", "");
|
||||
struct.add(QWORD, "weakBindingsAddr", "");
|
||||
struct.add(DWORD, "exportsTrieSize", "");
|
||||
struct.add(DWORD, "weakBindingsSize", "");
|
||||
struct.add(DWORD, "dependentsStartArrayIndex", "");
|
||||
struct.add(DWORD, "reExportsStartArrayIndex", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_image_text_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheImageTextInfo implements StructConverter {
|
||||
|
||||
private byte[] uuid;
|
||||
private long loadAddress;
|
||||
private int textSegmentSize;
|
||||
private int pathOffset;
|
||||
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheImageTextInfo}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD image text info
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD image text info
|
||||
*/
|
||||
public DyldCacheImageTextInfo(BinaryReader reader) throws IOException {
|
||||
uuid = reader.readNextByteArray(16);
|
||||
loadAddress = reader.readNextLong();
|
||||
textSegmentSize = reader.readNextInt();
|
||||
pathOffset = reader.readNextInt();
|
||||
|
||||
path = reader.readAsciiString(pathOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path of the image text.
|
||||
*
|
||||
* @return The path of the image text.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_image_text_info", 0);
|
||||
struct.add(new ArrayDataType(BYTE, 16, 1), "uuid", "");
|
||||
struct.add(QWORD, "loadAddress", "");
|
||||
struct.add(DWORD, "textSegmentSize", "");
|
||||
struct.add(DWORD, "pathOffset", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_local_symbols_entry structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheLocalSymbolsEntry implements StructConverter {
|
||||
|
||||
private int dylibOffset;
|
||||
private int nlistStartIndex;
|
||||
private int nlistCount;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheLocalSymbolsEntry}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD local symbols entry
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD local symbols entry
|
||||
*/
|
||||
public DyldCacheLocalSymbolsEntry(BinaryReader reader) throws IOException {
|
||||
dylibOffset = reader.readNextInt();
|
||||
nlistStartIndex = reader.readNextInt();
|
||||
nlistCount = reader.readNextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_local_symbols_entry", 0);
|
||||
struct.add(DWORD, "dylibOffset", "");
|
||||
struct.add(DWORD, "nlistStartIndex", "");
|
||||
struct.add(DWORD, "nlistCount", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import generic.continues.RethrowContinuesFactory;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.CpuTypes;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.app.util.bin.format.macho.commands.NList;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_local_symbols_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheLocalSymbolsInfo implements StructConverter {
|
||||
|
||||
private int nlistOffset;
|
||||
private int nlistCount;
|
||||
private int stringsOffset;
|
||||
private int stringsSize;
|
||||
private int entriesOffset;
|
||||
private int entriesCount;
|
||||
|
||||
private BinaryReader reader;
|
||||
private long startIndex;
|
||||
|
||||
private List<NList> nlistList;
|
||||
private List<DyldCacheLocalSymbolsEntry> localSymbolsEntryList;
|
||||
private boolean is32bit;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheLocalSymbolsInfo}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD local symbols info
|
||||
* @param architecture The {@link DyldArchitecture}
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD local symbols info
|
||||
*/
|
||||
public DyldCacheLocalSymbolsInfo(BinaryReader reader, DyldArchitecture architecture)
|
||||
throws IOException {
|
||||
this.reader = reader;
|
||||
this.startIndex = reader.getPointerIndex();
|
||||
|
||||
nlistOffset = reader.readNextInt();
|
||||
nlistCount = reader.readNextInt();
|
||||
stringsOffset = reader.readNextInt();
|
||||
stringsSize = reader.readNextInt();
|
||||
entriesOffset = reader.readNextInt();
|
||||
entriesCount = reader.readNextInt();
|
||||
|
||||
nlistList = new ArrayList<>(nlistCount);
|
||||
localSymbolsEntryList = new ArrayList<>(entriesCount);
|
||||
|
||||
is32bit = !(architecture.getCpuType() == CpuTypes.CPU_TYPE_ARM_64 &&
|
||||
architecture.getCpuType() == CpuTypes.CPU_TYPE_X86_64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the structures referenced by this {@link DyldCacheLocalSymbolsInfo}.
|
||||
*
|
||||
* @param log The log
|
||||
* @param monitor A cancellable task monitor
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void parse(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
parseNList(log, monitor);
|
||||
parseLocalSymbols(log, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up this {@link DyldCacheLocalSymbolsInfo} with data structures and comments.
|
||||
*
|
||||
* @param program The {@link Program} to mark up
|
||||
* @param localSymbolsInfoAddr The {@link Address} of the {@link DyldCacheLocalSymbolsInfo}
|
||||
* @param monitor A cancellable task monitor
|
||||
* @param log The log
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public void markup(Program program, Address localSymbolsInfoAddr, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
markupNList(program, localSymbolsInfoAddr, monitor, log);
|
||||
markupLocalSymbols(program, localSymbolsInfoAddr, monitor, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of {@link NList}.
|
||||
*
|
||||
* @return The {@link List} of {@link NList}
|
||||
*/
|
||||
public List<NList> getNList() {
|
||||
return nlistList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of {@link DyldCacheLocalSymbolsEntry}s.
|
||||
*
|
||||
* @return The {@link List} of {@link DyldCacheLocalSymbolsEntry}
|
||||
*/
|
||||
public List<DyldCacheLocalSymbolsEntry> getLocalSymbols() {
|
||||
return localSymbolsEntryList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_local_symbols_info", 0);
|
||||
struct.add(DWORD, "nlistOffset", "offset into this chunk of nlist entries");
|
||||
struct.add(DWORD, "nlistCount", "count of nlist entries");
|
||||
struct.add(DWORD, "stringsOffset", "offset into this chunk of string pool");
|
||||
struct.add(DWORD, "stringsSize", "byte count of string pool");
|
||||
struct.add(DWORD, "entriesOffset",
|
||||
"offset into this chunk of array of dyld_cache_local_symbols_entry ");
|
||||
struct.add(DWORD, "entriesCount",
|
||||
"number of elements in dyld_cache_local_symbols_entry array");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
|
||||
private void parseNList(MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
FactoryBundledWithBinaryReader nListReader = new FactoryBundledWithBinaryReader(
|
||||
RethrowContinuesFactory.INSTANCE, reader.getByteProvider(), reader.isLittleEndian());
|
||||
monitor.setMessage("Parsing DYLD nlist symbol table...");
|
||||
monitor.initialize(nlistCount);
|
||||
nListReader.setPointerIndex(startIndex + nlistOffset);
|
||||
try {
|
||||
for (int i = 0; i < nlistCount; ++i) {
|
||||
nlistList.add(NList.createNList(nListReader, is32bit, startIndex + stringsOffset));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(), "Failed to parse nlist.");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLocalSymbols(MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
monitor.setMessage("Parsing DYLD local symbol entries...");
|
||||
monitor.initialize(entriesCount);
|
||||
reader.setPointerIndex(startIndex + entriesOffset);
|
||||
try {
|
||||
for (int i = 0; i < entriesCount; ++i) {
|
||||
localSymbolsEntryList.add(new DyldCacheLocalSymbolsEntry(reader));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to parse dyld_cache_local_symbols_entry.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupNList(Program program, Address localSymbolsInfoAddr, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD nlist symbol table...");
|
||||
monitor.initialize(nlistCount);
|
||||
try {
|
||||
Address addr = localSymbolsInfoAddr.add(nlistOffset);
|
||||
for (NList nlist : nlistList) {
|
||||
Data d = DataUtilities.createData(program, addr, nlist.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(), "Failed to markup nlist.");
|
||||
}
|
||||
}
|
||||
|
||||
private void markupLocalSymbols(Program program, Address localSymbolsInfoAddr,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||
monitor.setMessage("Marking up DYLD local symbol entries...");
|
||||
monitor.initialize(entriesCount);
|
||||
try {
|
||||
Address addr = localSymbolsInfoAddr.add(entriesOffset);
|
||||
for (DyldCacheLocalSymbolsEntry localSymbolsEntry : localSymbolsEntryList) {
|
||||
Data d = DataUtilities.createData(program, addr, localSymbolsEntry.toDataType(), -1,
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
addr = addr.add(d.getLength());
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(),
|
||||
"Failed to markup dyld_cache_local_symbols_entry.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.app.util.bin.format.macho.commands.SegmentConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_mapping_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheMappingInfo implements StructConverter {
|
||||
|
||||
private long address;
|
||||
private long size;
|
||||
private long fileOffset;
|
||||
private int maxProt;
|
||||
private int initProt;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheImageInfo}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD mapping info
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD mapping info
|
||||
*/
|
||||
public DyldCacheMappingInfo(BinaryReader reader) throws IOException {
|
||||
address = reader.readNextLong();
|
||||
size = reader.readNextLong();
|
||||
fileOffset = reader.readNextLong();
|
||||
maxProt = reader.readNextInt();
|
||||
initProt = reader.readNextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the start of the mapping.
|
||||
*
|
||||
* @return The address of the start of the mapping
|
||||
*/
|
||||
public long getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the mapping.
|
||||
*
|
||||
* @return The size of the mapping
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file offset of the start of the mapping.
|
||||
*
|
||||
* @return The file offset of the start of the mapping
|
||||
*/
|
||||
public long getFileOffset() {
|
||||
return fileOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the initial protections include READ.
|
||||
*
|
||||
* @return true if the initial protections include READ
|
||||
*/
|
||||
public boolean isRead() {
|
||||
return (initProt & SegmentConstants.PROTECTION_R) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the initial protections include WRITE.
|
||||
*
|
||||
* @return true if the initial protections include WRITE
|
||||
*/
|
||||
public boolean isWrite() {
|
||||
return (initProt & SegmentConstants.PROTECTION_W) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the initial protections include EXECUTE.
|
||||
*
|
||||
* @return true if the initial protections include EXECUTE
|
||||
*/
|
||||
public boolean isExecute() {
|
||||
return (initProt & SegmentConstants.PROTECTION_X) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_mapping_info", 0);
|
||||
struct.add(QWORD, "address", "");
|
||||
struct.add(QWORD, "size", "");
|
||||
struct.add(QWORD, "fileOffset", "");
|
||||
struct.add(DWORD, "maxProt", "");
|
||||
struct.add(DWORD, "initProt", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_range_entry structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheRangeEntry implements StructConverter {
|
||||
|
||||
private long startAddress;
|
||||
private int size;
|
||||
private int imageIndex;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheRangeEntry}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD range entry
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD range entry
|
||||
*/
|
||||
public DyldCacheRangeEntry(BinaryReader reader) throws IOException {
|
||||
startAddress = reader.readNextLong();
|
||||
size = reader.readNextInt();
|
||||
imageIndex = reader.readNextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_range_entry", 0);
|
||||
struct.add(QWORD, "startAddress", "");
|
||||
struct.add(DWORD, "size", "");
|
||||
struct.add(DWORD, "imageIndex", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_slide_info structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
private int toc_offset;
|
||||
private int toc_count;
|
||||
private int entries_offset;
|
||||
private int entries_count;
|
||||
private int entries_size;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheSlideInfo1}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD slide info 1
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD slide info 1
|
||||
*/
|
||||
public DyldCacheSlideInfo1(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
toc_offset = reader.readNextInt();
|
||||
toc_count = reader.readNextInt();
|
||||
entries_offset = reader.readNextInt();
|
||||
entries_count = reader.readNextInt();
|
||||
entries_size = reader.readNextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_slide_info", 0);
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "toc_offset", "");
|
||||
struct.add(DWORD, "toc_count", "");
|
||||
struct.add(DWORD, "entries_offset", "");
|
||||
struct.add(DWORD, "entries_count", "");
|
||||
struct.add(DWORD, "entries_size", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_slide_info2 structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
private int page_size;
|
||||
private int page_starts_offset;
|
||||
private int page_starts_count;
|
||||
private int page_extras_offset;
|
||||
private int page_extras_count;
|
||||
private long delta_mask;
|
||||
private long value_add;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheSlideInfo2}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD slide info 2
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD slide info 2
|
||||
*/
|
||||
public DyldCacheSlideInfo2(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
page_size = reader.readNextInt();
|
||||
page_starts_offset = reader.readNextInt();
|
||||
page_starts_count = reader.readNextInt();
|
||||
page_extras_offset = reader.readNextInt();
|
||||
page_extras_count = reader.readNextInt();
|
||||
delta_mask = reader.readNextLong();
|
||||
value_add = reader.readNextLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_slide_info2", 0);
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "page_size", "");
|
||||
struct.add(DWORD, "page_starts_offset", "");
|
||||
struct.add(DWORD, "page_starts_count", "");
|
||||
struct.add(DWORD, "page_extras_offset", "");
|
||||
struct.add(DWORD, "page_extras_count", "");
|
||||
struct.add(QWORD, "delta_mask", "");
|
||||
struct.add(QWORD, "value_add", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Represents a dyld_cache_slide_info3 structure.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
private int page_size;
|
||||
private int page_starts_count;
|
||||
private long auth_value_add;
|
||||
private short page_starts[];
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheSlideInfo3}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD slide info 3
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD slide info 3
|
||||
*/
|
||||
public DyldCacheSlideInfo3(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
page_size = reader.readNextInt();
|
||||
page_starts_count = reader.readNextInt();
|
||||
auth_value_add = reader.readNextLong();
|
||||
page_starts = reader.readNextShortArray(page_starts_count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_slide_info3", 0);
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "page_size", "");
|
||||
struct.add(DWORD, "page_starts_count", "");
|
||||
struct.add(QWORD, "auth_value_add", "");
|
||||
struct.add(new ArrayDataType(WORD, page_starts_count, 1), "page_starts", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/* ###
|
||||
* 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.bin.format.macho.dyld;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Class for representing the common components of the various dyld_cache_slide_info structures.
|
||||
* The intent is for the the full dyld_cache_slide_info structures to extend this and add their
|
||||
* specific parts.
|
||||
*
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-625.13/launch-cache/dyld_cache_format.h.auto.html">launch-cache/dyld_cache_format.h</a>
|
||||
*/
|
||||
public class DyldCacheSlideInfoCommon implements StructConverter {
|
||||
|
||||
protected int version;
|
||||
|
||||
/**
|
||||
* Create a new {@link DyldCacheSlideInfoCommon}.
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of a DYLD slide info
|
||||
* @throws IOException if there was an IO-related problem creating the DYLD slide info
|
||||
*/
|
||||
public DyldCacheSlideInfoCommon(BinaryReader reader) throws IOException {
|
||||
version = reader.readNextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of the DYLD slide info.
|
||||
*
|
||||
* @return The version of the DYLD slide info.
|
||||
*/
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("dyld_cache_slide_info", 0);
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.dyld.DyldArchitecture;
|
||||
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
|
||||
import ghidra.app.util.importer.MemoryConflictHandler;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A {@link Loader} for DYLD shared cache files.
|
||||
*/
|
||||
public class DyldCacheLoader extends AbstractLibrarySupportLoader {
|
||||
|
||||
public final static String DYLD_CACHE_NAME = "DYLD Cache";
|
||||
|
||||
/** Loader option to process symbols*/
|
||||
static final String PROCESS_SYMBOLS_OPTION_NAME = "Process symbols";
|
||||
|
||||
/** Default value for loader option to process symbols */
|
||||
static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true;
|
||||
|
||||
/** Loader option to create memory blocks for DYLIB sections */
|
||||
static final String CREATE_DYLIB_SECTIONS_OPTION_NAME =
|
||||
"Create DYLIB section memory blocks (slow!)";
|
||||
|
||||
/** Default value for loader option to create memory blocks for DYLIB sections */
|
||||
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false;
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
List<LoadSpec> loadSpecs = new ArrayList<>();
|
||||
|
||||
if (!DyldCacheUtils.isDyldCache(provider)) {
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
try {
|
||||
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
|
||||
DyldArchitecture architecture = header.getArchitecture();
|
||||
if (architecture != null) {
|
||||
List<QueryResult> results =
|
||||
QueryOpinionService.query(getName(), architecture.getProcessor(), null);
|
||||
for (QueryResult result : results) {
|
||||
loadSpecs.add(new LoadSpec(this, header.getBaseAddress(), result));
|
||||
}
|
||||
if (loadSpecs.isEmpty()) {
|
||||
loadSpecs.add(new LoadSpec(this, header.getBaseAddress(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// It's not what we expect, so don't consider it
|
||||
}
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||
Program program, MemoryConflictHandler handler, TaskMonitor monitor, MessageLog log)
|
||||
throws IOException {
|
||||
|
||||
try {
|
||||
DyldCacheProgramBuilder.buildProgram(program, provider, shouldProcessSymbols(options),
|
||||
shouldCreateDylibSections(options), log, handler, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@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(PROCESS_SYMBOLS_OPTION_NAME, PROCESS_SYMBOLS_OPTION_DEFAULT,
|
||||
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-processSymbols"));
|
||||
list.add(
|
||||
new Option(CREATE_DYLIB_SECTIONS_OPTION_NAME, CREATE_DYLIB_SECTIONS_OPTION_DEFAULT,
|
||||
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-createDylibSections"));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean shouldProcessSymbols(List<Option> options) {
|
||||
if (options != null) {
|
||||
for (Option option : options) {
|
||||
String optName = option.getName();
|
||||
if (optName.equals(PROCESS_SYMBOLS_OPTION_NAME)) {
|
||||
return (Boolean) option.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return PROCESS_SYMBOLS_OPTION_DEFAULT;
|
||||
}
|
||||
|
||||
private boolean shouldCreateDylibSections(List<Option> options) {
|
||||
if (options != null) {
|
||||
for (Option option : options) {
|
||||
String optName = option.getName();
|
||||
if (optName.equals(CREATE_DYLIB_SECTIONS_OPTION_NAME)) {
|
||||
return (Boolean) option.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return CREATE_DYLIB_SECTIONS_OPTION_DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return DYLD_CACHE_NAME;
|
||||
}
|
||||
}
|
@ -0,0 +1,357 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.MachException;
|
||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||
import ghidra.app.util.bin.format.macho.commands.NList;
|
||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
||||
import ghidra.app.util.importer.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Builds up a DYLD Cache {@link Program} by parsing the DYLD Cache headers.
|
||||
*/
|
||||
public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
|
||||
protected DyldCacheHeader dyldCacheHeader;
|
||||
private boolean shouldProcessSymbols;
|
||||
private boolean shouldCreateDylibSections;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DyldCacheProgramBuilder} based on the given information.
|
||||
*
|
||||
* @param program The {@link Program} to build up
|
||||
* @param provider The {@link ByteProvider} that contains the DYLD Cache bytes
|
||||
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
|
||||
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
|
||||
* otherwise, false
|
||||
* @param log The log
|
||||
* @param memoryConflictHandler How to handle memory conflicts that may occur
|
||||
* @param monitor A cancelable task monitor
|
||||
*/
|
||||
protected DyldCacheProgramBuilder(Program program, ByteProvider provider,
|
||||
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
|
||||
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) {
|
||||
super(program, provider, log, memoryConflictHandler, monitor);
|
||||
this.shouldProcessSymbols = shouldProcessSymbols;
|
||||
this.shouldCreateDylibSections = shouldCreateDylibSections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up a DYLD Cache {@link Program}.
|
||||
*
|
||||
* @param program The {@link Program} to build up
|
||||
* @param provider The {@link ByteProvider} that contains the DYLD Cache's bytes
|
||||
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
|
||||
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
|
||||
* otherwise, false
|
||||
* @param log The log
|
||||
* @param memoryConflictHandler How to handle memory conflicts that may occur
|
||||
* @param monitor A cancelable task monitor
|
||||
* @throws Exception if a problem occurs
|
||||
*/
|
||||
public static void buildProgram(Program program, ByteProvider provider,
|
||||
boolean shouldProcessSymbols, boolean shouldCreateDylibSections, MessageLog log,
|
||||
MemoryConflictHandler memoryConflictHandler, TaskMonitor monitor) throws Exception {
|
||||
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
|
||||
provider, shouldProcessSymbols, shouldCreateDylibSections, log, memoryConflictHandler,
|
||||
monitor);
|
||||
dyldCacheProgramBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void build() throws Exception {
|
||||
|
||||
monitor.setMessage("Parsing DYLD Cache header ...");
|
||||
monitor.initialize(1);
|
||||
dyldCacheHeader = new DyldCacheHeader(new BinaryReader(provider, true));
|
||||
dyldCacheHeader.parseFromFile(shouldProcessSymbols, log, monitor);
|
||||
monitor.incrementProgress(1);
|
||||
|
||||
try {
|
||||
setDyldCacheImageBase();
|
||||
processDyldCacheMemoryBlocks();
|
||||
markupHeaders();
|
||||
markupBranchIslands();
|
||||
createSymbols();
|
||||
processDylibs();
|
||||
}
|
||||
finally {
|
||||
if (mbu != null) {
|
||||
mbu.dispose();
|
||||
mbu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the program's image base.
|
||||
*
|
||||
* @throws Exception if there was problem setting the program's image base
|
||||
*/
|
||||
private void setDyldCacheImageBase() throws Exception {
|
||||
monitor.setMessage("Setting image base...");
|
||||
monitor.initialize(1);
|
||||
program.setImageBase(space.getAddress(dyldCacheHeader.getBaseAddress()), true);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the DYLD Cache's memory mappings and creates memory blocks for them.
|
||||
*
|
||||
* @throws Exception if there was a problem creating the memory blocks
|
||||
*/
|
||||
private void processDyldCacheMemoryBlocks() throws Exception {
|
||||
List<DyldCacheMappingInfo> mappingInfos = dyldCacheHeader.getMappingInfos();
|
||||
|
||||
monitor.setMessage("Processing DYLD mapped memory blocks...");
|
||||
monitor.initialize(mappingInfos.size());
|
||||
long endOfMappedOffset = 0;
|
||||
for (DyldCacheMappingInfo mappingInfo : mappingInfos) {
|
||||
long offset = mappingInfo.getFileOffset();
|
||||
long size = mappingInfo.getSize();
|
||||
mbu.createInitializedBlock("DYLD", space.getAddress(mappingInfo.getAddress()),
|
||||
provider.getInputStream(offset), size, "", "", mappingInfo.isRead(),
|
||||
mappingInfo.isWrite(), mappingInfo.isExecute(), monitor);
|
||||
if (offset + size > endOfMappedOffset) {
|
||||
endOfMappedOffset = offset + size;
|
||||
}
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
if (endOfMappedOffset < provider.length()) {
|
||||
monitor.setMessage("Processing DYLD unmapped memory block...");
|
||||
mbu.createOverlayBlock("FILE", AddressSpace.OTHER_SPACE.getAddress(endOfMappedOffset),
|
||||
provider.getInputStream(endOfMappedOffset), provider.length() - endOfMappedOffset,
|
||||
"Useful bytes that don't get mapped into memory", "", false, false, false, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up the DYLD Cache headers.
|
||||
*
|
||||
* @throws Exception if there was a problem marking up the headers
|
||||
*/
|
||||
private void markupHeaders() throws Exception {
|
||||
monitor.setMessage("Marking up DYLD headers...");
|
||||
monitor.initialize(1);
|
||||
dyldCacheHeader.parseFromMemory(program, space, log, monitor);
|
||||
dyldCacheHeader.markup(program, space, monitor, log);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up the DYLD Cache branch islands.
|
||||
*
|
||||
* @throws Exception if there was a problem marking up the branch islands.
|
||||
*/
|
||||
private void markupBranchIslands() throws Exception {
|
||||
monitor.setMessage("Marking up DYLD branch islands...");
|
||||
monitor.initialize(dyldCacheHeader.getBranchPoolAddresses().size());
|
||||
for (Long addr : dyldCacheHeader.getBranchPoolAddresses()) {
|
||||
try {
|
||||
MachHeader header =
|
||||
MachHeader.createMachHeader(MessageLogContinuesFactory.create(log), provider,
|
||||
addr - dyldCacheHeader.getBaseAddress());
|
||||
header.parse();
|
||||
super.markupHeaders(header, space.getAddress(addr));
|
||||
}
|
||||
catch (MachException | IOException e) {
|
||||
// Not a show-stopper...carry on.
|
||||
}
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the DYLD Cache symbols.
|
||||
*
|
||||
* @throws Exception if there was a problem creating the symbols
|
||||
*/
|
||||
private void createSymbols() throws Exception {
|
||||
DyldCacheLocalSymbolsInfo localSymbolsInfo = dyldCacheHeader.getLocalSymbolsInfo();
|
||||
if (localSymbolsInfo != null) {
|
||||
monitor.setMessage("Processing DYLD symbols...");
|
||||
monitor.initialize(localSymbolsInfo.getNList().size());
|
||||
for (NList nlist : localSymbolsInfo.getNList()) {
|
||||
if (!nlist.getString().trim().isEmpty()) {
|
||||
try {
|
||||
program.getSymbolTable().createLabel(space.getAddress(nlist.getValue()),
|
||||
SymbolUtilities.replaceInvalidChars(nlist.getString(), true),
|
||||
program.getGlobalNamespace(), SourceType.IMPORTED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendMsg(e.getMessage() + " " + nlist.getString());
|
||||
}
|
||||
}
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the DYLD Cache's DYLIB files. This will mark up the DYLIB files, added them to the
|
||||
* program tree, and make memory blocks for them.
|
||||
*
|
||||
* @throws Exception if there was a problem processing the DYLIB files
|
||||
*/
|
||||
private void processDylibs() throws Exception {
|
||||
// Create an "info" object for each DyldCache DYLIB, which will make processing them
|
||||
// easier
|
||||
monitor.setMessage("Parsing DYLIB's...");
|
||||
monitor.initialize(dyldCacheHeader.getImageInfos().size());
|
||||
TreeSet<DyldCacheMachoInfo> dyldCacheMachoInfoSet =
|
||||
new TreeSet<>((a, b) -> a.headerAddr.compareTo(b.headerAddr));
|
||||
for (DyldCacheImageInfo dyldCacheImageInfo : dyldCacheHeader.getImageInfos()) {
|
||||
dyldCacheMachoInfoSet.add(new DyldCacheMachoInfo(provider,
|
||||
dyldCacheImageInfo.getAddress() - dyldCacheHeader.getBaseAddress(),
|
||||
space.getAddress(dyldCacheImageInfo.getAddress()), dyldCacheImageInfo.getPath()));
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
// Markup DyldCache Mach-O headers
|
||||
monitor.setMessage("Marking up DYLIB headers...");
|
||||
monitor.initialize(dyldCacheMachoInfoSet.size());
|
||||
for (DyldCacheMachoInfo info : dyldCacheMachoInfoSet) {
|
||||
info.markupHeaders();
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
// Add DyldCache Mach-O's to program tree
|
||||
monitor.setMessage("Adding DYLIB's to program tree...");
|
||||
monitor.initialize(dyldCacheMachoInfoSet.size());
|
||||
Iterator<DyldCacheMachoInfo> iter = dyldCacheMachoInfoSet.iterator();
|
||||
if (iter.hasNext()) {
|
||||
DyldCacheMachoInfo curr = iter.next();
|
||||
do {
|
||||
DyldCacheMachoInfo next = iter.hasNext() ? iter.next() : null;
|
||||
curr.addToProgramTree(next);
|
||||
curr = next;
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
while (iter.hasNext());
|
||||
}
|
||||
|
||||
// Process DyldCache DYLIB memory blocks. Need to do it in descending (reverse) order or
|
||||
// the memory block splitting will be way too slow.
|
||||
monitor.setMessage("Processing DYLIB memory blocks...");
|
||||
monitor.initialize(dyldCacheMachoInfoSet.size());
|
||||
Iterator<DyldCacheMachoInfo> descendingIter = dyldCacheMachoInfoSet.descendingIterator();
|
||||
while (descendingIter.hasNext()) {
|
||||
descendingIter.next().processMemoryBlocks();
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience class to store information we need about an individual Mach-O.
|
||||
*/
|
||||
private class DyldCacheMachoInfo {
|
||||
|
||||
private Address headerAddr;
|
||||
private MachHeader header;
|
||||
private String path;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DyldCacheMachoInfo} object with the given parameters.
|
||||
*
|
||||
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes
|
||||
* @param offset The offset in the provider to the start of the Mach-O
|
||||
* @param headerAddr The Mach-O's header address
|
||||
* @param path The path of the Mach-O
|
||||
* @throws Exception If there was a problem handling the Mach-O info
|
||||
*/
|
||||
public DyldCacheMachoInfo(ByteProvider provider, long offset, Address headerAddr,
|
||||
String path) throws Exception {
|
||||
this.headerAddr = headerAddr;
|
||||
this.header = MachHeader.createMachHeader(MessageLogContinuesFactory.create(log),
|
||||
provider, offset);
|
||||
this.header.parse();
|
||||
this.path = path;
|
||||
this.name = new File(path).getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes memory blocks for this Mach-O.
|
||||
*
|
||||
* @throws Exception If there was a problem processing memory blocks for this Mach-O
|
||||
* @see DyldCacheProgramBuilder#processMemoryBlocks(MachHeader, String, boolean, boolean)
|
||||
*/
|
||||
public void processMemoryBlocks() throws Exception {
|
||||
DyldCacheProgramBuilder.this.processMemoryBlocks(header, name,
|
||||
shouldCreateDylibSections, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up the Mach-O headers.
|
||||
*
|
||||
* @throws Exception If there was a problem marking up the Mach-O's headers
|
||||
* @see DyldCacheProgramBuilder#markupHeaders(MachHeader, Address)
|
||||
*/
|
||||
public void markupHeaders() throws Exception {
|
||||
DyldCacheProgramBuilder.this.markupHeaders(header, headerAddr);
|
||||
|
||||
if (!name.isEmpty()) {
|
||||
listing.setComment(headerAddr, CodeUnit.PLATE_COMMENT, path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the program tree for this Mach-O
|
||||
*
|
||||
* @param next The Mach-O that comes directly after this one. Could be null if this
|
||||
* is the last one.
|
||||
* @throws Exception If there was a problem adding this Mach-O to the program tree
|
||||
*/
|
||||
public void addToProgramTree(DyldCacheMachoInfo next) throws Exception {
|
||||
ProgramFragment fragment = listing.getDefaultRootModule().createFragment(path);
|
||||
if (next != null) {
|
||||
fragment.move(headerAddr, next.headerAddr.subtract(1));
|
||||
}
|
||||
else {
|
||||
// This is the last Mach-O, so we'll assume it ends where the mapping that contains
|
||||
// it ends.
|
||||
for (DyldCacheMappingInfo mappingInfo : dyldCacheHeader.getMappingInfos()) {
|
||||
Address mappingAddr = space.getAddress(mappingInfo.getAddress());
|
||||
if (headerAddr.compareTo(mappingAddr) >= 0 &&
|
||||
headerAddr.compareTo(mappingAddr.add(mappingInfo.getSize() - 1)) <= 0) {
|
||||
fragment.move(headerAddr, mappingAddr.add(mappingInfo.getSize() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,16 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.file.formats.ios.dyldcache;
|
||||
package ghidra.app.util.opinion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.dyld.DyldArchitecture;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.exception.NotYetImplementedException;
|
||||
|
||||
public final class DyldCacheUtil {
|
||||
/**
|
||||
* Utilities methods for working with Mach-O DYLD shared cache binaries.
|
||||
*/
|
||||
public class DyldCacheUtils {
|
||||
|
||||
/**
|
||||
* Determines if the given {@link Program} is a DYLD cache.
|
||||
*
|
||||
* @param program The {@link Program}
|
||||
* @return True if the given {@link Program} is a DYLD cache; otherwise, false
|
||||
*/
|
||||
public final static boolean isDyldCache(Program program) {
|
||||
if (program == null) {
|
||||
return false;
|
||||
@ -30,20 +41,45 @@ public final class DyldCacheUtil {
|
||||
if (program.getMemory().getSize() < DyldArchitecture.DYLD_V1_SIGNATURE_LEN) {
|
||||
return false;
|
||||
}
|
||||
byte [] bytes = new byte[ DyldArchitecture.DYLD_V1_SIGNATURE_LEN ];
|
||||
byte[] bytes = new byte[DyldArchitecture.DYLD_V1_SIGNATURE_LEN];
|
||||
try {
|
||||
Address address = program.getMinAddress();
|
||||
program.getMemory().getBytes(address, bytes);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
return false;
|
||||
}
|
||||
return isDyldCache(new String(bytes).trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given {@link ByteProvider} is a DYLD cache.
|
||||
*
|
||||
* @param provider The {@link ByteProvider}
|
||||
* @return True if the given {@link ByteProvider} is a DYLD cache; otherwise, false
|
||||
*/
|
||||
public final static boolean isDyldCache(ByteProvider provider) {
|
||||
throw new NotYetImplementedException();
|
||||
if (provider == null) {
|
||||
return false;
|
||||
}
|
||||
byte[] bytes = new byte[DyldArchitecture.DYLD_V1_SIGNATURE_LEN];
|
||||
try {
|
||||
bytes = provider.readBytes(0, DyldArchitecture.DYLD_V1_SIGNATURE_LEN);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
return isDyldCache(new String(bytes).trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given signature represents a DYLD cache signature with an architecture we
|
||||
* support.
|
||||
*
|
||||
* @param signature The DYLD cache signature
|
||||
* @return True if the given signature represents a DYLD cache signature with an architecture we
|
||||
* support; otherwise, false
|
||||
*/
|
||||
public final static boolean isDyldCache(String signature) {
|
||||
for (DyldArchitecture architecture : DyldArchitecture.ARCHITECTURES) {
|
||||
if (architecture.getSignature().equals(signature)) {
|
@ -305,10 +305,10 @@ public class MachoPrelinkProgramBuilder extends MachoProgramBuilder {
|
||||
*
|
||||
* @throws Exception If there was a problem processing memory blocks for this PRELINK
|
||||
* Mach-O.
|
||||
* @see MachoPrelinkProgramBuilder#processMemoryBlocks(MachHeader, String, boolean)
|
||||
* @see MachoPrelinkProgramBuilder#processMemoryBlocks(MachHeader, String, boolean, boolean)
|
||||
*/
|
||||
public void processMemoryBlocks() throws Exception {
|
||||
MachoPrelinkProgramBuilder.this.processMemoryBlocks(header, name, false);
|
||||
MachoPrelinkProgramBuilder.this.processMemoryBlocks(header, name, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,7 @@ public class MachoProgramBuilder {
|
||||
try {
|
||||
setImageBase();
|
||||
processEntryPoint();
|
||||
processMemoryBlocks(machoHeader, provider.getName(), true);
|
||||
processMemoryBlocks(machoHeader, provider.getName(), true, true);
|
||||
processUnsupportedLoadCommands();
|
||||
processSymbolTables();
|
||||
processIndirectSymbols();
|
||||
@ -206,20 +206,25 @@ public class MachoProgramBuilder {
|
||||
*
|
||||
* @param header The Mach-O header to process for memory block creation.
|
||||
* @param source A name that represents where the memory blocks came from.
|
||||
* @param processSections True to split segments into their sections.
|
||||
* @param allowZeroAddr True if memory blocks at address 0 should be processed; otherwise,
|
||||
* false.
|
||||
* @throws Exception If there was a problem processing the memory blocks.
|
||||
*/
|
||||
protected void processMemoryBlocks(MachHeader header, String source, boolean allowZeroAddr)
|
||||
throws Exception {
|
||||
protected void processMemoryBlocks(MachHeader header, String source, boolean processSections,
|
||||
boolean allowZeroAddr) throws Exception {
|
||||
monitor.setMessage("Processing memory blocks for " + source + "...");
|
||||
|
||||
if (header.getFileType() == MachHeaderFileTypes.MH_DYLIB_STUB) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create memory blocks for segments
|
||||
for (SegmentCommand segment : header.getAllSegments()) {
|
||||
// Create memory blocks for segments. Create them in reverse order so the splitting
|
||||
// is more efficient.
|
||||
List<SegmentCommand> segments = header.getAllSegments();
|
||||
segments.sort((SegmentCommand a, SegmentCommand b) -> Long.compare(b.getVMaddress(),
|
||||
a.getVMaddress()));
|
||||
for (SegmentCommand segment : segments) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
@ -251,25 +256,31 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
|
||||
// Create memory blocks for sections. They will be in the segments we just created, so the
|
||||
// segment blocks will be split and possible replaced.
|
||||
for (Section section : header.getAllSections()) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (section.getSize() > 0 && (allowZeroAddr || section.getAddress() != 0)) {
|
||||
if (createMemoryBlock(section.getSectionName(),
|
||||
space.getAddress(section.getAddress()), section.getOffset(), section.getSize(),
|
||||
section.getSegmentName(), source, section.isRead(), section.isWrite(),
|
||||
section.isExecute(), section.getType() == SectionTypes.S_ZEROFILL) == null) {
|
||||
log.appendMsg(String.format("Failed to create block: %s.%s 0x%x 0x%x %s",
|
||||
section.getSegmentName(), section.getSectionName(), section.getAddress(),
|
||||
section.getSize(), source));
|
||||
// segment blocks will be split and possibly replaced. Create them in reverse order so
|
||||
// the splitting is more efficient.
|
||||
if (processSections) {
|
||||
List<Section> sections = header.getAllSections();
|
||||
sections.sort((Section a, Section b) -> Long.compare(b.getAddress(), a.getAddress()));
|
||||
for (Section section : sections) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (section.getSize() > 0 && (allowZeroAddr || section.getAddress() != 0)) {
|
||||
if (createMemoryBlock(section.getSectionName(),
|
||||
space.getAddress(section.getAddress()), section.getOffset(),
|
||||
section.getSize(), section.getSegmentName(), source, section.isRead(),
|
||||
section.isWrite(), section.isExecute(),
|
||||
section.getType() == SectionTypes.S_ZEROFILL) == null) {
|
||||
log.appendMsg(String.format("Failed to create block: %s.%s 0x%x 0x%x %s",
|
||||
section.getSegmentName(), section.getSectionName(),
|
||||
section.getAddress(), section.getSize(), source));
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.appendMsg("Skipping section: " + section.getSegmentName() + "." +
|
||||
section.getSectionName() + " (" + source + ")");
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.appendMsg("Skipping section: " + section.getSegmentName() + "." +
|
||||
section.getSectionName() + " (" + source + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -527,7 +538,7 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
else if (command instanceof SubLibraryCommand) {
|
||||
SubLibraryCommand sublibCommand = (SubLibraryCommand) command;
|
||||
addLibrary(sublibCommand.getSubLibraryName());
|
||||
addLibrary(sublibCommand.getSubLibraryName().getString());
|
||||
}
|
||||
else if (command instanceof PreboundDynamicLibraryCommand) {
|
||||
PreboundDynamicLibraryCommand pbdlCommand = (PreboundDynamicLibraryCommand) command;
|
||||
@ -550,14 +561,14 @@ public class MachoProgramBuilder {
|
||||
List<SubUmbrellaCommand> umbrellas = machoHeader.getLoadCommands(SubUmbrellaCommand.class);
|
||||
for (int i = 0; i < umbrellas.size(); ++i) {
|
||||
props.setString("Mach-O Sub-umbrella " + i,
|
||||
umbrellas.get(i).getSubUmbrellaFrameworkName());
|
||||
umbrellas.get(i).getSubUmbrellaFrameworkName().getString());
|
||||
}
|
||||
|
||||
List<SubFrameworkCommand> frameworks =
|
||||
machoHeader.getLoadCommands(SubFrameworkCommand.class);
|
||||
for (int i = 0; i < frameworks.size(); ++i) {
|
||||
props.setString("Mach-O Sub-framework " + i,
|
||||
frameworks.get(i).getUmbrellaFrameworkName());
|
||||
frameworks.get(i).getUmbrellaFrameworkName().getString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,6 +804,34 @@ public class MachoProgramBuilder {
|
||||
StructConverter.STRING, loadCommand.getCommandSize() - path.getOffset(),
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
else if (loadCommand instanceof SubFrameworkCommand) {
|
||||
SubFrameworkCommand subFrameworkCommand = (SubFrameworkCommand) loadCommand;
|
||||
LoadCommandString name = subFrameworkCommand.getUmbrellaFrameworkName();
|
||||
DataUtilities.createData(program, loadCommandAddr.add(name.getOffset()),
|
||||
StructConverter.STRING, loadCommand.getCommandSize() - name.getOffset(),
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
else if (loadCommand instanceof SubClientCommand) {
|
||||
SubClientCommand subClientCommand = (SubClientCommand) loadCommand;
|
||||
LoadCommandString name = subClientCommand.getClientName();
|
||||
DataUtilities.createData(program, loadCommandAddr.add(name.getOffset()),
|
||||
StructConverter.STRING, loadCommand.getCommandSize() - name.getOffset(),
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
else if (loadCommand instanceof SubLibraryCommand) {
|
||||
SubLibraryCommand subLibraryCommand = (SubLibraryCommand) loadCommand;
|
||||
LoadCommandString name = subLibraryCommand.getSubLibraryName();
|
||||
DataUtilities.createData(program, loadCommandAddr.add(name.getOffset()),
|
||||
StructConverter.STRING, loadCommand.getCommandSize() - name.getOffset(),
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
else if (loadCommand instanceof SubUmbrellaCommand) {
|
||||
SubUmbrellaCommand subUmbrellaCommand = (SubUmbrellaCommand) loadCommand;
|
||||
LoadCommandString name = subUmbrellaCommand.getSubUmbrellaFrameworkName();
|
||||
DataUtilities.createData(program, loadCommandAddr.add(name.getOffset()),
|
||||
StructConverter.STRING, loadCommand.getCommandSize() - name.getOffset(),
|
||||
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
|
@ -17,8 +17,12 @@ package ghidra.file.formats.ios.dyldcache;
|
||||
|
||||
import ghidra.app.cmd.formats.MachoBinaryAnalysisCommand;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.BinaryLoader;
|
||||
import ghidra.app.util.opinion.DyldCacheUtils;
|
||||
import ghidra.file.analyzers.FileFormatAnalyzer;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.data.DataType;
|
||||
@ -53,22 +57,22 @@ public class DyldCacheAnalyzer extends FileFormatAnalyzer {
|
||||
createFragment(program, headerDataType.getName(), headerData.getMinAddress(),
|
||||
headerData.getMaxAddress().add(1));
|
||||
|
||||
reader.setPointerIndex(header.getStartAddress());
|
||||
Address address = toAddr(program, header.getStartAddress());
|
||||
reader.setPointerIndex(header.getImagesOffset());
|
||||
Address address = toAddr(program, header.getImagesOffset());
|
||||
|
||||
for (int i = 0; i < header.getLibraryCount(); ++i) {
|
||||
for (int i = 0; i < header.getImagesCount(); ++i) {
|
||||
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
DyldCacheData data = new DyldCacheData(reader);
|
||||
DyldCacheImageInfo data = new DyldCacheImageInfo(reader);
|
||||
DataType dataDataType = data.toDataType();
|
||||
Data dataData = createData(program, address, dataDataType);
|
||||
createFragment(program, dataDataType.getName(), dataData.getMinAddress(),
|
||||
dataData.getMaxAddress().add(1));
|
||||
|
||||
Address fileOffset = toAddr(program, data.getFileOffset());
|
||||
Address fileOffset = toAddr(program, data.getAddress());
|
||||
Data fileData = createData(program, fileOffset, new StringDataType());
|
||||
createFragment(program, "LibraryNames", fileData.getMinAddress(),
|
||||
fileData.getMaxAddress().add(1));
|
||||
@ -76,7 +80,7 @@ public class DyldCacheAnalyzer extends FileFormatAnalyzer {
|
||||
String filePath = (String) fileData.getValue();
|
||||
|
||||
Address libraryOffsetAddress =
|
||||
toAddr(program, data.getLibraryOffset() - header.getBaseAddress());
|
||||
toAddr(program, data.getAddress() - header.getBaseAddress());
|
||||
|
||||
MachoBinaryAnalysisCommand command = new MachoBinaryAnalysisCommand(
|
||||
libraryOffsetAddress, false, program.getListing().getDefaultRootModule());
|
||||
@ -102,12 +106,17 @@ public class DyldCacheAnalyzer extends FileFormatAnalyzer {
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
return DyldCacheUtil.isDyldCache(program);
|
||||
Options options = program.getOptions("Program Information");
|
||||
String format = options.getString("Executable Format", null);
|
||||
if (!BinaryLoader.BINARY_NAME.equals(format)) {
|
||||
return false;
|
||||
}
|
||||
return DyldCacheUtils.isDyldCache(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDefaultEnablement(Program program) {
|
||||
return DyldCacheUtil.isDyldCache(program);
|
||||
return DyldCacheUtils.isDyldCache(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,65 +0,0 @@
|
||||
/* ###
|
||||
* 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.file.formats.ios.dyldcache;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DyldCacheData implements StructConverter{
|
||||
|
||||
private long libraryOffset;
|
||||
private long unknown0;
|
||||
private long unknown1;
|
||||
private long fileOffset;
|
||||
|
||||
private String _path;
|
||||
|
||||
public DyldCacheData(BinaryReader reader) throws IOException {
|
||||
libraryOffset = reader.readNextLong();
|
||||
unknown0 = reader.readNextLong();
|
||||
unknown1 = reader.readNextLong();
|
||||
fileOffset = reader.readNextLong();
|
||||
|
||||
_path = reader.readAsciiString( fileOffset );
|
||||
}
|
||||
|
||||
public long getLibraryOffset() {
|
||||
return libraryOffset;
|
||||
}
|
||||
|
||||
public long getFileOffset() {
|
||||
return fileOffset;
|
||||
}
|
||||
|
||||
public long getUnknown(int index) {
|
||||
switch (index) {
|
||||
case 0: return unknown0;
|
||||
case 1: return unknown1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return _path;
|
||||
}
|
||||
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return StructConverterUtil.toDataType(this);
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@ import java.util.*;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.MachException;
|
||||
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
|
||||
import ghidra.app.util.bin.format.macho.dyld.DyldCacheImageInfo;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.DyldCacheUtils;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemBaseFactory;
|
||||
@ -33,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
|
||||
private DyldCacheHeader header;
|
||||
private Map<GFile, DyldCacheData> map = new HashMap<>();
|
||||
private Map<GFile, DyldCacheImageInfo> map = new HashMap<>();
|
||||
|
||||
public DyldCacheFileSystem(String fileSystemName, ByteProvider provider) {
|
||||
super(fileSystemName, provider);
|
||||
@ -47,11 +51,11 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
|
||||
@Override
|
||||
protected InputStream getData(GFile file, TaskMonitor monitor) throws IOException {
|
||||
DyldCacheData data = map.get(file);
|
||||
DyldCacheImageInfo data = map.get(file);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
long machHeaderStartIndexInProvider = data.getLibraryOffset() - header.getBaseAddress();
|
||||
long machHeaderStartIndexInProvider = data.getAddress() - header.getBaseAddress();
|
||||
try {
|
||||
/*
|
||||
* //check to make sure mach-o header is valid MachHeader header =
|
||||
@ -136,11 +140,7 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
|
||||
@Override
|
||||
public boolean isValid(TaskMonitor monitor) throws IOException {
|
||||
BinaryReader reader = new BinaryReader(provider, true);
|
||||
|
||||
DyldCacheHeader header = new DyldCacheHeader(reader);
|
||||
|
||||
return DyldCacheUtil.isDyldCache(new String(header.getVersion()).trim());
|
||||
return DyldCacheUtils.isDyldCache(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,13 +150,13 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
BinaryReader reader = new BinaryReader(provider, true);
|
||||
|
||||
header = new DyldCacheHeader(reader);
|
||||
header.parse(monitor);
|
||||
header.parseFromFile(false, new MessageLog(), monitor);
|
||||
|
||||
List<DyldCacheData> dataList = header.getDataList();
|
||||
List<DyldCacheImageInfo> dataList = header.getImageInfos();
|
||||
|
||||
monitor.initialize(dataList.size());
|
||||
|
||||
for (DyldCacheData data : dataList) {
|
||||
for (DyldCacheImageInfo data : dataList) {
|
||||
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
@ -168,11 +168,11 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
0/*TODO compute length?*/ );
|
||||
storeFile(file, data);
|
||||
|
||||
file.setLength(provider.length() - (data.getLibraryOffset() - header.getBaseAddress()));
|
||||
file.setLength(provider.length() - (data.getAddress() - header.getBaseAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
private void storeFile(GFile file, DyldCacheData data) {
|
||||
private void storeFile(GFile file, DyldCacheImageInfo data) {
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,101 +0,0 @@
|
||||
/* ###
|
||||
* 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.file.formats.ios.dyldcache;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DyldCacheHeader implements StructConverter {
|
||||
|
||||
private byte [] version;
|
||||
private int baseAddressOffset;
|
||||
private int unknown;
|
||||
private int startAddress;
|
||||
private int libraryCount;
|
||||
private long dyldAddress;
|
||||
|
||||
private BinaryReader _reader;
|
||||
private long _baseAddress;
|
||||
private List<DyldCacheData> _list = new ArrayList<DyldCacheData>();
|
||||
private DyldArchitecture _architecture;
|
||||
|
||||
public DyldCacheHeader(BinaryReader reader) throws IOException {
|
||||
_reader = reader;
|
||||
|
||||
version = reader.readNextByteArray( 16 );
|
||||
baseAddressOffset = reader.readNextInt();
|
||||
unknown = reader.readNextInt();
|
||||
startAddress = reader.readNextInt();
|
||||
libraryCount = reader.readNextInt();
|
||||
dyldAddress = reader.readNextLong();
|
||||
|
||||
_baseAddress = reader.readLong( baseAddressOffset & 0xffffffffL );
|
||||
|
||||
_architecture = DyldArchitecture.getArchitecture( new String( version ).trim() );
|
||||
}
|
||||
|
||||
public void parse(TaskMonitor monitor) throws IOException {
|
||||
_reader.setPointerIndex( startAddress );
|
||||
|
||||
for (int i = 0 ; i < libraryCount ; ++i) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
DyldCacheData data = new DyldCacheData( _reader );
|
||||
_list.add( data );
|
||||
}
|
||||
}
|
||||
|
||||
public byte [] getVersion() {
|
||||
return version;
|
||||
}
|
||||
public int getBaseAddressOffset() {
|
||||
return baseAddressOffset;
|
||||
}
|
||||
public long getBaseAddress() {
|
||||
return _baseAddress;
|
||||
}
|
||||
public int getUnknown() {
|
||||
return unknown;
|
||||
}
|
||||
public int getStartAddress() {
|
||||
return startAddress;
|
||||
}
|
||||
public int getLibraryCount() {
|
||||
return libraryCount;
|
||||
}
|
||||
public long getDyldAddress() {
|
||||
return dyldAddress;
|
||||
}
|
||||
|
||||
public List<DyldCacheData> getDataList() {
|
||||
return _list;
|
||||
}
|
||||
|
||||
public DyldArchitecture getArchitecture() {
|
||||
return _architecture;
|
||||
}
|
||||
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return StructConverterUtil.toDataType(this);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/* ###
|
||||
* 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.file.formats.ios.dyldcache;
|
||||
|
||||
public class DyldCacheLibrary {
|
||||
|
||||
|
||||
}
|
@ -5,6 +5,9 @@
|
||||
<constraint loader="Mac OS X Mach-O" compilerSpecID="default">
|
||||
<constraint primary="16777228" processor="AARCH64" endian="little" size="64" />
|
||||
</constraint>
|
||||
<constraint loader="DYLD Cache" compilerSpecID="default">
|
||||
<constraint primary="AARCH64" processor="AARCH64" endian="little" size="64" />
|
||||
</constraint>
|
||||
<constraint loader="Portable Executable (PE)" compilerSpecID="windows">
|
||||
<constraint primary="43620" processor="AARCH64" endian="little" size="64" variant="v8A" />
|
||||
</constraint>
|
||||
|
@ -26,6 +26,10 @@
|
||||
<constraint primary="12.11" processor="ARM" endian="little" size="32" variant="v8" /><!-- ARM v8s -->
|
||||
<constraint primary="12.12" processor="ARM" endian="little" size="32" variant="v8" /><!-- ARM v8k -->
|
||||
</constraint>
|
||||
<constraint loader="DYLD Cache" compilerSpecID="default">
|
||||
<constraint primary="armv6" processor="ARM" endian="little" size="32" variant="v6" />
|
||||
<constraint primary="arm7" processor="ARM" endian="little" size="32" variant="v7" />
|
||||
</constraint>
|
||||
<constraint loader="MS Common Object File Format (COFF)" compilerSpecID="windows">
|
||||
<constraint primary="448" processor="ARM" endian="little" size="32" variant="v8" />
|
||||
<constraint primary="450" processor="ARM" endian="little" size="32" variant="v8" />
|
||||
|
Loading…
Reference in New Issue
Block a user