mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
317 lines
13 KiB
Java
317 lines
13 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.
|
|
*/
|
|
// 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.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.program.model.listing.Program;
|
|
import ghidra.util.MessageType;
|
|
import ghidra.util.exception.CancelledException;
|
|
import ghidra.util.task.TaskLauncher;
|
|
|
|
public class AutoVersionTrackingScript extends GhidraScript {
|
|
|
|
private Program sourceProgram;
|
|
private Program destinationProgram;
|
|
|
|
@Override
|
|
public void cleanup(boolean success) {
|
|
if (sourceProgram != null && sourceProgram.isUsedBy(this)) {
|
|
sourceProgram.release(this);
|
|
}
|
|
if (destinationProgram != null && destinationProgram.isUsedBy(this)) {
|
|
destinationProgram.release(this);
|
|
}
|
|
super.cleanup(success);
|
|
}
|
|
|
|
@Override
|
|
public void run() throws Exception {
|
|
|
|
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());
|
|
|
|
|
|
if (isCurrentProgramSourceProg) {
|
|
sourceProgram = currentProgram;
|
|
destinationProgram = otherProgram;
|
|
}
|
|
else {
|
|
destinationProgram = currentProgram;
|
|
sourceProgram = otherProgram;
|
|
}
|
|
|
|
if (sourceProgram == null || destinationProgram == null) {
|
|
return;
|
|
}
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
if (folder.getFile(name) == null) {
|
|
folder.createFile(name, session, monitor);
|
|
}
|
|
|
|
// create a default options map in case cannot get user input
|
|
GhidraValuesMap optionsMap = createDefaultOptions();
|
|
|
|
// 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, vtOptions);
|
|
|
|
TaskLauncher.launch(autoVtTask);
|
|
|
|
|
|
// if not running headless user can decide whether to save or not
|
|
// 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();
|
|
}
|
|
|
|
|
|
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 {
|
|
|
|
DomainFile[] files = folder.getFiles();
|
|
|
|
for (DomainFile file : files) {
|
|
monitor.checkCancelled();
|
|
|
|
if (file.getName().equals(name)) {
|
|
if (file.getContentType().equals("VersionTracking")) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
|
|
}
|
|
|
|
}
|