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 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<>();
@ -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]",