From 7613e374442d4d5168d965e46152fe61436181ac Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Fri, 30 May 2025 14:19:03 +0800 Subject: [PATCH] Pcode finder --- java/ghidra/FindRelocations.java | 180 +++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 43 deletions(-) diff --git a/java/ghidra/FindRelocations.java b/java/ghidra/FindRelocations.java index a80e7f43..0d483bf5 100644 --- a/java/ghidra/FindRelocations.java +++ b/java/ghidra/FindRelocations.java @@ -11,6 +11,8 @@ 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<>(); @@ -78,34 +80,151 @@ public class FindRelocations extends GhidraScript { private void analyzeInstruction(Instruction instruction) { String mnemonic = instruction.getMnemonicString().toLowerCase(); - // Check for instructions that commonly use absolute addresses + // Use pcode analysis for better accuracy if (isRelocatableInstruction(mnemonic)) { - // Check operands for absolute addresses + analyzeInstructionPcode(instruction); + + // Still check operands for direct absolute addresses for (int i = 0; i < instruction.getNumOperands(); i++) { analyzeOperand(instruction, i); } + } + } + + private void analyzeInstructionPcode(Instruction instruction) { + try { + PcodeOp[] pcode = instruction.getPcode(); - // 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"); - } + 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"); } - } 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"); + } 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 } } } } + // 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) { @@ -216,31 +335,6 @@ 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]",