GP-3077 Added constant tracking through stack for stack parameters, fixed issues with values getting crossed moving in and out of memory, added prototype param type creation, added setting for restricting parameters to know pointers to handle harvard architectures and pointertypedefs

This commit is contained in:
emteere 2023-05-01 01:57:56 -04:00
parent 269ea1ae7a
commit 02248d2251
27 changed files with 1258 additions and 392 deletions

View file

@ -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,

View file

@ -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);

View file

@ -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....

View file

@ -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)) {

View file

@ -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)) {

View file

@ -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);
} }
} }

View file

@ -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;
}
} }

View file

@ -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;

View file

@ -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

View file

@ -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;
} }

View file

@ -27,12 +27,13 @@ import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
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.*;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.BigEndianDataConverter;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -62,6 +63,7 @@ public class SymbolicPropogator {
protected boolean readExecutableAddress; protected boolean readExecutableAddress;
protected VarnodeContext context; protected VarnodeContext context;
protected AddressSet body; // body of processed instructions
protected boolean hitCodeFlow = false; // no branching so far protected boolean hitCodeFlow = false; // no branching so far
protected boolean debug = false; protected boolean debug = false;
@ -73,6 +75,8 @@ public class SymbolicPropogator {
new NotFoundException("Divide by zero"); new NotFoundException("Divide by zero");
private long pointerMask; private long pointerMask;
private int pointerSize;
private DataType pointerSizedDT = null;
protected static final int MAX_EXACT_INSTRUCTIONS = 100; protected static final int MAX_EXACT_INSTRUCTIONS = 100;
@ -119,7 +123,9 @@ public class SymbolicPropogator {
if (ptrSize > 8) { if (ptrSize > 8) {
ptrSize = 8; ptrSize = 8;
} }
pointerSize = ptrSize;
pointerMask = maskSize[ptrSize]; pointerMask = maskSize[ptrSize];
pointerSizedDT = IntegerDataType.getUnsignedDataType(pointerSize, null);
} }
/** /**
@ -297,7 +303,7 @@ public class SymbolicPropogator {
if (val == null) { if (val == null) {
return null; return null;
} }
if (val.isConstant()) { if (context.isConstant(val)) {
return new Value(val.getOffset()); return new Value(val.getOffset());
} }
AddressSpace space = val.getAddress().getAddressSpace(); AddressSpace space = val.getAddress().getAddressSpace();
@ -390,6 +396,7 @@ public class SymbolicPropogator {
protected int sameInstrCount = 0; // # of the same instructions protected int sameInstrCount = 0; // # of the same instructions
private boolean checkForParamRefs = true; // true if params to functions should be checked for references private boolean checkForParamRefs = true; // true if params to functions should be checked for references
private boolean checkForParamPointerRefs = true; // true if param must be a marked pointer data type
private boolean checkForReturnRefs = true; // true if return values from functions should be checked for references private boolean checkForReturnRefs = true; // true if return values from functions should be checked for references
private boolean checkForStoredRefs = true; // true if stored values should be checked for references private boolean checkForStoredRefs = true; // true if stored values should be checked for references
@ -402,7 +409,7 @@ public class SymbolicPropogator {
public AddressSet flowConstants(Address fromAddr, Address startAddr, AddressSetView restrictSet, public AddressSet flowConstants(Address fromAddr, Address startAddr, AddressSetView restrictSet,
ContextEvaluator eval, VarnodeContext vContext, TaskMonitor monitor) ContextEvaluator eval, VarnodeContext vContext, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
AddressSet body = new AddressSet(); body = new AddressSet();
AddressSet conflicts = new AddressSet(); AddressSet conflicts = new AddressSet();
// prime the context stack with the entry point address // prime the context stack with the entry point address
@ -762,7 +769,8 @@ public class SymbolicPropogator {
} }
Address minInstrAddress = instruction.getMinAddress(); Address minInstrAddress = instruction.getMinAddress();
if (debug) { if (debug)
{
Msg.info(this, minInstrAddress + " " + instruction); Msg.info(this, minInstrAddress + " " + instruction);
} }
@ -788,6 +796,7 @@ public class SymbolicPropogator {
Varnode val1, val2, val3, result; Varnode val1, val2, val3, result;
long lval1, lval2; long lval1, lval2;
long lresult; long lresult;
boolean suspectOffset = false;
Varnode vt; Varnode vt;
if (debug) { if (debug) {
Msg.info(this, " " + pcodeOp); Msg.info(this, " " + pcodeOp);
@ -798,8 +807,8 @@ public class SymbolicPropogator {
case PcodeOp.COPY: case PcodeOp.COPY:
if (in[0].isAddress() && if (in[0].isAddress() &&
!in[0].getAddress().getAddressSpace().hasMappedRegisters()) { !in[0].getAddress().getAddressSpace().hasMappedRegisters()) {
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
RefType.READ, monitor); null, RefType.READ, ptype, true, monitor);
} }
vContext.copy(out, in[0], mustClearAll, evaluator); vContext.copy(out, in[0], mustClearAll, evaluator);
break; break;
@ -808,23 +817,35 @@ public class SymbolicPropogator {
val1 = vContext.getValue(in[0], evaluator); val1 = vContext.getValue(in[0], evaluator);
val2 = vContext.getValue(in[1], evaluator); val2 = vContext.getValue(in[1], evaluator);
suspectOffset = vContext.isSuspectConstant(val2);
vt = vContext.getVarnode(in[0], val2, out.getSize(), evaluator); vt = vContext.getVarnode(in[0], val2, out.getSize(), evaluator);
// TODO: may need to use DATA refType in some cases // TODO: may need to use DATA refType in some cases
addLoadStoreReference(vContext, instruction, ptype, vt, in[0], in[1], addLoadStoreReference(vContext, instruction, ptype, vt, in[0], in[1],
RefType.READ, monitor); RefType.READ, suspectOffset==false, monitor);
// If vt is a bad varnode (bad space, no memory, no value in varnode) you won't get a value // If vt is a bad varnode (bad space, no memory, no value in varnode) you won't get a value
Varnode memVal = vContext.getValue(vt, evaluator); Varnode memVal = vContext.getValue(vt, evaluator);
vContext.putValue(out, memVal, mustClearAll); vContext.putValue(out, memVal, mustClearAll);
break; break;
case PcodeOp.STORE: case PcodeOp.STORE:
out = getStoredLocation(vContext, in);
Varnode offs = null;
try {
offs = vContext.getValue(in[1], true, evaluator);
suspectOffset = vContext.isSuspectConstant(offs);
out = getStoredLocation(vContext, in[0], offs, in[2]);
} catch (NotFoundException e) {
// if can't get the value of the relative store location
// this isn't an exception, the output will be null/unknown
}
// TODO: may need to use DATA refType in some cases // TODO: may need to use DATA refType in some cases
addLoadStoreReference(vContext, instruction, ptype, out, in[0], in[1], addLoadStoreReference(vContext, instruction, ptype, out, in[0], in[1],
RefType.WRITE, monitor); RefType.WRITE, suspectOffset==false, monitor);
val3 = vContext.getValue(in[2], null); val3 = vContext.getValue(in[2], null);
@ -837,9 +858,11 @@ public class SymbolicPropogator {
case PcodeOp.BRANCHIND: case PcodeOp.BRANCHIND:
try { try {
val1 = vContext.getValue(in[0], evaluator); val1 = vContext.getValue(in[0], evaluator);
suspectOffset = vContext.isSuspectConstant(val1);
vt = getConstantOrExternal(vContext, minInstrAddress, val1); vt = getConstantOrExternal(vContext, minInstrAddress, val1);
makeReference(vContext, instruction, ptype, -1, vt, makeReference(vContext, instruction, -1, vt, null,
instruction.getFlowType(), monitor); instruction.getFlowType(), ptype, !suspectOffset, monitor);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
// constant not found, ignore // constant not found, ignore
@ -873,7 +896,8 @@ public class SymbolicPropogator {
// TODO: Revisit handling of external functions... // TODO: Revisit handling of external functions...
if (val1.isConstant()) { if (vContext.isConstant(val1)) {
suspectOffset = vContext.isSuspectConstant(val1);
// indirect target - assume single code space (same as instruction) // indirect target - assume single code space (same as instruction)
target = instruction.getAddress() target = instruction.getAddress()
.getNewTruncatedAddress(val1.getOffset(), true); .getNewTruncatedAddress(val1.getOffset(), true);
@ -893,11 +917,12 @@ public class SymbolicPropogator {
// make sure we aren't replacing a read ref with a call to the same place // make sure we aren't replacing a read ref with a call to the same place
if (refs.length <= 0 || if (refs.length <= 0 ||
!refs[0].getToAddress().equals(target)) { !refs[0].getToAddress().equals(target)) {
makeReference(vContext, instruction, Reference.MNEMONIC, target = makeReference(vContext, instruction, Reference.MNEMONIC,
// Use target in case location has shifted (external...) // Use target in case location has shifted (external...)
target.getAddressSpace().getSpaceID(), target.getAddressSpace().getSpaceID(),
target.getAddressableWordOffset(), val1.getSize(), target.getAddressableWordOffset(), val1.getSize(),
instruction.getFlowType(), ptype, true, monitor); null,
instruction.getFlowType(), ptype, !suspectOffset, false, monitor);
} }
} }
@ -1103,8 +1128,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_ZEXT: case PcodeOp.INT_ZEXT:
if (in[0].isAddress()) { if (in[0].isAddress()) {
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
RefType.READ, monitor); null, RefType.READ, ptype, true, monitor);
} }
val1 = vContext.extendValue(out, in, false, evaluator); val1 = vContext.extendValue(out, in, false, evaluator);
vContext.putValue(out, val1, mustClearAll); vContext.putValue(out, val1, mustClearAll);
@ -1112,8 +1137,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_SEXT: case PcodeOp.INT_SEXT:
if (in[0].isAddress()) { if (in[0].isAddress()) {
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
RefType.READ, monitor); null, RefType.READ, ptype, true, monitor);
} }
val1 = vContext.extendValue(out, in, true, evaluator); val1 = vContext.extendValue(out, in, true, evaluator);
vContext.putValue(out, val1, mustClearAll); vContext.putValue(out, val1, mustClearAll);
@ -1453,17 +1478,18 @@ public class SymbolicPropogator {
} }
return vt; return vt;
} }
private Varnode getStoredLocation(VarnodeContext vContext, Varnode[] in) { private Varnode getStoredLocation(VarnodeContext vContext, Varnode space, Varnode offset, Varnode size) {
Varnode out = null; Varnode out = null;
Varnode val;
try {
// first create the ref, even if don't know the value to be stored
val = vContext.getValue(in[1], true, evaluator);
if (offset == null) {
return null;
}
try {
// out is a calculated location for store. If got to here, need to set out // out is a calculated location for store. If got to here, need to set out
// because it might need to be cleared by a bad value access! // because it might need to be cleared by a bad value access!
out = vContext.getVarnode(in[0], val, in[2].getSize(), evaluator); out = vContext.getVarnode(space, offset, size.getSize(), evaluator);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
// if can't get the value of the relative store location // if can't get the value of the relative store location
@ -1482,6 +1508,7 @@ public class SymbolicPropogator {
} }
Address fallThruAddr = instruction.getFallThrough(); Address fallThruAddr = instruction.getFallThrough();
// if the call is right below this routine, ignore the call // if the call is right below this routine, ignore the call
// otherwise clear out the return and killed by call variables
if (fallThruAddr == null || target == null || if (fallThruAddr == null || target == null ||
target.getOffset() != fallThruAddr.getOffset()) { target.getOffset() != fallThruAddr.getOffset()) {
@ -1490,7 +1517,7 @@ public class SymbolicPropogator {
if (checkForParamRefs && evaluator != null && if (checkForParamRefs && evaluator != null &&
evaluator.evaluateReference(context, instruction, PcodeOp.UNIMPLEMENTED, evaluator.evaluateReference(context, instruction, PcodeOp.UNIMPLEMENTED,
(target == null ? Address.NO_ADDRESS : target), 0, (target == null ? Address.NO_ADDRESS : target), 0,
RefType.UNCONDITIONAL_CALL)) { null, RefType.UNCONDITIONAL_CALL)) {
// put references on any register parameters with values in // put references on any register parameters with values in
// them. // them.
addParamReferences(targetFunc, target, instruction, context, monitor); addParamReferences(targetFunc, target, instruction, context, monitor);
@ -1503,6 +1530,14 @@ public class SymbolicPropogator {
context.putValue(varnode, context.createBadVarnode(), false); context.putValue(varnode, context.createBadVarnode(), false);
} }
} }
// clear out any killed by call variables
Varnode killedVarnodes[] = context.getKilledVarnodes(targetFunc);
if (killedVarnodes != null) {
for (Varnode varnode : killedVarnodes) {
context.putValue(varnode, context.createBadVarnode(), false);
}
}
} }
// inlined function, don't worry about it's function effects // inlined function, don't worry about it's function effects
@ -1688,7 +1723,7 @@ public class SymbolicPropogator {
ArrayList<Varnode> inputs = new ArrayList<Varnode>(); ArrayList<Varnode> inputs = new ArrayList<Varnode>();
for (int i = 1; i < ins.length; i++) { for (int i = 1; i < ins.length; i++) {
Varnode vval = context.getValue(ins[i], evaluator); Varnode vval = context.getValue(ins[i], evaluator);
if (!vval.isConstant()) { if (!context.isConstant(vval)) {
return null; return null;
} }
inputs.add(vval); inputs.add(vval);
@ -1786,6 +1821,9 @@ public class SymbolicPropogator {
int callStackMod = model.getExtrapop(); int callStackMod = model.getExtrapop();
int callStackShift = model.getStackshift(); int callStackShift = model.getStackshift();
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) { if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
// TODO: If the purge is set, the calling convention could be wrong
// If the purge can from a RET <X> if will be correct so should use it!
// Need to make sure that is happening in the program before accepting
return callStackShift; return callStackShift;
} }
if (depth == Function.UNKNOWN_STACK_DEPTH_CHANGE || if (depth == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
@ -1825,7 +1863,7 @@ public class SymbolicPropogator {
} }
// don't check for params on external calls // don't check for params on external calls
if ((callTarget != null) && callTarget.isExternalAddress()) { if (callTarget != null && callTarget.isExternalAddress()) {
return; return;
} }
@ -1847,29 +1885,58 @@ public class SymbolicPropogator {
params = func.getParameters(); params = func.getParameters();
signatureSource = func.getSignatureSource(); signatureSource = func.getSignatureSource();
} }
else if (checkForParamPointerRefs) {
// no function chan't check for pointer types
return;
}
long callOffset = (callTarget == null ? -1 : callTarget.getOffset()); long callOffset = (callTarget == null ? -1 : callTarget.getOffset());
// If there are params defined or the params were specified (meaning it could be VOID params) // If there are params defined or the params were specified (meaning it could be VOID params)
boolean signatureAssigned = signatureSource != SourceType.DEFAULT; boolean signatureAssigned = signatureSource != SourceType.DEFAULT;
boolean trustSignature = signatureAssigned || params.length > 0; boolean trustSignature = signatureAssigned || params.length > 0;
if (trustSignature) { if (trustSignature && !func.hasVarArgs()) {
// Loop through defined parameters for a valid address value // Loop through defined parameters for a valid address value
for (Parameter param : params) { for (Parameter param : params) {
Parameter p = param; Parameter p = param;
if (!p.isRegisterVariable()) {
continue; // check if known pointer DT.
// construct pointer of the right type, given the constant
// if not a pointer && flag must be pointer, don't add pointer
DataType dataType = p.getDataType();
if (!(dataType instanceof Pointer ||
(dataType instanceof TypeDef && ((TypeDef) dataType).isPointer()))) {
// wasn't a pointer immediately
if (checkForParamPointerRefs) {
continue;
}
// if undefined, or int/long could still be pointer
if (!(Undefined.isUndefined(dataType) || dataType instanceof IntegerDataType)) {
continue;
}
} }
createVariableStorageReference(instruction, varnodeContext, monitor, // use the varnode to pull out the bytes from the varnode
p.getVariableStorage(), callOffset); // only use constants, not symbolic?
// put the bytes in a membuffer
// Hand bytes to data type to decode as if in memory
// get pointer out
createVariableStorageReference(instruction, varnodeContext, monitor, conv,
p.getVariableStorage(), dataType, callOffset);
} }
} }
else { else if (!checkForParamPointerRefs) {
// loop through potential params, since none defined, to find a potential pointer // loop through potential params, since none defined, to find a potential pointer
VariableStorage[] vars = conv.getPotentialInputRegisterStorage(program); // only check the first seven param locations, if don't have a signature
for (VariableStorage var : vars) { for (int pi=0; pi < 8; pi++) {
createVariableStorageReference(instruction, varnodeContext, monitor, var, // TODO Should cache the arg locations for each convention
callOffset); VariableStorage var = conv.getArgLocation(pi, null, pointerSizedDT, program);
// can't trust stack storage if params aren't known
if (var.isStackStorage()) {
continue;
}
createVariableStorageReference(instruction, varnodeContext, monitor, conv, var,
null, callOffset);
} }
} }
} }
@ -1891,12 +1958,12 @@ public class SymbolicPropogator {
return; return;
} }
createVariableStorageReference(instruction, varnodeContext, monitor, returnLoc, 0); createVariableStorageReference(instruction, varnodeContext, monitor, null, returnLoc, null, 0);
} }
private void addLoadStoreReference(VarnodeContext vContext, Instruction instruction, private void addLoadStoreReference(VarnodeContext vContext, Instruction instruction,
int pcodeType, Varnode refLocation, Varnode targetSpaceID, Varnode assigningVarnode, int pcodeType, Varnode refLocation, Varnode targetSpaceID, Varnode assigningVarnode,
RefType reftype, TaskMonitor monitor) { RefType reftype, boolean knownReference, TaskMonitor monitor) {
// no output or load // no output or load
if (refLocation == null) { if (refLocation == null) {
@ -1906,7 +1973,7 @@ public class SymbolicPropogator {
int opIndex = findOperandWithVarnodeAssignment(instruction, assigningVarnode); int opIndex = findOperandWithVarnodeAssignment(instruction, assigningVarnode);
if (instruction.getFlowType().isCall()) { if (instruction.getFlowType().isCall()) {
makeReference(vContext, instruction, pcodeType, opIndex, refLocation, reftype, monitor); makeReference(vContext, instruction, opIndex, refLocation, null, reftype, pcodeType, knownReference, monitor);
} }
else { else {
int spaceID = refLocation.getSpace(); int spaceID = refLocation.getSpace();
@ -1915,35 +1982,25 @@ public class SymbolicPropogator {
long offset = refLocation.getOffset(); long offset = refLocation.getOffset();
if (evaluator != null) { if (evaluator != null) {
// symbolic spaces will have the name of the symbolic space be the register space
// String spaceName = refLocation.getAddress().getAddressSpace().getName();
// Register register = vContext.getRegister(spaceName);
// never make an offset onto the stack
// if (register != null) {
// if (!register.equals(vContext.getStackRegister())) {
// // need to get the register, because we want to find the last place the register
// // was set to this value so that we can create a reference.
// RegisterValue rval = new RegisterValue(register,BigInteger.valueOf(offset));
// createRegisterStorageReference(instruction, vContext, monitor, 0, rval);
// }
// } else
if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) { if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) {
Address constant = program.getAddressFactory() Address constant = program.getAddressFactory()
.getAddress((int) targetSpaceID.getOffset(), offset); .getAddress((int) targetSpaceID.getOffset(), offset);
Address newTarget = evaluator.evaluateConstant(vContext, instruction, Address newTarget = evaluator.evaluateConstant(vContext, instruction,
pcodeType, constant, 0, reftype); pcodeType, constant, 0, null, reftype);
if (newTarget != null) { // TODO: This is speculative, should not be doing here
// need to check if there is a memory/label at the other end, or some other
// corroborating evidence very late in analysis
if (newTarget != null ) {
makeReference(vContext, instruction, Reference.MNEMONIC, makeReference(vContext, instruction, Reference.MNEMONIC,
newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(), 0, newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(), 0,
reftype, pcodeType, false, monitor); null, reftype.DATA, pcodeType, false, false, monitor);
return; return;
} }
} }
} }
} }
// even if this is symbolic space, give the evaluator a chance to do something with the symbolic value // even if this is symbolic space, give the evaluator a chance to do something with the symbolic value
makeReference(vContext, instruction, pcodeType, opIndex, refLocation, reftype, monitor); makeReference(vContext, instruction, opIndex, refLocation, null, reftype, pcodeType, knownReference, monitor);
} }
} }
@ -2004,57 +2061,101 @@ public class SymbolicPropogator {
// TODO: this could be a calculated OFFSET reference with a base address // TODO: this could be a calculated OFFSET reference with a base address
if (!valueToStore.isConstant()) { if (!vContext.isConstant(valueToStore)) {
return; return;
} }
long valueOffset = valueToStore.getOffset(); long valueOffset = valueToStore.getOffset();
makeReference(vContext, instruction, -1, -1, valueOffset, 0, RefType.DATA, PcodeOp.STORE, makeReference(vContext, instruction, -1, -1, valueOffset, 0, null, RefType.DATA, PcodeOp.STORE,
false, monitor); false, false, monitor);
} }
private void createVariableStorageReference(Instruction instruction, private void createVariableStorageReference(Instruction instruction,
VarnodeContext varnodeContext, TaskMonitor monitor, VariableStorage storage, VarnodeContext varnodeContext, TaskMonitor monitor, PrototypeModel conv, VariableStorage storage,
long callOffset) { DataType dataType, long callOffset) {
Address lastSetAddr;
BigInteger bval;
// TODO: need to handle memory
// TODO: need to handle multi-piece variables and re-assemble
//
if (storage.isStackStorage()) {
if (conv == null) {
return;
}
Varnode sVnode = storage.getFirstVarnode();
// translate the variable relative to the current stackpointer symbolic value
Varnode stackVarnode = varnodeContext.getStackVarnode();
Varnode stackVal = null;
try {
stackVal = varnodeContext.getValue(stackVarnode, null);
if (stackVal == null) {
return;
}
} catch (NotFoundException e) {
return;
}
Varnode realSPVarnode = varnodeContext.createVarnode(stackVal.getOffset() + sVnode.getOffset(),
stackVal.getSpace(), sVnode.getAddress().getAddressSpace().getPointerSize());
Varnode value = null;
try {
value = varnodeContext.getValue(realSPVarnode,evaluator);
}
catch (NotFoundException e) {
return;
}
if (!storage.isRegisterStorage()) { if (!varnodeContext.isConstant(value)) {
return;
}
bval = BigInteger.valueOf(value.getOffset());
lastSetAddr = varnodeContext.getLastSetLocation(realSPVarnode, bval);
// TODO: What if last set location is in a delayslot?
}
else if (storage.isRegisterStorage()) {
// TODO: need to handle compound register storage (e.g., two registers
// used)
Register reg = storage.getRegister();
// RegisterValue rval =
// context.getRegisterValue(reg,instruction.getMinAddress());
RegisterValue rval = varnodeContext.getRegisterValue(reg);
if (rval == null || !rval.hasValue()) {
return;
}
reg = rval.getRegister();
bval = rval.getUnsignedValue();
lastSetAddr = varnodeContext.getLastSetLocation(reg, bval);
// if instruction has a delay slot, carefully check the location of the
// lastSetAddr Value
// to make sure it matches. If it doesn't, use this instruction
if (lastSetAddr != null && instruction.getPrototype().hasDelaySlots()) {
RegisterValue lastRval = varnodeContext.getRegisterValue(reg, lastSetAddr);
if (lastRval == null || !lastRval.hasAnyValue() || !lastRval.equals(rval)) {
lastSetAddr = instruction.getMaxAddress();
}
}
}
else {
return; return;
} }
// TODO: need to handle compound register storage (e.g., two registers makeVariableStorageReference(storage, instruction, varnodeContext, monitor, callOffset, dataType, lastSetAddr, bval);
// used)
Register reg = storage.getRegister();
// RegisterValue rval =
// context.getRegisterValue(reg,instruction.getMinAddress());
RegisterValue rval = varnodeContext.getRegisterValue(reg);
if (rval == null || !rval.hasValue()) {
return;
}
createRegisterStorageReference(instruction, varnodeContext, monitor, callOffset, rval);
} }
private void createRegisterStorageReference(Instruction instruction, private void makeVariableStorageReference(VariableStorage storage, Instruction instruction, VarnodeContext varnodeContext,
VarnodeContext varnodeContext, TaskMonitor monitor, long callOffset, TaskMonitor monitor, long callOffset, DataType dataType, Address lastSetAddr, BigInteger bval) {
RegisterValue rval) {
Address lastSetAddr;
Register reg = rval.getRegister();
BigInteger bval;
bval = rval.getUnsignedValue();
lastSetAddr = varnodeContext.getLastSetLocation(reg, bval);
// if instruction has a delay slot, carefully check the location of the
// lastSetAddr Value
// to make sure it matches. If it doesn't, use this instruction
if (lastSetAddr != null && instruction.getPrototype().hasDelaySlots()) {
RegisterValue lastRval = varnodeContext.getRegisterValue(reg, lastSetAddr);
if (lastRval == null || !lastRval.hasAnyValue() || !lastRval.equals(rval)) {
lastSetAddr = instruction.getMaxAddress();
}
}
if (lastSetAddr == null) { if (lastSetAddr == null) {
lastSetAddr = instruction.getMaxAddress(); lastSetAddr = instruction.getMaxAddress();
} }
@ -2067,30 +2168,74 @@ public class SymbolicPropogator {
return; return;
} }
if (lastSetAddr != null) { if (lastSetAddr == null) {
Instruction instr = instruction; return;
// last setAddr could be in the base instruction }
if (!instr.contains(lastSetAddr)) {
instr = getInstructionContaining(lastSetAddr); // if the dataType is known, try to interpret it to an address given the
} // bytes in the storage location
Reference[] refs = instr.getReferencesFrom(); int knownSpaceID = -1;
boolean found = false; boolean knownReference = false;
for (Reference ref : refs) { if (dataType != null) {
Address refAddr = ref.getToAddress(); if ((dataType instanceof TypeDef typedef && typedef.isPointer())) {
Address addr = refAddr.getAddressSpace().getTruncatedAddress(val, true); // pointer type defs need to be handled specially they could be re-mapping to another space
if (refAddr.getOffset() == addr.getOffset()) { // or interpretting the value
found = true; Object value = getPointerDataTypeValue(dataType, lastSetAddr, bval);
break; if (value instanceof Address) {
Address addrVal = (Address) value;
val = addrVal.getAddressableWordOffset();
knownSpaceID = addrVal.getAddressSpace().getSpaceID();
knownReference = true;
} }
} }
if (!found) { }
RefType refType = (callOffset == 0 ? RefType.DATA : RefType.PARAM);
makeReference(varnodeContext, instr, Reference.MNEMONIC, -1, val, 0, refType, // last setAddr could be in the base instruction
PcodeOp.UNIMPLEMENTED, false, monitor); Instruction instr = instruction;
if (!instr.contains(lastSetAddr)) {
instr = getInstructionContaining(lastSetAddr);
}
Reference[] refs = instr.getReferencesFrom();
boolean found = false;
for (Reference ref : refs) {
Address refAddr = ref.getToAddress();
Address addr = refAddr.getAddressSpace().getTruncatedAddress(val, true);
if (ref.getReferenceType() == RefType.PARAM && !body.contains(ref.getFromAddress())) {
// if reference address is not in body yet, this is the first time at this location
// get rid of the reference, reference could be changed to new AddressSpace or value
instr.removeOperandReference(ref.getOperandIndex(), refAddr);
} else if (refAddr.getOffset() == addr.getOffset()) {
found = true;
} }
} }
RefType refType = (callOffset == 0 ? RefType.DATA : RefType.PARAM);
makeReference(varnodeContext, instr, Reference.MNEMONIC, knownSpaceID, val, 0, dataType, refType,
PcodeOp.UNIMPLEMENTED, knownReference, found, monitor);
} }
private Object getPointerDataTypeValue(DataType dataType, Address lastSetAddr,
BigInteger bval) {
int len = dataType.getLength();
byte[] byteArray = new byte[len];
BigEndianDataConverter.INSTANCE.putBigInteger(byteArray, 0, len, bval);
MemBuffer buf =
new ByteMemBufferImpl(program.getMemory(), lastSetAddr, byteArray, true);
// if not enough bytes for data type, can't do it
if (len > byteArray.length) {
return null;
}
Object value = dataType.getValue(buf, dataType.getDefaultSettings(), len);
return value;
}
/** /**
* get the return variable storage location for this function * get the return variable storage location for this function
* *
@ -2219,20 +2364,22 @@ public class SymbolicPropogator {
* @param opIndex - operand it should be placed on, or -1 if unknown * @param opIndex - operand it should be placed on, or -1 if unknown
* @param vt - place to reference, could be a full address, or just a constant * @param vt - place to reference, could be a full address, or just a constant
* @param refType - type of reference * @param refType - type of reference
* @param knownReference true if this is a know good address, speculative otherwise
* @param monitor to cancel * @param monitor to cancel
* @return address that was marked up, null otherwise
*/ */
public void makeReference(VarnodeContext varnodeContext, Instruction instruction, int pcodeop, public Address makeReference(VarnodeContext varnodeContext, Instruction instruction, int opIndex, Varnode vt, DataType dataType, RefType refType,
int opIndex, Varnode vt, RefType refType, TaskMonitor monitor) { int pcodeop, boolean knownReference, TaskMonitor monitor) {
if (!vt.isAddress() && !varnodeContext.isExternalSpace(vt.getSpace())) { if (!vt.isAddress() && !varnodeContext.isExternalSpace(vt.getSpace())) {
if (evaluator != null) { if (evaluator != null) {
evaluator.evaluateSymbolicReference(varnodeContext, instruction, vt.getAddress()); evaluator.evaluateSymbolicReference(varnodeContext, instruction, vt.getAddress());
} }
return; return null;
} }
// offset must be word based to compute the reference correctly // offset must be word based to compute the reference correctly
makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(), return makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(),
vt.getSize(), refType, pcodeop, true, monitor); vt.getSize(), dataType, refType, pcodeop, knownReference, false, monitor);
} }
/** /**
@ -2252,17 +2399,20 @@ public class SymbolicPropogator {
* @param refType - type of reference * @param refType - type of reference
* @param pcodeop - op that caused the reference * @param pcodeop - op that caused the reference
* @param knownReference - true if reference is known to be a real reference, not speculative * @param knownReference - true if reference is known to be a real reference, not speculative
* @param preExisting preExisting reference
* @param monitor - the task monitor * @param monitor - the task monitor
* @return address that was marked up, null otherwise
*/ */
public void makeReference(VarnodeContext vContext, Instruction instruction, int opIndex, public Address makeReference(VarnodeContext vContext, Instruction instruction, int opIndex,
long knownSpaceID, long wordOffset, int size, RefType refType, int pcodeop, long knownSpaceID, long wordOffset, int size, DataType dataType, RefType refType, int pcodeop,
boolean knownReference, TaskMonitor monitor) { boolean knownReference, boolean preExisting, TaskMonitor monitor) {
long spaceID = knownSpaceID; long spaceID = knownSpaceID;
if (spaceID == -1) { // speculative reference - only offset is known if (spaceID == -1) { // speculative reference - only offset is known
spaceID = getReferenceSpaceID(instruction, wordOffset); spaceID = getReferenceSpaceID(instruction, wordOffset);
if (spaceID == -1) { if (spaceID == -1) {
return; // don't make speculative reference return null; // don't make speculative reference
} }
} }
@ -2278,12 +2428,12 @@ public class SymbolicPropogator {
else { else {
// do checks that are actual memory, and not fabricated externals // do checks that are actual memory, and not fabricated externals
if (!space.isLoadedMemorySpace()) { if (!space.isLoadedMemorySpace()) {
return; return null;
} }
// for now, don't mark up this area of memory. // for now, don't mark up this area of memory.
// Memory at too low an offset could be from a bad calculation (use of zero or other small number) // Memory at too low an offset could be from a bad calculation (use of zero or other small number)
if (wordOffset == 0) { if (wordOffset == 0) {
return; return null;
} }
// wrap offset within address space // wrap offset within address space
@ -2301,7 +2451,7 @@ public class SymbolicPropogator {
// don't make references to registers // don't make references to registers
if (space.hasMappedRegisters() && program.getRegister(target) != null) { if (space.hasMappedRegisters() && program.getRegister(target) != null) {
return; return null;
} }
// normalize the address into this overlay space. // normalize the address into this overlay space.
@ -2312,38 +2462,24 @@ public class SymbolicPropogator {
// it could be in a non-allocated memory space // it could be in a non-allocated memory space
// TODO: Really at this point it should be a constant, and put on a list // TODO: Really at this point it should be a constant, and put on a list
// to be considered later as a pointer. // to be considered later as a pointer.
if (!program.getReferenceManager().hasReferencesTo(target)) { // allow flow references to memory not in program
return; // program could be located in the wrong place, or other flow issues
if (!refType.isFlow() && !program.getReferenceManager().hasReferencesTo(target)) {
return null;
} }
} }
} }
// if the refType is a call, and it isn't computed, we shouldn't be here // if the refType is a call, and it isn't computed, we shouldn't be here
if (refType.isCall() && !refType.isComputed()) { if (refType.isCall() && !refType.isComputed()) {
return; return null;
} }
// give evaluator a chance to stop or change the reference // give evaluator a chance to stop or change the reference
if (evaluator != null) { target = evaluateReference(vContext, instruction, knownSpaceID, wordOffset, size,
// if this was a speculative reference, pass to the evaluateConstant dataType, refType, pcodeop, knownReference, target);
if (knownSpaceID == -1 || !knownReference) { if (target == null || preExisting) {
Address constant = program.getAddressFactory().getConstantAddress(wordOffset); return null;
Address newTarget = evaluator.evaluateConstant(vContext, instruction, pcodeop,
constant, size, refType);
if (newTarget == null) {
return;
}
if (newTarget != constant) {
target = newTarget; // updated the target, if same, then don't update to constant
// since the target address was already computed.
}
}
else {
if (!evaluator.evaluateReference(vContext, instruction, pcodeop, target, size,
refType)) {
return;
}
}
} }
// Pure data references need to be scrutinized // Pure data references need to be scrutinized
@ -2351,7 +2487,7 @@ public class SymbolicPropogator {
// //
if (refType.isData() && if (refType.isData() &&
!evaluatePureDataRef(instruction, wordOffset, refType, target)) { !evaluatePureDataRef(instruction, wordOffset, refType, target)) {
return; return null;
} }
if (refType.isJump() && refType.isComputed()) { if (refType.isJump() && refType.isComputed()) {
@ -2359,17 +2495,17 @@ public class SymbolicPropogator {
// if there are more than one reference, don't do the jump here // if there are more than one reference, don't do the jump here
Address[] flows = getInstructionFlows(instruction); Address[] flows = getInstructionFlows(instruction);
if (flows.length > 1) { if (flows.length > 1) {
return; return target;
} }
for (Address address : flows) { for (Address address : flows) {
if (address.equals(target)) { if (address.equals(target)) {
return; return target;
} }
} }
} }
} }
catch (AddressOutOfBoundsException e) { catch (AddressOutOfBoundsException e) {
return; return null;
} }
opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType); opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType);
@ -2379,7 +2515,7 @@ public class SymbolicPropogator {
if (!instruction.getFlowType().equals(refType)) { if (!instruction.getFlowType().equals(refType)) {
instruction = instruction.getNext(); instruction = instruction.getNext();
if (instruction == null) { if (instruction == null) {
return; return target;
} }
opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType); opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType);
} }
@ -2406,19 +2542,39 @@ public class SymbolicPropogator {
else { else {
instruction.addOperandReference(opIndex, target, refType, SourceType.ANALYSIS); instruction.addOperandReference(opIndex, target, refType, SourceType.ANALYSIS);
} }
return target;
}
if (refType.isData()) { private Address evaluateReference(VarnodeContext vContext, Instruction instruction,
createData(target, size); long knownSpaceID, long wordOffset, int size, DataType dataType, RefType refType,
int pcodeop, boolean knownReference, Address target) {
if (evaluator == null) {
return target;
} }
if (refType.isFlow() && !refType.isIndirect() && // if this was a speculative reference, pass to the evaluateConstant
!program.getMemory().isExternalBlockAddress(target)) { if (knownSpaceID == -1 || !knownReference) {
Data udata = program.getListing().getUndefinedDataAt(target); Address constant = program.getAddressFactory().getConstantAddress(wordOffset);
if (udata != null) { Address newTarget = evaluator.evaluateConstant(vContext, instruction, pcodeop,
DisassembleCommand cmd = new DisassembleCommand(target, null, true); constant, size, dataType, refType);
cmd.applyTo(program, monitor); if (newTarget == null) {
return null;
}
if (newTarget != constant) {
target = newTarget; // updated the target, if same, then don't update to constant
// since the target address was already computed.
} }
} }
// was a known reference, or constant evalutator allowed the reference and
// didn't handle it
if (!evaluator.evaluateReference(vContext, instruction, pcodeop, target, size,
dataType, refType)) {
return null;
}
return target;
} }
/** /**
@ -2476,32 +2632,6 @@ public class SymbolicPropogator {
return true; return true;
} }
private int createData(Address address, int size) {
if (program.getMemory().isExternalBlockAddress(address) ||
!program.getListing().isUndefined(address, address)) {
return 0;
}
if (size < 1 || size > 8) {
return 0;
}
DataType dt = Undefined.getUndefinedDataType(size);
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.
// This should only be done on references that are know good read/write, not data
program.getListing().createData(address, dt);
}
catch (CodeUnitInsertionException e) {
program.getListing().getDefinedDataAt(address);
}
int addrByteSize = dt.getLength();
return addrByteSize;
}
private int findOpIndexForRef(VarnodeContext vcontext, Instruction instruction, int opIndex, private int findOpIndexForRef(VarnodeContext vcontext, Instruction instruction, int opIndex,
long wordOffset, RefType refType) { long wordOffset, RefType refType) {
@ -2648,6 +2778,16 @@ public class SymbolicPropogator {
checkForParamRefs = checkParamRefsOption; checkForParamRefs = checkParamRefsOption;
} }
/**
* enable/disable creating param references for constants
* only if the function parameter is specified as a known pointer
*
* @param checkParamRefsOption true to enable
*/
public void setParamPointerRefCheck(boolean checkParamRefsOption) {
checkForParamPointerRefs = checkParamRefsOption;
}
/** /**
* enable/disable checking return for constant references * enable/disable checking return for constant references
* *

View file

@ -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
* *

View file

@ -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);
} }

View file

@ -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)) {

View file

@ -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

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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) {

View file

@ -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);

View file

@ -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);

View file

@ -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;
} }

View file

@ -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()) &&

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
} }

View file

@ -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;