mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 12:49:45 +00:00
GP-2113: Objective-C support in dyld_shared_cache
This commit is contained in:
parent
d2883bbb8c
commit
1430d18f65
@ -15,8 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.macho.dyld.LibObjcOptimization;
|
||||
import ghidra.app.util.bin.format.objc2.*;
|
||||
import ghidra.app.util.bin.format.objectiveC.ObjectiveC1_Constants;
|
||||
import ghidra.app.util.bin.format.objectiveC.ObjectiveC1_Utilities;
|
||||
@ -32,8 +36,6 @@ import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
|
||||
private static final String NAME = "Objective-C 2 Class";
|
||||
private static final String DESCRIPTION =
|
||||
@ -47,11 +49,13 @@ public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
|
||||
setPriority(AnalysisPriority.FORMAT_ANALYSIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
return processObjectiveC2(program, monitor, log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
return ObjectiveC2_Constants.isObjectiveC2(program);
|
||||
}
|
||||
@ -60,27 +64,52 @@ public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
|
||||
/* ************************************************************************** */
|
||||
|
||||
private boolean processObjectiveC2(Program program, TaskMonitor monitor, MessageLog log) {
|
||||
ByteProvider provider =
|
||||
new MemoryByteProvider(program.getMemory(),
|
||||
program.getAddressFactory().getDefaultAddressSpace());
|
||||
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
|
||||
|
||||
ObjectiveC2_State state =
|
||||
new ObjectiveC2_State(program, monitor, ObjectiveC2_Constants.CATEGORY_PATH);
|
||||
|
||||
try {
|
||||
processImageInfo(state, reader);
|
||||
try (ByteProvider provider = new MemoryByteProvider(program.getMemory(),
|
||||
program.getAddressFactory().getDefaultAddressSpace())) {
|
||||
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
|
||||
|
||||
processClassList(state, reader);
|
||||
processCategoryList(state, reader);
|
||||
processProtocolList(state, reader);
|
||||
// Create a map of Objective-C specific memory blocks. If this is a dyld_shared_cache
|
||||
// file, there will be many of each type.
|
||||
Map<String, List<MemoryBlock>> objcBlockMap = new HashMap<>();
|
||||
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
||||
String name = block.getName();
|
||||
if (name.startsWith(ObjectiveC2_Constants.OBJC2_PREFIX)) {
|
||||
List<MemoryBlock> list = objcBlockMap.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
objcBlockMap.put(name, list);
|
||||
}
|
||||
list.add(block);
|
||||
}
|
||||
if (name.equals(LibObjcOptimization.SECTION_NAME)) {
|
||||
// If this is a dyld_shared_cache, there should one of these. We'll need to
|
||||
// save it so we can later extract selector/method names.
|
||||
try {
|
||||
state.libObjcOptimization =
|
||||
new LibObjcOptimization(program, block.getStart());
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(
|
||||
"Failed to parse libobjc. Method names may not be recoverable.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processClassReferences(state);
|
||||
processSuperReferences(state);
|
||||
processProtocolReferences(state);
|
||||
processNonLazyClassReferences(state);
|
||||
processSelectorReferences(state);
|
||||
processMessageReferences(state, reader);
|
||||
processImageInfo(state, reader, objcBlockMap);
|
||||
|
||||
processClassList(state, reader, objcBlockMap);
|
||||
processCategoryList(state, reader, objcBlockMap);
|
||||
processProtocolList(state, reader, objcBlockMap);
|
||||
|
||||
processClassReferences(state, objcBlockMap);
|
||||
processSuperReferences(state, objcBlockMap);
|
||||
processProtocolReferences(state, objcBlockMap);
|
||||
processNonLazyClassReferences(state, objcBlockMap);
|
||||
processSelectorReferences(state, objcBlockMap);
|
||||
processMessageReferences(state, reader, objcBlockMap);
|
||||
|
||||
ObjectiveC1_Utilities.createMethods(state);
|
||||
ObjectiveC1_Utilities.createInstanceVariablesC2_OBJC2(state);
|
||||
@ -96,12 +125,6 @@ public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
finally {
|
||||
state.dispose();
|
||||
|
||||
try {
|
||||
provider.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -139,289 +162,313 @@ public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
private void processProtocolReferences(ObjectiveC2_State state) throws Exception {
|
||||
private void processProtocolReferences(ObjectiveC2_State state,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Protocol References...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_PROTOCOL_REFS);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_PROTOCOL_REFS);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void processClassReferences(ObjectiveC2_State state) throws Exception {
|
||||
private void processClassReferences(ObjectiveC2_State state,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Class References...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_CLASS_REFS);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_CLASS_REFS);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void processNonLazyClassReferences(ObjectiveC2_State state) throws Exception {
|
||||
private void processNonLazyClassReferences(ObjectiveC2_State state,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Non-lazy Class Lists...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_NON_LAZY_CLASS_LIST);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks =
|
||||
objcBlockMap.get(ObjectiveC2_Constants.OBJC2_NON_LAZY_CLASS_LIST);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void processSuperReferences(ObjectiveC2_State state) throws Exception {
|
||||
private void processSuperReferences(ObjectiveC2_State state,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Super References...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_SUPER_REFS);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_SUPER_REFS);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void processCategoryList(ObjectiveC2_State state, BinaryReader reader) throws Exception {
|
||||
private void processCategoryList(ObjectiveC2_State state, BinaryReader reader,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Category Information...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_CATEGORY_LIST);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_CATEGORY_LIST);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
Address address = block.getStart();
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
Address categoryAddress = ObjectiveC1_Utilities
|
||||
.createPointerAndReturnAddressBeingReferenced(state.program, address);
|
||||
reader.setPointerIndex(categoryAddress.getOffset());
|
||||
ObjectiveC2_Category category = new ObjectiveC2_Category(state, reader);
|
||||
category.applyTo();
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
Address categoryAddress =
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
reader.setPointerIndex(categoryAddress.getOffset());
|
||||
ObjectiveC2_Category category = new ObjectiveC2_Category(state, reader);
|
||||
category.applyTo();
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void processImageInfo(ObjectiveC2_State state, BinaryReader reader) throws Exception {
|
||||
private void processImageInfo(ObjectiveC2_State state, BinaryReader reader,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Image Information...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_IMAGE_INFO);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_IMAGE_INFO);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
Address address = block.getStart();
|
||||
reader.setPointerIndex(address.getOffset());
|
||||
ObjectiveC2_ImageInfo imageInfo = new ObjectiveC2_ImageInfo(state, reader);
|
||||
imageInfo.applyTo();
|
||||
for (MemoryBlock block : blocks) {
|
||||
Address address = block.getStart();
|
||||
reader.setPointerIndex(address.getOffset());
|
||||
ObjectiveC2_ImageInfo imageInfo = new ObjectiveC2_ImageInfo(state, reader);
|
||||
imageInfo.applyTo();
|
||||
}
|
||||
}
|
||||
|
||||
private void processProtocolList(ObjectiveC2_State state, BinaryReader reader) throws Exception {
|
||||
private void processProtocolList(ObjectiveC2_State state, BinaryReader reader,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Protocol Information...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_PROTOCOL_LIST);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_PROTOCOL_LIST);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
Address address = block.getStart();
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
|
||||
Address protocolAddress =
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
reader.setPointerIndex(protocolAddress.getOffset());
|
||||
Address protocolAddress = ObjectiveC1_Utilities
|
||||
.createPointerAndReturnAddressBeingReferenced(state.program, address);
|
||||
reader.setPointerIndex(protocolAddress.getOffset());
|
||||
|
||||
ObjectiveC2_Protocol protocol = new ObjectiveC2_Protocol(state, reader);
|
||||
Namespace namespace =
|
||||
ObjectiveC1_Utilities.createNamespace(state.program,
|
||||
ObjectiveC2_Protocol protocol = new ObjectiveC2_Protocol(state, reader);
|
||||
Namespace namespace = ObjectiveC1_Utilities.createNamespace(state.program,
|
||||
ObjectiveC1_Constants.NAMESPACE, "Protocols", protocol.getName());
|
||||
protocol.applyTo(namespace);
|
||||
address = address.add(state.pointerSize);
|
||||
protocol.applyTo(namespace);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processClassList(ObjectiveC2_State state, BinaryReader reader) throws Exception {
|
||||
private void processClassList(ObjectiveC2_State state, BinaryReader reader,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Class Information...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_CLASS_LIST);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_CLASS_LIST);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
Address address = block.getStart();
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
|
||||
Address classAddress = ObjectiveC1_Utilities
|
||||
.createPointerAndReturnAddressBeingReferenced(state.program, address);
|
||||
reader.setPointerIndex(classAddress.getOffset() & 0xfffffffffffL);
|
||||
|
||||
ObjectiveC2_Class clazz = new ObjectiveC2_Class(state, reader);
|
||||
clazz.applyTo();
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
|
||||
Address classAddress =
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
reader.setPointerIndex(classAddress.getOffset());
|
||||
|
||||
ObjectiveC2_Class clazz = new ObjectiveC2_Class(state, reader);
|
||||
clazz.applyTo();
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void processMessageReferences(ObjectiveC2_State state, BinaryReader reader)
|
||||
private void processMessageReferences(ObjectiveC2_State state, BinaryReader reader,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap)
|
||||
throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Message References...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_MESSAGE_REFS);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_MESSAGE_REFS);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / ObjectiveC2_MessageReference.SIZEOF(state);
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / ObjectiveC2_MessageReference.SIZEOF(state);
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
reader.setPointerIndex(address.getOffset());
|
||||
ObjectiveC2_MessageReference messageRef =
|
||||
new ObjectiveC2_MessageReference(state, reader);
|
||||
DataType dt = messageRef.toDataType();
|
||||
Data messageRefData = state.program.getListing().createData(address, dt);
|
||||
Data selData = messageRefData.getComponent(1);
|
||||
Object selAddress = selData.getValue();
|
||||
Data selStringData = state.program.getListing().getDataAt((Address) selAddress);
|
||||
Object selString = selStringData.getValue();
|
||||
ObjectiveC1_Utilities.createSymbol(state.program, null,
|
||||
selString + "_" + ObjectiveC2_MessageReference.NAME, address);
|
||||
address = address.add(dt.getLength());
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
reader.setPointerIndex(address.getOffset());
|
||||
ObjectiveC2_MessageReference messageRef =
|
||||
new ObjectiveC2_MessageReference(state, reader);
|
||||
DataType dt = messageRef.toDataType();
|
||||
Data messageRefData = state.program.getListing().createData(address, dt);
|
||||
Data selData = messageRefData.getComponent(1);
|
||||
Object selAddress = selData.getValue();
|
||||
Data selStringData = state.program.getListing().getDataAt((Address) selAddress);
|
||||
Object selString = selStringData.getValue();
|
||||
ObjectiveC1_Utilities.createSymbol(state.program, null, selString + "_" +
|
||||
ObjectiveC2_MessageReference.NAME, address);
|
||||
address = address.add(dt.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
private void processSelectorReferences(ObjectiveC2_State state) throws Exception {
|
||||
private void processSelectorReferences(ObjectiveC2_State state,
|
||||
Map<String, List<MemoryBlock>> objcBlockMap) throws Exception {
|
||||
state.monitor.setMessage("Objective-C 2.0 Selector References...");
|
||||
|
||||
MemoryBlock block =
|
||||
state.program.getMemory().getBlock(ObjectiveC2_Constants.OBJC2_SELECTOR_REFS);
|
||||
if (block == null) {
|
||||
List<MemoryBlock> blocks = objcBlockMap.get(ObjectiveC2_Constants.OBJC2_SELECTOR_REFS);
|
||||
if (blocks == null) {
|
||||
return;
|
||||
}
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
for (MemoryBlock block : blocks) {
|
||||
ObjectiveC1_Utilities.clear(state, block);
|
||||
|
||||
state.monitor.initialize((int) count);
|
||||
long count = block.getSize() / state.pointerSize;
|
||||
|
||||
Address address = block.getStart();
|
||||
state.monitor.initialize((int) count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
Address address = block.getStart();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (state.monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
state.monitor.setProgress(i);
|
||||
ObjectiveC1_Utilities.createPointerAndReturnAddressBeingReferenced(state.program,
|
||||
address);
|
||||
address = address.add(state.pointerSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -696,9 +696,8 @@ public class DyldCacheHeader implements StructConverter {
|
||||
}
|
||||
monitor.setMessage("Parsing DYLD accelerateor info...");
|
||||
monitor.initialize(imagesTextCount);
|
||||
try {
|
||||
Address addr = space.getAddress(accelerateInfoAddr);
|
||||
ByteProvider bytes = new MemoryByteProvider(program.getMemory(), addr);
|
||||
Address addr = space.getAddress(accelerateInfoAddr);
|
||||
try (ByteProvider bytes = new MemoryByteProvider(program.getMemory(), addr)) {
|
||||
BinaryReader memoryReader =
|
||||
new BinaryReader(bytes, !program.getLanguage().isBigEndian());
|
||||
accelerateInfo = new DyldCacheAccelerateInfo(memoryReader);
|
||||
|
@ -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.format.macho.MachHeader;
|
||||
import ghidra.app.util.bin.format.macho.Section;
|
||||
import ghidra.app.util.bin.format.macho.commands.SegmentNames;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A class to represent the libobjc DYLIB Mach-O that resides within a DYLD cache
|
||||
*/
|
||||
public class LibObjcDylib {
|
||||
|
||||
private MachHeader libObjcHeader;
|
||||
private Program program;
|
||||
private AddressSpace space;
|
||||
private MessageLog log;
|
||||
private TaskMonitor monitor;
|
||||
|
||||
private LibObjcOptimization libObjcOptimization;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LibObjcDylib}
|
||||
*
|
||||
* @param libObjcHeader The libobjc DYLIB header
|
||||
* @param program The {@link Program}
|
||||
* @param space The {@link AddressSpace}
|
||||
* @param log The log
|
||||
* @param monitor A cancelable task monitor
|
||||
* @throws IOException if an IO-related error occurred while parsing
|
||||
*/
|
||||
public LibObjcDylib(MachHeader libObjcHeader, Program program, AddressSpace space,
|
||||
MessageLog log, TaskMonitor monitor) throws IOException {
|
||||
this.libObjcHeader = libObjcHeader;
|
||||
this.program = program;
|
||||
this.space = space;
|
||||
this.log = log;
|
||||
this.monitor = monitor;
|
||||
|
||||
libObjcOptimization = parseLibObjcOptimization();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up the libobjc DYLIB
|
||||
*/
|
||||
public void markup() {
|
||||
if (libObjcOptimization != null) {
|
||||
libObjcOptimization.markup(program, space, log, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the objc_opt_t structure which lives at the start of the __objc_opt_ro section in the
|
||||
* libobjc DYLIB
|
||||
*
|
||||
* @return The parsed {@link LibObjcOptimization objc_opt_t} structure, or null if it doesn't
|
||||
* exist
|
||||
* @throws IOException if an IO-related error occurred while parsing
|
||||
*/
|
||||
private LibObjcOptimization parseLibObjcOptimization() throws IOException {
|
||||
Section section =
|
||||
libObjcHeader.getSection(SegmentNames.SEG_TEXT, LibObjcOptimization.SECTION_NAME);
|
||||
if (section == null) {
|
||||
return null;
|
||||
}
|
||||
return new LibObjcOptimization(program, space.getAddress(section.getAddress()));
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/* ###
|
||||
* 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.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Represents a objc_opt_t structure, which resides in the libobjc DYLIB within a DYLD cache
|
||||
*
|
||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/objc-shared-cache.h">dyld/include/objc-shared-cache.h</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LibObjcOptimization implements StructConverter {
|
||||
|
||||
/**
|
||||
* The name of the section that contains the objc_opt_t_structure
|
||||
*/
|
||||
public final static String SECTION_NAME = "__objc_opt_ro";
|
||||
|
||||
private int version;
|
||||
private int flags;
|
||||
private int selopt_offset;
|
||||
private int headeropt_ro_offset;
|
||||
private int clsopt_offset;
|
||||
private int protocolopt1_offset;
|
||||
private int headeropt_rw_offset;
|
||||
private int protocolopt2_offset;
|
||||
private int largeSharedCachesClassOffset;
|
||||
private int largeSharedCachesProtocolOffset;
|
||||
private long relativeMethodSelectorBaseAddressOffset;
|
||||
|
||||
private long objcOptAddr;
|
||||
|
||||
/**
|
||||
* Create a new {@link LibObjcOptimization}.
|
||||
*
|
||||
* @param program The {@link Program}
|
||||
* @param objcOptRoSectionAddr The start address of the __objc_opt_ro section
|
||||
* @throws IOException if there was an IO-related problem parsing the structure
|
||||
*/
|
||||
public LibObjcOptimization(Program program, Address objcOptRoSectionAddr) throws IOException {
|
||||
try (ByteProvider provider =
|
||||
new MemoryByteProvider(program.getMemory(), objcOptRoSectionAddr)) {
|
||||
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
|
||||
|
||||
version = reader.readNextInt();
|
||||
if (version <= 14) {
|
||||
selopt_offset = reader.readNextInt();
|
||||
headeropt_ro_offset = reader.readNextInt();
|
||||
clsopt_offset = reader.readNextInt();
|
||||
if (version >= 13) {
|
||||
protocolopt1_offset = reader.readNextInt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
flags = reader.readNextInt();
|
||||
selopt_offset = reader.readNextInt();
|
||||
headeropt_ro_offset = reader.readNextInt();
|
||||
clsopt_offset = reader.readNextInt();
|
||||
protocolopt1_offset = reader.readNextInt();
|
||||
headeropt_rw_offset = reader.readNextInt();
|
||||
protocolopt2_offset = reader.readNextInt();
|
||||
if (version >= 16) {
|
||||
largeSharedCachesClassOffset = reader.readNextInt();
|
||||
largeSharedCachesProtocolOffset = reader.readNextInt();
|
||||
relativeMethodSelectorBaseAddressOffset = reader.readNextLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objcOptAddr = objcOptRoSectionAddr.getOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the objc_opt_t structure
|
||||
*
|
||||
* @return The address of the objc_opt_t structure
|
||||
*/
|
||||
public long getAddr() {
|
||||
return objcOptAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative method selector base address offset. This will be 0 if the version < 16.
|
||||
*
|
||||
* @return The relative method selector base address offset
|
||||
*/
|
||||
public long getRelativeSelectorBaseAddressOffset() {
|
||||
return relativeMethodSelectorBaseAddressOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks up up this structure in memory
|
||||
*
|
||||
* @param program The {@link Program}
|
||||
* @param space The {@link AddressSpace}
|
||||
* @param log The log
|
||||
* @param monitor A cancelable task monitor
|
||||
*/
|
||||
public void markup(Program program, AddressSpace space, MessageLog log, TaskMonitor monitor) {
|
||||
Address addr = space.getAddress(getAddr());
|
||||
try {
|
||||
DataUtilities.createData(program, addr, toDataType(), -1, false,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||
log.appendMsg(LibObjcOptimization.class.getSimpleName(),
|
||||
"Failed to markup objc_opt_t.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType("objc_opt_t", 0);
|
||||
if (version <= 12) {
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "selopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_offset", "");
|
||||
struct.add(DWORD, "clsopt_offset", "");
|
||||
}
|
||||
else if (version >= 13 && version <= 14) {
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "selopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_offset", "");
|
||||
struct.add(DWORD, "clsopt_offset", "");
|
||||
struct.add(DWORD, "protocolopt_offset", "");
|
||||
}
|
||||
else if (version == 15) {
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "flags", "");
|
||||
struct.add(DWORD, "selopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_ro_offset", "");
|
||||
struct.add(DWORD, "clsopt_offset", "");
|
||||
struct.add(DWORD, "unused_protocolopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_rw_offset", "");
|
||||
struct.add(DWORD, "protocolopt_offset", "");
|
||||
}
|
||||
else { // version >= 16
|
||||
struct.add(DWORD, "version", "");
|
||||
struct.add(DWORD, "flags", "");
|
||||
struct.add(DWORD, "selopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_ro_offset", "");
|
||||
struct.add(DWORD, "unused_clsopt_offset", "");
|
||||
struct.add(DWORD, "unused_protocolopt_offset", "");
|
||||
struct.add(DWORD, "headeropt_rw_offset", "");
|
||||
struct.add(DWORD, "unused_protocolopt2_offset", "");
|
||||
struct.add(DWORD, "largeSharedCachesClassOffset", "");
|
||||
struct.add(DWORD, "largeSharedCachesProtocolOffset", "");
|
||||
struct.add(QWORD, "relativeMethodSelectorBaseAddressOffset", "");
|
||||
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,21 +15,22 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.objc2;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.opinion.DyldCacheLoader;
|
||||
import ghidra.app.util.opinion.MachoLoader;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class ObjectiveC2_Constants {
|
||||
|
||||
/**
|
||||
* The name prefix of all Objective-C 2 sections.
|
||||
*/
|
||||
private final static String OBJC2_PREFIX = "__objc_";
|
||||
public final static String OBJC2_PREFIX = "__objc_";
|
||||
|
||||
/** Objective-C 2 category list. */
|
||||
public final static String OBJC2_CATEGORY_LIST = "__objc_catlist";
|
||||
@ -84,7 +84,8 @@ public final class ObjectiveC2_Constants {
|
||||
*/
|
||||
public final static boolean isObjectiveC2(Program program) {
|
||||
String format = program.getExecutableFormat();
|
||||
if (MachoLoader.MACH_O_NAME.equals(format)) {
|
||||
if (MachoLoader.MACH_O_NAME.equals(format) ||
|
||||
DyldCacheLoader.DYLD_CACHE_NAME.equals(format)) {
|
||||
MemoryBlock [] blocks = program.getMemory().getBlocks();
|
||||
for (MemoryBlock memoryBlock : blocks) {
|
||||
if (memoryBlock.getName().startsWith(OBJC2_PREFIX)) {
|
||||
|
@ -42,7 +42,20 @@ public class ObjectiveC2_Method extends ObjectiveC_Method {
|
||||
namePtr = reader.readInt(_index + nameOffset);
|
||||
}
|
||||
else {
|
||||
namePtr = reader.readLong(_index + nameOffset);
|
||||
if (state.libObjcOptimization != null) {
|
||||
// We are in a DYLD Cache
|
||||
if (state.libObjcOptimization.getRelativeSelectorBaseAddressOffset() > 0) {
|
||||
namePtr = state.libObjcOptimization.getAddr() +
|
||||
state.libObjcOptimization.getRelativeSelectorBaseAddressOffset() +
|
||||
nameOffset;
|
||||
}
|
||||
else {
|
||||
namePtr = _index + nameOffset;
|
||||
}
|
||||
}
|
||||
else {
|
||||
namePtr = reader.readLong(_index + nameOffset);
|
||||
}
|
||||
}
|
||||
|
||||
name = reader.readAsciiString(namePtr);
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,14 +15,15 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.objc2;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.format.macho.dyld.LibObjcOptimization;
|
||||
import ghidra.app.util.bin.format.objectiveC.ObjectiveC1_State;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ObjectiveC2_State extends ObjectiveC1_State {
|
||||
|
||||
/**
|
||||
@ -36,6 +36,11 @@ public class ObjectiveC2_State extends ObjectiveC1_State {
|
||||
*/
|
||||
public final Map<Address, ObjectiveC2_InstanceVariable> variableMap = new HashMap<Address, ObjectiveC2_InstanceVariable>();
|
||||
|
||||
/**
|
||||
* The dyld_shared_cache libobjc objc_opt_t structure, if it exists
|
||||
*/
|
||||
public LibObjcOptimization libObjcOptimization = null;
|
||||
|
||||
public ObjectiveC2_State(Program program, TaskMonitor monitor, CategoryPath categoryPath) {
|
||||
super(program, monitor, categoryPath);
|
||||
}
|
||||
|
@ -45,9 +45,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
|
||||
/** Loader option to create memory blocks for DYLIB sections */
|
||||
static final String CREATE_DYLIB_SECTIONS_OPTION_NAME = "Create DYLIB section memory blocks";
|
||||
|
||||
/** Default value for loader option to create memory blocks for DYLIB sections */
|
||||
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false;
|
||||
|
||||
/** Loader option to add relocation entries for chained fixups */
|
||||
static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME =
|
||||
"Add relocation entries for chained fixups";
|
||||
@ -97,9 +94,8 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
|
||||
try {
|
||||
DyldCacheProgramBuilder.buildProgram(program, provider,
|
||||
MemoryBlockUtils.createFileBytes(program, provider, monitor),
|
||||
shouldProcessSymbols(options), shouldCreateDylibSections(options),
|
||||
shouldAddChainedFixupsRelocations(options), shouldCombineSplitFiles(options), log,
|
||||
monitor);
|
||||
shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options),
|
||||
shouldCombineSplitFiles(options), log, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return;
|
||||
@ -117,9 +113,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
|
||||
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"));
|
||||
list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME,
|
||||
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class,
|
||||
Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations"));
|
||||
@ -134,11 +127,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
|
||||
PROCESS_SYMBOLS_OPTION_DEFAULT);
|
||||
}
|
||||
|
||||
private boolean shouldCreateDylibSections(List<Option> options) {
|
||||
return OptionUtils.getOption(CREATE_DYLIB_SECTIONS_OPTION_NAME, options,
|
||||
CREATE_DYLIB_SECTIONS_OPTION_DEFAULT);
|
||||
}
|
||||
|
||||
private boolean shouldAddChainedFixupsRelocations(List<Option> options) {
|
||||
return OptionUtils.getOption(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, options,
|
||||
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT);
|
||||
|
@ -45,7 +45,6 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
|
||||
private boolean shouldProcessSymbols;
|
||||
private boolean shouldCreateDylibSections;
|
||||
private boolean shouldCombineSplitFiles;
|
||||
|
||||
/**
|
||||
@ -55,8 +54,6 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
* @param provider The {@link ByteProvider} that contains the DYLD Cache bytes
|
||||
* @param fileBytes Where the DYLD Cache's bytes came from
|
||||
* @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 shouldAddChainedFixupsRelocations True if relocations should be added for chained
|
||||
* fixups; otherwise, false
|
||||
* @param shouldCombineSplitFiles True if split DYLD Cache files should be automatically
|
||||
@ -65,12 +62,10 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
* @param monitor A cancelable task monitor
|
||||
*/
|
||||
protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
|
||||
boolean shouldProcessSymbols, boolean shouldCreateDylibSections,
|
||||
boolean shouldAddChainedFixupsRelocations, boolean shouldCombineSplitFiles,
|
||||
MessageLog log, TaskMonitor monitor) {
|
||||
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations,
|
||||
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor) {
|
||||
super(program, provider, fileBytes, shouldAddChainedFixupsRelocations, log, monitor);
|
||||
this.shouldProcessSymbols = shouldProcessSymbols;
|
||||
this.shouldCreateDylibSections = shouldCreateDylibSections;
|
||||
this.shouldCombineSplitFiles = shouldCombineSplitFiles;
|
||||
}
|
||||
|
||||
@ -81,8 +76,6 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
* @param provider The {@link ByteProvider} that contains the DYLD Cache's bytes
|
||||
* @param fileBytes Where the Mach-O's bytes came from
|
||||
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
|
||||
* @param shouldCreateDylibSections True if memory blocks should be created for DYLIB sections;
|
||||
* otherwise, false
|
||||
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
|
||||
* fixups; otherwise, false
|
||||
* @param shouldCombineSplitFiles True if split DYLD Cache files should be automatically
|
||||
@ -92,12 +85,11 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
* @throws Exception if a problem occurs
|
||||
*/
|
||||
public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
|
||||
boolean shouldProcessSymbols, boolean shouldCreateDylibSections,
|
||||
boolean shouldAddChainedFixupsRelocations, boolean shouldCombineSplitFiles,
|
||||
MessageLog log, TaskMonitor monitor) throws Exception {
|
||||
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations,
|
||||
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor) throws Exception {
|
||||
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
|
||||
provider, fileBytes, shouldProcessSymbols, shouldCreateDylibSections,
|
||||
shouldAddChainedFixupsRelocations, shouldCombineSplitFiles, log, monitor);
|
||||
provider, fileBytes, shouldProcessSymbols, shouldAddChainedFixupsRelocations,
|
||||
shouldCombineSplitFiles, log, monitor);
|
||||
dyldCacheProgramBuilder.build();
|
||||
}
|
||||
|
||||
@ -294,16 +286,21 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
private void processDylibs(SplitDyldCache splitDyldCache, DyldCacheHeader dyldCacheHeader,
|
||||
ByteProvider bp, boolean localSymbolsPresent) throws Exception {
|
||||
// Create an "info" object for each DyldCache DYLIB, which will make processing them
|
||||
// easier
|
||||
// easier. Save off the "libobjc" DYLIB for additional processing later.
|
||||
monitor.setMessage("Parsing DYLIB's...");
|
||||
DyldCacheMachoInfo libobjcInfo = null;
|
||||
TreeSet<DyldCacheMachoInfo> infoSet =
|
||||
new TreeSet<>((a, b) -> a.headerAddr.compareTo(b.headerAddr));
|
||||
List<DyldCacheImage> mappedImages = dyldCacheHeader.getMappedImages();
|
||||
monitor.initialize(mappedImages.size());
|
||||
for (DyldCacheImage mappedImage : mappedImages) {
|
||||
infoSet.add(new DyldCacheMachoInfo(splitDyldCache, bp,
|
||||
DyldCacheMachoInfo info = new DyldCacheMachoInfo(splitDyldCache, bp,
|
||||
mappedImage.getAddress() - dyldCacheHeader.getBaseAddress(),
|
||||
space.getAddress(mappedImage.getAddress()), mappedImage.getPath()));
|
||||
space.getAddress(mappedImage.getAddress()), mappedImage.getPath());
|
||||
infoSet.add(info);
|
||||
if (libobjcInfo == null && info.name.contains("libobjc.")) {
|
||||
libobjcInfo = info;
|
||||
}
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
@ -328,7 +325,6 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Markup DyldCache Mach-O headers
|
||||
monitor.setMessage("Marking up DYLIB headers...");
|
||||
@ -348,7 +344,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
// Process DyldCache DYLIB memory blocks.
|
||||
// Process DyldCache DYLIB memory blocks
|
||||
monitor.setMessage("Processing DYLIB memory blocks...");
|
||||
monitor.initialize(infoSet.size());
|
||||
for (DyldCacheMachoInfo info : infoSet) {
|
||||
@ -356,6 +352,16 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
monitor.checkCanceled();
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
// Process and markup the libobjc DYLIB
|
||||
monitor.setMessage("Processing libobjc...");
|
||||
DyldCacheMachoInfo libObjcInfo =
|
||||
infoSet.stream().filter(e -> e.name.contains("libobjc.")).findAny().orElse(null);
|
||||
if (libObjcInfo != null) {
|
||||
LibObjcDylib libObjcDylib =
|
||||
new LibObjcDylib(libObjcInfo.header, program, space, log, monitor);
|
||||
libObjcDylib.markup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -393,8 +399,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
||||
* @see DyldCacheProgramBuilder#processMemoryBlocks(MachHeader, String, boolean, boolean)
|
||||
*/
|
||||
public void processMemoryBlocks() throws Exception {
|
||||
DyldCacheProgramBuilder.this.processMemoryBlocks(header, name,
|
||||
shouldCreateDylibSections, false);
|
||||
DyldCacheProgramBuilder.this.processMemoryBlocks(header, name, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user