/* ### * 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 affected, accessed; Vector restored; Stack 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(); affected = new HashSet(); accessed = new HashSet(); restored = new Vector(); 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 c, int itemsPerLine) { TreeSet ts = new TreeSet(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"; } }