mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Candidate release of source code.
This commit is contained in:
parent
db81e6b3b0
commit
79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
409
Ghidra/Features/Base/ghidra_scripts/CompareAnalysisScript.java
Normal file
409
Ghidra/Features/Base/ghidra_scripts/CompareAnalysisScript.java
Normal file
|
@ -0,0 +1,409 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
//Script to compare analysis between current and chosen program.
|
||||
//@category Testing
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
||||
public class CompareAnalysisScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (currentAddress == null) {
|
||||
println("No Location.");
|
||||
return;
|
||||
}
|
||||
|
||||
Program otherProgram = askProgram("Choose a program to compare to");
|
||||
if (otherProgram == null) {
|
||||
return;
|
||||
}
|
||||
println("\n\n****** COMPARING FUNCTIONS:\n");
|
||||
compareFunctions(otherProgram);
|
||||
println("\n\n****** COMPARING STRINGS:\n");
|
||||
compareStrings(otherProgram);
|
||||
println("\n\n****** PERCENT ANALYZED COMPARE SUMMARY:\n");
|
||||
reportPercentDisassembled(currentProgram);
|
||||
reportPercentDisassembled(otherProgram);
|
||||
println("\n\n****** COMPARING SWITCH TABLES:\n");
|
||||
compareSwitchTables(otherProgram);
|
||||
println("\n\n****** COMPARING NON-RETURNING FUNCTIONS:\n");
|
||||
compareNoReturns(otherProgram);
|
||||
println("\n\n****** COMPARING ERRORS:\n");
|
||||
compareErrors(otherProgram);
|
||||
}
|
||||
|
||||
void compareFunctions(Program otherProgram) {
|
||||
FunctionManager functionManager = otherProgram.getFunctionManager();
|
||||
String currentProgramName = currentProgram.getDomainFile().getName();
|
||||
String otherProgramName = otherProgram.getDomainFile().getName();
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
|
||||
int numMissingFuncs = 0;
|
||||
int numFuncsInCurrentProg = 0;
|
||||
println("Iterating through functions in " + currentProgramName);
|
||||
FunctionIterator currentFunctions =
|
||||
listing.getFunctions(currentProgram.getMinAddress(), true);
|
||||
while (currentFunctions.hasNext() && !monitor.isCancelled()) {
|
||||
Function func = currentFunctions.next();
|
||||
numFuncsInCurrentProg++;
|
||||
Address funcAddress = func.getBody().getMinAddress();
|
||||
Function otherFunction = functionManager.getFunctionAt(funcAddress);
|
||||
if (otherFunction == null) {
|
||||
numMissingFuncs++;
|
||||
println(numMissingFuncs + ": Missing function in " + otherProgramName + " at " +
|
||||
funcAddress.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println("Iterating through functions in " + otherProgramName);
|
||||
FunctionManager currentFunctionManager = currentProgram.getFunctionManager();
|
||||
int numMissingFuncs2 = 0;
|
||||
int numFuncsInOtherProg = 0;
|
||||
FunctionIterator otherFunctions =
|
||||
otherProgram.getListing().getFunctions(otherProgram.getMinAddress(), true);
|
||||
while (otherFunctions.hasNext() && !monitor.isCancelled()) {
|
||||
Function otherfunc = otherFunctions.next();
|
||||
numFuncsInOtherProg++;
|
||||
Address funcAddress = otherfunc.getBody().getMinAddress();
|
||||
Function func = currentFunctionManager.getFunctionAt(funcAddress);
|
||||
if (func == null) {
|
||||
numMissingFuncs2++;
|
||||
println(numMissingFuncs2 + ": Missing function in " + currentProgramName + " at " +
|
||||
funcAddress.toString());
|
||||
}
|
||||
|
||||
}
|
||||
println("\n\n****** FUNCTION COMPARE SUMMARY:\n");
|
||||
println("There are " + numFuncsInCurrentProg + " functions in " + currentProgramName +
|
||||
" and " + numFuncsInOtherProg + " functions in " + otherProgramName);
|
||||
println("There are " + numMissingFuncs + " functions missing in " + otherProgramName +
|
||||
" that are in " + currentProgramName);
|
||||
println("There are " + numMissingFuncs2 + " functions missing in " + currentProgramName +
|
||||
" that are in " + otherProgramName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void reportPercentDisassembled(Program prog) throws MemoryAccessException {
|
||||
// find all the sections of memory marked as executable
|
||||
String programName = prog.getDomainFile().getName();
|
||||
|
||||
AddressSetView execMemSet = prog.getMemory().getExecuteSet();
|
||||
/*
|
||||
int myExecSetLen = 0;
|
||||
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].isExecute()) {
|
||||
myExecSetLen += blocks[i].getSize();
|
||||
}
|
||||
}*/
|
||||
|
||||
// tally up all the bytes that have been marked as instructions
|
||||
// (probably faster ways to do this, but it works)
|
||||
long numPossibleDis = execMemSet.getNumAddresses();
|
||||
InstructionIterator instIter = prog.getListing().getInstructions(execMemSet, true);
|
||||
int instCount = 0;
|
||||
while (instIter.hasNext()) {
|
||||
Instruction inst = instIter.next();
|
||||
instCount += inst.getBytes().length;
|
||||
}
|
||||
DataIterator dataIter = prog.getListing().getData(execMemSet, true);
|
||||
int dataCount = 0;
|
||||
while (dataIter.hasNext()) {
|
||||
Data data = dataIter.next();
|
||||
if (data.isDefined()) {
|
||||
dataCount += data.getBytes().length;
|
||||
}
|
||||
}
|
||||
|
||||
// dump the info
|
||||
int total = instCount + dataCount;
|
||||
if (numPossibleDis != 0) {
|
||||
float coverage = (float) total / (float) numPossibleDis;
|
||||
// Msg.info(this,"execSetLen = " + numPossibleDis);
|
||||
// Msg.info(this,"MyExecSetLen = " + myExecSetLen);
|
||||
// Msg.info(this,"NumInsts = " + instCount);
|
||||
// Msg.info(this,"numData = " + dataCount);
|
||||
//
|
||||
// Msg.info(this,"totalDis = " + total);
|
||||
float percentage = coverage * 100;
|
||||
println(programName + ": " + percentage + "% disassembled.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void compareStrings(Program otherProgram) {
|
||||
Listing listing = currentProgram.getListing();
|
||||
Listing otherListing = otherProgram.getListing();
|
||||
|
||||
String currentProgramName = currentProgram.getDomainFile().getName();
|
||||
String otherProgramName = otherProgram.getDomainFile().getName();
|
||||
|
||||
int numMissingStrings = 0;
|
||||
int numStringsInCurrentProg = 0;
|
||||
println("Iterating through strings in " + currentProgramName);
|
||||
|
||||
DataIterator definedDataIter = listing.getDefinedData(currentProgram.getMinAddress(), true);
|
||||
|
||||
while (definedDataIter.hasNext() && !monitor.isCancelled()) {
|
||||
Data currentProgData = definedDataIter.next();
|
||||
|
||||
if (isString(currentProgData.getMnemonicString())) {
|
||||
Address stringAddress = currentProgData.getAddress();
|
||||
numStringsInCurrentProg++;
|
||||
Data otherProgData = otherListing.getDataAt(stringAddress);
|
||||
if (otherProgData == null || !isString(otherProgData.getMnemonicString())) {
|
||||
numMissingStrings++;
|
||||
println(numMissingStrings + ": Missing string in " + otherProgramName +
|
||||
" at " + stringAddress.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("Iterating through strings in " + otherProgramName);
|
||||
DataIterator otherDataIter =
|
||||
otherListing.getDefinedData(otherProgram.getMinAddress(), true);
|
||||
|
||||
int numMissingStrings2 = 0;
|
||||
int numStringsInOtherProg = 0;
|
||||
while (otherDataIter.hasNext() && !monitor.isCancelled()) {
|
||||
Data otherString = otherDataIter.next();
|
||||
if (isString(otherString.getMnemonicString())) {
|
||||
numStringsInOtherProg++;
|
||||
Address otherStringAddress = otherString.getAddress();
|
||||
Data currentData = listing.getDataAt(otherStringAddress);
|
||||
|
||||
if (currentData == null || !isString(currentData.getMnemonicString())) {
|
||||
numMissingStrings2++;
|
||||
println(numMissingStrings2 + ": Missing string in " + currentProgramName +
|
||||
" at " + otherStringAddress.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
println("\n\n******STRING COMPARE SUMMARY:\n");
|
||||
println("There are " + numStringsInCurrentProg + " strings in " + currentProgramName +
|
||||
" and " + numStringsInOtherProg + " strings in " + otherProgramName);
|
||||
println("There are " + numMissingStrings + " strings missing in " + otherProgramName +
|
||||
" that are in " + currentProgramName);
|
||||
println("There are " + numMissingStrings2 + " strings missing in " + currentProgramName +
|
||||
" that are in " + otherProgramName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void compareSwitchTables(Program otherProgram) {
|
||||
String currentProgramName = currentProgram.getDomainFile().getName();
|
||||
String otherProgramName = otherProgram.getDomainFile().getName();
|
||||
|
||||
SymbolTable currentSymbolTable = currentProgram.getSymbolTable();
|
||||
SymbolTable otherSymbolTable = otherProgram.getSymbolTable();
|
||||
|
||||
int numMissingSwitches = 0;
|
||||
int numSwitchesInCurrentProg = 0;
|
||||
println("Iterating through switch tables in " + currentProgramName);
|
||||
|
||||
SymbolIterator currentSymIter = currentSymbolTable.getSymbolIterator("switchdataD_*", true);
|
||||
|
||||
while (currentSymIter.hasNext() && !monitor.isCancelled()) {
|
||||
Symbol currentSym = currentSymIter.next();
|
||||
Address switchAddress = currentSym.getAddress();
|
||||
numSwitchesInCurrentProg++;
|
||||
Symbol otherSyms[] = otherSymbolTable.getSymbols(switchAddress);
|
||||
if (!isSwitch(otherSyms, "switchdataD_")) {
|
||||
numMissingSwitches++;
|
||||
println(numMissingSwitches + ": Missing switch table in " + otherProgramName +
|
||||
" at " + switchAddress.toString());
|
||||
}
|
||||
}
|
||||
|
||||
println("Iterating through switch tables in " + otherProgramName);
|
||||
SymbolIterator otherSymIter = otherSymbolTable.getSymbolIterator("switchdataD_*", true);
|
||||
|
||||
int numMissingSwitches2 = 0;
|
||||
int numSwitchesInOtherProg = 0;
|
||||
while (otherSymIter.hasNext() && !monitor.isCancelled()) {
|
||||
Symbol otherSym = otherSymIter.next();
|
||||
Address otherSwitchAddress = otherSym.getAddress();
|
||||
numSwitchesInOtherProg++;
|
||||
Symbol currentSyms[] = currentSymbolTable.getSymbols(otherSwitchAddress);
|
||||
if (!isSwitch(currentSyms, "switchdataD_")) {
|
||||
numMissingSwitches2++;
|
||||
println(numMissingSwitches2 + ": Missing switch table in " + currentProgramName +
|
||||
" at " + otherSwitchAddress.toString());
|
||||
}
|
||||
}
|
||||
|
||||
println("\n\n******SWITCH TABLE COMPARE SUMMARY:\n");
|
||||
println(
|
||||
"There are " + numSwitchesInCurrentProg + " switch tables in " + currentProgramName +
|
||||
" and " + numSwitchesInOtherProg + " switch table in " + otherProgramName);
|
||||
println("There are " + numMissingSwitches + " switch tables missing in " +
|
||||
otherProgramName + " that are in " + currentProgramName);
|
||||
println("There are " + numMissingSwitches2 + " switch tables missing in " +
|
||||
currentProgramName + " that are in " + otherProgramName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void compareNoReturns(Program otherProgram) {
|
||||
FunctionManager functionManager = otherProgram.getFunctionManager();
|
||||
String currentProgramName = currentProgram.getDomainFile().getName();
|
||||
String otherProgramName = otherProgram.getDomainFile().getName();
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
|
||||
int numMissingNonReturningFuncs = 0;
|
||||
int numNonReturningFuncsInCurrentProg = 0;
|
||||
println("Iterating through non-returning functions in " + currentProgramName);
|
||||
FunctionIterator currentFunctions =
|
||||
listing.getFunctions(currentProgram.getMinAddress(), true);
|
||||
while (currentFunctions.hasNext() && !monitor.isCancelled()) {
|
||||
Function func = currentFunctions.next();
|
||||
if (func.hasNoReturn()) {
|
||||
numNonReturningFuncsInCurrentProg++;
|
||||
Address funcAddress = func.getBody().getMinAddress();
|
||||
Function otherFunction = functionManager.getFunctionAt(funcAddress);
|
||||
if (otherFunction == null || !otherFunction.hasNoReturn()) {
|
||||
numMissingNonReturningFuncs++;
|
||||
println(numMissingNonReturningFuncs +
|
||||
": Missing function or function is not marked as non-returning in " +
|
||||
otherProgramName + " at " + funcAddress.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println("Iterating through non-returning functions in " + otherProgramName);
|
||||
FunctionManager currentFunctionManager = currentProgram.getFunctionManager();
|
||||
int numMissingNonReturningFuncs2 = 0;
|
||||
int numNonReturningFuncsInOtherProg = 0;
|
||||
FunctionIterator otherFunctions =
|
||||
otherProgram.getListing().getFunctions(otherProgram.getMinAddress(), true);
|
||||
while (otherFunctions.hasNext() && !monitor.isCancelled()) {
|
||||
Function otherfunc = otherFunctions.next();
|
||||
if (otherfunc.hasNoReturn()) {
|
||||
numNonReturningFuncsInOtherProg++;
|
||||
Address funcAddress = otherfunc.getBody().getMinAddress();
|
||||
Function func = currentFunctionManager.getFunctionAt(funcAddress);
|
||||
if (func == null || !func.hasNoReturn()) {
|
||||
numMissingNonReturningFuncs2++;
|
||||
println(numMissingNonReturningFuncs2 +
|
||||
": Missing function or function is not marked as non-returning in " +
|
||||
currentProgramName + " at " + funcAddress.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
println("\n\n****** NON-RETURNING FUNCTION COMPARE SUMMARY:\n");
|
||||
println("There are " + numNonReturningFuncsInCurrentProg + " non-returning functions in " +
|
||||
currentProgramName + " and " + numNonReturningFuncsInOtherProg +
|
||||
" non-returning functions in " + otherProgramName);
|
||||
println(
|
||||
"There are " + numMissingNonReturningFuncs + " non-returning functions missing in " +
|
||||
otherProgramName + " that are in " + currentProgramName);
|
||||
println(
|
||||
"There are " + numMissingNonReturningFuncs2 + " non-returning functions missing in " +
|
||||
currentProgramName + " that are in " + otherProgramName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void compareErrors(Program otherProgram) {
|
||||
BookmarkManager currentBookmarkManager = currentProgram.getBookmarkManager();
|
||||
BookmarkManager otherBookmarkManager = otherProgram.getBookmarkManager();
|
||||
String currentProgramName = currentProgram.getDomainFile().getName();
|
||||
String otherProgramName = otherProgram.getDomainFile().getName();
|
||||
|
||||
int numMissingErrors = 0;
|
||||
int numErrorsInCurrentProg = 0;
|
||||
println("Iterating through errors in " + currentProgramName);
|
||||
Iterator<Bookmark> currentErrorIterator =
|
||||
currentBookmarkManager.getBookmarksIterator("Error");
|
||||
|
||||
while (currentErrorIterator.hasNext() && !monitor.isCancelled()) {
|
||||
Bookmark error = currentErrorIterator.next();
|
||||
numErrorsInCurrentProg++;
|
||||
Address errorAddress = error.getAddress();
|
||||
Bookmark[] otherErrors = otherBookmarkManager.getBookmarks(errorAddress, "Error");
|
||||
if (otherErrors.length == 0) {
|
||||
numMissingErrors++;
|
||||
println(numMissingErrors + ": No error in " + otherProgramName + " at " +
|
||||
errorAddress.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println("Iterating through errors in " + otherProgramName);
|
||||
|
||||
int numMissingErrors2 = 0;
|
||||
int numErrorsInOtherProg = 0;
|
||||
Iterator<Bookmark> otherErrorIterator = otherBookmarkManager.getBookmarksIterator("Error");
|
||||
while (otherErrorIterator.hasNext() && !monitor.isCancelled()) {
|
||||
Bookmark otherError = otherErrorIterator.next();
|
||||
numErrorsInOtherProg++;
|
||||
Address otherErrorAddress = otherError.getAddress();
|
||||
Bookmark[] currentErrors =
|
||||
currentBookmarkManager.getBookmarks(otherErrorAddress, "Error");
|
||||
if (currentErrors.length == 0) {
|
||||
numMissingErrors2++;
|
||||
println(numMissingErrors2 + ": No error in " + currentProgramName + " at " +
|
||||
otherErrorAddress.toString());
|
||||
}
|
||||
}
|
||||
|
||||
println("\n\n****** ERROR COMPARE SUMMARY:\n");
|
||||
println("There are " + numErrorsInCurrentProg + " errors in " + currentProgramName +
|
||||
" and " + numErrorsInOtherProg + " errors in " + otherProgramName);
|
||||
println("There are " + numMissingErrors + " errors not in " + otherProgramName +
|
||||
" that are in " + currentProgramName);
|
||||
println("There are " + numMissingErrors2 + " errors not in " + currentProgramName +
|
||||
" that are in " + otherProgramName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isString(String mnemonic) {
|
||||
|
||||
if (mnemonic.equals(new String("ds")) || mnemonic.equals(new String("unicode")) ||
|
||||
mnemonic.equals(new String("p_unicode")) || mnemonic.equals(new String("p_string")) ||
|
||||
mnemonic.equals(new String("p_string255")) || mnemonic.equals(new String("mbcs"))) {
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isSwitch(Symbol[] syms, String name) {
|
||||
for (int i = 0; i < syms.length; i++) {
|
||||
if (syms[i].getName().startsWith(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue