From faf2e134f28b24d2a9264840a1b9efb1a14c02fa Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Fri, 30 May 2025 14:34:14 +0800 Subject: [PATCH] Wip relo finder --- java/ghidra/FindRelocations.java | 216 +++++++++++-------------------- 1 file changed, 77 insertions(+), 139 deletions(-) diff --git a/java/ghidra/FindRelocations.java b/java/ghidra/FindRelocations.java index 0d483bf5..ecf3f71e 100644 --- a/java/ghidra/FindRelocations.java +++ b/java/ghidra/FindRelocations.java @@ -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
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 "??"; + } }