Pcode finder

This commit is contained in:
Guus Waals 2025-05-30 14:19:03 +08:00
parent 0edba96773
commit 7613e37444
1 changed files with 137 additions and 43 deletions

View File

@ -11,6 +11,8 @@ 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<>();
@ -78,34 +80,151 @@ 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();
// Check for instructions that commonly use absolute addresses // Use pcode analysis for better accuracy
if (isRelocatableInstruction(mnemonic)) { 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++) { for (int i = 0; i < instruction.getNumOperands(); i++) {
analyzeOperand(instruction, i); analyzeOperand(instruction, i);
} }
}
}
// Check references from this instruction - but filter out relative references private void analyzeInstructionPcode(Instruction instruction) {
Reference[] refs = instruction.getReferencesFrom(); try {
for (Reference ref : refs) { PcodeOp[] pcode = instruction.getPcode();
// Skip relative references (jumps/calls with relative addressing)
if (ref.getReferenceType().isCall() || ref.getReferenceType().isJump()) { for (PcodeOp op : pcode) {
// For jumps and calls, check if it's using absolute addressing // Look for operations that use absolute addresses
if (usesAbsoluteAddressing(instruction, ref)) { switch (op.getOpcode()) {
Address toAddr = ref.getToAddress(); case PcodeOp.LOAD:
if (isInMainMemorySpace(toAddr)) { case PcodeOp.STORE:
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "absolute_reference"); // 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()) { } catch (Exception e) {
// Data references are more likely to be absolute // Invalid address
Address toAddr = ref.getToAddress(); }
if (isInMainMemorySpace(toAddr)) { }
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "data_reference"); }
}
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) { private boolean isRelocatableInstruction(String mnemonic) {
@ -216,31 +335,6 @@ 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 line = String.format("0x%s -> 0x%s (%s) [%s]",