Merge remote-tracking branch 'origin/GP-5290_d-millar_angr--SQUASHED'

This commit is contained in:
Ryan Kurtz 2025-02-03 16:11:13 -05:00
commit 70d43e73d8
24 changed files with 605 additions and 113 deletions

View file

@ -29,6 +29,7 @@ dependencies {
api project(':Base')
api project(':ByteViewer')
api project(':Decompiler')
api project(':DecompilerDependent')
api project(':FunctionGraph')
api project(':ProposedUtils')

View file

@ -0,0 +1,234 @@
/* ###
* 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.
*/
package ghidra.app.plugin.core.debug.taint;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import ghidra.app.decompiler.ClangFuncNameToken;
import ghidra.app.plugin.core.decompiler.taint.*;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.ConsoleService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.HighParam;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
/**
* Container for all the decompiler elements the users "selects" via the menu.
* This data is used to build queries.
*/
public class AngrTaintState extends AbstractTaintState {
private DebuggerTraceManagerService traceManager;
public AngrTaintState(TaintPlugin plugin) {
super(plugin);
ENGINE_NAME = "angr";
usesIndex = false;
}
private Address start;
@Override
public void buildQuery(List<String> paramList, Path engine, File indexDBFile,
String indexDirectory) {
paramList.add("python");
paramList.add(engine.toString());
}
@Override
public void buildIndex(List<String> paramList, String engine_path, String facts_path,
String indexDirectory) {
// Unused
}
@Override
public GhidraScript getExportScript(ConsoleService console, boolean perFunction) {
return null;
}
@Override
protected void writeHeader(PrintWriter writer) {
Program currentProgram = plugin.getCurrentProgram();
start = currentProgram.getMaxAddress().getNewAddress(Integer.MAX_VALUE);
writer.println("{");
writer.println("\t\"binary_file\":\"" + currentProgram.getExecutablePath() + "\",");
writer.println("\t\"base_address\":\"" +
Long.toHexString(currentProgram.getImageBase().getOffset()) + "\",");
}
/*
* NOTE: This is the only method used now for Sources and Sinks.
*/
@Override
protected void writeRule(PrintWriter writer, TaintLabel mark, boolean isSource) {
Program currentProgram = plugin.getCurrentProgram();
Address addr = mark.getAddress();
if (isSource) {
if (start.getOffset() > addr.getOffset()) {
start = addr;
}
}
else {
writer.println("\t\"find_address\":\"" + Long.toHexString(addr.getOffset()) + "\",");
return;
}
if (isSource) {
if (mark.getToken() instanceof ClangFuncNameToken) {
CodeUnit cu = currentProgram.getListing().getCodeUnitAt(addr);
writer.println("\t\"hooks\":[{\"" + Long.toHexString(addr.getOffset()) +
"\":{\"length\":\"" + cu.getLength() + "\"}}],");
return;
}
if (mark.getHighVariable() instanceof HighParam hp) {
writer.println(
"\t\"arguments\":{\"" + hp.getSlot() + "\":\"" + mark.getSize() + "\"},");
return;
}
Address vaddr = mark.getVarnodeAddress();
if (vaddr != null) {
if (vaddr.isRegisterAddress()) {
Language language = currentProgram.getLanguage();
Register register = language.getRegister(vaddr, mark.getSize());
writer.println("\t\"regs_vals\":{\"" + register.getName() + "\":\"" +
mark.getSize() + "\"},");
}
if (vaddr.isMemoryAddress()) {
writer.println("\t\"vectors\":{\"" + vaddr + "\":\"" + mark.getSize() + "\"},");
}
}
}
}
@Override
public void writeGate(PrintWriter writer, TaintLabel mark) {
Address addr = mark.getAddress();
writer.println("\t\"avoid_address\":\"" + Long.toHexString(addr.getOffset()) + "\",");
}
@Override
protected void writeFooter(PrintWriter writer) {
writeState(writer);
writer.println("\t\"blank_state\":\"" + Long.toHexString(start.getOffset()) + "\",");
writer.println("\t\"auto_load_libs\":false");
writer.println("}");
}
private void writeState(PrintWriter writer) {
if (traceManager == null) {
traceManager = plugin.getTool().getService(DebuggerTraceManagerService.class);
if (traceManager == null) {
return;
}
}
DebuggerCoordinates current = traceManager.getCurrent();
Trace trace = current.getTrace();
if (trace == null) {
return;
}
TraceMemoryManager memoryManager = trace.getMemoryManager();
Collection<? extends TraceMemoryRegion> allRegions =
memoryManager.getRegionsAtSnap(current.getSnap());
for (TraceMemoryRegion region : allRegions) {
AddressRange range = region.getRange();
Address min = range.getMinAddress();
int len = (int) range.getLength();
byte[] bytes = new byte[len];
int nread =
memoryManager.getBytes(current.getSnap(), min, ByteBuffer.wrap(bytes));
if (nread == len) {
writer.println("\t\"mem_store\":{\"" + min + "\":\"" + convert(bytes) + "\"},");
}
else {
Msg.error(this, "Requested " + len + " but returned " + nread);
}
}
Program currentProgram = plugin.getCurrentProgram();
List<Register> registers = currentProgram.getLanguage().getRegisters();
TraceThread thread = current.getThread();
if (thread == null) {
return;
}
TraceMemorySpace regs =
memoryManager.getMemoryRegisterSpace(thread, current.getFrame(), true);
if (regs == null) {
return;
}
for (Register r : registers) {
TraceMemoryState state = regs.getState(current.getPlatform(), current.getSnap(), r);
if (!state.equals(TraceMemoryState.KNOWN)) {
continue;
}
RegisterValue value = regs.getValue(current.getSnap(), r);
byte[] bytes = value.getUnsignedValue().toByteArray();
String bytestr = convert(bytes);
if (!bytestr.equals("") && !bytestr.equals("00")) {
writer.println(
"\t\"regs_vals\":{\"" + r.getName() + "\":\"0x" + convert(bytes) + "\"},");
}
}
}
private String convert(byte[] bytes) {
return NumericUtilities.convertBytesToString(bytes);
}
@Override
protected void readQueryResultsIntoDataFrame(Program program, InputStream is) {
Program currentProgram = plugin.getCurrentProgram();
String line = null;
taintAddressSet.clear();
taintVarnodeMap.clear();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((line = bufferedReader.readLine()) != null) {
if (line.startsWith("t:")) {
String addrStr = line.substring(line.indexOf(":") + 1);
Address address = currentProgram.getMinAddress().getAddress(addrStr);
taintAddressSet.add(address);
}
else {
System.err.println(line);
}
}
bufferedReader.close();
}
catch (IOException | AddressFormatException e) {
plugin.consoleMessage("IO Error Reading Query Results from Process: " + e.getMessage());
}
}
}

