ghidra/Ghidra/Features/Base/ghidra_scripts/RegisterTouchesPerFunction.java

157 lines
4.6 KiB
Java

/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//This script analyzes how registers are modified in a single
// function or the complete listing and stores the results in the
// function's plate comment.
//@category Analysis
import java.util.*;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
public class RegisterTouchesPerFunction extends GhidraScript {
private final static String DIVIDER =
"*************************************************************\r\n";
@Override
public void run() throws Exception {
Listing l = this.currentProgram.getListing();
if (this.askYesNo("Function Analysis - Register Touches", "Analyze complete listing?")) {
FunctionIterator fi = l.getFunctions(true);
while (fi.hasNext() && !monitor.isCancelled()) {
doAnalysis(l, fi.next());
}
}
else {
doAnalysis(l, l.getFunctionContaining(this.currentAddress));
}
}
private void doAnalysis(Listing list, Function func) {
if (func == null) {
println("No function to analyze.");
return;
}
HashSet<String> affected, accessed;
Vector<String> restored;
Stack<String> pushPops;
boolean reviewRestored = false;
Instruction inst;
InstructionIterator iIter;
monitor.setMessage("Analyzing registers in " + func.getName());
String comment = list.getComment(CommentType.PLATE, func.getBody().getMinAddress());
if (comment != null && comment.indexOf("TOUCHED REGISTER SUMMARY") > -1)
return;
pushPops = new Stack<String>();
affected = new HashSet<String>();
accessed = new HashSet<String>();
restored = new Vector<String>();
iIter = list.getInstructions(func.getBody(), true);
while (iIter.hasNext() && !monitor.isCancelled()) {
inst = iIter.next();
Object o[] = inst.getResultObjects();
for (Object element : o) {
if (element instanceof Register) {
String name = ((Register) element).getName();
if (inst.getMnemonicString().equalsIgnoreCase("pop")) {
if (!name.equalsIgnoreCase("mult_addr") && !name.equalsIgnoreCase("sp")) {
if (pushPops.size() > 0) {
restored.add(pushPops.pop() + "->" + name);
}
else {
reviewRestored = true;
}
}
}
else {
affected.add(name);
}
}
}
o = inst.getInputObjects();
for (Object element : o) {
if (element instanceof Register) {
String name = ((Register) element).getName();
if (inst.getMnemonicString().equalsIgnoreCase("push")) {
if (!name.equalsIgnoreCase("mult_addr") && !name.equalsIgnoreCase("sp")) {
pushPops.push(name);
}
}
else {
accessed.add(name);
}
}
}
}
StringBuffer buffer = new StringBuffer();
if (comment != null) {
buffer.append(comment);
buffer.append("\r\n");
buffer.append(DIVIDER);
}
buffer.append("TOUCHED REGISTER SUMMARY:\r\n");
buffer.append(DIVIDER);
buffer.append("Register(s) Affected:\r\n");
buffer.append(getString(affected, 8));
buffer.append(DIVIDER);
buffer.append("Register(s) Accessed:\r\n");
buffer.append(getString(accessed, 8));
buffer.append(DIVIDER);
buffer.append("Register(s) Restored:\r\n");
buffer.append(getString(restored, 4));
if (reviewRestored) {
buffer.append("##Review - due to branches this list may not be accurate\r\n");
println(func.getName() + " - Review - due to branches this list may not be accurate");
}
buffer.append(DIVIDER);
if (pushPops.size() > 0) {
buffer.append("Registers Remaining on Stack:\r\n");
buffer.append(" " + getString(pushPops, 8));
}
list.setComment(func.getEntryPoint(), CommentType.PLATE, buffer.toString());
}
private String getString(Collection<String> c, int itemsPerLine) {
TreeSet<Object> ts = new TreeSet<Object>(c);
String temp = ts.toString();
temp = temp.substring(1, temp.length() - 1);
int i = 0;
int commaCount = 0;
while ((i = temp.indexOf(',', i + 1)) >= 0) {
commaCount++;
if (commaCount % itemsPerLine == 0)
temp = temp.substring(0, i + 1) + "\r\n" + temp.substring(i + 1).trim();
}
return temp + "\r\n";
}
}