Merge remote-tracking branch 'origin/GP-3077_emteere_CrossedConstants--SQUASHED'

This commit is contained in:
Ryan Kurtz
2023-05-01 06:25:01 -04:00
27 changed files with 1258 additions and 392 deletions
@@ -46,6 +46,7 @@ import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.block.CodeBlock; import ghidra.program.model.block.CodeBlock;
import ghidra.program.model.block.PartitionCodeSubModel; import ghidra.program.model.block.PartitionCodeSubModel;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
@@ -177,9 +178,9 @@ public class MultiInstructionMemReference extends GhidraScript {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
private boolean checkInstructionMatch(final int opIdx, boolean input, private boolean checkInstructionMatch(final int opIdx, boolean input,
@@ -70,7 +70,7 @@ public class PropagateConstantReferences extends GhidraScript {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true); ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, true);
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram); SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
@@ -31,6 +31,7 @@ import ghidra.app.plugin.core.disassembler.AddressTable;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.block.*; import ghidra.program.model.block.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -88,7 +89,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
// Always trust values read from writable memory // Always trust values read from writable memory
ConstantPropagationContextEvaluator eval = ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(true) { new ConstantPropagationContextEvaluator(monitor, true) {
@Override @Override
public boolean evaluateDestination(VarnodeContext context, public boolean evaluateDestination(VarnodeContext context,
Instruction instruction) { Instruction instruction) {
@@ -131,10 +132,13 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
return true; // just go ahead and mark up the instruction return true; // just go ahead and mark up the instruction
} }
}; };
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram); SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
symEval.setParamRefCheck(true); symEval.setParamRefCheck(true);
@@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
symEval.flowConstants(start, func.getBody(), eval, true, monitor); symEval.flowConstants(start, func.getBody(), eval, true, monitor);
// now handle symbolic execution assuming values! // now handle symbolic execution assuming values!
eval = new ConstantPropagationContextEvaluator() { eval = new ConstantPropagationContextEvaluator(monitor) {
@Override @Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) { public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, public Address evaluateConstant(VarnodeContext context, Instruction instr,
int pcodeop, Address constant, int size, RefType refType) { int pcodeop, Address constant, int size, DataType dataType, RefType refType) {
// don't create any references from constants, only looking for flow refs // don't create any references from constants, only looking for flow refs
return null; return null;
} }
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
// TODO: if ever loading from instructions in memory, must // TODO: if ever loading from instructions in memory, must
// EXIT! // EXIT!
if (!(instr.getFlowType().isComputed() && if (!(instr.getFlowType().isComputed() &&
@@ -220,6 +224,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
return true; return true;
} }
}; };
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
// now flow with the simple block of this branch.... // now flow with the simple block of this branch....
@@ -281,7 +281,7 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
Register syscallReg = program.getLanguage().getRegister(syscallRegister); Register syscallReg = program.getLanguage().getRegister(syscallRegister);
for (Function func : funcsToCalls.keySet()) { for (Function func : funcsToCalls.keySet()) {
Address start = func.getEntryPoint(); Address start = func.getEntryPoint();
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true); ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, true);
SymbolicPropogator symEval = new SymbolicPropogator(program); SymbolicPropogator symEval = new SymbolicPropogator(program);
symEval.flowConstants(start, func.getBody(), eval, true, tMonitor); symEval.flowConstants(start, func.getBody(), eval, true, tMonitor);
for (Address callSite : funcsToCalls.get(func)) { for (Address callSite : funcsToCalls.get(func)) {
@@ -32,6 +32,7 @@ import ghidra.program.model.block.CodeBlock;
import ghidra.program.model.block.CodeBlockReference; import ghidra.program.model.block.CodeBlockReference;
import ghidra.program.model.block.CodeBlockReferenceIterator; import ghidra.program.model.block.CodeBlockReferenceIterator;
import ghidra.program.model.block.SimpleBlockModel; import ghidra.program.model.block.SimpleBlockModel;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -474,7 +475,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
new ContextEvaluatorAdapter() { new ContextEvaluatorAdapter() {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
// go ahead and place the reference, since it is a constant. // go ahead and place the reference, since it is a constant.
if (refType.isComputed() && refType.isFlow() && if (refType.isComputed() && refType.isFlow() &&
program.getMemory().contains(address)) { program.getMemory().contains(address)) {
@@ -38,55 +38,71 @@ import ghidra.util.task.TaskMonitor;
public class ConstantPropagationAnalyzer extends AbstractAnalyzer { public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
private static final String NAME = " Constant Reference Analyzer"; private static final String NAME = " Constant Reference Analyzer";
private static final String DESCRIPTION =
static final String DESCRIPTION =
" Constant Propagation Analyzer for constant references computed with multiple instructions."; " Constant Propagation Analyzer for constant references computed with multiple instructions.";
protected static final String OPTION_NAME = "Function parameter/return Pointer analysis"; protected static final String OPTION_NAME = "Function parameter/return Pointer analysis";
protected static final String OPTION_DESCRIPTION = protected static final String OPTION_DESCRIPTION =
"Turn on to check if values passed as parameters or returned could be pointer references"; "Turn on to check if values passed as parameters or returned could be pointer references";
protected static final boolean OPTION_DEFAULT_VALUE = true; protected static final boolean OPTION_DEFAULT_VALUE = true;
protected static final String POINTER_PARAM_OPTION_NAME = "Require pointer param data type";
protected static final String POINTER_PARAM_OPTION_DESCRIPTION =
"Turn on to require values passed as parameters or returned to be a known pointer data type";
protected static final boolean POINTER_PARAM_OPTION_DEFAULT_VALUE = false;
protected static final String STORED_OPTION_NAME = "Stored Value Pointer analysis"; protected static final String STORED_OPTION_NAME = "Stored Value Pointer analysis";
protected static final String STORED_OPTION_DESCRIPTION = protected static final String STORED_OPTION_DESCRIPTION =
"Turn on to check if values stored into memory or the stack could be pointer references"; "Turn on to check if values stored into memory or the stack could be pointer references";
protected static final boolean STORED_OPTION_DEFAULT_VALUE = true; protected static final boolean STORED_OPTION_DEFAULT_VALUE = true;
protected static final String TRUSTWRITEMEM_OPTION_NAME = protected static final String TRUST_WRITEMEM_OPTION_NAME =
"Trust values read from writable memory"; "Trust values read from writable memory";
protected static final String TRUSTWRITEMEM_OPTION_DESCRIPTION = protected static final String TRUST_WRITEMEM_OPTION_DESCRIPTION =
"Turn on to trust values read from writable memory"; "Turn on to trust values read from writable memory";
protected static final boolean TRUSTWRITEMEM_OPTION_DEFAULT_VALUE = true; protected static final boolean TRUST_WRITEMEM_OPTION_DEFAULT_VALUE = true;
protected static final String MAXTHREADCOUNT_OPTION_NAME = "Max Threads"; protected static final String MAX_THREAD_COUNT_OPTION_NAME = "Max Threads";
protected static final String MAXTHREADCOUNT_OPTION_DESCRIPTION = protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION =
"Maximum threads for constant propagation. Too many threads causes thrashing in DB."; "Maximum threads for constant propagation. Too many threads causes thrashing in DB.";
protected static final int MAXTHREADCOUNT_OPTION_DEFAULT_VALUE = 2; protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2;
protected static final String MINKNOWNREFADDRESS_OPTION_NAME = "Min absolute reference"; protected static final String MIN_KNOWN_REFADDRESS_OPTION_NAME = "Min absolute reference";
protected static final String MINKNOWNREFADDRESS_OPTION_DESCRIPTION = protected static final String MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION =
"Minimum address for calcuated constant store/load references"; "Minimum address for calcuated constant store/load references";
protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4; protected static final int MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE = 4;
protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME = protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_NAME =
"Speculative reference min"; "Speculative reference min";
protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
"Minimum speculative reference address for offsets and parameters"; "Minimum speculative reference address for offsets and parameters";
protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024; protected static final int MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 1024;
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_NAME = protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_NAME =
"Speculative reference max"; "Speculative reference max";
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
"Maxmimum speculative reference address offset from the end of memory for offsets and parameters"; "Prototype - Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
protected static final int MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 256; protected static final int MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 256;
protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME =
"Create Data from pointer";
protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION =
"Create complex data types from pointers if the data type is known, currently from function parameters.";
protected static final boolean CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE = false;
protected final static int NOTIFICATION_INTERVAL = 100; protected final static int NOTIFICATION_INTERVAL = 100;
protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE; protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE;
protected boolean checkPointerParamRefsOption = POINTER_PARAM_OPTION_DEFAULT_VALUE;
protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE; protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE;
protected boolean trustWriteMemOption = TRUSTWRITEMEM_OPTION_DEFAULT_VALUE; protected boolean trustWriteMemOption = TRUST_WRITEMEM_OPTION_DEFAULT_VALUE;
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE; protected boolean createComplexDataFromPointers = CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE;
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE;
protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; protected long minStoreLoadRefAddress = MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE;
protected long minSpeculativeRefAddress = MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE;
protected long maxSpeculativeRefAddress = MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE;
protected boolean followConditional = false; protected boolean followConditional = false;
@@ -105,6 +121,10 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before().before().before().before()); setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before().before().before().before());
} }
public ConstantPropagationAnalyzer(String processorName, AnalyzerType type) {
super(processorName + NAME, processorName + DESCRIPTION, type);
}
/** /**
* Called to to register a more specific analyzer. * Called to to register a more specific analyzer.
* *
@@ -114,13 +134,25 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
handledProcessors.add(processorName); handledProcessors.add(processorName);
} }
/**
* Called to register a more specific analyzer.
*
* @param processorName
*/
static public boolean isClaimedProcessor(String processorName) {
return handledProcessors.contains(processorName);
}
@Override @Override
public boolean canAnalyze(Program program) { public boolean canAnalyze(Program program) {
// Set the default for checking parameter passing // Set the default for checking parameter passing
// don't look for constant passing in things that have a small address space, or is segmented // don't look for constant passing in things that have a small address space, or is segmented
checkParamRefsOption = program.getDefaultPointerSize() > 2; // unless there is a good data type at the location
checkParamRefsOption &= boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace();
!(program.getAddressFactory().getDefaultAddressSpace() instanceof SegmentedAddressSpace); checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard;
checkParamRefsOption = !(program.getAddressFactory()
.getDefaultAddressSpace() instanceof SegmentedAddressSpace);
if (processorName.equals("Basic")) { if (processorName.equals("Basic")) {
if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) { if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) {
@@ -129,8 +161,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
return true; return true;
} }
return program.getLanguage().getProcessor().equals( return program.getLanguage()
Processor.findOrPossiblyCreateProcessor(processorName)); .getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor(processorName));
} }
@Override @Override
@@ -138,7 +171,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
throws CancelledException { throws CancelledException {
AddressSet unanalyzedSet = new AddressSet(set); AddressSet unanalyzedSet = new AddressSet(set);
removeUninitializedBlocks(program, unanalyzedSet); removeUninitializedBlocks(program, unanalyzedSet);
try { try {
@@ -434,6 +467,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
SymbolicPropogator symEval = new SymbolicPropogator(program); SymbolicPropogator symEval = new SymbolicPropogator(program);
symEval.setParamRefCheck(checkParamRefsOption); symEval.setParamRefCheck(checkParamRefsOption);
symEval.setParamPointerRefCheck(checkPointerParamRefsOption);
symEval.setReturnRefCheck(checkParamRefsOption); symEval.setReturnRefCheck(checkParamRefsOption);
symEval.setStoredRefCheck(checkStoredRefsOption); symEval.setStoredRefCheck(checkStoredRefsOption);
@@ -456,8 +492,12 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor) AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
throws CancelledException { throws CancelledException {
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption, ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor)
minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress); .setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor); return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
} }
@@ -515,39 +555,52 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
options.registerOption(OPTION_NAME, checkParamRefsOption, null, OPTION_DESCRIPTION); options.registerOption(OPTION_NAME, checkParamRefsOption, null, OPTION_DESCRIPTION);
options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null, options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null,
STORED_OPTION_DESCRIPTION); STORED_OPTION_DESCRIPTION);
options.registerOption(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption, null, options.registerOption(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption, null,
TRUSTWRITEMEM_OPTION_DESCRIPTION); TRUST_WRITEMEM_OPTION_DESCRIPTION);
options.registerOption(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount, null,
MAXTHREADCOUNT_OPTION_DESCRIPTION);
options.registerOption(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null, options.registerOption(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers, null,
MINKNOWNREFADDRESS_OPTION_DESCRIPTION); CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION);
options.registerOption(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption, null,
POINTER_PARAM_OPTION_DESCRIPTION);
options.registerOption(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount, null,
MAX_THREAD_COUNT_OPTION_DESCRIPTION);
options.registerOption(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null,
MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION);
long size = program.getAddressFactory().getDefaultAddressSpace().getSize(); long size = program.getAddressFactory().getDefaultAddressSpace().getSize();
minSpeculativeRefAddress = size * 16; minSpeculativeRefAddress = size * 16;
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null, options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
maxSpeculativeRefAddress = size * 8; maxSpeculativeRefAddress = size * 8;
options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null, options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
} }
@Override @Override
public void optionsChanged(Options options, Program program) { public void optionsChanged(Options options, Program program) {
checkParamRefsOption = options.getBoolean(OPTION_NAME, checkParamRefsOption); checkParamRefsOption = options.getBoolean(OPTION_NAME, checkParamRefsOption);
checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption);
trustWriteMemOption = options.getBoolean(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption);
maxThreadCount = options.getInt(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount); checkPointerParamRefsOption =
options.getBoolean(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption);
checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption);
trustWriteMemOption = options.getBoolean(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption);
createComplexDataFromPointers = options.getBoolean(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers);
maxThreadCount = options.getInt(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount);
// TODO: there should be a getAddress on option that validates and allows entry of addresses // TODO: there should be a getAddress on option that validates and allows entry of addresses
minStoreLoadRefAddress = minStoreLoadRefAddress =
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress); options.getLong(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
minSpeculativeRefAddress = minSpeculativeRefAddress =
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress); options.getLong(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
maxSpeculativeRefAddress = maxSpeculativeRefAddress =
options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress); options.getLong(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
} }
} }
@@ -15,14 +15,24 @@
*/ */
package ghidra.app.plugin.core.analysis; package ghidra.app.plugin.core.analysis;
import ghidra.app.cmd.function.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.PseudoDisassembler;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBufferImpl;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.program.util.ContextEvaluatorAdapter; import ghidra.program.util.ContextEvaluatorAdapter;
import ghidra.program.util.VarnodeContext; import ghidra.program.util.VarnodeContext;
import ghidra.util.task.TaskMonitor;
/** /**
* The ConstantPropogatorEvaluator is used as the evaluator for the SymbolicPropagator when finding constant * The ConstantPropogatorEvaluator is used as the evaluator for the SymbolicPropagator when finding constant
* references and laying them down for a generic processor. Extend this class to add additional checks * references and laying them down for a generic processor. Extend this class to add additional checks
* and behaviors necessary for a unique processor such as the PowerPC. * and behaviors necessary for a unique processor such as the PowerPC.
@@ -39,31 +49,95 @@ import ghidra.program.util.VarnodeContext;
*/ */
public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter { public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter {
private static final int MAX_UNICODE_STRING_LEN = 200;
private static final int MAX_CHAR_STRING__LEN = 100;
protected AddressSet destSet = new AddressSet(); protected AddressSet destSet = new AddressSet();
private boolean trustMemoryWrite = false; private boolean trustMemoryWrite = false;
private boolean createDataFromPointers = false;
private long minStoreLoadOffset = 4; private long minStoreLoadOffset = 4;
private long minSpeculativeOffset = 1024; // from the beginning of memory private long minSpeculativeOffset = 1024; // from the beginning of memory
private long maxSpeculativeOffset = 256; // from the end of memory private long maxSpeculativeOffset = 256; // from the end of memory
protected TaskMonitor monitor;
private final int NULL_TERMINATOR_PROBE = -1;
public ConstantPropagationContextEvaluator() { public ConstantPropagationContextEvaluator(TaskMonitor monitor) {
this.monitor = monitor;
} }
/** /**
* @param monitor TODO
* @param trustMemoryWrite - true to trust values read from memory that is marked writable * @param trustMemoryWrite - true to trust values read from memory that is marked writable
*/ */
public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) { public ConstantPropagationContextEvaluator(TaskMonitor monitor, boolean trustMemoryWrite) {
this.monitor = monitor;
this.trustMemoryWrite = trustMemoryWrite; this.trustMemoryWrite = trustMemoryWrite;
} }
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption, public ConstantPropagationContextEvaluator(TaskMonitor monitor,
long minStoreLoadRefAddress, long minSpeculativeRefAddress, boolean trustWriteMemOption, long minStoreLoadRefAddress,
long maxSpeculativeRefAddress) { long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
this(trustWriteMemOption); this(monitor, trustWriteMemOption);
this.minStoreLoadOffset = minStoreLoadRefAddress; this.minStoreLoadOffset = minStoreLoadRefAddress;
this.minSpeculativeOffset = minSpeculativeRefAddress; this.minSpeculativeOffset = minSpeculativeRefAddress;
this.maxSpeculativeOffset = maxSpeculativeRefAddress; this.maxSpeculativeOffset = maxSpeculativeRefAddress;
} }
/**
* Set option to trust reads from memory that is marked writeable
*
* @param trustWriteableMemOption true to trust values read from memory that is marked writable
* @return this
*/
public ConstantPropagationContextEvaluator setTrustWritableMemory(boolean trustWriteableMemOption) {
trustMemoryWrite = trustWriteableMemOption;
return this;
}
/**
* Set mimimum speculative memory offset for references
*
* @param minSpeculativeRefAddress minimum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMinpeculativeOffset(long minSpeculativeRefAddress) {
minSpeculativeOffset = minSpeculativeRefAddress;
return this;
}
/**
* Set maximum speculative memory offset for references
*
* @param maxSpeculativeRefAddress maximum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMaxSpeculativeOffset(long maxSpeculativeRefAddress) {
maxSpeculativeOffset = maxSpeculativeRefAddress;
return this;
}
/**
* Set maximum speculative memory offset for references
*
* @param minStoreLoadRefAddress maximum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMinStoreLoadOffset(long minStoreLoadRefAddress) {
maxSpeculativeOffset = minStoreLoadRefAddress;
return this;
}
/**
* Set option to create complex data for pointers if the datatype is known
*
* @param doCreateData true to create complex data types if the data type is known
* @return this
*/
public ConstantPropagationContextEvaluator setCreateComplexDataFromPointers(boolean doCreateData) {
createDataFromPointers = doCreateData;
return this;
}
/** /**
* The computed destination set is useful if follow on switch analysis is to be done. * The computed destination set is useful if follow on switch analysis is to be done.
* *
@@ -79,7 +153,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
*/ */
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) { Address constant, int size, DataType dataType, RefType refType) {
// Constant references below minSpeculative or near the end of the address space are suspect, // Constant references below minSpeculative or near the end of the address space are suspect,
// even if memory exists for those locations. // even if memory exists for those locations.
@@ -107,8 +181,8 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
*/ */
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
// special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally // special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally
// really there should be another callback when adding parameters // really there should be another callback when adding parameters
if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) { if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) {
@@ -137,8 +211,241 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
} }
} }
Program program = instr.getProgram();
AutoAnalysisManager aMgr= AutoAnalysisManager.getAnalysisManager(program);
// if data reference, handle data
if (refType.isData()) {
createPointedToData(aMgr, program, address, refType, dataType, size);
}
// if flowing to an address, disassemble it
if (refType.isFlow() && !refType.isIndirect() &&
!program.getMemory().isExternalBlockAddress(address)) {
Data udata = program.getListing().getUndefinedDataAt(address);
if (udata != null) {
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(program, monitor);
}
//
// TODO: need to kick analysis if the target is a function and non-returning
// Function functionAt = program.getFunctionManager().getFunctionAt(address);
// if (functionAt != null && functionAt.hasNoReturn()) {
// aMgr.functionModifierChanged(address);
// }
}
return true; return true;
} }
private int createPointedToData(AutoAnalysisManager aMgr, Program program, Address address, RefType refType, DataType dataType, int size) {
// don't do in external memory
if (program.getMemory().isExternalBlockAddress(address) || address.isExternalAddress()) {
return 0;
}
// don't create if not in real memory
if (!program.getMemory().contains(address)) {
return 0;
}
// Get the data type that is pointed to, strip off pointer, or pointer typedef
DataType pointedToDT = null;
if (dataType instanceof Pointer ptr) {
pointedToDT = ptr.getDataType();
}
else if ((dataType instanceof TypeDef typeDef && typeDef.getBaseDataType() instanceof Pointer ptr)) {
pointedToDT = ptr.getDataType();
}
// if this is a function pointer, create the code/function/signature
if (pointedToDT instanceof FunctionDefinition funcDefn) {
createFunctionApplySignature(aMgr, program, address, funcDefn);
return dataType.getLength();
}
// otherwise it is data
if (dataType != null) {
// System.out.println("@ " + address + " Data Type - " + dataType);
}
return createData(program, address, pointedToDT, size);
}
/**
* Create Data at an address in the program
*
* @param program the program
* @param address location to create data
* @param dataType dataType if known
* @param size size of the data type (from a read/write)
* @return size of the data item created, or 0 if none created
*/
private int createData(Program program, Address address, DataType dataType, int size) {
// defined data (that isn't an undefined) don't do anything
Data data = program.getListing().getDataAt(address);
if (data == null || !Undefined.isUndefined(data.getDataType())) {
return 0;
}
// get a default undefined data type of the right size for the access
DataType dt = Undefined.getUndefinedDataType(size);
int maxLen = -1;
if (createDataFromPointers && dataType != null) {
DataType originalDT = dataType;
// if typedef, get the base type
if (dataType instanceof TypeDef typeDef) {
dataType = typeDef.getBaseDataType();
}
if (dataType instanceof CharDataType) {
// Use Terminated in case strings are referenced offcut
maxLen = getRestrictedStringLen(program, address, TerminatedStringDataType.dataType, MAX_CHAR_STRING__LEN);
if (maxLen > 0) {
dt = TerminatedStringDataType.dataType;
}
} else if (dataType instanceof WideCharDataType) {
maxLen = getRestrictedStringLen(program, address, TerminatedUnicodeDataType.dataType, MAX_UNICODE_STRING_LEN);
if (maxLen > 0) {
dt = TerminatedUnicodeDataType.dataType;
}
} else if (dataType instanceof Composite comp) {
// create empty structures, they can get filled out later
// if they don't fit later because they grow, then there will be an error at the location
dt = originalDT; // original might have been a typedef, use original
} else if (dataType instanceof VoidDataType) {
// ptr to void should be ignored
return 0;
} else if (dataType instanceof AbstractFloatDataType) {
dt = dataType;
} else {
// don't do any other types other than above for now
return 0;
}
} else if (size < 1 || size > 8) {
return 0;
}
try {
// create data at the location so that we record the access size
// the data is undefined, and SHOULD be overwritten if something
// else knows better about the location.
if (maxLen > 0) {
data = DataUtilities.createData(program, address, dt, maxLen,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
} else {
data = DataUtilities.createData(program, address, dt, -1,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
}
return data.getLength();
}
catch (CodeUnitInsertionException e) {
// couldn't create data
}
return 0;
}
/**
* Create a function/code at a location and apply the
*
* @param aMgr auto analysis manager
* @param program the program
* @param address location to create function
* @param funcDefn function definition if known
*/
private void createFunctionApplySignature(AutoAnalysisManager aMgr, Program program,
Address address, FunctionDefinition funcDefn) {
// System.out.println("@ " + address + " - Typedef Function " + ((FunctionDefinition)ptrToDT).getPrototypeString());
Listing listing = program.getListing();
// defined data (that isn't an undefined) don't do anything
Data data = listing.getDefinedDataContaining(address);
if (data != null) {
return;
}
// if memory is undefined bytes, don't disassemble or create function
MemoryBlock block = program.getMemory().getBlock(address);
if (block == null || !block.isInitialized()) {
return;
}
// normalize the address to where code should start (ARM and MIPS can be offset by one)
Address normalizedAddr = PseudoDisassembler.getNormalizedDisassemblyAddress(program, address);
if (!listing.isUndefined(normalizedAddr, normalizedAddr)) {
// if not undefined, must be an instruction to continue
Instruction instr = listing.getInstructionAt(normalizedAddr);
if (instr == null) {
return;
}
} else {
// if nothing defined here, disassemble
address = PseudoDisassembler.setTargeContextForDisassembly(program, address);
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(program, monitor);
}
// see if there is an existing function
FunctionManager funcMgr = program.getFunctionManager();
Function func = funcMgr.getFunctionAt(address);
// if no function at the address, make sure not in the middle of a function
if (func == null) {
func = funcMgr.getFunctionContaining(address);
// don't create a function in the middle of another
if (func != null) {
return;
}
}
if (func != null) {
if (func.isThunk()) {
return;
}
SourceType mostTrusted = getMostTrustedParameterSource(func);
if (SourceType.ANALYSIS.isLowerPriorityThan(mostTrusted)) {
return;
}
} else {
CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(address, false);
aMgr.schedule(createFunctionCmd, AnalysisPriority.FUNCTION_ANALYSIS.priority());
}
// only apply the signature if actually creating data, the function/code has already been created
if (!createDataFromPointers) {
return;
}
// if no arguments, could be an opaque function pointer, don't apply arguments
ParameterDefinition[] arguments = funcDefn.getArguments();
DataType returnType = funcDefn.getReturnType();
if (arguments == null || (arguments.length == 0 && (returnType==null || Undefined.isUndefined(returnType)))) {
return;
}
// applying function signatures considered data
// don't change name, even default name
ApplyFunctionSignatureCmd applyFunctionSignatureCmd = new ApplyFunctionSignatureCmd(address, funcDefn, SourceType.ANALYSIS, true, FunctionRenameOption.NO_CHANGE);
aMgr.schedule(applyFunctionSignatureCmd, AnalysisPriority.FUNCTION_ANALYSIS.after().priority());
}
private SourceType getMostTrustedParameterSource(Function func) {
SourceType highestSource = func.getSignatureSource();
Parameter[] parameters = func.getParameters();
for (Parameter parameter : parameters) {
SourceType paramSource = parameter.getSource();
if (paramSource.isHigherPriorityThan(highestSource)) {
highestSource = paramSource;
}
}
return highestSource;
}
/** /**
* Add instructions to destination set for unknown computed branches. * Add instructions to destination set for unknown computed branches.
@@ -168,4 +475,60 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
public boolean allowAccess(VarnodeContext context, Address addr) { public boolean allowAccess(VarnodeContext context, Address addr) {
return trustMemoryWrite; return trustMemoryWrite;
} }
/**
* Looks at bytes at given address and converts to format String
*
* @param address Address of format String
* @param pointer Pointer "type" of string
* @return format String
*/
int getRestrictedStringLen(Program program, Address address, AbstractStringDataType dataType, int maxLength) {
maxLength = getMaxStringLength(program, address, maxLength);
MemoryBufferImpl memoryBuffer =
new MemoryBufferImpl(program.getMemory(), address);
StringDataInstance stringDataInstance = dataType.getStringDataInstance(memoryBuffer, dataType.getDefaultSettings(), -1);
stringDataInstance.getStringDataTypeGuess();
int detectedLength = stringDataInstance.getStringLength();
if (detectedLength == -1) {
return 0;
}
if (detectedLength > maxLength) {
detectedLength = maxLength;
}
return detectedLength;
}
/**
* Get the number of bytes to the next reference, or the max length
*
* @param program
* @param address
* @return maximum length to create the string
*/
private int getMaxStringLength(Program program, Address address, int maxLen) {
AddressIterator refIter = program.getReferenceManager().getReferenceDestinationIterator(address.next(), true);
Address next = refIter.next();
if (next == null) {
return -1;
}
long len = -1;
try {
len = next.subtract(address);
if (len > maxLen) {
len = maxLen;
}
return (int) len;
} catch (IllegalArgumentException exc) {
// bad address subtraction
}
return (int) len;
}
} }
@@ -36,6 +36,7 @@ import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler; import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -144,7 +145,17 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
pointerEnabled = false; pointerEnabled = false;
addressTablesEnabled = false; addressTablesEnabled = false;
} }
boolean isArm = program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor("ARM"));
// if arm, turn off reference to pointer analysis
if (isArm) {
pointerEnabled = false;
addressTablesEnabled = false;
}
// only analyze programs with address spaces > 16 bits // only analyze programs with address spaces > 16 bits
int bitSize = defaultAddressSpace.getSize(); int bitSize = defaultAddressSpace.getSize();
return bitSize > 16; return bitSize > 16;
@@ -16,6 +16,7 @@
package ghidra.program.util; package ghidra.program.util;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
@@ -56,12 +57,13 @@ public interface ContextEvaluator {
* @param pcodeop the PcodeOp operation that is causing this reference * @param pcodeop the PcodeOp operation that is causing this reference
* @param address address being referenced * @param address address being referenced
* @param size size of the item being referenced (only non-zero if load or store of data) * @param size size of the item being referenced (only non-zero if load or store of data)
* @param dataType dataType associated with the reference if known
* @param refType reference type (flow, data/read/write) * @param refType reference type (flow, data/read/write)
* *
* @return false if the reference should be ignored (or has been taken care of by this routine) * @return false if the reference should be ignored (or has been taken care of by this routine)
*/ */
boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, int size, boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, int size,
RefType refType); DataType dataType, RefType refType);
/** /**
* Evaluate a potential constant to be used as an address or an interesting constant that * Evaluate a potential constant to be used as an address or an interesting constant that
@@ -73,6 +75,7 @@ public interface ContextEvaluator {
* @param pcodeop the PcodeOp operation that is causing this potential constant * @param pcodeop the PcodeOp operation that is causing this potential constant
* @param constant constant value (in constant.getOffset() ) * @param constant constant value (in constant.getOffset() )
* @param size size of constant value in bytes * @param size size of constant value in bytes
* @param dataType dataType associated with the reference if known
* @param refType reference type (flow, data/read/write) * @param refType reference type (flow, data/read/write)
* *
* @return the original address unchanged if it should be a reference * @return the original address unchanged if it should be a reference
@@ -80,7 +83,8 @@ public interface ContextEvaluator {
* a new address if the value should be a different address or address space * a new address if the value should be a different address or address space
* Using something like instr.getProgram().getAddressFactory().getDefaultAddressSpace(); * Using something like instr.getProgram().getAddressFactory().getDefaultAddressSpace();
*/ */
Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, Address constant, int size, RefType refType); Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, Address constant, int size,
DataType dataType, RefType refType);
/** /**
* Evaluate the instruction for an unknown destination * Evaluate the instruction for an unknown destination
@@ -16,6 +16,7 @@
package ghidra.program.util; package ghidra.program.util;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
@@ -40,13 +41,13 @@ public class ContextEvaluatorAdapter implements ContextEvaluator {
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) { Address constant, int size, DataType dataType, RefType refType) {
return null; return null;
} }
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
int size, RefType refType) { int size, DataType dataType, RefType refType) {
return false; return false;
} }
File diff suppressed because it is too large Load Diff
@@ -19,11 +19,12 @@ import java.math.BigInteger;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang3.ArrayUtils;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
@@ -38,8 +39,6 @@ import ghidra.util.exception.*;
public class VarnodeContext implements ProcessorContext { public class VarnodeContext implements ProcessorContext {
public static final int BAD_SPACE_ID_VALUE = 0xffff;
protected DisassemblerContextImpl offsetContext; protected DisassemblerContextImpl offsetContext;
protected DisassemblerContextImpl spaceContext; protected DisassemblerContextImpl spaceContext;
@@ -63,6 +62,10 @@ public class VarnodeContext implements ProcessorContext {
protected VarnodeTranslator trans; // translator for varnodes<-->registers protected VarnodeTranslator trans; // translator for varnodes<-->registers
protected Varnode[] retVarnodes = null; // varnodes used to return values protected Varnode[] retVarnodes = null; // varnodes used to return values
protected Varnode[] killedVarnodes = null; // varnodes killed by default calling convention
protected Varnode stackVarnode = null; // varnode that represents the stack protected Varnode stackVarnode = null; // varnode that represents the stack
protected Register stackReg = null; protected Register stackReg = null;
private HashSet<String> validSymbolicStackNames = new HashSet<>(); // list of stack related register names private HashSet<String> validSymbolicStackNames = new HashSet<>(); // list of stack related register names
@@ -72,6 +75,13 @@ public class VarnodeContext implements ProcessorContext {
public final Address BAD_ADDRESS; public final Address BAD_ADDRESS;
private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value; private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value;
private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values
public final Address SUSPECT_ZERO_ADDRESS;
public final int BAD_SPACE_ID_VALUE;
private static final BigInteger BIG_NEGATIVE_ONE = BigInteger.ONE.negate();
protected boolean hitDest = false; protected boolean hitDest = false;
@@ -92,8 +102,15 @@ public class VarnodeContext implements ProcessorContext {
this.addrFactory = new OffsetAddressFactory(program); this.addrFactory = new OffsetAddressFactory(program);
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0); BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
BAD_SPACE_ID_VALUE = BAD_ADDRESS.getAddressSpace().getSpaceID();
BAD_OFFSET_SPACEID = getAddressSpace("(Bad Address Offset)"); BAD_OFFSET_SPACEID = getAddressSpace("(Bad Address Offset)");
/* Suspect constants act like constants, but are in a SuspectConst
* address space instead of the constant space.
*/
SUSPECT_ZERO_ADDRESS = addrFactory.getAddress(getAddressSpace("SuspectConst"), 0);
SUSPECT_OFFSET_SPACEID = SUSPECT_ZERO_ADDRESS.getAddressSpace().getSpaceID();
this.programContext = programContext; this.programContext = programContext;
@@ -293,6 +310,48 @@ public class VarnodeContext implements ProcessorContext {
} }
return retVarnodes; return retVarnodes;
} }
/**
*
* @param targetFunc function to get killed varnodes for
*
* NOTE: this removes the return varnodes so they aren't duplicated
*
* @return varnode that represents where functions place their return value
*/
public Varnode[] getKilledVarnodes(Function targetFunc) {
// TODO: This doesn't handle full bonded yet!
PrototypeModel defaultCallingConvention =
program.getCompilerSpec().getDefaultCallingConvention();
if (targetFunc != null) {
// TODO handle custom calling convention killed by call when supported
PrototypeModel callingConvention = targetFunc.getCallingConvention();
if (callingConvention != null) {
return callingConvention.getKilledByCallList();
}
}
// no function, so get the default convention and use that.
if (killedVarnodes != null) {
return killedVarnodes;
}
killedVarnodes = defaultCallingConvention.getKilledByCallList();
// clean return varnodes out of list
Varnode[] returnVarnodes = getReturnVarnode(null);
ArrayList<Varnode> list = new ArrayList<Varnode>();
for (Varnode varnode : killedVarnodes) {
if (!ArrayUtils.contains(returnVarnodes, varnode)) {
list.add(varnode);
}
}
killedVarnodes = list.toArray(new Varnode[list.size()]);
return killedVarnodes;
}
/** /**
* *
@@ -356,7 +415,7 @@ public class VarnodeContext implements ProcessorContext {
public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator) public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator)
throws NotFoundException { throws NotFoundException {
// for constant, return the constant value // for constant, return the constant value
if (varnode.isConstant()) { if (isConstant(varnode)) {
return varnode; return varnode;
} }
Varnode rvnode = null; Varnode rvnode = null;
@@ -383,21 +442,26 @@ public class VarnodeContext implements ProcessorContext {
if (bigVal != null) { if (bigVal != null) {
BigInteger spaceVal = getTranslatedSpaceValue(reg); BigInteger spaceVal = getTranslatedSpaceValue(reg);
// -1 and zero constants pulled from a register are suspect
if (spaceVal == null && (bigVal.equals(BIG_NEGATIVE_ONE) || bigVal.equals(BigInteger.ZERO))) {
spaceVal = BigInteger.valueOf(SUSPECT_OFFSET_SPACEID);
}
rvnode = createVarnode(bigVal, spaceVal, varnode.getSize()); rvnode = createVarnode(bigVal, spaceVal, varnode.getSize());
if (rvnode == null) { if (rvnode == null) {
throw notFoundExc; throw notFoundExc;
} }
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
if (debug) { if (debug) {
Msg.info(this, " " + reg.getName() + " = " + print(rvnode)); Msg.info(this, " " + reg.getName() + " = " + print(rvnode));
} }
// value is bad, just return original, someone else will deal with it
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
return rvnode;
} }
return rvnode;
} }
} }
// TODO: should this return a new space at offset 0?
return varnode; // just return the register then, someone else will deal with it... return varnode; // just return the register then, someone else will deal with it...
} }
@@ -418,12 +482,6 @@ public class VarnodeContext implements ProcessorContext {
if (debug) { if (debug) {
Msg.info(this, " " + varnode + " = " + print(lvalue)); Msg.info(this, " " + varnode + " = " + print(lvalue));
} }
if (isSymbolicSpace(lvalue.getSpace())) {
if (debug) {
Msg.info(this, " out " + varnode + " = " + print(lvalue));
}
throw notFoundExc;
}
// if this is an offset reference, ONLY allow it to be offset into the stack, no other register offset. // if this is an offset reference, ONLY allow it to be offset into the stack, no other register offset.
// can't count on the offset staying the same. // can't count on the offset staying the same.
if (isSymbolicAddr) { if (isSymbolicAddr) {
@@ -431,15 +489,9 @@ public class VarnodeContext implements ProcessorContext {
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace()); AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
// figure out what register is used for stack values // figure out what register is used for stack values
Register stackRegister = getStackRegister(); Register stackRegister = getStackRegister();
if (!isStackSymbolicSpace(varnode)) {
if (debug) { // don't allow a zero/-1 constant pulled from a symbolic space.
Msg.info(this, if (isConstant(lvalue) && (lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) {
"Don't Trust value from " + varnode + " = " + print(lvalue));
}
throw notFoundExc;
}
// don't allow a zero constant pulled from a symbolic space.
if (lvalue.isConstant() && lvalue.getOffset() == 0) {
throw notFoundExc; throw notFoundExc;
} }
} }
@@ -520,7 +572,8 @@ public class VarnodeContext implements ProcessorContext {
value = (value << 8 * (8 - size)) >> 8 * (8 - size); value = (value << 8 * (8 - size)) >> 8 * (8 - size);
} }
return createConstantVarnode(value, size); // constants pulled from memory are always suspect
return createVarnode(value, SUSPECT_OFFSET_SPACEID, size);
} }
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
@@ -642,9 +695,11 @@ public class VarnodeContext implements ProcessorContext {
AddressSpace spc = addrFactory.getAddressSpace(spaceID); AddressSpace spc = addrFactory.getAddressSpace(spaceID);
Address addr = null; Address addr = null;
if (spaceID == BAD_SPACE_ID_VALUE || spc == null || if (spaceID == BAD_SPACE_ID_VALUE || spc == null) {
spc.equals(BAD_ADDRESS.getAddressSpace())) {
addr = BAD_ADDRESS; addr = BAD_ADDRESS;
} else if (spaceID == BAD_OFFSET_SPACEID) {
// special case of unknown value + constant
addr = spc.getTruncatedAddress(value, true);
} }
else { else {
addr = spc.getTruncatedAddress(value, true); addr = spc.getTruncatedAddress(value, true);
@@ -700,10 +755,16 @@ public class VarnodeContext implements ProcessorContext {
// put the location on both the lastSet, and all locations set // put the location on both the lastSet, and all locations set
addSetVarnodeToLastSetLocations(out, location); addSetVarnodeToLastSetLocations(out, location);
// don't put a value into a bad address space
// could get values pulled from a different badd address offset
if (isSymbolicAddr && out.getAddress().getAddressSpace().getSpaceID() == BAD_OFFSET_SPACEID) {
return;
}
putMemoryValue(out, result); putMemoryValue(out, result);
return; return;
} }
} }
// don't ever store an unknown unique into a location // don't ever store an unknown unique into a location
if (result != null && result.isUnique()) { if (result != null && result.isUnique()) {
result = null; result = null;
@@ -715,6 +776,20 @@ public class VarnodeContext implements ProcessorContext {
tempUniqueVals.put(out.getOffset(), result); tempUniqueVals.put(out.getOffset(), result);
} }
else { else {
// if storing a bad address, need to create a new register/address
// relative symbolic space
if (result != null && result.getAddress()==BAD_ADDRESS) {
String spaceName = out.getAddress().getAddressSpace().getName();
Register register = getRegister(out);
if (register == null) {
spaceName = out.toString();
} else {
spaceName = register.getName();
}
int newRegSpaceID = getAddressSpace(spaceName+"-"+currentAddress);
result = createVarnode(0, newRegSpaceID, out.getSize());
}
tempVals.put(out, result); tempVals.put(out, result);
} }
@@ -907,7 +982,7 @@ public class VarnodeContext implements ProcessorContext {
} }
public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException { public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException {
if (!vnode.isConstant()) { if (!isConstant(vnode)) {
if (evaluator == null) { if (evaluator == null) {
throw notFoundExc; throw notFoundExc;
} }
@@ -940,6 +1015,12 @@ public class VarnodeContext implements ProcessorContext {
valbase = offset.getOffset(); valbase = offset.getOffset();
spaceID = (int) space.getOffset(); spaceID = (int) space.getOffset();
} }
else if (isSuspectConstant(offset)) {
// constant suspicious don't let if fall into symbolic
// handle same as normal constant but keep suspicious space
valbase = offset.getOffset();
spaceID = (int) space.getOffset();
}
else if (OffsetAddressFactory.isSymbolSpace(spaceID)) { else if (OffsetAddressFactory.isSymbolSpace(spaceID)) {
if (evaluator == null) { if (evaluator == null) {
throw notFoundExc; throw notFoundExc;
@@ -1037,7 +1118,10 @@ public class VarnodeContext implements ProcessorContext {
} }
BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr); BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr);
if (spaceVal != null) { if (spaceVal != null) {
if (addrFactory.getConstantSpace().getSpaceID() != spaceVal.intValue()) { int spaceID = spaceVal.intValue();
// check normal constant and suspect constants
if (spaceID != addrFactory.getConstantSpace().getSpaceID() &&
spaceID != SUSPECT_OFFSET_SPACEID) {
return null; return null;
} }
} }
@@ -1054,7 +1138,7 @@ public class VarnodeContext implements ProcessorContext {
/** /**
* Copy the varnode with as little manipulation as possible. * Copy the varnode with as little manipulation as possible.
* Try to keep whatever partical state there is intact if a real value isn't required. * Try to keep whatever partial state there is intact if a real value isn't required.
* *
* @param out varnode to put it in * @param out varnode to put it in
* @param in varnode to copy from. * @param in varnode to copy from.
@@ -1067,8 +1151,10 @@ public class VarnodeContext implements ProcessorContext {
Varnode val1 = null; Varnode val1 = null;
val1 = getValue(in, evaluator); val1 = getValue(in, evaluator);
// if truncating a constant get a new constant of the proper size // if truncating a constant get a new constant of the proper size
if (val1 != null && val1.isConstant() && in.getSize() > out.getSize()) { if (val1 != null && in.getSize() > out.getSize()) {
val1 = createConstantVarnode(val1.getOffset(), out.getSize()); if (isConstant(val1)) {
val1 = createVarnode(val1.getOffset(), val1.getSpace(), out.getSize());
}
} }
if (!in.isRegister() || !out.isRegister()) { if (!in.isRegister() || !out.isRegister()) {
@@ -1097,7 +1183,7 @@ public class VarnodeContext implements ProcessorContext {
throws NotFoundException { throws NotFoundException {
// try to make the constant value the addend. // try to make the constant value the addend.
if (val1.isConstant() || val1.isAddress()) { if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1; Varnode swap = val1;
val1 = val2; val1 = val2;
val2 = swap; val2 = swap;
@@ -1142,8 +1228,11 @@ public class VarnodeContext implements ProcessorContext {
} }
} }
} }
else if (val1.isConstant()) { else if (isConstant(val1)) {
valbase = val1.getOffset(); valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
} }
else if (isSymbolicSpace(spaceID)) { else if (isSymbolicSpace(spaceID)) {
Instruction instr = getCurrentInstruction(offsetContext.getAddress()); Instruction instr = getCurrentInstruction(offsetContext.getAddress());
@@ -1181,7 +1270,6 @@ public class VarnodeContext implements ProcessorContext {
} }
} }
} }
else { else {
throw notFoundExc; throw notFoundExc;
@@ -1199,7 +1287,7 @@ public class VarnodeContext implements ProcessorContext {
if (val1.equals(val2)) { if (val1.equals(val2)) {
return val1; return val1;
} }
if (val1.isConstant() || val1.isAddress()) { if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1; Varnode swap = val1;
val1 = val2; val1 = val2;
val2 = swap; val2 = swap;
@@ -1216,6 +1304,9 @@ public class VarnodeContext implements ProcessorContext {
} }
else if (val1.isConstant()) { else if (val1.isConstant()) {
valbase = val1.getOffset(); valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
} }
else if (isSymbolicSpace(spaceID)) { else if (isSymbolicSpace(spaceID)) {
valbase = val1.getOffset(); valbase = val1.getOffset();
@@ -1244,25 +1335,29 @@ public class VarnodeContext implements ProcessorContext {
return val1; return val1;
} }
if (val1.isConstant() || val1.isAddress()) { if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1; Varnode swap = val1;
val1 = val2; val1 = val2;
val2 = swap; val2 = swap;
} }
int spaceID = val1.getSpace();
long val2Const = getConstant(val2, null); long val2Const = getConstant(val2, null);
// got a constant from val2, (value | 0) == value, so just return value // got a constant from val2, (value | 0) == value, so just return value
if (val2Const == 0) { if (val2Const == 0) {
return val1; if (!isSuspectConstant(val2)) {
return val1;
}
spaceID = val2.getSpace();
} }
long lresult = getConstant(val1, evaluator) | val2Const; long lresult = getConstant(val1, evaluator) | val2Const;
return createConstantVarnode(lresult, val1.getSize()); return createVarnode(lresult, spaceID, val1.getSize());
} }
public Varnode left(Varnode val1, Varnode val2, ContextEvaluator evaluator) public Varnode left(Varnode val1, Varnode val2, ContextEvaluator evaluator)
throws NotFoundException { throws NotFoundException {
long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator); long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator);
lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8)); lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
Varnode result = createConstantVarnode(lresult, val1.getSize()); Varnode result = createVarnode(lresult, val1.getSpace(), val1.getSize());
return result; return result;
} }
@@ -1306,8 +1401,11 @@ public class VarnodeContext implements ProcessorContext {
} }
int spaceID = val1.getSpace(); int spaceID = val1.getSpace();
long valbase = 0; long valbase = 0;
if (val1.isConstant()) { if (isConstant(val1)) {
valbase = val1.getOffset(); valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
} }
else if (isRegister(val1)) { else if (isRegister(val1)) {
Register reg = trans.getRegister(val1); Register reg = trans.getRegister(val1);
@@ -1329,7 +1427,6 @@ public class VarnodeContext implements ProcessorContext {
return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator); return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);
} }
} }
} }
else { else {
throw notFoundExc; throw notFoundExc;
@@ -1353,15 +1450,15 @@ public class VarnodeContext implements ProcessorContext {
vnodeVal = getValue(in[0], signExtend, evaluator); vnodeVal = getValue(in[0], signExtend, evaluator);
if (vnodeVal.isConstant() && in[0].getSize() < out.getSize()) { if (isConstant(vnodeVal) && in[0].getSize() < out.getSize()) {
// TODO: Is there a better way to do this - it was not sign-extending temp values before // TODO: Is there a better way to do this - it was not sign-extending temp values before
if (vnodeVal.getSize() <= 8) { if (vnodeVal.getSize() <= 8) {
Scalar sVal = new Scalar(8 * vnodeVal.getSize(), vnodeVal.getOffset(), signExtend); Scalar sVal = new Scalar(8 * vnodeVal.getSize(), vnodeVal.getOffset(), signExtend);
vnodeVal = createConstantVarnode(sVal.getValue(), out.getSize()); vnodeVal = createVarnode(sVal.getValue(), vnodeVal.getSpace(), out.getSize());
} }
else { else {
// too big anyway,already extended as far as it will go. // too big anyway,already extended as far as it will go.
vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize()); vnodeVal = createVarnode(vnodeVal.getOffset(), vnodeVal.getSpace(), out.getSize());
} }
} }
else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) { else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) {
@@ -1414,7 +1511,7 @@ public class VarnodeContext implements ProcessorContext {
Varnode regVnode = trans.getVarnode(register); Varnode regVnode = trans.getVarnode(register);
try { try {
Varnode value = this.getValue(regVnode, false, null); Varnode value = this.getValue(regVnode, false, null);
if (value.isConstant()) { if (isConstant(value)) {
return new RegisterValue(register, BigInteger.valueOf(value.getOffset())); return new RegisterValue(register, BigInteger.valueOf(value.getOffset()));
} }
} }
@@ -1457,7 +1554,7 @@ public class VarnodeContext implements ProcessorContext {
Varnode regVnode = trans.getVarnode(register); Varnode regVnode = trans.getVarnode(register);
try { try {
Varnode value = this.getValue(regVnode, signed, null); Varnode value = this.getValue(regVnode, signed, null);
if (value.isConstant()) { if (isConstant(value)) {
return BigInteger.valueOf(value.getOffset()); return BigInteger.valueOf(value.getOffset());
} }
} }
@@ -1503,7 +1600,33 @@ public class VarnodeContext implements ProcessorContext {
public boolean isRegister(Varnode varnode) { public boolean isRegister(Varnode varnode) {
return varnode.isRegister() || trans.getRegister(varnode) != null; return varnode.isRegister() || trans.getRegister(varnode) != null;
} }
/**
* Check if this is a constant, or a suspect constant
*
* @param varnode to check
* @return true if should be treated as a constant for most purposes
*/
public boolean isConstant(Varnode varnode) {
if (varnode.isConstant()) {
return true;
}
return isSuspectConstant(varnode);
}
/**
* Check if the constant is a suspect constant
* It shouldn't be trusted in certain cases.
* Suspect constants act like constants, but are in a Suspicious
* address space instead of the constant space.
*
* @param val1 varnode to check
* @return true if varnode is a suspect constant
*/
public boolean isSuspectConstant(Varnode val1) {
return val1.getSpace() == SUSPECT_OFFSET_SPACEID;
}
/** /**
* Check if varnode is in the stack space * Check if varnode is in the stack space
* *
@@ -98,18 +98,11 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS); builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS);
builder.setBytes("0x1000", "3c 1c 00 14 27 9c b3 34 03 99 e0 21 27 bd ff e0" + builder.setBytes("0x1000", "3c 1c 00 14 27 9c b3 34 03 99 e0 21 27 bd ff e0" +
"af bc 00 10 3c 07 12 34 24 e7 45 67" + "af bc 00 10 3c 07 12 34 24 e7 45 67 ac a7 00 10" +
"ac a7 00 10 3c 06 0a 0b 24 c6 0c 0d" + "3c 06 0a 0b 24 c6 0c 0d ae 06 00 10 8e 11 00 10" +
"ae 06 00 10 8e 11 00 10 8c b1 00 10" + "8c b1 00 10 8f b1 00 10 8e 51 00 10 ae 53 00 10" +
"8f b1 00 10 8e 51 00 10 ae 53 00 10" + "8e 51 00 10 36 92 00 00 8e 51 00 10 8e 92 00 10" +
"8e 51 00 10" + "3c 11 00 53 8e 51 00 10 03 e0 00 08 27 bd 00 20");
"36 92 00 00" +
"8e 51 00 10" +
"8e 92 00 10" +
"3c 11 00 53" +
"8e 51 00 10" +
"03 e0 00 08" +
"27 bd 00 20");
//00001000 lui gp,0x14 //00001000 lui gp,0x14
//00001004 addiu gp,gp,-0x4ccc //00001004 addiu gp,gp,-0x4ccc
@@ -153,7 +146,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true) { ContextEvaluator eval = new ConstantPropagationContextEvaluator(TaskMonitor.DUMMY, true) {
@Override @Override
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) { public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
@@ -176,8 +169,92 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
registerVarnode = regValue(context,"gp"); registerVarnode = regValue(context,"gp");
assertTrue("symbolic value", context.isSymbol(registerVarnode)); assertTrue("symbolic value", context.isSymbol(registerVarnode));
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
// S3 should be S3 at entry
registerVarnode = regValue(context,"s3");
assertTrue("register s3", context.isRegister(registerVarnode));
assertEquals("s3", context.getRegister(registerVarnode).getName());
break;
case "0000102c":
// s1 restored from space 0x10(s0) space
registerVarnode = regValue(context,"s1");
assertTrue("constant value", registerVarnode.isConstant());
assertEquals("(const, 0xa0b0c0d, 4)", registerVarnode.toString());
break;
case "00001030":
// s1 restored from space 0x10(a1) space
registerVarnode = regValue(context,"s1");
assertTrue("symbolic value", registerVarnode.isConstant());
assertEquals("(const, 0x12344567, 4)", registerVarnode.toString());
break;
case "00001034":
// s1 restored from space 0x10(sp) space
registerVarnode = regValue(context,"s1");
assertTrue("symbolic value", context.isSymbol(registerVarnode));
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
break;
case "00001038":
// s1 restored from space 0x10(s2) space
registerVarnode = regValue(context,"s1");
//assertTrue("Still s1", registerVarnode.isRegister());
boolean isBad = false;
try {
context.getConstant(registerVarnode, null);
} catch (NotFoundException e) {
isBad = true;
}
assertTrue("Can get constant value", isBad);
break;
case "00001040":
// s1 restored from space 0x10(s2) space - stored a3
registerVarnode = regValue(context,"s1");
assertTrue("register s3", registerVarnode.isRegister());
assertEquals("s3", context.getRegister(registerVarnode).getName());
Address lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
assertEquals("s2 last set", null, lastSetLocation);
break;
case "00001048":
// s1 restored from space 0x10(s2) after s2 has been set again
// it should no longer be s3 that was stored in another s2 relative space
registerVarnode = regValue(context,"s1");
//assertTrue("Still s1", registerVarnode.isRegister());
isBad = false;
try {
context.getConstant(registerVarnode, null);
} catch (NotFoundException e) {
isBad = true;
}
assertTrue("Can get constant value", isBad);
break;
case "0000104c":
// s1 restored from space 0x10(s2) after s2 has been set again
// it should no longer be s3 that was stored in another s2 relative space
registerVarnode = regValue(context,"s2");
//assertTrue("Still s2", registerVarnode.isRegister());
isBad = false;
try {
context.getConstant(registerVarnode, null);
} catch (NotFoundException e) {
isBad = true;
}
assertTrue("Can get constant value", isBad);
lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
assertEquals("s2 last set", 0x104fL, lastSetLocation.getOffset());
break;
case "00001054":
// s1 restored from space 0x10(s2) after s2 has been set again
// it should no longer be s3 that was stored in another s2 relative space
registerVarnode = regValue(context,"s1");
//assertTrue("Still s1", registerVarnode.isRegister());
//assertEquals(context.getRegister(registerVarnode).getName(),"s1");
isBad = false;
try {
context.getConstant(registerVarnode, null);
} catch (NotFoundException e) {
isBad = true;
}
assertTrue("Can get constant value", isBad);
break; break;
// TODO: more tests
} }
return super.evaluateContext(context, instr); return super.evaluateContext(context, instr);
} }
@@ -31,6 +31,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.block.*; import ghidra.program.model.block.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@@ -364,7 +365,7 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
new ContextEvaluatorAdapter() { new ContextEvaluatorAdapter() {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
// go ahead and place the reference, since it is a constant. // go ahead and place the reference, since it is a constant.
if (refType.isComputed() && refType.isFlow() && if (refType.isComputed() && refType.isFlow() &&
program.getMemory().contains(address)) { program.getMemory().contains(address)) {
@@ -21,9 +21,8 @@ import ghidra.program.model.address.Address;
import ghidra.util.GhidraDataConverter; import ghidra.util.GhidraDataConverter;
/** /**
* Simple byte buffer implementation of the memBuffer. Since there is no * Simple byte buffer implementation of the memBuffer. Even if a Memory is
* actual memory object associated with this object, the getMemory method * provided, the available bytes will be limited to the bytes provided during
* is not implemented and all gets are limited to the bytes supplied during
* construction. * construction.
*/ */
public class ByteMemBufferImpl implements MemBuffer { public class ByteMemBufferImpl implements MemBuffer {
@@ -31,6 +30,7 @@ public class ByteMemBufferImpl implements MemBuffer {
private final GhidraDataConverter converter; private final GhidraDataConverter converter;
private byte[] bytes; private byte[] bytes;
private Address addr; private Address addr;
private Memory mem;
/** /**
* Construct a ByteMemBufferImpl object * Construct a ByteMemBufferImpl object
@@ -39,9 +39,22 @@ public class ByteMemBufferImpl implements MemBuffer {
* @param isBigEndian true for BigEndian, false for LittleEndian. * @param isBigEndian true for BigEndian, false for LittleEndian.
*/ */
public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) { public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) {
this(null, addr, bytes, isBigEndian);
}
/**
* Construct a ByteMemBufferImpl object
* @param memory the memory in case getMemory() is called to get associated things like address spaces
*
* @param addr the address to associate with the bytes
* @param bytes the data that normally would be coming from memory.
* @param isBigEndian true for BigEndian, false for LittleEndian.
*/
public ByteMemBufferImpl(Memory memory, Address addr, byte[] bytes, boolean isBigEndian) {
this.addr = addr; this.addr = addr;
this.bytes = bytes; this.bytes = bytes;
this.converter = GhidraDataConverter.getInstance(isBigEndian); this.converter = GhidraDataConverter.getInstance(isBigEndian);
this.mem = memory;
} }
/** /**
@@ -67,7 +80,7 @@ public class ByteMemBufferImpl implements MemBuffer {
@Override @Override
public Memory getMemory() { public Memory getMemory() {
return null; return mem;
} }
@Override @Override
@@ -66,7 +66,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval = ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) { new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) { public boolean evaluateContext(VarnodeContext context, Instruction instr) {
String mnemonic = instr.getMnemonicString(); String mnemonic = instr.getMnemonicString();
@@ -124,7 +124,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
if (instr.getFlowType().isJump()) { if (instr.getFlowType().isJump()) {
return false; return false;
} }
@@ -132,7 +132,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
return false; return false;
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
@Override @Override
@@ -153,6 +153,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
return false; return false;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) { Address constant, int size, DataType dataType, RefType refType) {
return null; return null;
} }
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
if (targetList.contains(address)) { if (targetList.contains(address)) {
return false; return false;
} }
@@ -29,6 +29,7 @@ import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -190,7 +191,7 @@ public class AARCH64PltThunkAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
int size, RefType refType) { int size, DataType dataType, RefType refType) {
return true; return true;
} }
@@ -81,7 +81,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval = ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) { new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) { public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@@ -104,7 +104,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
// if LR is a constant and is set right after this, this is a call // if LR is a constant and is set right after this, this is a call
Varnode lrVal = context.getRegisterVarnodeValue(lrRegister); Varnode lrVal = context.getRegisterVarnodeValue(lrRegister);
if (lrVal != null) { if (lrVal != null) {
if (lrVal.isConstant()) { if (context.isConstant(lrVal)) {
long target = lrVal.getAddress().getOffset(); long target = lrVal.getAddress().getOffset();
Address addr = instr.getMaxAddress().add(1); Address addr = instr.getMaxAddress().add(1);
if (target == addr.getOffset() && !instr.getFlowType().isCall()) { if (target == addr.getOffset() && !instr.getFlowType().isCall()) {
@@ -176,7 +176,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
if (refType.isJump() && refType.isComputed() && if (refType.isJump() && refType.isComputed() &&
program.getMemory().contains(address) && address.getOffset() != 0) { program.getMemory().contains(address) && address.getOffset() != 0) {
if (instr.getMnemonicString().startsWith("tb")) { if (instr.getMnemonicString().startsWith("tb")) {
@@ -184,24 +184,29 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
} }
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(), doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor); true, monitor);
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
return !symEval.encounteredBranch(); return !symEval.encounteredBranch();
} }
if (refType.isData() && program.getMemory().contains(address)) { if (refType.isData() && program.getMemory().contains(address)) {
if (refType.isRead() || refType.isWrite()) { if (refType.isRead() || refType.isWrite()) {
int numOperands = instr.getNumOperands();
// if two operands, then all read/write refs go on the 2nd operand
createData(program, address, size); createData(program, address, size);
instr.addOperandReference(instr.getNumOperands() - 1, address, refType, if (numOperands <= 2) {
SourceType.ANALYSIS); instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
return false; SourceType.ANALYSIS);
return false;
}
return true;
} }
} }
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) { else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
// must disassemble right now, because TB flag could get set back at end of blx // must disassemble right now, because TB flag could get set back at end of blx
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(), doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor); true, monitor);
return false;
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
@Override @Override
@@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) { public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
// check if a return is actually returning, or is branching with a constant PC // check if a return is actually returning, or is branching with a constant PC
if (retVN != null && retVN.isConstant()) { if (retVN != null && context.isConstant(retVN)) {
long offset = retVN.getOffset(); long offset = retVN.getOffset();
if (offset > 3 && offset != -1) { if (offset > 3 && offset != -1) {
// need to override the return to a branch // need to override the return to a branch
@@ -236,6 +241,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
return false; return false;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) { Address constant, int size, DataType dataType, RefType refType) {
return null; return null;
} }
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
// if ever see a reference to 0, something went wrong, stop the process // if ever see a reference to 0, something went wrong, stop the process
if (address == null) { if (address == null) {
@@ -25,6 +25,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler; import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
@@ -247,7 +248,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
private Address localGPAssumptionValue = currentGPAssumptionValue; private Address localGPAssumptionValue = currentGPAssumptionValue;
private boolean mustStopNow = false; // if something discovered in processing, mustStop flag private boolean mustStopNow = false; // if something discovered in processing, mustStop flag
@@ -267,7 +268,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
// this was copylefted from the arm analyzer // this was copylefted from the arm analyzer
Varnode raVal = context.getRegisterVarnodeValue(rareg); Varnode raVal = context.getRegisterVarnodeValue(rareg);
if (raVal != null) { if (raVal != null) {
if (raVal.isConstant()) { if (context.isConstant(raVal)) {
long target = raVal.getAddress().getOffset(); long target = raVal.getAddress().getOffset();
Address addr = instr.getMaxAddress(); Address addr = instr.getMaxAddress();
if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) { if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) {
@@ -317,22 +318,25 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
lastSetInstr = instructionAt; lastSetInstr = instructionAt;
} }
} }
symEval.makeReference(context, lastSetInstr, -1, // if an instruction actually set the GP
instr.getMinAddress().getAddressSpace().getSpaceID(), if (lastSetAddr != null) {
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true, symEval.makeReference(context, lastSetInstr, -1,
monitor); instr.getMinAddress().getAddressSpace().getSpaceID(),
if (localGPAssumptionValue == null) { unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
program.getBookmarkManager().setBookmark( false, monitor);
lastSetInstr.getMinAddress(), BookmarkType.WARNING, if (localGPAssumptionValue == null) {
"GP Global Register Set", program.getBookmarkManager().setBookmark(
"Global GP Register is set here."); lastSetInstr.getMinAddress(), BookmarkType.WARNING,
} "GP Global Register Set",
if (localGPAssumptionValue != null && "Global GP Register is set here.");
!localGPAssumptionValue.equals(gpRefAddr)) { }
localGPAssumptionValue = gp_assumption_value = null; if (localGPAssumptionValue != null &&
} !localGPAssumptionValue.equals(gpRefAddr)) {
else { localGPAssumptionValue = gp_assumption_value = null;
localGPAssumptionValue = gp_assumption_value = gpRefAddr; }
else {
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
}
} }
} }
} }
@@ -372,9 +376,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
Address addr = address; Address addr = address;
if (addr == Address.NO_ADDRESS) {
return false;
}
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) { //if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
// if this isn't straight code (thunk computation), let someone else lay down the reference // if this isn't straight code (thunk computation), let someone else lay down the reference
@@ -386,9 +394,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
} }
if ((refType.isJump() || refType.isCall()) & refType.isComputed()) { if ((refType.isJump() || refType.isCall()) & refType.isComputed()) {
//if (refType.isJump() || refType.isCall()) {
addr = mipsExtDisassembly(program, instr, context, address, monitor); addr = mipsExtDisassembly(program, instr, context, address, monitor);
//addr = flowISA(program, instr, context, address);
if (addr == null) { if (addr == null) {
addr = address; addr = address;
} }
@@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
context.clearRegister(reg); context.clearRegister(reg);
// need to add the reference here, register operand will no longer have a value // need to add the reference here, register operand will no longer have a value
instr.addOperandReference(0, addr, refType, instr.addOperandReference(0, addr, instr.getFlowType(),
SourceType.ANALYSIS); SourceType.ANALYSIS);
// set the register value on the target address // set the register value on the target address
@@ -433,7 +439,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
} }
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
@Override @Override
@@ -497,6 +503,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
return null; return null;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
@@ -20,6 +20,7 @@ import java.math.BigInteger;
import ghidra.app.services.AnalysisPriority; import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@@ -79,11 +80,11 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
int size, RefType refType) { int size, DataType dataType, RefType refType) {
AddressSpace space = address.getAddressSpace(); AddressSpace space = address.getAddressSpace();
if (address.isExternalAddress()) { if (address.isExternalAddress()) {
@@ -97,7 +98,7 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
if (refType.isComputed() && refType.isFlow() && isCodeSpace) { if (refType.isComputed() && refType.isFlow() && isCodeSpace) {
return true; return true;
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
@Override @Override
@@ -146,6 +147,12 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
startNewBlock(program, flowStart); startNewBlock(program, flowStart);
AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@@ -29,6 +29,7 @@ import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
@@ -264,7 +265,7 @@ public class PPC64CallStubAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
int size, RefType refType) { int size, DataType dataType, RefType refType) {
return true; return true;
} }
@@ -154,7 +154,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval = ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) { new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) { public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
@@ -224,7 +224,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) { int pcodeop, Address address, int size, DataType dataType, RefType refType) {
if (instr.getFlowType().isJump()) { if (instr.getFlowType().isJump()) {
// for branching instructions, if we have a good target, mark it // for branching instructions, if we have a good target, mark it
@@ -259,7 +259,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
return true; return true;
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
@Override @Override
@@ -316,6 +316,12 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
if (recoverSwitchTables) { if (recoverSwitchTables) {
@@ -454,13 +460,13 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
@Override @Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) { Address constant, int size, DataType dataType, RefType refType) {
return null; return null;
} }
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType,RefType refType) {
// TODO: if ever loading from instructions in memory, must EXIT! // TODO: if ever loading from instructions in memory, must EXIT!
if (!((refType.isComputed() || refType.isConditional()) && if (!((refType.isComputed() || refType.isConditional()) &&
@@ -99,7 +99,7 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
ConstantPropagationContextEvaluator eval = ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) { new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
private boolean mustStopNow = false; private boolean mustStopNow = false;
@Override @Override
@@ -112,7 +112,13 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
return mustStopNow; return mustStopNow;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
return resultSet; return resultSet;
@@ -76,7 +76,7 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) { public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@@ -126,7 +126,13 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
return false; return false;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
return resultSet; return resultSet;
@@ -21,6 +21,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler; import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
@@ -76,11 +77,11 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
if (address.isExternalAddress()) { if (address.isExternalAddress()) {
return true; return true;
@@ -98,7 +99,7 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
} }
boolean doRef = boolean doRef =
super.evaluateReference(context, instr, pcodeop, address, size, refType); super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
if (!doRef) { if (!doRef) {
return false; return false;
} }
@@ -109,6 +110,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
return doRef; return doRef;
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
@@ -17,6 +17,7 @@ package ghidra.app.plugin.core.analysis;
import ghidra.app.services.AnalysisPriority; import ghidra.app.services.AnalysisPriority;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
@@ -45,11 +46,11 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
// if this is a call, some processors use the register value // if this is a call, some processors use the register value
// used in the call for PIC calculations // used in the call for PIC calculations
@@ -67,7 +68,7 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
if (refType.isComputed()) { if (refType.isComputed()) {
boolean doRef = super.evaluateReference(context, instr, pcodeop, address, boolean doRef = super.evaluateReference(context, instr, pcodeop, address,
size, refType); size, dataType, refType);
if (!doRef) { if (!doRef) {
return false; return false;
} }
@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.analysis;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Processor; import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
@@ -48,7 +49,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context // follow all flows building up context
// use context to fill out addresses on certain instructions // use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override @Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) { public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@@ -74,7 +75,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
@Override @Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) { Address address, int size, DataType dataType, RefType refType) {
// don't allow flow references to locations not in memory if the location is not external. // don't allow flow references to locations not in memory if the location is not external.
if (refType.isFlow() && !instr.getMemory().contains(address) && if (refType.isFlow() && !instr.getMemory().contains(address) &&
@@ -82,10 +83,16 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
return false; return false;
} }
return super.evaluateReference(context, instr, pcodeop, address, size, refType); return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
} }
}; };
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
return resultSet; return resultSet;