View file

@ -1 +1,2 @@
DataTypeReferenceFinder
TaintState

View file

@ -151,6 +151,14 @@
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintAllAccess"></a>Match on Fields</h3></div></div></div>
<p>
Use all access paths, including field references, for sink/source variables.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintOutputFormat"></a>Output Format</h3></div></div></div>
@ -163,9 +171,9 @@
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintAllAccess"></a>Match on Fields</h3></div></div></div>
<a name="TaintEngine"></a>Query Engine</h3></div></div></div>
<p>
Use all access paths, including field references, for sink/source variables.
The engine to be used for formatting queries (e.g. ctadl, angr).
</p>
</div>

View file

@ -43,22 +43,22 @@ public abstract class AbstractTaintState implements TaintState {
public static String ENGINE_NAME = "";
private Set<TaintLabel> sources = new HashSet<>();
private Set<TaintLabel> sinks = new HashSet<>();
private Set<TaintLabel> gates = new HashSet<>();
protected Set<TaintLabel> sources = new HashSet<>();
protected Set<TaintLabel> sinks = new HashSet<>();
protected Set<TaintLabel> gates = new HashSet<>();
// Sets used for highlighting.
private AddressSet taintAddressSet = new AddressSet();
private Map<Address, Set<TaintQueryResult>> taintVarnodeMap = new HashMap<>();
protected AddressSet taintAddressSet = new AddressSet();
protected Map<Address, Set<TaintQueryResult>> taintVarnodeMap = new HashMap<>();
private AddressSet deltaAddressSet = new AddressSet();
private Map<Address, Set<TaintQueryResult>> deltaVarnodeMap = new HashMap<>();
private SarifSchema210 currentQueryData;
protected SarifSchema210 currentQueryData;
protected TaintOptions taintOptions;
private TaintPlugin plugin;
protected TaintPlugin plugin;
protected boolean usesIndex = true;
private boolean cancellation;
private TaskType taskType;
@ -74,10 +74,14 @@ public abstract class AbstractTaintState implements TaintState {
public abstract void buildIndex(List<String> param_list, String engine_path, String facts_path,
String index_path);
protected abstract void writeHeader(PrintWriter writer);
protected abstract void writeRule(PrintWriter writer, TaintLabel mark, boolean isSource);
protected abstract void writeGate(PrintWriter writer, TaintLabel mark);
protected abstract void writeFooter(PrintWriter writer);
@Override
public boolean wasCancelled() {
return this.cancellation;
@ -122,6 +126,17 @@ public abstract class AbstractTaintState implements TaintState {
return tlabel;
}
@Override
public TaintLabel getLabelForToken(MarkType type, ClangToken token) {
Set<TaintLabel> marks = getTaintLabels(type);
for (TaintLabel existingLabel : marks) {
if (token.equals(existingLabel.getToken())) {
return existingLabel;
}
}
return null;
}
/**
* Predicate indicating the presence of one or more sources in the source set;
* this is used to determine state validity.
@ -173,7 +188,7 @@ public abstract class AbstractTaintState implements TaintState {
public boolean writeQueryFile(File queryTextFile) throws Exception {
PrintWriter writer = new PrintWriter(queryTextFile);
writer.println("#include \"pcode/taintquery.dl\"");
writeHeader(writer);
for (TaintLabel mark : sources) {
if (mark.isActive()) {
@ -181,8 +196,6 @@ public abstract class AbstractTaintState implements TaintState {
}
}
writer.println("");
for (TaintLabel mark : sinks) {
if (mark.isActive()) {
// CAREFUL note the "false"
@ -191,7 +204,6 @@ public abstract class AbstractTaintState implements TaintState {
}
if (!gates.isEmpty()) {
writer.println("");
for (TaintLabel mark : gates) {
if (mark.isActive()) {
writeGate(writer, mark);
@ -199,6 +211,8 @@ public abstract class AbstractTaintState implements TaintState {
}
}
writeFooter(writer);
writer.flush();
writer.close();
@ -220,7 +234,7 @@ public abstract class AbstractTaintState implements TaintState {
return false;
}
List<String> param_list = new ArrayList<String>();
List<String> paramList = new ArrayList<String>();
File queryFile = null;
taintOptions = plugin.getOptions();
@ -228,37 +242,39 @@ public abstract class AbstractTaintState implements TaintState {
// Make sure we can access and execute the engine binary.
Path engine = Path.of(taintOptions.getTaintEnginePath());
File engine_file = engine.toFile();
File engineFile = engine.toFile();
if (!engine_file.exists() || !engine_file.canExecute()) {
if (!engineFile.exists()) {
plugin.consoleMessage("The " + getName() + " binary (" +
engine_file.getCanonicalPath() + ") cannot be found or executed.");
engine_file = getFilePath(taintOptions.getTaintEnginePath(),
engineFile.getCanonicalPath() + ") cannot be found or executed.");
engineFile = getFilePath(taintOptions.getTaintEnginePath(),
"Select the " + getName() + " binary");
if (engine_file == null) {
if (engineFile == null) {
plugin.consoleMessage(
"No " + getName() + " engine has been specified; exiting query function.");
return false;
}
}
plugin.consoleMessage("Using " + getName() + " binary: " + engine_file.toString());
plugin.consoleMessage("Using " + getName() + " binary: " + engineFile.toString());
Path index_directory = Path.of(taintOptions.getTaintOutputDirectory());
Path indexDirectory = Path.of(taintOptions.getTaintOutputDirectory());
Path indexDBPath = Path.of(taintOptions.getTaintOutputDirectory(),
taintOptions.getTaintIndexDBName(program.getName()));
File indexDBFile = indexDBPath.toFile();
plugin.consoleMessage("Attempting to use index: " + indexDBFile.toString());
if (!indexDBFile.exists()) {
plugin.consoleMessage("The index database for the binary named: " +
program.getName() + " does not exist; create it first.");
return false;
if (usesIndex) {
plugin.consoleMessage("Attempting to use index: " + indexDBFile.toString());
if (!indexDBFile.exists()) {
plugin.consoleMessage("The index database for the binary named: " +
program.getName() + " does not exist; create it first.");
return false;
}
plugin.consoleMessage("Using index database: " + indexDBFile);
}
plugin.consoleMessage("Using index database: " + indexDBFile);
switch (queryType) {
case SRCSINK:
// Generate a datalog query file based on the selected source, sink, etc. data.
@ -280,7 +296,7 @@ public abstract class AbstractTaintState implements TaintState {
plugin.consoleMessage("Unknown query type.");
}
buildQuery(param_list, engine, indexDBFile, index_directory.toString());
buildQuery(paramList, engine, indexDBFile, indexDirectory.toString());
if (queryType.equals(QueryType.SRCSINK) || queryType.equals(QueryType.CUSTOM)) {
// The datalog that specifies the query.
@ -294,12 +310,12 @@ public abstract class AbstractTaintState implements TaintState {
return false;
}
}
param_list.add(queryFile.getAbsolutePath());
paramList.add(queryFile.getAbsolutePath());
}
Msg.info(this, "Query Param List: " + param_list.toString());
Msg.info(this, "Query Param List: " + paramList.toString());
try {
ProcessBuilder pb = new ProcessBuilder(param_list);
ProcessBuilder pb = new ProcessBuilder(paramList);
pb.directory(new File(taintOptions.getTaintOutputDirectory()));
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();
@ -326,9 +342,10 @@ public abstract class AbstractTaintState implements TaintState {
}
/**
* @param prog current program if needed
* @param is the input stream (SARIF json) from the process builder that runs the engine
*/
private void readQueryResultsIntoDataFrame(Program program, InputStream is) {
protected void readQueryResultsIntoDataFrame(Program prog, InputStream is) {
StringBuilder sb = new StringBuilder();
String line = null;
@ -533,6 +550,7 @@ public abstract class AbstractTaintState implements TaintState {
return plugin.getOptions();
}
@Override
public String getName() {
return ENGINE_NAME;
}

View file

@ -28,6 +28,7 @@ public class TaintLabel {
private String fname;
private HighFunction hfun;
private HighVariable hvar;
private Varnode vnode;
private boolean active;
private String label;
private boolean isGlobal = false;
@ -36,8 +37,10 @@ public class TaintLabel {
// TODO: This is not a good identifier since it could change during re work!
private Address addr;
private ClangLine clangLine;
private int size = 0;
public TaintLabel(MarkType mtype, ClangToken token) throws PcodeException {
HighVariable highVar = token.getHighVariable();
if (highVar == null) {
hfun = token.getClangFunction().getHighFunction();
@ -50,25 +53,31 @@ public class TaintLabel {
}
}
Varnode exactSpot = token.getVarnode();
if (exactSpot != null) { // The user pointed at a particular usage, not just the vardecl
HighVariable high = exactSpot.getHigh();
this.vnode = token.getVarnode();
if (vnode != null) { // The user pointed at a particular usage, not just the vardecl
HighVariable high = vnode.getHigh();
if (high instanceof HighLocal) {
highVar = hfun.splitOutMergeGroup(high, exactSpot);
highVar = hfun.splitOutMergeGroup(high, vnode);
}
}
String fn = token instanceof ClangFuncNameToken ftoken ? ftoken.getText()
: hfun.getFunction().getName();
PcodeOp pcodeOp = token.getPcodeOp();
Address target = pcodeOp == null ? null : pcodeOp.getSeqnum().getTarget();
Address target = pcodeOp == null ? hfun.getFunction().getEntryPoint() : pcodeOp.getSeqnum().getTarget();
if (vnode == null && pcodeOp != null) {
vnode = pcodeOp.getOutput();
}
this.mtype = mtype;
this.token = token;
this.fname = fn;
this.hvar = highVar;
this.active = true;
this.addr = target;
if (hvar != null) {
size = hvar.getSize();
}
this.clangLine = token.getLineParent();
// Initial label is one of SOURCE, SINK, or GATE
@ -145,6 +154,14 @@ public class TaintLabel {
public void activate() {
active = true;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public void toggle() {
active = !active;
@ -213,5 +230,12 @@ public class TaintLabel {
}
return true;
}
public Address getVarnodeAddress() {
if (vnode != null) {
return vnode.getAddress();
}
return null;
}
}

View file

@ -45,6 +45,7 @@ public class TaintOptions {
/* The default name of the index database file. */
public final static String OP_KEY_TAINT_DB = "Taint.Query.Index";
public final static String OP_KEY_TAINT_QUERY_ENGINE = "Taint.Query Engine";
public final static String OP_KEY_TAINT_QUERY_DIRECTION = "Taint.Force Direction";
public final static String OP_KEY_TAINT_QUERY_OUTPUT_FORM = "Taint.Output Format";
/* Color used in the decompiler to highlight taint. */
@ -68,13 +69,14 @@ public class TaintOptions {
new GColor("color.bg.listing.highlighter.default");
private final static Highlighter TAINT_HIGHLIGHT_STYLE_DEFAULT = Highlighter.DEFAULT;
private String taintEngine;
private String taintEnginePath;
private String taintFactsDir;
private String taintOutputDir;
private String taintQuery;
private String taintDB;
private String taintQueryEngine;
private TaintDirection taintQueryDirection;
private TaintFormat taintQueryOutputForm;
@ -106,7 +108,7 @@ public class TaintOptions {
public TaintOptions(TaintProvider provider) {
taintProvider = provider;
taintEngine = DEFAULT_TAINT_ENGINE_PATH;
taintEnginePath = DEFAULT_TAINT_ENGINE_PATH;
taintFactsDir = DEFAULT_TAINT_FACTS_DIR;
taintOutputDir = DEFAULT_TAINT_OUTPUT_DIR;
taintQuery = DEFAULT_TAINT_QUERY;
@ -129,7 +131,11 @@ public class TaintOptions {
opt.registerOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, TaintFormat.ALL,
new HelpLocation(HelpTopics.DECOMPILER, "Taint Output Type"),
"The type of Source-Sink query output (e.g., sarif, summary, text");
"The type of Source-Sink query output (e.g., sarif, summary, text)");
opt.registerOption(OP_KEY_TAINT_QUERY_ENGINE, "",
new HelpLocation(HelpTopics.DECOMPILER, "Taint Query Engine"),
"The query engine (e.g., angr, ctadl)");
opt.registerOption(OP_KEY_TAINT_ENGINE_PATH, DEFAULT_TAINT_ENGINE_PATH,
new HelpLocation(HelpTopics.DECOMPILER, "Taint Engine Directory"),
@ -176,7 +182,17 @@ public class TaintOptions {
*/
public void grabFromToolAndProgram(Plugin ownerPlugin, ToolOptions opt, Program program) {
taintEngine = opt.getString(OP_KEY_TAINT_ENGINE_PATH, "");
String engine = opt.getString(OP_KEY_TAINT_QUERY_ENGINE, "");
if (!engine.equals(taintQueryEngine)) {
TaintPlugin plugin = (TaintPlugin) ownerPlugin;
TaintState state = TaintState.newInstance(plugin, engine);
if (state != null) {
plugin.setTaintState(state);
taintQueryEngine = engine;
}
}
taintEnginePath = opt.getString(OP_KEY_TAINT_ENGINE_PATH, "");
taintFactsDir = opt.getString(OP_KEY_TAINT_FACTS_DIR, "");
taintQuery = opt.getString(OP_KEY_TAINT_QUERY, "");
// taintQueryResultsFile = opt.getString(OP_KEY_TAINT_QUERY_RESULTS, "");
@ -196,8 +212,12 @@ public class TaintOptions {
return taintQueryOutputForm;
}
public String getTaintEngineType() {
return taintQueryEngine;
}
public String getTaintEnginePath() {
return taintEngine;
return taintEnginePath;
}
public String getTaintFactsDirectory() {
@ -244,6 +264,11 @@ public class TaintOptions {
return taintUseAllAccess;
}
public void setTaintQueryEngine(String engine) {
this.taintQueryEngine = engine;
taintProvider.setOption(OP_KEY_TAINT_QUERY_ENGINE, engine);
}
public void setTaintOutputForm(TaintFormat form) {
this.taintQueryOutputForm = form;
taintProvider.setOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, form.getOptionString());

View file

@ -111,8 +111,11 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
}
public static enum TaintFormat {
ALL("all", "sarif+all"), GRAPHS("graphs", "sarif+graphs"),
INSTS("insts", "sarif+instructions"), PATHS("paths", "sarif");
ALL("all", "sarif+all"),
GRAPHS("graphs", "sarif+graphs"),
INSTS("insts", "sarif+instructions"),
PATHS("paths", "sarif"),
NONE("none", "none");
private String label;
private String optionString;
@ -175,7 +178,6 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
public TaintPlugin(PluginTool tool) {
super(tool);
state = TaintState.newInstance(this);
taintProvider = new TaintProvider(this);
taintDecompMarginProvider = new TaintDecompilerMarginProvider(this);
createActions();
@ -353,9 +355,11 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
GhidraState ghidraState = new GhidraState(tool, null, currentProgram,
currentLocation, currentHighlight, currentHighlight);
GhidraScript exportScript = state.getExportScript(consoleService, false);
RunPCodeExportScriptTask export_task =
new RunPCodeExportScriptTask(tool, exportScript, ghidraState, consoleService);
tool.execute(export_task);
if (exportScript != null) {
RunPCodeExportScriptTask export_task =
new RunPCodeExportScriptTask(tool, exportScript, ghidraState, consoleService);
tool.execute(export_task);
}
}
@Override
@ -433,6 +437,10 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
return state;
}
public void setTaintState(TaintState state) {
this.state = state;
}
public TaintProvider getProvider() {
return taintProvider;
}

View file

@ -61,8 +61,6 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
private DecompilerProvider decompilerProvider;
private Navigatable navigatable;
private TaintState state;
private DecompilerHighlighter highlighter;
private TaintCTokenHighlighterPalette highlightPalette;
@ -84,7 +82,6 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
super(plugin.getTool(), "TaintProvider", plugin.getName(), DecompilerActionContext.class);
this.plugin = plugin;
this.taintOptions = new TaintOptions(this);
this.state = plugin.getTaintState();
this.cachedHighlightsByToken = new HashMap<>();
this.cachedHighlightByAddress = new HashMap<>();
this.highlightPalette = new TaintCTokenHighlighterPalette(256);
@ -108,34 +105,37 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
// These actions are only available in the drop-down window
TaintSourceAction taintSourceAction = new TaintSourceAction(plugin, state);
TaintSourceAction taintSourceAction = new TaintSourceAction(plugin);
setGroupInfo(taintSourceAction, variableGroup, subGroupPosition++);
TaintSourceBySymbolAction taintSourceBySymbolAction =
new TaintSourceBySymbolAction(plugin, state);
new TaintSourceBySymbolAction(plugin);
setGroupInfo(taintSourceBySymbolAction, variableGroup, subGroupPosition++);
TaintSinkAction taintSinkAction = new TaintSinkAction(plugin, state);
TaintSinkAction taintSinkAction = new TaintSinkAction(plugin);
setGroupInfo(taintSinkAction, variableGroup, subGroupPosition++);
TaintSinkBySymbolAction taintSinkBySymbolAction =
new TaintSinkBySymbolAction(plugin, state);
new TaintSinkBySymbolAction(plugin);
setGroupInfo(taintSinkBySymbolAction, variableGroup, subGroupPosition++);
TaintGateAction taintGateAction = new TaintGateAction(plugin, state);
TaintGateAction taintGateAction = new TaintGateAction(plugin);
setGroupInfo(taintGateAction, variableGroup, subGroupPosition++);
TaintClearAction taintClearAction = new TaintClearAction(plugin, state);
TaintClearAction taintClearAction = new TaintClearAction(plugin);
setGroupInfo(taintClearAction, variableGroup, subGroupPosition++);
// These actions have an icon and a drop-down menu option in the decompiler window.
TaintQueryAction taintQueryAction = new TaintQueryAction(plugin, state);
TaintQueryDefaultAction taintQueryDefaultAction =
new TaintQueryDefaultAction(plugin, state);
TaintQueryCustomAction taintQueryCustomAction = new TaintQueryCustomAction(plugin, state);
TaintLoadAction taintLoadAction = new TaintLoadAction(plugin, state);
TaintSetSizeAction taintSizeAction = new TaintSetSizeAction(plugin);
setGroupInfo(taintSizeAction, variableGroup, subGroupPosition++);
TaintSliceTreeAction taintSliceTreeAction = new TaintSliceTreeAction(plugin, state);
// These actions have an icon and a drop-down menu option in the decompiler window.
TaintQueryAction taintQueryAction = new TaintQueryAction(plugin);
TaintQueryDefaultAction taintQueryDefaultAction =
new TaintQueryDefaultAction(plugin);
TaintQueryCustomAction taintQueryCustomAction = new TaintQueryCustomAction(plugin);
TaintLoadAction taintLoadAction = new TaintLoadAction(plugin);
TaintSliceTreeAction taintSliceTreeAction = new TaintSliceTreeAction(plugin);
DockingAction taintLabelTableAction = new DockingAction("TaintShowLabels", TaintPlugin.HELP_LOCATION) {
@ -153,7 +153,8 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
@Override
public boolean isEnabledForContext(ActionContext context) {
return state.hasMarks();
TaintState state = plugin.getTaintState();
return state == null ? false : state.hasMarks();
}
};
@ -175,6 +176,7 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
provider.addLocalAction(taintQueryCustomAction);
provider.addLocalAction(taintLoadAction);
provider.addLocalAction(taintClearAction);
provider.addLocalAction(taintSizeAction);
}
/**
@ -253,6 +255,10 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
* @param taskType subtract previous result
*/
public void setTaint(TaskType taskType) {
TaintState state = plugin.getTaintState();
if (state == null) {
return;
}
if (navigatable == null) {
navigatable = tool.getService(CodeViewerService.class).getNavigatable();
}
@ -284,6 +290,11 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
}
public boolean matchOn(ClangToken token) {
TaintState state = plugin.getTaintState();
if (state == null) {
return false;
}
if (token instanceof ClangBreak ||
token instanceof ClangTypeToken ||
@ -372,7 +383,7 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
Msg.info(this,
"TaintProvider: clearTaint() - state clearTaint() and highligher apply highlights.");
matchCount = 0;
state.clearTaint();
plugin.getTaintState().clearTaint();
highlighter.clearHighlights();
cachedHighlightByAddress.clear();
cachedHighlightsByToken.clear();

View file

@ -16,12 +16,12 @@
package ghidra.app.plugin.core.decompiler.taint;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.*;
import com.contrastsecurity.sarif.SarifSchema210;
import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.decompiler.taint.ctadl.TaintStateCTADL;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.ConsoleService;
import ghidra.framework.plugintool.PluginTool;
@ -31,12 +31,18 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ExtensionPoint;
/**
* The interface for the methods that collect desired taint information from the decompiler window and store them
* for construction of queries and indexing.
* <p>
* NOTE: ALL TaintState CLASSES MUST END IN "TaintState". If not,
* the ClassSearcher will not find them.
*/
public interface TaintState {
public interface TaintState extends ExtensionPoint {
public enum MarkType {
SOURCE, SINK, GATE
@ -50,10 +56,31 @@ public interface TaintState {
SET_TAINT, SET_DELTA, APPLY_DELTA
}
public static TaintState newInstance(TaintPlugin plugin) {
return new TaintStateCTADL(plugin);
public static TaintState newInstance(TaintPlugin plugin, String type) {
List<Class<? extends TaintState>> list = ClassSearcher.getClasses(TaintState.class)
.stream()
.toList();
Class<?>[] constructorArgumentTypes = {TaintPlugin.class};
Object[] args = new Object[1];
args[0] = plugin;
for (Class<? extends TaintState> clazz : list) {
if (clazz.getName().toLowerCase().contains(type)) {
try {
Constructor<?> constructor = clazz.getConstructor(constructorArgumentTypes);
Object obj = constructor.newInstance(plugin);
return TaintState.class.cast(obj);
}
catch (Exception e) {
throw new RuntimeException("Unable to instantiate TaintState");
}
}
}
Msg.error(plugin, "No match for engine = "+type);
return null;
}
public String getName();
/**
* Perform a Source-Sink query on the index database.
*
@ -108,6 +135,10 @@ public interface TaintState {
public GhidraScript getExportScript(ConsoleService console, boolean perFunction);
public void setTaskType(TaskType taskType);
public TaintLabel getLabelForToken(MarkType type, ClangToken token);
public static String hvarName(ClangToken token) {
HighVariable hv = token.getHighVariable();
HighFunction hf =
@ -159,6 +190,4 @@ public interface TaintState {
return false;
}
public void setTaskType(TaskType taskType);
}

View file

@ -20,6 +20,7 @@ import javax.swing.Icon;
import docking.action.MenuData;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.*;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin.TaintFormat;
import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
import ghidra.app.plugin.core.decompiler.taint.sarif.SarifTaintGraphRunHandler;
import ghidra.framework.plugintool.PluginTool;
@ -37,7 +38,6 @@ import sarif.SarifService;
public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAction {
protected TaintPlugin plugin;
protected TaintState state;
protected String desc;
protected String title;
@ -45,14 +45,13 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
protected Icon executeTaintQueryIcon;
protected QueryType queryType;
public TaintAbstractQueryAction(TaintPlugin plugin, TaintState state, String desc, String title, String cmd) {
public TaintAbstractQueryAction(TaintPlugin plugin, String desc, String title, String cmd) {
super(cmd);
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "Taint"+desc));
setMenuBarData(new MenuData(new String[] { "Source-Sink", getName() }));
this.plugin = plugin;
this.state = state;
this.desc = desc;
this.title = title;
}
@ -62,6 +61,9 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
*/
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
return true;
}
@ -73,6 +75,7 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
Task defaultQueryTask = new Task(title, true, true, true, true) {
@Override
public void run(TaskMonitor monitor) {
TaintState state = plugin.getTaintState();
state.setCancellation(false);
monitor.initialize(program.getFunctionManager().getFunctionCount());
state.queryIndex(program, tool, queryType);
@ -87,10 +90,14 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
// We still get a progress bar and option to cancel.
tool.execute(defaultQueryTask);
TaintState state = plugin.getTaintState();
if (!state.wasCancelled()) {
SarifService sarifService = plugin.getSarifService();
sarifService.getController().setDefaultGraphHander(SarifTaintGraphRunHandler.class);
sarifService.showSarif(desc, state.getData());
TaintFormat format = state.getOptions().getTaintOutputForm();
if (!format.equals(TaintFormat.NONE)) {
SarifService sarifService = plugin.getSarifService();
sarifService.getController().setDefaultGraphHander(SarifTaintGraphRunHandler.class);
sarifService.showSarif(desc, state.getData());
}
plugin.consoleMessage("executing query...");
TaintProvider provider = plugin.getProvider();

View file

@ -23,7 +23,6 @@ import docking.action.MenuData;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
/**
@ -34,25 +33,26 @@ import ghidra.util.HelpLocation;
public class TaintClearAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private TaintState state;
public TaintClearAction(TaintPlugin plugin, TaintState state) {
public TaintClearAction(TaintPlugin plugin) {
super("Clear Markers");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintClear"));
setPopupMenuData(new MenuData(new String[] { "Taint", "Clear" }, "Decompile"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
this.plugin = plugin;
this.state = state;
}
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
return true;
}
@Override
protected void decompilerActionPerformed(DecompilerActionContext context) {
state.clearMarkers();
plugin.getTaintState().clearMarkers();
plugin.clearIcons();
plugin.clearTaint();
plugin.consoleMessage("taint cleared");

View file

@ -25,7 +25,6 @@ import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -43,7 +42,7 @@ public class TaintGateAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private MarkType mtype;
public TaintGateAction(TaintPlugin plugin, TaintState state) {
public TaintGateAction(TaintPlugin plugin) {
super("Mark Gate");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintGate"));
setPopupMenuData(new MenuData(new String[] { "Taint", "Gate" }, "Decompile"));
@ -58,6 +57,10 @@ public class TaintGateAction extends TaintAbstractDecompilerAction {
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;

View file

@ -27,7 +27,6 @@ import generic.theme.GIcon;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
@ -47,12 +46,11 @@ import ghidra.util.HelpLocation;
public class TaintLoadAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private TaintState state;
private static String loadSarifFileIconString = "icon.fsbrowser.file.extension.obj";
private static Icon loadSarifFileIcon = new GIcon(loadSarifFileIconString);
public TaintLoadAction(TaintPlugin plugin, TaintState state) {
public TaintLoadAction(TaintPlugin plugin) {
super("Load SARIF file");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintLoadSarif"));
@ -60,7 +58,6 @@ public class TaintLoadAction extends TaintAbstractDecompilerAction {
setToolBarData(new ToolBarData(loadSarifFileIcon));
this.plugin = plugin;
this.state = state;
}
@Override
@ -78,6 +75,7 @@ public class TaintLoadAction extends TaintAbstractDecompilerAction {
// Pop a file dialog to select the SARIF file.
// need to pop-up a file chooser dialog.
TaintState state = plugin.getTaintState();
GhidraFileChooser file_chooser = new GhidraFileChooser(tool.getToolFrame());
file_chooser.setCurrentDirectory(new File(state.getOptions().getTaintEnginePath()));
file_chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);

View file

@ -27,8 +27,8 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryAction extends TaintAbstractQueryAction {
public TaintQueryAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "Query", "Source-Sink Taint Query", "Run taint query");
public TaintQueryAction(TaintPlugin plugin) {
super(plugin, "Query", "Source-Sink Taint Query", "Run taint query");
executeTaintQueryIconString = "icon.graph.default.display.program.graph";
executeTaintQueryIcon = new GIcon(executeTaintQueryIconString);
queryType = QueryType.SRCSINK;
@ -39,7 +39,8 @@ public class TaintQueryAction extends TaintAbstractQueryAction {
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
return state.isValid();
TaintState state = plugin.getTaintState();
return state == null ? false : state.isValid();
}
}

View file

@ -25,8 +25,8 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryCustomAction extends TaintAbstractQueryAction {
public TaintQueryCustomAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "CustomQuery", "Custom Taint Query", "Run custom taint query");
public TaintQueryCustomAction(TaintPlugin plugin) {
super(plugin, "CustomQuery", "Custom Taint Query", "Run custom taint query");
queryType = QueryType.CUSTOM;
setKeyBindingData(new KeyBindingData(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
}

View file

@ -27,8 +27,8 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryDefaultAction extends TaintAbstractQueryAction {
public TaintQueryDefaultAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "DefaultQuery", "Default Taint Query", "Run default taint query");
public TaintQueryDefaultAction(TaintPlugin plugin) {
super(plugin, "DefaultQuery", "Default Taint Query", "Run default taint query");
executeTaintQueryIconString = "icon.version.tracking.markup.status.conflict";
executeTaintQueryIcon = new GIcon(executeTaintQueryIconString);
queryType = QueryType.DEFAULT;

View file

@ -0,0 +1,97 @@
/* ###
* 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.
*/
package ghidra.app.plugin.core.decompiler.taint.actions;
import docking.action.MenuData;
import docking.widgets.dialogs.InputDialog;
import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintLabel;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.program.model.listing.Function;
import ghidra.util.UndefinedFunction;
/**
* Triggered by right-click on a token in the decompiler window.
* <p>
* Action triggered from a specific token in the decompiler window to mark a variable as a
* source or sink and generate the requisite query. Legal tokens to select include:
* <ul><li>
* An input parameter,
* </li><li>
* A stack variable,
* </li><li>
* A variable associated with a register, or
* </li><li>
* A "dynamic" variable.
* </li></ul>
*/
public class TaintSetSizeAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
public TaintSetSizeAction(TaintPlugin plugin) {
super("Set length");
// Taint Menu -> Source sub item.
setPopupMenuData(new MenuData(new String[] { "Taint", "Set length" }, "Decompile"));
this.plugin = plugin;
}
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;
}
ClangToken tokenAtCursor = context.getTokenAtCursor();
if (tokenAtCursor == null) {
return false;
}
if (tokenAtCursor instanceof ClangFieldToken) {
return true;
}
if (tokenAtCursor.Parent() instanceof ClangReturnType) {
return false;
}
if (tokenAtCursor instanceof ClangFuncNameToken) {
return true;
}
if (!tokenAtCursor.isVariableRef()) {
return false;
}
return true;
}
@Override
protected void decompilerActionPerformed(DecompilerActionContext context) {
TaintLabel label = plugin.getTaintState().getLabelForToken(MarkType.SOURCE, context.getTokenAtCursor());
if (label != null) {
InputDialog dialog = new InputDialog("Update length", "Length", Integer.toHexString(label.getSize()));
plugin.getTool().showDialog(dialog);
if (dialog.isCanceled()) {
return;
}
String val = dialog.getValue();
label.setSize(Integer.parseInt(val, 16));
}
}
}

View file

@ -25,7 +25,6 @@ import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -40,7 +39,7 @@ public class TaintSinkAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private MarkType mtype;
public TaintSinkAction(TaintPlugin plugin, TaintState state) {
public TaintSinkAction(TaintPlugin plugin) {
super("Mark Sink");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintSink"));
setPopupMenuData(new MenuData(new String[] { "Taint", "Sink" }, "Decompile"));
@ -59,6 +58,10 @@ public class TaintSinkAction extends TaintAbstractDecompilerAction {
*/
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;

View file

@ -21,7 +21,6 @@ import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -36,7 +35,7 @@ public class TaintSinkBySymbolAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private MarkType mtype;
public TaintSinkBySymbolAction(TaintPlugin plugin, TaintState state) {
public TaintSinkBySymbolAction(TaintPlugin plugin) {
super("Mark Sink (Symbol)");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintSinkSymbol"));
setPopupMenuData(new MenuData(new String[] { "Taint", "Sink (Symbol)" }, "Decompile"));
@ -54,6 +53,10 @@ public class TaintSinkBySymbolAction extends TaintAbstractDecompilerAction {
*/
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;

View file

@ -20,7 +20,6 @@ import ghidra.app.decompiler.ClangToken;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.HighVariable;
import ghidra.util.HelpLocation;
@ -45,7 +44,7 @@ public class TaintSliceTreeAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
public TaintSliceTreeAction(TaintPlugin plugin, TaintState state) {
public TaintSliceTreeAction(TaintPlugin plugin) {
super("Show Slice Tree");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintSliceTree"));
setPopupMenuData(new MenuData(new String[] { "Taint", "Slice Tree" }, "Decompile"));
@ -56,6 +55,10 @@ public class TaintSliceTreeAction extends TaintAbstractDecompilerAction {
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
return true;
}

View file

@ -24,7 +24,6 @@ import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -49,7 +48,7 @@ public class TaintSourceAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private MarkType mtype;
public TaintSourceAction(TaintPlugin plugin, TaintState state) {
public TaintSourceAction(TaintPlugin plugin) {
super("Mark Source");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintSource"));
// Taint Menu -> Source sub item.
@ -66,6 +65,10 @@ public class TaintSourceAction extends TaintAbstractDecompilerAction {
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;

View file

@ -21,7 +21,6 @@ import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.util.HelpTopics;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -46,7 +45,7 @@ public class TaintSourceBySymbolAction extends TaintAbstractDecompilerAction {
private TaintPlugin plugin;
private MarkType mtype;
public TaintSourceBySymbolAction(TaintPlugin plugin, TaintState state) {
public TaintSourceBySymbolAction(TaintPlugin plugin) {
super("Mark Source (Symbol)");
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "TaintSourceSymbol"));
// Taint Menu -> Source sub item.
@ -61,6 +60,10 @@ public class TaintSourceBySymbolAction extends TaintAbstractDecompilerAction {
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
if (plugin.getTaintState() == null) {
return false;
}
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;

View file

@ -35,9 +35,9 @@ import ghidra.program.model.pcode.HighVariable;
* Container for all the decompiler elements the users "selects" via the menu.
* This data is used to build queries.
*/
public class TaintStateCTADL extends AbstractTaintState {
public class CTADLTaintState extends AbstractTaintState {
public TaintStateCTADL(TaintPlugin plugin) {
public CTADLTaintState(TaintPlugin plugin) {
super(plugin);
ENGINE_NAME = "ctadl";
}
@ -106,6 +106,12 @@ public class TaintStateCTADL extends AbstractTaintState {
return perFunction ? "ExportPCodeForSingleFunction.java" : "ExportPCodeForCTADL.java";
}
@Override
protected void writeHeader(PrintWriter writer) {
writer.println("#include \"pcode/taintquery.dl\"");
}
/*
* NOTE: This is the only method used now for Sources and Sinks.
*/
@ -178,6 +184,7 @@ public class TaintStateCTADL extends AbstractTaintState {
Boolean allAccess = taintOptions.getTaintUseAllAccess();
String method = "TaintSanitizeAll";
Address addr = mark.getAddress();
// TODO: verify setting entryPoint as addr doesn't break things
if (mark.getFunctionName() == null) {
return;
@ -199,4 +206,9 @@ public class TaintStateCTADL extends AbstractTaintState {
writer.println("\tVertex(vn, p).");
}
@Override
protected void writeFooter(PrintWriter writer) {
// Nothing to do here
}
}