From f1b346fb0eaae98a4992c6fb97e5c9f915e67e99 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Fri, 30 May 2025 14:36:39 +0800 Subject: [PATCH] W --- java/ghidra/FindRelocations.java | 134 ++++++++++++++++--------------- 1 file changed, 71 insertions(+), 63 deletions(-) diff --git a/java/ghidra/FindRelocations.java b/java/ghidra/FindRelocations.java index ecf3f71e..8f7fd470 100644 --- a/java/ghidra/FindRelocations.java +++ b/java/ghidra/FindRelocations.java @@ -10,81 +10,85 @@ import ghidra.program.model.symbol.Reference; import java.util.*; import java.io.*; import re3lib.RemanConfig; -import ghidra.util.task.TaskMonitor; public class FindRelocations extends GhidraScript { private Set
foundRelocations = new HashSet<>(); private PrintWriter outputFile; - + + long addrMin, addrMax; + @Override public void run() throws Exception { RemanConfig.INSTANCE = new RemanConfig(this); RemanConfig.INSTANCE.createDirectories(); - + + addrMin = RemanConfig.INSTANCE.staticMemoryBlockStart.getOffset(); + addrMax = RemanConfig.INSTANCE.staticMemoryBlockEnd.getOffset(); + // Create output file for relocations File relocFile = new File(RemanConfig.INSTANCE.outputDir, "relocations.txt"); outputFile = new PrintWriter(new FileWriter(relocFile)); - + try { println("Counting instructions and data for progress tracking..."); - + // Count total work for progress monitoring long totalInstructions = currentProgram.getListing().getNumInstructions(); long totalDataBytes = currentProgram.getMemory().getLoadedAndInitializedAddressSet().getNumAddresses(); long totalWork = totalInstructions + (totalDataBytes / currentProgram.getDefaultPointerSize()); - + monitor.initialize(totalWork); monitor.setMessage("Scanning for relocations..."); - + println("Scanning " + totalInstructions + " instructions and " + totalDataBytes + " data bytes..."); - + // Get all instructions in the program InstructionIterator instructions = currentProgram.getListing().getInstructions(true); long processedInstructions = 0; - + while (instructions.hasNext()) { if (monitor.isCancelled()) { println("Operation cancelled by user"); return; } - + Instruction instruction = instructions.next(); analyzeInstruction(instruction); - + processedInstructions++; if (processedInstructions % 1000 == 0) { monitor.setProgress(processedInstructions); monitor.setMessage("Processed " + processedInstructions + "/" + totalInstructions + " instructions..."); } } - + monitor.setProgress(totalInstructions); monitor.setMessage("Analyzing data sections..."); - + // Also check data references analyzeDataReferences(totalInstructions, totalWork); - + monitor.setMessage("Scan complete"); println("Found " + foundRelocations.size() + " potential relocations"); println("Results saved to: " + relocFile.getAbsolutePath()); - + } finally { if (outputFile != null) { outputFile.close(); } } } - + private void analyzeInstruction(Instruction instruction) { String mnemonic = instruction.getMnemonicString().toLowerCase(); - + // Check for instructions that commonly use absolute addresses if (isRelocatableInstruction(mnemonic)) { // Check operands for absolute addresses for (int i = 0; i < instruction.getNumOperands(); i++) { analyzeOperand(instruction, i); } - + // Check references from this instruction - but filter out relative references Reference[] refs = instruction.getReferencesFrom(); for (Reference ref : refs) { @@ -107,27 +111,27 @@ public class FindRelocations extends GhidraScript { } } } - + private boolean isRelocatableInstruction(String mnemonic) { // Instructions that commonly use absolute addresses - return mnemonic.equals("mov") || mnemonic.equals("lea") || - mnemonic.equals("call") || mnemonic.equals("jmp") || - mnemonic.equals("push") || mnemonic.equals("cmp") || - mnemonic.equals("test") || mnemonic.equals("add") || - mnemonic.equals("sub") || mnemonic.equals("and") || - mnemonic.equals("or") || mnemonic.equals("xor") || - mnemonic.startsWith("j"); // conditional jumps + return mnemonic.equals("mov") || mnemonic.equals("lea") || + mnemonic.equals("call") || mnemonic.equals("jmp") || + mnemonic.equals("push") || mnemonic.equals("cmp") || + mnemonic.equals("test") || mnemonic.equals("add") || + mnemonic.equals("sub") || mnemonic.equals("and") || + mnemonic.equals("or") || mnemonic.equals("xor") || + mnemonic.startsWith("j"); // conditional jumps } - + private void analyzeOperand(Instruction instruction, int opIndex) { Object[] operandObjects = instruction.getOpObjects(opIndex); - + for (Object obj : operandObjects) { if (obj instanceof Address) { Address addr = (Address) obj; if (isInMainMemorySpace(addr)) { - recordRelocation(instruction.getAddress(), addr, - instruction.getMnemonicString(), "operand_" + opIndex); + recordRelocation(instruction.getAddress(), addr, + instruction.getMnemonicString(), "operand_" + opIndex); } } else if (obj instanceof Scalar) { Scalar scalar = (Scalar) obj; @@ -137,8 +141,8 @@ public class FindRelocations extends GhidraScript { try { Address addr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value); if (isInMainMemorySpace(addr)) { - recordRelocation(instruction.getAddress(), addr, - instruction.getMnemonicString(), "scalar_" + opIndex); + recordRelocation(instruction.getAddress(), addr, + instruction.getMnemonicString(), "scalar_" + opIndex); } } catch (Exception e) { // Invalid address, ignore @@ -147,32 +151,32 @@ public class FindRelocations extends GhidraScript { } } } - + private void analyzeDataReferences(long instructionsProcessed, long totalWork) { // Check data sections for absolute addresses AddressSetView dataAddresses = currentProgram.getMemory().getLoadedAndInitializedAddressSet(); long totalDataBytes = dataAddresses.getNumAddresses(); long processedBytes = 0; int pointerSize = currentProgram.getDefaultPointerSize(); - + for (AddressRange range : dataAddresses) { if (monitor.isCancelled()) { println("Operation cancelled by user"); return; } - + Address addr = range.getMinAddress(); while (addr != null && addr.compareTo(range.getMaxAddress()) <= 0) { try { // Check if this location contains a pointer-sized value byte[] bytes = new byte[pointerSize]; currentProgram.getMemory().getBytes(addr, bytes); - + long value = 0; for (int i = 0; i < bytes.length; i++) { - value |= ((long)(bytes[i] & 0xFF)) << (i * 8); + value |= ((long) (bytes[i] & 0xFF)) << (i * 8); } - + if (looksLikeAddress(value)) { try { Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value); @@ -183,17 +187,17 @@ public class FindRelocations extends GhidraScript { // Invalid address, ignore } } - + addr = addr.add(pointerSize); // Jump by pointer size for efficiency processedBytes += pointerSize; - + // Update progress every 10000 bytes if (processedBytes % 10000 == 0) { long currentProgress = instructionsProcessed + (processedBytes / pointerSize); monitor.setProgress(currentProgress); monitor.setMessage("Analyzing data: " + (processedBytes * 100 / totalDataBytes) + "% complete"); } - + } catch (Exception e) { addr = addr.add(1); processedBytes++; @@ -201,61 +205,63 @@ public class FindRelocations extends GhidraScript { } } } - + private boolean isInMainMemorySpace(Address addr) { - if (addr == null) return false; - + if (addr == null) + return false; + // Check if address is in a loaded memory block - return currentProgram.getMemory().contains(addr) && - !addr.getAddressSpace().isOverlaySpace(); + return currentProgram.getMemory().contains(addr) && + !addr.getAddressSpace().isOverlaySpace(); } - + private boolean looksLikeAddress(long value) { // Heuristic: check if value is in reasonable address range // Adjust these ranges based on your target architecture - return value >= 0x400000 && value <= 0x7FFFFFFF; // Typical executable range + return value >= addrMin + && value <= addrMax; // 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 instructionBytes = getInstructionBytesString(fromAddr); - String line = String.format("0x%s -> 0x%s (%s) [%s] | %s", - fromAddr.toString(), - toAddr.toString(), - instruction, - type, - instructionBytes); + String line = String.format("0x%s -> 0x%s (%s) [%s] | %s", + fromAddr.toString(), + toAddr.toString(), + instruction, + type, + instructionBytes); println(line); outputFile.println(line); outputFile.flush(); } } - + private String getInstructionBytesString(Address addr) { try { Instruction instruction = currentProgram.getListing().getInstructionAt(addr); @@ -263,7 +269,8 @@ public class FindRelocations extends GhidraScript { byte[] bytes = instruction.getBytes(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { - if (i > 0) sb.append(" "); + if (i > 0) + sb.append(" "); sb.append(String.format("%02x", bytes[i] & 0xFF)); } return sb.toString(); @@ -275,7 +282,8 @@ public class FindRelocations extends GhidraScript { currentProgram.getMemory().getBytes(addr, bytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { - if (i > 0) sb.append(" "); + if (i > 0) + sb.append(" "); sb.append(String.format("%02x", bytes[i] & 0xFF)); } return sb.toString();