Wip relo finder

This commit is contained in:
Guus Waals 2025-05-30 14:34:14 +08:00
parent 7613e37444
commit faf2e134f2
1 changed files with 77 additions and 139 deletions

View File

@ -11,8 +11,6 @@ import java.util.*;
import java.io.*;
import re3lib.RemanConfig;
import ghidra.util.task.TaskMonitor;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
public class FindRelocations extends GhidraScript {
private Set<Address> foundRelocations = new HashSet<>();
@ -80,151 +78,34 @@ public class FindRelocations extends GhidraScript {
private void analyzeInstruction(Instruction instruction) {
String mnemonic = instruction.getMnemonicString().toLowerCase();
// Use pcode analysis for better accuracy
// Check for instructions that commonly use absolute addresses
if (isRelocatableInstruction(mnemonic)) {
analyzeInstructionPcode(instruction);
// Still check operands for direct absolute addresses
// Check operands for absolute addresses
for (int i = 0; i < instruction.getNumOperands(); i++) {
analyzeOperand(instruction, i);
}
}
}
private void analyzeInstructionPcode(Instruction instruction) {
try {
PcodeOp[] pcode = instruction.getPcode();
for (PcodeOp op : pcode) {
// Look for operations that use absolute addresses
switch (op.getOpcode()) {
case PcodeOp.LOAD:
case PcodeOp.STORE:
// Memory operations - check if using absolute address
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");
// Check references from this instruction - but filter out relative references
Reference[] refs = instruction.getReferencesFrom();
for (Reference ref : refs) {
// Skip relative references (jumps/calls with relative addressing)
if (ref.getReferenceType().isCall() || ref.getReferenceType().isJump()) {
// For jumps and calls, check if it's using absolute addressing
if (usesAbsoluteAddressing(instruction, ref)) {
Address toAddr = ref.getToAddress();
if (isInMainMemorySpace(toAddr)) {
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "absolute_reference");
}
} 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) {
@ -335,16 +216,73 @@ public class FindRelocations extends GhidraScript {
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) {
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(),
toAddr.toString(),
instruction,
type);
type,
instructionBytes);
println(line);
outputFile.println(line);
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 "??";
}
}