90 lines
4.5 KiB
Java
90 lines
4.5 KiB
Java
// Report executable-segment instruction and function-body coverage for the current program.
|
|
// @category TDKPIN
|
|
|
|
import java.io.BufferedWriter;
|
|
import java.io.FileWriter;
|
|
import java.io.PrintWriter;
|
|
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.program.model.address.AddressSet;
|
|
import ghidra.program.model.address.AddressSetView;
|
|
import ghidra.program.model.listing.Function;
|
|
import ghidra.program.model.listing.FunctionIterator;
|
|
import ghidra.program.model.listing.Instruction;
|
|
import ghidra.program.model.listing.InstructionIterator;
|
|
import ghidra.program.model.mem.MemoryBlock;
|
|
|
|
public class AuditCoverage extends GhidraScript {
|
|
@Override
|
|
public void run() throws Exception {
|
|
String[] args = getScriptArgs();
|
|
if (args.length != 1) {
|
|
throw new IllegalArgumentException("usage: AuditCoverage.java OUTPUT_TSV");
|
|
}
|
|
|
|
AddressSet executable = new AddressSet();
|
|
AddressSet instructions = new AddressSet();
|
|
AddressSet definedData = new AddressSet();
|
|
AddressSet functionBodies = new AddressSet();
|
|
int internalFunctions = 0;
|
|
|
|
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(args[0])))) {
|
|
out.println("record\tname_or_start\tend\tbytes\tdetail");
|
|
for (MemoryBlock block : currentProgram.getMemory().getBlocks()) {
|
|
String detail = String.format("r=%s,w=%s,x=%s,initialized=%s",
|
|
block.isRead(), block.isWrite(), block.isExecute(), block.isInitialized());
|
|
out.printf("block\t%s\t%s\t%d\t%s%n", block.getName(), block.getEnd(),
|
|
block.getSize(), detail);
|
|
if (block.isExecute()) {
|
|
executable.add(block.getStart(), block.getEnd());
|
|
}
|
|
}
|
|
|
|
InstructionIterator instructionIterator =
|
|
currentProgram.getListing().getInstructions(executable, true);
|
|
while (instructionIterator.hasNext()) {
|
|
Instruction instruction = instructionIterator.next();
|
|
instructions.add(instruction.getMinAddress(), instruction.getMaxAddress());
|
|
}
|
|
var dataIterator = currentProgram.getListing().getDefinedData(executable, true);
|
|
while (dataIterator.hasNext()) {
|
|
var data = dataIterator.next();
|
|
definedData.add(data.getMinAddress(), data.getMaxAddress());
|
|
}
|
|
|
|
FunctionIterator functionIterator = currentProgram.getFunctionManager().getFunctions(true);
|
|
while (functionIterator.hasNext()) {
|
|
Function function = functionIterator.next();
|
|
MemoryBlock block = currentProgram.getMemory().getBlock(function.getEntryPoint());
|
|
if (!function.isExternal() && block != null && block.isExecute()) {
|
|
internalFunctions++;
|
|
functionBodies.add(function.getBody());
|
|
}
|
|
}
|
|
|
|
AddressSet explained = instructions.union(definedData);
|
|
AddressSet undefined = executable.subtract(explained);
|
|
out.printf("summary\texecutable-bytes\t\t%d\t%n", executable.getNumAddresses());
|
|
out.printf("summary\tdisassembled-bytes\t\t%d\t%.2f%% of executable%n",
|
|
instructions.getNumAddresses(), percent(instructions, executable));
|
|
out.printf("summary\tdefined-data-bytes\t\t%d\t%.2f%% of executable%n",
|
|
definedData.getNumAddresses(), percent(definedData, executable));
|
|
out.printf("summary\texplained-code-or-data-bytes\t\t%d\t%.2f%% of executable%n",
|
|
explained.getNumAddresses(), percent(explained, executable));
|
|
out.printf("summary\tfunction-body-bytes\t\t%d\t%.2f%% of executable%n",
|
|
functionBodies.intersect(executable).getNumAddresses(), percent(functionBodies, executable));
|
|
out.printf("summary\tinternal-functions\t\t%d\t%n", internalFunctions);
|
|
out.printf("summary\tundefined-executable-bytes\t\t%d\t%n", undefined.getNumAddresses());
|
|
for (var range : undefined) {
|
|
out.printf("undefined-range\t%s\t%s\t%d\t%n", range.getMinAddress(),
|
|
range.getMaxAddress(), range.getLength());
|
|
}
|
|
}
|
|
}
|
|
|
|
private double percent(AddressSetView numerator, AddressSetView denominator) {
|
|
long total = denominator.getNumAddresses();
|
|
return total == 0 ? 0.0 : 100.0 * numerator.intersect(denominator).getNumAddresses() / total;
|
|
}
|
|
}
|