mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 20:29:50 +08:00
GP-4462: Marking up the Mach-O rebase opcode table
This commit is contained in:
+28
-10
@@ -20,8 +20,7 @@ import java.io.IOException;
|
|||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||||
import ghidra.app.util.bin.format.macho.commands.dyld.BindOpcode;
|
import ghidra.app.util.bin.format.macho.commands.dyld.*;
|
||||||
import ghidra.app.util.bin.format.macho.commands.dyld.BindingTable;
|
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
@@ -47,6 +46,7 @@ public class DyldInfoCommand extends LoadCommand {
|
|||||||
private int exportOff;
|
private int exportOff;
|
||||||
private int exportSize;
|
private int exportSize;
|
||||||
|
|
||||||
|
private RebaseTable rebaseTable;
|
||||||
private BindingTable bindingTable;
|
private BindingTable bindingTable;
|
||||||
private BindingTable weakBindingTable;
|
private BindingTable weakBindingTable;
|
||||||
private BindingTable lazyBindingTable;
|
private BindingTable lazyBindingTable;
|
||||||
@@ -77,7 +77,13 @@ public class DyldInfoCommand extends LoadCommand {
|
|||||||
exportOff = loadCommandReader.readNextInt();
|
exportOff = loadCommandReader.readNextInt();
|
||||||
exportSize = loadCommandReader.readNextInt();
|
exportSize = loadCommandReader.readNextInt();
|
||||||
|
|
||||||
// TODO: rebase
|
if (rebaseOff > 0 && rebaseSize > 0) {
|
||||||
|
dataReader.setPointerIndex(header.getStartIndex() + rebaseOff);
|
||||||
|
rebaseTable = new RebaseTable(dataReader, header, rebaseSize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rebaseTable = new RebaseTable();
|
||||||
|
}
|
||||||
|
|
||||||
if (bindOff > 0 && bindSize > 0) {
|
if (bindOff > 0 && bindSize > 0) {
|
||||||
dataReader.setPointerIndex(header.getStartIndex() + bindOff);
|
dataReader.setPointerIndex(header.getStartIndex() + bindOff);
|
||||||
@@ -182,6 +188,13 @@ public class DyldInfoCommand extends LoadCommand {
|
|||||||
return exportSize;
|
return exportSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return The rebase table}
|
||||||
|
*/
|
||||||
|
public RebaseTable getRebaseTable() {
|
||||||
|
return rebaseTable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return The binding table}
|
* {@return The binding table}
|
||||||
*/
|
*/
|
||||||
@@ -246,22 +259,27 @@ public class DyldInfoCommand extends LoadCommand {
|
|||||||
|
|
||||||
private void markupRebaseInfo(Program program, MachHeader header, String source,
|
private void markupRebaseInfo(Program program, MachHeader header, String source,
|
||||||
TaskMonitor monitor, MessageLog log) {
|
TaskMonitor monitor, MessageLog log) {
|
||||||
|
Address rebaseAddr = fileOffsetToAddress(program, header, rebaseOff, rebaseSize);
|
||||||
markupPlateComment(program, fileOffsetToAddress(program, header, rebaseOff, rebaseSize),
|
markupPlateComment(program, fileOffsetToAddress(program, header, rebaseOff, rebaseSize),
|
||||||
source, "rebase");
|
source, "rebase");
|
||||||
|
markupOpcodeTable(program, rebaseAddr, rebaseTable, RebaseOpcode.toDataType(), source,
|
||||||
|
"rebase", log);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markupBindings(Program program, MachHeader header, String source,
|
private void markupBindings(Program program, MachHeader header, String source,
|
||||||
TaskMonitor monitor, MessageLog log) {
|
TaskMonitor monitor, MessageLog log) {
|
||||||
Address bindAddr = fileOffsetToAddress(program, header, bindOff, bindSize);
|
Address bindAddr = fileOffsetToAddress(program, header, bindOff, bindSize);
|
||||||
markupPlateComment(program, bindAddr, source, "bind");
|
markupPlateComment(program, bindAddr, source, "bind");
|
||||||
markupBindingTable(program, bindAddr, bindingTable, source, "bind", log);
|
markupOpcodeTable(program, bindAddr, bindingTable, BindOpcode.toDataType(), source, "bind",
|
||||||
|
log);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markupWeakBindings(Program program, MachHeader header, String source,
|
private void markupWeakBindings(Program program, MachHeader header, String source,
|
||||||
TaskMonitor monitor, MessageLog log) {
|
TaskMonitor monitor, MessageLog log) {
|
||||||
Address addr = fileOffsetToAddress(program, header, weakBindOff, weakBindSize);
|
Address addr = fileOffsetToAddress(program, header, weakBindOff, weakBindSize);
|
||||||
markupPlateComment(program, addr, source, "weak bind");
|
markupPlateComment(program, addr, source, "weak bind");
|
||||||
markupBindingTable(program, addr, weakBindingTable, source, "weak bind", log);
|
markupOpcodeTable(program, addr, weakBindingTable, BindOpcode.toDataType(), source,
|
||||||
|
"weak bind", log);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,18 +287,18 @@ public class DyldInfoCommand extends LoadCommand {
|
|||||||
TaskMonitor monitor, MessageLog log) {
|
TaskMonitor monitor, MessageLog log) {
|
||||||
Address addr = fileOffsetToAddress(program, header, lazyBindOff, lazyBindSize);
|
Address addr = fileOffsetToAddress(program, header, lazyBindOff, lazyBindSize);
|
||||||
markupPlateComment(program, addr, source, "lazy bind");
|
markupPlateComment(program, addr, source, "lazy bind");
|
||||||
markupBindingTable(program, addr, lazyBindingTable, source, "lazy bind", log);
|
markupOpcodeTable(program, addr, lazyBindingTable, BindOpcode.toDataType(), source,
|
||||||
|
"lazy bind", log);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markupBindingTable(Program program, Address addr, BindingTable table,
|
private void markupOpcodeTable(Program program, Address addr, OpcodeTable table,
|
||||||
String source, String additionalDescription, MessageLog log) {
|
DataType opcodeDataType, String source, String additionalDescription, MessageLog log) {
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
DataType bindOpcodeDataType = BindOpcode.toDataType();
|
|
||||||
for (long offset : table.getOpcodeOffsets()) {
|
for (long offset : table.getOpcodeOffsets()) {
|
||||||
DataUtilities.createData(program, addr.add(offset), bindOpcodeDataType, -1,
|
DataUtilities.createData(program, addr.add(offset), opcodeDataType, -1,
|
||||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||||
}
|
}
|
||||||
for (long offset : table.getUlebOffsets()) {
|
for (long offset : table.getUlebOffsets()) {
|
||||||
|
|||||||
+4
-43
@@ -28,29 +28,18 @@ import ghidra.program.model.data.LEB128;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A Mach-O binding table
|
* A Mach-O binding table
|
||||||
*
|
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOLayout.cpp">common/MachOLayout.cpp</a>
|
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOAnalyzer.cpp">common/MachOAnalyzer.cpp</a>
|
|
||||||
*/
|
*/
|
||||||
public class BindingTable {
|
public class BindingTable extends OpcodeTable {
|
||||||
|
|
||||||
private List<Binding> bindings;
|
private List<Binding> bindings = new ArrayList<>();
|
||||||
private List<Binding> threadedBindings;
|
private List<Binding> threadedBindings;
|
||||||
private List<Long> opcodeOffsets;
|
|
||||||
private List<Long> ulebOffsets;
|
|
||||||
private List<Long> slebOffsets;
|
|
||||||
private List<Long> stringOffsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty {@link BindingTable}
|
* Creates an empty {@link BindingTable}
|
||||||
*/
|
*/
|
||||||
public BindingTable() {
|
public BindingTable() {
|
||||||
bindings = new ArrayList<>();
|
super();
|
||||||
threadedBindings = null;
|
|
||||||
opcodeOffsets = new ArrayList<>();
|
|
||||||
ulebOffsets = new ArrayList<>();
|
|
||||||
slebOffsets = new ArrayList<>();
|
|
||||||
stringOffsets = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,34 +195,6 @@ public class BindingTable {
|
|||||||
return threadedBindings;
|
return threadedBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@return opcode offsets from the start of the bind data}
|
|
||||||
*/
|
|
||||||
public List<Long> getOpcodeOffsets() {
|
|
||||||
return opcodeOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@return ULEB128 offsets from the start of the bind data}
|
|
||||||
*/
|
|
||||||
public List<Long> getUlebOffsets() {
|
|
||||||
return ulebOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@return SLEB128 offsets from the start of the bind data}
|
|
||||||
*/
|
|
||||||
public List<Long> getSlebOffsets() {
|
|
||||||
return slebOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@return string offsets from the start of the bind data}
|
|
||||||
*/
|
|
||||||
public List<Long> getStringOffsets() {
|
|
||||||
return stringOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A piece of binding information from a {@link BindingTable}
|
* A piece of binding information from a {@link BindingTable}
|
||||||
*/
|
*/
|
||||||
|
|||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.commands.dyld;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class used to represent the generic components of a Mach-O opcode table
|
||||||
|
*
|
||||||
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOLayout.cpp">common/MachOLayout.cpp</a>
|
||||||
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOAnalyzer.cpp">common/MachOAnalyzer.cpp</a>
|
||||||
|
*/
|
||||||
|
public abstract class OpcodeTable {
|
||||||
|
|
||||||
|
protected List<Long> opcodeOffsets = new ArrayList<>();
|
||||||
|
protected List<Long> ulebOffsets = new ArrayList<>();
|
||||||
|
protected List<Long> slebOffsets = new ArrayList<>();
|
||||||
|
protected List<Long> stringOffsets = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return opcode offsets from the start of the bind data}
|
||||||
|
*/
|
||||||
|
public List<Long> getOpcodeOffsets() {
|
||||||
|
return opcodeOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return ULEB128 offsets from the start of the bind data}
|
||||||
|
*/
|
||||||
|
public List<Long> getUlebOffsets() {
|
||||||
|
return ulebOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return SLEB128 offsets from the start of the bind data}
|
||||||
|
*/
|
||||||
|
public List<Long> getSlebOffsets() {
|
||||||
|
return slebOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return string offsets from the start of the bind data}
|
||||||
|
*/
|
||||||
|
public List<Long> getStringOffsets() {
|
||||||
|
return stringOffsets;
|
||||||
|
}
|
||||||
|
}
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.commands.dyld;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebase opcodes
|
||||||
|
*
|
||||||
|
* @see <a href="https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h">EXTERNAL_HEADERS/mach-o/loader.h</a>
|
||||||
|
*/
|
||||||
|
public enum RebaseOpcode {
|
||||||
|
|
||||||
|
REBASE_OPCODE_DONE(0x00),
|
||||||
|
REBASE_OPCODE_SET_TYPE_IMM(0x10),
|
||||||
|
REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x20),
|
||||||
|
REBASE_OPCODE_ADD_ADDR_ULEB(0x30),
|
||||||
|
REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x40),
|
||||||
|
REBASE_OPCODE_DO_REBASE_IMM_TIMES(0x50),
|
||||||
|
REBASE_OPCODE_DO_REBASE_ULEB_TIMES(0x60),
|
||||||
|
REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x70),
|
||||||
|
REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(0x80);
|
||||||
|
|
||||||
|
private int opcode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link RebaseOpcode} for the given opcode value
|
||||||
|
*
|
||||||
|
* @param opcode The opcode value
|
||||||
|
*/
|
||||||
|
private RebaseOpcode(int opcode) {
|
||||||
|
this.opcode = opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the opcode value}
|
||||||
|
*/
|
||||||
|
public int getOpcode() {
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return a new data type from this enum}
|
||||||
|
*/
|
||||||
|
public static DataType toDataType() {
|
||||||
|
EnumDataType enumDataType = new EnumDataType("rebase_opcode", 1);
|
||||||
|
enumDataType.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||||
|
for (RebaseOpcode rebaseOpcode : RebaseOpcode.values()) {
|
||||||
|
enumDataType.add(rebaseOpcode.toString(), rebaseOpcode.getOpcode());
|
||||||
|
}
|
||||||
|
return enumDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link RebaseOpcode} that corresponds to the given opcode value
|
||||||
|
*
|
||||||
|
* @param opcode The opcode value
|
||||||
|
* @return The {@link RebaseOpcode} that corresponds to the given opcode value, or null if it
|
||||||
|
* does not exist
|
||||||
|
*/
|
||||||
|
public static RebaseOpcode forOpcode(int opcode) {
|
||||||
|
for (RebaseOpcode rebaseOpcode : RebaseOpcode.values()) {
|
||||||
|
if (rebaseOpcode.getOpcode() == opcode) {
|
||||||
|
return rebaseOpcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+200
@@ -0,0 +1,200 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.commands.dyld;
|
||||||
|
|
||||||
|
import static ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
|
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||||
|
import ghidra.program.model.data.LEB128;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Mach-O rebase table
|
||||||
|
*/
|
||||||
|
public class RebaseTable extends OpcodeTable {
|
||||||
|
|
||||||
|
private List<Rebase> rebases = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty {@link RebaseTable}
|
||||||
|
*/
|
||||||
|
public RebaseTable() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and parses a new {@link RebaseTable}
|
||||||
|
*
|
||||||
|
* @param reader A {@link BinaryReader reader} positioned at the start of the rebase table
|
||||||
|
* @param header The header
|
||||||
|
* @param tableSize The size of the table, in bytes
|
||||||
|
* @throws IOException if an IO-related error occurs while parsing
|
||||||
|
*/
|
||||||
|
public RebaseTable(BinaryReader reader, MachHeader header, int tableSize) throws IOException {
|
||||||
|
this();
|
||||||
|
|
||||||
|
int pointerSize = header.getAddressSize();
|
||||||
|
long origIndex = reader.getPointerIndex();
|
||||||
|
Rebase rebase = new Rebase();
|
||||||
|
|
||||||
|
while (reader.getPointerIndex() < origIndex + tableSize) {
|
||||||
|
|
||||||
|
opcodeOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
byte b = reader.readNextByte();
|
||||||
|
RebaseOpcode opcode = RebaseOpcode.forOpcode(b & REBASE_OPCODE_MASK);
|
||||||
|
int immediate = b & REBASE_IMMEDIATE_MASK;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case REBASE_OPCODE_DONE: { // 0x00
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_SET_TYPE_IMM: { // 0x10
|
||||||
|
rebase.type = immediate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: { // 0x20
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
rebase.segmentIndex = immediate;
|
||||||
|
rebase.segmentOffset = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_ADD_ADDR_ULEB: { // 0x30
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
rebase.segmentOffset += reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: { // 0x40
|
||||||
|
rebase.segmentOffset += immediate * pointerSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_DO_REBASE_IMM_TIMES: { // 0x50
|
||||||
|
for (int i = 0; i < immediate; ++i) {
|
||||||
|
rebases.add(new Rebase(rebase));
|
||||||
|
rebase.segmentOffset += pointerSize;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: { // 0x60
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
rebases.add(new Rebase(rebase));
|
||||||
|
rebase.segmentOffset += pointerSize;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: { // 0x70
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
rebases.add(new Rebase(rebase));
|
||||||
|
rebase.segmentOffset += reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: { // 0x80
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||||
|
int skip = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
rebases.add(new Rebase(rebase));
|
||||||
|
rebase.segmentOffset += skip + pointerSize;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Rebase unknownRebase = new Rebase(rebase);
|
||||||
|
unknownRebase.unknownOpcode = Byte.toUnsignedInt(b) & REBASE_OPCODE_MASK;
|
||||||
|
rebases.add(unknownRebase);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the rebases}
|
||||||
|
*/
|
||||||
|
public List<Rebase> getRebases() {
|
||||||
|
return rebases;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A piece of rebase information from a {@link RebaseTable}
|
||||||
|
*/
|
||||||
|
public static class Rebase {
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
private long segmentOffset;
|
||||||
|
private int segmentIndex = -1;
|
||||||
|
private Integer unknownOpcode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Rebase}
|
||||||
|
*/
|
||||||
|
public Rebase() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of the given {@link Rebase}
|
||||||
|
*
|
||||||
|
* @param rebase The {@link Rebase} to copy
|
||||||
|
*/
|
||||||
|
public Rebase(Rebase rebase) {
|
||||||
|
this.segmentIndex = rebase.segmentIndex;
|
||||||
|
this.segmentOffset = rebase.segmentOffset;
|
||||||
|
this.type = rebase.type;
|
||||||
|
this.unknownOpcode = rebase.unknownOpcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return The segment index}
|
||||||
|
*/
|
||||||
|
public int getSegmentIndex() {
|
||||||
|
return segmentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return The segment offset}
|
||||||
|
*/
|
||||||
|
public long getSegmentOffset() {
|
||||||
|
return segmentOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return The type}
|
||||||
|
*/
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return null if the opcode is known; otherwise, returns the unknown opcode's value}
|
||||||
|
*/
|
||||||
|
public Integer getUnknownOpcode() {
|
||||||
|
return unknownOpcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "segment: 0x%x, index: 0x%x, kind: %d".formatted(segmentIndex, segmentOffset,
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,7 +134,7 @@ public class MachoProgramBuilder {
|
|||||||
processAbsoluteSymbols();
|
processAbsoluteSymbols();
|
||||||
List<String> libraryPaths = processLibraries();
|
List<String> libraryPaths = processLibraries();
|
||||||
List<Address> chainedFixups = processChainedFixups(libraryPaths);
|
List<Address> chainedFixups = processChainedFixups(libraryPaths);
|
||||||
processBindings(false, libraryPaths);
|
processDyldInfo(false, libraryPaths);
|
||||||
processSectionRelocations();
|
processSectionRelocations();
|
||||||
processExternalRelocations();
|
processExternalRelocations();
|
||||||
processLocalRelocations();
|
processLocalRelocations();
|
||||||
@@ -824,10 +824,11 @@ public class MachoProgramBuilder {
|
|||||||
log, monitor);
|
log, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processBindings(boolean doClassic, List<String> libraryPaths) throws Exception {
|
protected void processDyldInfo(boolean doClassic, List<String> libraryPaths) throws Exception {
|
||||||
|
|
||||||
List<DyldInfoCommand> commands = machoHeader.getLoadCommands(DyldInfoCommand.class);
|
List<DyldInfoCommand> commands = machoHeader.getLoadCommands(DyldInfoCommand.class);
|
||||||
for (DyldInfoCommand command : commands) {
|
for (DyldInfoCommand command : commands) {
|
||||||
|
processRebases(command.getRebaseTable());
|
||||||
processBindings(command.getBindingTable(), libraryPaths);
|
processBindings(command.getBindingTable(), libraryPaths);
|
||||||
processBindings(command.getLazyBindingTable(), libraryPaths);
|
processBindings(command.getLazyBindingTable(), libraryPaths);
|
||||||
processBindings(command.getWeakBindingTable(), libraryPaths);
|
processBindings(command.getWeakBindingTable(), libraryPaths);
|
||||||
@@ -854,6 +855,10 @@ public class MachoProgramBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processRebases(RebaseTable rebaseTable) throws Exception {
|
||||||
|
// If we ever support rebasing a Mach-O at load time, this should get implemented
|
||||||
|
}
|
||||||
|
|
||||||
private void processBindings(BindingTable bindingTable, List<String> libraryPaths)
|
private void processBindings(BindingTable bindingTable, List<String> libraryPaths)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
DataConverter converter = DataConverter.getInstance(program.getLanguage().isBigEndian());
|
DataConverter converter = DataConverter.getInstance(program.getLanguage().isBigEndian());
|
||||||
|
|||||||
Reference in New Issue
Block a user