mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-3934 Added options to autoVT task and script. Made example options script for headless. Updated Documentation. Updated and added tests.
This commit is contained in:
parent
f98258aa74
commit
d4d703368b
11 changed files with 1542 additions and 280 deletions
|
@ -13,21 +13,51 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// An example of how to create Version Tracking session, run some correlators to find matching
|
||||
// data and and then save the session.
|
||||
//@category Examples.Version Tracking
|
||||
|
||||
// A script that runs Auto Version Tracking given the options set in one of the following ways:
|
||||
// 1. If script is run from the CodeBrowser, the GUI options are set in a pop up dialog by user.
|
||||
// 2. If script is run in headless mode either the defaults provided by the script are used or the
|
||||
// user can specify a script to be run that sets the options. See example script
|
||||
// SetAutoVersionTrackingOptionsScript that can be copied and updated to reflect the users
|
||||
// desired options.
|
||||
//
|
||||
// NOTE: This is an example to show how run this script in headless mode
|
||||
//
|
||||
// <ghidra_install>/support/analyzeHeadless.bat/sh c:/MyGhidraProjectFolder
|
||||
// MyProjectName/OptionalFolderContainingProgram -process Program1.exe -postScript
|
||||
// MyOptionsSetupScript -postScript AutoVersionTrackingScript.java "/FolderContainingSession"
|
||||
// "MySessionName" true "/OptionalFolderContainingProgram/Program2.exe"
|
||||
//
|
||||
//
|
||||
// NOTE: The first program will be analyzed for you if it is not already analyzed (and if you
|
||||
// do not include the -noanalysis option) as it is part of the typical analyzeHeadless run.
|
||||
// The second program must be analyzed prior to running the script as the headless analyzer
|
||||
// itself knows nothing about the file other than as a given option name. This is true in
|
||||
// both GUI and headless mode.
|
||||
//
|
||||
// NOTE: The second to last parameter is to identify whether the first listed program
|
||||
// is the source program or not. True means first program is source program and second
|
||||
// program is destination program. False means second program is source program and first
|
||||
// program is destination program. This is important if you want the correct markup to be
|
||||
// applied from the source to destination program.
|
||||
//
|
||||
// NOTE: The options setup script is optional. It is only necessary if users want to change the
|
||||
// default options. To use it make a copy of the example one and save to a new script. You
|
||||
// You may need to add the -scriptPath to the headless run so it will find your script.
|
||||
//
|
||||
//@category Version Tracking
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.feature.vt.api.db.VTSessionDB;
|
||||
import ghidra.feature.vt.api.main.VTSession;
|
||||
import ghidra.feature.vt.api.util.VTOptions;
|
||||
import ghidra.feature.vt.gui.actions.AutoVersionTrackingTask;
|
||||
import ghidra.feature.vt.gui.plugin.VTController;
|
||||
import ghidra.feature.vt.gui.util.VTOptionDefines;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.MessageType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
|
||||
public class AutoVersionTrackingScript extends GhidraScript {
|
||||
|
@ -49,47 +79,106 @@ public class AutoVersionTrackingScript extends GhidraScript {
|
|||
@Override
|
||||
public void run() throws Exception {
|
||||
|
||||
DomainFolder folder =
|
||||
askProjectFolder("Please choose a folder for your Version Tracking session.");
|
||||
String name = askString("Please enter a Version Tracking session name", "Session Name");
|
||||
GhidraValuesMap startupValues = new GhidraValuesMap();
|
||||
|
||||
startupValues.defineProjectFolder("Version Tracking Session Folder", "/");
|
||||
startupValues.defineString("Version Tracking Session Name");
|
||||
startupValues.defineBoolean("Check if current program is the Source Program", true);
|
||||
startupValues.defineProgram("Please select the other program");
|
||||
|
||||
startupValues.setValidator((valueMap, status) -> {
|
||||
|
||||
GhidraValuesMap map = (GhidraValuesMap) valueMap;
|
||||
|
||||
if (!valueMap.hasValue("Version Tracking Session Name")) {
|
||||
status.setStatusText("Session Name must be filled in!", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (hasExistingSession(map.getString("Version Tracking Session Name"),
|
||||
map.getProjectFolder("Version Tracking Session Folder"))) {
|
||||
status.setStatusText("Session cannot be an existing session!",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!valueMap.hasValue("Please select the other program")) {
|
||||
status.setStatusText("Must choose second program!", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
startupValues = askValues("Enter Auto Version Tracking Information",
|
||||
"Changing these options will not change the corresponding tool options",
|
||||
startupValues);
|
||||
|
||||
DomainFolder folder = startupValues.getProjectFolder("Version Tracking Session Folder");
|
||||
|
||||
String name = startupValues.getString("Version Tracking Session Name");
|
||||
boolean isCurrentProgramSourceProg =
|
||||
startupValues.getBoolean("Check if current program is the Source Program");
|
||||
Program otherProgram =
|
||||
startupValues.getProgram("Please select the other program", this, state.getTool());
|
||||
|
||||
boolean isCurrentProgramSourceProg = askYesNo("Current Program Source Program?",
|
||||
"Is the current program your source program?");
|
||||
|
||||
if (isCurrentProgramSourceProg) {
|
||||
sourceProgram = currentProgram;
|
||||
destinationProgram = askProgram("Please select the destination (new) program");
|
||||
destinationProgram = otherProgram;
|
||||
}
|
||||
else {
|
||||
destinationProgram = currentProgram;
|
||||
sourceProgram = askProgram("Please select the source (existing annotated) program");
|
||||
sourceProgram = otherProgram;
|
||||
}
|
||||
|
||||
if (sourceProgram == null || destinationProgram == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean autoCreateImpliedMatches = askYesNo("Implied Matches?",
|
||||
"Would you like the script to figure out implied matches from any matches it creates?");
|
||||
|
||||
// Need to end the script transaction or it interferes with vt things that need locks
|
||||
end(true);
|
||||
|
||||
|
||||
VTSession session =
|
||||
VTSessionDB.createVTSession(name, sourceProgram, destinationProgram, this);
|
||||
|
||||
folder.createFile(name, session, monitor);
|
||||
|
||||
ToolOptions options = getOptions();
|
||||
if (folder.getFile(name) == null) {
|
||||
folder.createFile(name, session, monitor);
|
||||
}
|
||||
|
||||
boolean originalImpliedMatchSetting =
|
||||
options.getBoolean(VTOptionDefines.AUTO_CREATE_IMPLIED_MATCH, false);
|
||||
// create a default options map in case cannot get user input
|
||||
GhidraValuesMap optionsMap = createDefaultOptions();
|
||||
|
||||
options.setBoolean(VTOptionDefines.AUTO_CREATE_IMPLIED_MATCH, autoCreateImpliedMatches);
|
||||
// if running script in GUI get options from user and update the vtOptions with them
|
||||
if(!isRunningHeadless()) {
|
||||
optionsMap = getOptionsFromUser();
|
||||
|
||||
}
|
||||
// else if running script in headless get possible options set by prescript that saves
|
||||
// optionsMap in script state variable and update the vtOptions with them
|
||||
else {
|
||||
// try to get options map from state if running headless
|
||||
// if user runs prescript to set up their own options map those options will be used
|
||||
// See SetAutoVersionTrackingOptionsScript.java as an example
|
||||
GhidraValuesMap stateOptionsMap =
|
||||
(GhidraValuesMap) state.getEnvironmentVar("autoVTOptionsMap");
|
||||
if (optionsMap != null) {
|
||||
optionsMap = stateOptionsMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ToolOptions vtOptions = setToolOptionsFromOptionsMap(optionsMap);
|
||||
|
||||
AutoVersionTrackingTask autoVtTask =
|
||||
new AutoVersionTrackingTask(session, options, 0.95, 10.0);
|
||||
|
||||
new AutoVersionTrackingTask(session, vtOptions);
|
||||
|
||||
TaskLauncher.launch(autoVtTask);
|
||||
|
||||
|
@ -98,21 +187,131 @@ public class AutoVersionTrackingScript extends GhidraScript {
|
|||
// if running headless - must save here or nothing that was done in this script will be
|
||||
// accessible later.
|
||||
if (isRunningHeadless()) {
|
||||
otherProgram.save("Updated with Auto Version Tracking", monitor);
|
||||
session.save();
|
||||
}
|
||||
options.setBoolean(VTOptionDefines.AUTO_CREATE_IMPLIED_MATCH, originalImpliedMatchSetting);
|
||||
|
||||
|
||||
println(autoVtTask.getStatusMsg());
|
||||
otherProgram.release(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if there is an existing VTSession in the given folder with the given name
|
||||
* @param name the given name
|
||||
* @param folder the given Ghidra project folder
|
||||
* @return true if there is an existing VTSession with the given name in the given folder, false
|
||||
* otherwise
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private boolean hasExistingSession(String name, DomainFolder folder) throws CancelledException {
|
||||
|
||||
private ToolOptions getOptions() {
|
||||
ToolOptions vtOptions = new VTOptions("Dummy");
|
||||
PluginTool tool = state.getTool();
|
||||
if (tool != null) {
|
||||
vtOptions = tool.getOptions(VTController.VERSION_TRACKING_OPTIONS_NAME);
|
||||
DomainFile[] files = folder.getFiles();
|
||||
|
||||
for (DomainFile file : files) {
|
||||
monitor.checkCancelled();
|
||||
|
||||
if (file.getName().equals(name)) {
|
||||
if (file.getContentType().equals("VersionTracking")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vtOptions;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create the default GhidraValuesMap AutoVT options
|
||||
* @return the default GhidraValuesMap AutoVT options
|
||||
*/
|
||||
private GhidraValuesMap createDefaultOptions() {
|
||||
GhidraValuesMap optionsValues = new GhidraValuesMap();
|
||||
|
||||
optionsValues.defineBoolean(VTOptionDefines.CREATE_IMPLIED_MATCHES_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_EXACT_SYMBOL_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_EXACT_DATA_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_BYTES_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_INST_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_DUPE_FUNCTION_OPTION_TEXT, true);
|
||||
optionsValues.defineBoolean(VTOptionDefines.RUN_REF_CORRELATORS_OPTION_TEXT, true);
|
||||
optionsValues.defineInt(VTOptionDefines.DATA_CORRELATOR_MIN_LEN_OPTION_TEXT, 5);
|
||||
optionsValues.defineInt(VTOptionDefines.SYMBOL_CORRELATOR_MIN_LEN_OPTION_TEXT, 3);
|
||||
optionsValues.defineInt(VTOptionDefines.FUNCTION_CORRELATOR_MIN_LEN_OPTION_TEXT, 10);
|
||||
optionsValues.defineInt(VTOptionDefines.DUPE_FUNCTION_CORRELATOR_MIN_LEN_OPTION_TEXT, 10);
|
||||
optionsValues.defineBoolean(VTOptionDefines.APPLY_IMPLIED_MATCHES_OPTION_TEXT, true);
|
||||
optionsValues.defineInt(VTOptionDefines.MIN_VOTES_OPTION_TEXT, 2);
|
||||
optionsValues.defineInt(VTOptionDefines.MAX_CONFLICTS_OPTION_TEXT, 0);
|
||||
optionsValues.defineDouble(VTOptionDefines.REF_CORRELATOR_MIN_SCORE_OPTION_TEXT, 0.95);
|
||||
optionsValues.defineDouble(VTOptionDefines.REF_CORRELATOR_MIN_CONF_OPTION_TEXT, 10.0);
|
||||
|
||||
return optionsValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to ask the user for AutoVT options
|
||||
* @return a GhidraValuesMap containing AutoVT options values
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private GhidraValuesMap getOptionsFromUser() throws CancelledException {
|
||||
|
||||
GhidraValuesMap optionsValues = createDefaultOptions();
|
||||
|
||||
optionsValues = askValues("Enter Auto Version Tracking Options",
|
||||
"These options will not be saved to your current tool options.",
|
||||
optionsValues);
|
||||
|
||||
return optionsValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Auto Version Tracking options given a GhidraValuesMap containing the options values
|
||||
* @param optionsValues the option values in a GhidraValuesMap
|
||||
* @return ToolOptions containing the Auto Version Tracking options values
|
||||
*/
|
||||
private ToolOptions setToolOptionsFromOptionsMap(GhidraValuesMap optionsValues) {
|
||||
|
||||
ToolOptions toolOptions = new VTOptions("Dummy");
|
||||
|
||||
toolOptions.setBoolean(VTOptionDefines.CREATE_IMPLIED_MATCHES_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.CREATE_IMPLIED_MATCHES_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_EXACT_SYMBOL_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_EXACT_SYMBOL_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_EXACT_DATA_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_EXACT_DATA_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_BYTES_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_BYTES_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_INST_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_EXACT_FUNCTION_INST_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_DUPE_FUNCTION_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_DUPE_FUNCTION_OPTION_TEXT));
|
||||
toolOptions.setBoolean(VTOptionDefines.RUN_REF_CORRELATORS_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.RUN_REF_CORRELATORS_OPTION_TEXT));
|
||||
|
||||
toolOptions.setInt(VTOptionDefines.DATA_CORRELATOR_MIN_LEN_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.DATA_CORRELATOR_MIN_LEN_OPTION_TEXT));
|
||||
toolOptions.setInt(VTOptionDefines.SYMBOL_CORRELATOR_MIN_LEN_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.SYMBOL_CORRELATOR_MIN_LEN_OPTION_TEXT));
|
||||
toolOptions.setInt(VTOptionDefines.FUNCTION_CORRELATOR_MIN_LEN_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.FUNCTION_CORRELATOR_MIN_LEN_OPTION_TEXT));
|
||||
toolOptions.setInt(VTOptionDefines.DUPE_FUNCTION_CORRELATOR_MIN_LEN_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.DUPE_FUNCTION_CORRELATOR_MIN_LEN_OPTION_TEXT));
|
||||
|
||||
toolOptions.setDouble(VTOptionDefines.REF_CORRELATOR_MIN_SCORE_OPTION,
|
||||
optionsValues.getDouble(VTOptionDefines.REF_CORRELATOR_MIN_SCORE_OPTION_TEXT));
|
||||
toolOptions.setDouble(VTOptionDefines.REF_CORRELATOR_MIN_CONF_OPTION,
|
||||
optionsValues.getDouble(VTOptionDefines.REF_CORRELATOR_MIN_CONF_OPTION_TEXT));
|
||||
|
||||
toolOptions.setBoolean(VTOptionDefines.APPLY_IMPLIED_MATCHES_OPTION,
|
||||
optionsValues.getBoolean(VTOptionDefines.APPLY_IMPLIED_MATCHES_OPTION_TEXT));
|
||||
|
||||
toolOptions.setInt(VTOptionDefines.MIN_VOTES_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.MIN_VOTES_OPTION_TEXT));
|
||||
|
||||
toolOptions.setInt(VTOptionDefines.MAX_CONFLICTS_OPTION,
|
||||
optionsValues.getInt(VTOptionDefines.MAX_CONFLICTS_OPTION_TEXT));
|
||||
|
||||
return toolOptions;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue