-
Notifications
You must be signed in to change notification settings - Fork 14
/
ListCallsWithXrefs.java
145 lines (132 loc) · 4.74 KB
/
ListCallsWithXrefs.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// List all functions called in the current function together with their number of references
//@author larsborn
//@category malRE
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.OptionalLong;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOpAST;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.Reference;
public class ListCallsWithXrefs extends GhidraScript {
class UnknownVariableCopy extends Exception {
public UnknownVariableCopy(PcodeOp unknownCode, Address addr) {
super(String.format("unknown opcode %s for variable copy at %08X", unknownCode.getMnemonic(),
addr.getOffset()));
}
}
private class FunctionXrefs implements Comparable<FunctionXrefs> {
public String name;
public Address address;
public long count;
public FunctionXrefs(Function function) {
name = function.getName();
address = function.getEntryPoint();
count = getCallAddresses(function).size();
}
@Override
public int compareTo(FunctionXrefs other) {
return other.count == count ? 0 : (other.count > count ? -1 : 1);
}
}
private boolean addressAlreadyOnList(List<FunctionXrefs> lst, Address address) {
for (FunctionXrefs xrefs : lst) {
if (xrefs.address == address) {
return true;
}
}
return false;
}
private List<FunctionXrefs> getCallsAndRefs(Function func) throws UnknownVariableCopy {
List<FunctionXrefs> ret = new ArrayList<FunctionXrefs>();
DecompInterface decompInterface = new DecompInterface();
decompInterface.openProgram(currentProgram);
DecompileResults decompileResults = decompInterface.decompileFunction(func, 120, monitor);
if (!decompileResults.decompileCompleted())
throw new IllegalStateException();
HighFunction highFunction = decompileResults.getHighFunction();
for (Instruction asmInstruction : currentProgram.getListing().getInstructions(func.getEntryPoint(), true)) {
if (asmInstruction.getMnemonicString().equals("RET")) {
break;
} else if (asmInstruction.getMnemonicString().equals("CALL")) {
Iterator<PcodeOpAST> pCodes = highFunction.getPcodeOps(asmInstruction.getAddress());
// iterate all p-code instructions of the parent function
while (pCodes.hasNext()) {
PcodeOpAST callInstruction = pCodes.next();
if (callInstruction.getOpcode() == PcodeOp.CALL) {
// get addresses of all call instructions
OptionalLong calledAddress = traceVarnodeValue(callInstruction.getInput(0));
if (calledAddress.isPresent()) {
Address address = toAddr(calledAddress.getAsLong());
Function function = getFunctionAt(address);
if (function != null && !addressAlreadyOnList(ret, function.getEntryPoint())) {
if (function != null) {
ret.add(new FunctionXrefs(function));
}
}
}
}
}
}
}
return ret;
}
private OptionalLong traceVarnodeValue(Varnode argument) throws UnknownVariableCopy {
while (!argument.isConstant()) {
PcodeOp ins = argument.getDef();
if (ins == null) {
break;
}
switch (ins.getOpcode()) {
case PcodeOp.CAST:
case PcodeOp.COPY:
argument = ins.getInput(0);
break;
case PcodeOp.PTRSUB:
case PcodeOp.PTRADD:
argument = ins.getInput(1);
break;
case PcodeOp.INT_MULT:
case PcodeOp.MULTIEQUAL:
// known cases where an array is indexed
return OptionalLong.empty();
default:
// don't know how to handle this yet.
throw new UnknownVariableCopy(ins, argument.getAddress());
}
}
return OptionalLong.of(argument.getOffset());
}
public void run() throws Exception {
// add one to address to select the correct function in case the target function
// itself is selected
Function functionBefore = getFunctionBefore(currentAddress.add(1));
if (functionBefore == null) {
return;
}
List<FunctionXrefs> callsAndRefs = getCallsAndRefs(functionBefore);
Collections.sort(callsAndRefs);
for (FunctionXrefs xrefs : callsAndRefs) {
println(String.format("0x%08x (%s): %d", xrefs.address.getOffset(), xrefs.name, xrefs.count));
}
}
private List<Address> getCallAddresses(Function func) {
List<Address> addresses = new ArrayList<Address>();
for (Reference ref : getReferencesTo(func.getEntryPoint())) {
if (ref.getReferenceType() != RefType.UNCONDITIONAL_CALL)
continue;
addresses.add(ref.getFromAddress());
}
return addresses;
}
}