mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-5290_d-millar_angr--SQUASHED'
This commit is contained in:
commit
70d43e73d8
24 changed files with 605 additions and 113 deletions
|
@ -29,6 +29,7 @@ dependencies {
|
|||
api project(':Base')
|
||||
api project(':ByteViewer')
|
||||
api project(':Decompiler')
|
||||
api project(':DecompilerDependent')
|
||||
api project(':FunctionGraph')
|
||||
api project(':ProposedUtils')
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
DataTypeReferenceFinder
|
||||
TaintState
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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,27 +242,28 @@ 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();
|
||||
|
||||
if (usesIndex) {
|
||||
plugin.consoleMessage("Attempting to use index: " + indexDBFile.toString());
|
||||
|
||||
if (!indexDBFile.exists()) {
|
||||
|
@ -258,6 +273,7 @@ public abstract class AbstractTaintState implements TaintState {
|
|||
}
|
||||
|
||||
plugin.consoleMessage("Using index database: " + indexDBFile);
|
||||
}
|
||||
|
||||
switch (queryType) {
|
||||
case SRCSINK:
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,18 +53,21 @@ 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;
|
||||
|
@ -69,6 +75,9 @@ public class TaintLabel {
|
|||
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
|
||||
|
@ -146,6 +155,14 @@ public class TaintLabel {
|
|||
active = true;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
active = !active;
|
||||
}
|
||||
|
@ -214,4 +231,11 @@ public class TaintLabel {
|
|||
return true;
|
||||
}
|
||||
|
||||
public Address getVarnodeAddress() {
|
||||
if (vnode != null) {
|
||||
return vnode.getAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,10 +355,12 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
|
|||
GhidraState ghidraState = new GhidraState(tool, null, currentProgram,
|
||||
currentLocation, currentHighlight, currentHighlight);
|
||||
GhidraScript exportScript = state.getExportScript(consoleService, false);
|
||||
if (exportScript != null) {
|
||||
RunPCodeExportScriptTask export_task =
|
||||
new RunPCodeExportScriptTask(tool, exportScript, ghidraState, consoleService);
|
||||
tool.execute(export_task);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
@ -285,6 +291,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 ||
|
||||
token instanceof ClangSyntaxToken ||
|
||||
|
@ -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();
|
||||
|
|
|
@ -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,9 +56,30 @@ 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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue