Wip relo finder
This commit is contained in:
parent
7613e37444
commit
faf2e134f2
|
@ -11,8 +11,6 @@ import java.util.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import re3lib.RemanConfig;
|
import re3lib.RemanConfig;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
|
||||||
import ghidra.program.model.pcode.Varnode;
|
|
||||||
|
|
||||||
public class FindRelocations extends GhidraScript {
|
public class FindRelocations extends GhidraScript {
|
||||||
private Set<Address> foundRelocations = new HashSet<>();
|
private Set<Address> foundRelocations = new HashSet<>();
|
||||||
|
@ -80,151 +78,34 @@ public class FindRelocations extends GhidraScript {
|
||||||
private void analyzeInstruction(Instruction instruction) {
|
private void analyzeInstruction(Instruction instruction) {
|
||||||
String mnemonic = instruction.getMnemonicString().toLowerCase();
|
String mnemonic = instruction.getMnemonicString().toLowerCase();
|
||||||
|
|
||||||
// Use pcode analysis for better accuracy
|
// Check for instructions that commonly use absolute addresses
|
||||||
if (isRelocatableInstruction(mnemonic)) {
|
if (isRelocatableInstruction(mnemonic)) {
|
||||||
analyzeInstructionPcode(instruction);
|
// Check operands for absolute addresses
|
||||||
|
|
||||||
// Still check operands for direct absolute addresses
|
|
||||||
for (int i = 0; i < instruction.getNumOperands(); i++) {
|
for (int i = 0; i < instruction.getNumOperands(); i++) {
|
||||||
analyzeOperand(instruction, i);
|
analyzeOperand(instruction, i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeInstructionPcode(Instruction instruction) {
|
// Check references from this instruction - but filter out relative references
|
||||||
try {
|
Reference[] refs = instruction.getReferencesFrom();
|
||||||
PcodeOp[] pcode = instruction.getPcode();
|
for (Reference ref : refs) {
|
||||||
|
// Skip relative references (jumps/calls with relative addressing)
|
||||||
for (PcodeOp op : pcode) {
|
if (ref.getReferenceType().isCall() || ref.getReferenceType().isJump()) {
|
||||||
// Look for operations that use absolute addresses
|
// For jumps and calls, check if it's using absolute addressing
|
||||||
switch (op.getOpcode()) {
|
if (usesAbsoluteAddressing(instruction, ref)) {
|
||||||
case PcodeOp.LOAD:
|
Address toAddr = ref.getToAddress();
|
||||||
case PcodeOp.STORE:
|
if (isInMainMemorySpace(toAddr)) {
|
||||||
// Memory operations - check if using absolute address
|
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "absolute_reference");
|
||||||
analyzeMemoryOperation(instruction, op);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PcodeOp.CALL:
|
|
||||||
case PcodeOp.CALLIND:
|
|
||||||
// Call operations - check if target is absolute
|
|
||||||
analyzeCallOperation(instruction, op);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PcodeOp.BRANCH:
|
|
||||||
case PcodeOp.BRANCHIND:
|
|
||||||
// Branch operations - usually relative, but check indirect branches
|
|
||||||
analyzeBranchOperation(instruction, op);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PcodeOp.COPY:
|
|
||||||
// Copy operations that move absolute addresses
|
|
||||||
analyzeCopyOperation(instruction, op);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Fallback to reference analysis if pcode fails
|
|
||||||
analyzeReferences(instruction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeMemoryOperation(Instruction instruction, PcodeOp op) {
|
|
||||||
// LOAD/STORE operations with absolute addresses
|
|
||||||
Varnode input = op.getInput(1); // Address input
|
|
||||||
if (input != null && input.isConstant()) {
|
|
||||||
long addr = input.getOffset();
|
|
||||||
if (looksLikeAddress(addr)) {
|
|
||||||
try {
|
|
||||||
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(addr);
|
|
||||||
if (isInMainMemorySpace(targetAddr)) {
|
|
||||||
recordRelocation(instruction.getAddress(), targetAddr,
|
|
||||||
instruction.getMnemonicString(), "memory_op");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Invalid address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeCallOperation(Instruction instruction, PcodeOp op) {
|
|
||||||
// Only flag indirect calls or calls with absolute targets
|
|
||||||
if (op.getOpcode() == PcodeOp.CALLIND) {
|
|
||||||
// Indirect call - check if target address is absolute
|
|
||||||
Varnode target = op.getInput(0);
|
|
||||||
if (target != null && target.isConstant()) {
|
|
||||||
long addr = target.getOffset();
|
|
||||||
if (looksLikeAddress(addr)) {
|
|
||||||
try {
|
|
||||||
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(addr);
|
|
||||||
if (isInMainMemorySpace(targetAddr)) {
|
|
||||||
recordRelocation(instruction.getAddress(), targetAddr,
|
|
||||||
instruction.getMnemonicString(), "indirect_call");
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
}
|
||||||
// Invalid address
|
} else if (ref.getReferenceType().isData()) {
|
||||||
|
// Data references are more likely to be absolute
|
||||||
|
Address toAddr = ref.getToAddress();
|
||||||
|
if (isInMainMemorySpace(toAddr)) {
|
||||||
|
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "data_reference");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Direct calls are usually relative, skip them
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeBranchOperation(Instruction instruction, PcodeOp op) {
|
|
||||||
// Only flag indirect branches (direct branches are relative)
|
|
||||||
if (op.getOpcode() == PcodeOp.BRANCHIND) {
|
|
||||||
Varnode target = op.getInput(0);
|
|
||||||
if (target != null && target.isConstant()) {
|
|
||||||
long addr = target.getOffset();
|
|
||||||
if (looksLikeAddress(addr)) {
|
|
||||||
try {
|
|
||||||
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(addr);
|
|
||||||
if (isInMainMemorySpace(targetAddr)) {
|
|
||||||
recordRelocation(instruction.getAddress(), targetAddr,
|
|
||||||
instruction.getMnemonicString(), "indirect_branch");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Invalid address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Direct branches (BRANCH) are relative, ignore them
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeCopyOperation(Instruction instruction, PcodeOp op) {
|
|
||||||
// COPY operations that load absolute addresses (like LEA or MOV immediate)
|
|
||||||
Varnode input = op.getInput(0);
|
|
||||||
if (input != null && input.isConstant()) {
|
|
||||||
long addr = input.getOffset();
|
|
||||||
if (looksLikeAddress(addr)) {
|
|
||||||
try {
|
|
||||||
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(addr);
|
|
||||||
if (isInMainMemorySpace(targetAddr)) {
|
|
||||||
recordRelocation(instruction.getAddress(), targetAddr,
|
|
||||||
instruction.getMnemonicString(), "load_address");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Invalid address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void analyzeReferences(Instruction instruction) {
|
|
||||||
// Fallback method - but be more selective
|
|
||||||
Reference[] refs = instruction.getReferencesFrom();
|
|
||||||
for (Reference ref : refs) {
|
|
||||||
if (ref.getReferenceType().isData()) {
|
|
||||||
// Data references are usually absolute
|
|
||||||
Address toAddr = ref.getToAddress();
|
|
||||||
if (isInMainMemorySpace(toAddr)) {
|
|
||||||
recordRelocation(instruction.getAddress(), toAddr,
|
|
||||||
instruction.getMnemonicString(), "data_reference");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Skip flow references (calls/jumps) as they're usually relative
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRelocatableInstruction(String mnemonic) {
|
private boolean isRelocatableInstruction(String mnemonic) {
|
||||||
|
@ -335,16 +216,73 @@ public class FindRelocations extends GhidraScript {
|
||||||
return value >= 0x400000 && value <= 0x7FFFFFFF; // Typical executable range
|
return value >= 0x400000 && value <= 0x7FFFFFFF; // Typical executable range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean usesAbsoluteAddressing(Instruction instruction, Reference ref) {
|
||||||
|
// Check the instruction bytes to determine addressing mode
|
||||||
|
String mnemonic = instruction.getMnemonicString().toLowerCase();
|
||||||
|
|
||||||
|
// For x86, most conditional jumps (JA, JE, JNE, etc.) use relative addressing
|
||||||
|
if (mnemonic.startsWith("j") && !mnemonic.equals("jmp")) {
|
||||||
|
return false; // Conditional jumps are typically relative
|
||||||
|
}
|
||||||
|
|
||||||
|
// For JMP and CALL, check the operand representation
|
||||||
|
for (int i = 0; i < instruction.getNumOperands(); i++) {
|
||||||
|
String operandStr = instruction.getDefaultOperandRepresentation(i);
|
||||||
|
// If operand shows as a direct address (not offset), it might be absolute
|
||||||
|
// But we need to be more sophisticated here...
|
||||||
|
|
||||||
|
// Check if this is an indirect reference [address] which would be absolute
|
||||||
|
if (operandStr.contains("[") && operandStr.contains("]")) {
|
||||||
|
return true; // Indirect addressing typically uses absolute addresses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, assume most jumps/calls are relative unless proven otherwise
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void recordRelocation(Address fromAddr, Address toAddr, String instruction, String type) {
|
private void recordRelocation(Address fromAddr, Address toAddr, String instruction, String type) {
|
||||||
if (foundRelocations.add(toAddr)) {
|
if (foundRelocations.add(toAddr)) {
|
||||||
String line = String.format("0x%s -> 0x%s (%s) [%s]",
|
String instructionBytes = getInstructionBytesString(fromAddr);
|
||||||
|
String line = String.format("0x%s -> 0x%s (%s) [%s] | %s",
|
||||||
fromAddr.toString(),
|
fromAddr.toString(),
|
||||||
toAddr.toString(),
|
toAddr.toString(),
|
||||||
instruction,
|
instruction,
|
||||||
type);
|
type,
|
||||||
|
instructionBytes);
|
||||||
println(line);
|
println(line);
|
||||||
outputFile.println(line);
|
outputFile.println(line);
|
||||||
outputFile.flush();
|
outputFile.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getInstructionBytesString(Address addr) {
|
||||||
|
try {
|
||||||
|
Instruction instruction = currentProgram.getListing().getInstructionAt(addr);
|
||||||
|
if (instruction != null) {
|
||||||
|
byte[] bytes = instruction.getBytes();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
if (i > 0) sb.append(" ");
|
||||||
|
sb.append(String.format("%02x", bytes[i] & 0xFF));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If it's a data reference, try to get the bytes at that location
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[4]; // Show 4 bytes for data
|
||||||
|
currentProgram.getMemory().getBytes(addr, bytes);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
if (i > 0) sb.append(" ");
|
||||||
|
sb.append(String.format("%02x", bytes[i] & 0xFF));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return "??";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "??";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue