mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
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:
parent
269ea1ae7a
commit
02248d2251
@ -46,6 +46,7 @@ import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.block.CodeBlock;
|
||||
import ghidra.program.model.block.PartitionCodeSubModel;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
@ -177,9 +178,9 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||
|
||||
@Override
|
||||
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,
|
||||
|
@ -70,7 +70,7 @@ public class PropagateConstantReferences extends GhidraScript {
|
||||
|
||||
// follow all flows building up context
|
||||
// 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);
|
||||
|
||||
|
@ -31,6 +31,7 @@ import ghidra.app.plugin.core.disassembler.AddressTable;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.block.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.*;
|
||||
@ -88,7 +89,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||
// use context to fill out addresses on certain instructions
|
||||
// Always trust values read from writable memory
|
||||
ConstantPropagationContextEvaluator eval =
|
||||
new ConstantPropagationContextEvaluator(true) {
|
||||
new ConstantPropagationContextEvaluator(monitor, true) {
|
||||
@Override
|
||||
public boolean evaluateDestination(VarnodeContext context,
|
||||
Instruction instruction) {
|
||||
@ -131,10 +132,13 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||
|
||||
@Override
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(true)
|
||||
.setCreateComplexDataFromPointers(true);
|
||||
|
||||
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
|
||||
symEval.setParamRefCheck(true);
|
||||
@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||
symEval.flowConstants(start, func.getBody(), eval, true, monitor);
|
||||
|
||||
// now handle symbolic execution assuming values!
|
||||
eval = new ConstantPropagationContextEvaluator() {
|
||||
eval = new ConstantPropagationContextEvaluator(monitor) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||
@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||
|
||||
@Override
|
||||
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
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
// EXIT!
|
||||
if (!(instr.getFlowType().isComputed() &&
|
||||
@ -220,6 +224,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(true)
|
||||
.setCreateComplexDataFromPointers(true);
|
||||
|
||||
// now flow with the simple block of this branch....
|
||||
|
||||
|
@ -281,7 +281,7 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
|
||||
Register syscallReg = program.getLanguage().getRegister(syscallRegister);
|
||||
for (Function func : funcsToCalls.keySet()) {
|
||||
Address start = func.getEntryPoint();
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true);
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, true);
|
||||
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
||||
symEval.flowConstants(start, func.getBody(), eval, true, tMonitor);
|
||||
for (Address callSite : funcsToCalls.get(func)) {
|
||||
|
@ -32,6 +32,7 @@ import ghidra.program.model.block.CodeBlock;
|
||||
import ghidra.program.model.block.CodeBlockReference;
|
||||
import ghidra.program.model.block.CodeBlockReferenceIterator;
|
||||
import ghidra.program.model.block.SimpleBlockModel;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.*;
|
||||
@ -474,7 +475,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
|
||||
new ContextEvaluatorAdapter() {
|
||||
@Override
|
||||
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.
|
||||
if (refType.isComputed() && refType.isFlow() &&
|
||||
program.getMemory().contains(address)) {
|
||||
|
@ -38,55 +38,71 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
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.";
|
||||
|
||||
protected static final String OPTION_NAME = "Function parameter/return Pointer analysis";
|
||||
protected static final String OPTION_DESCRIPTION =
|
||||
"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 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_DESCRIPTION =
|
||||
"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 String TRUSTWRITEMEM_OPTION_NAME =
|
||||
protected static final String TRUST_WRITEMEM_OPTION_NAME =
|
||||
"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";
|
||||
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 MAXTHREADCOUNT_OPTION_DESCRIPTION =
|
||||
protected static final String MAX_THREAD_COUNT_OPTION_NAME = "Max Threads";
|
||||
protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION =
|
||||
"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 MINKNOWNREFADDRESS_OPTION_DESCRIPTION =
|
||||
protected static final String MIN_KNOWN_REFADDRESS_OPTION_NAME = "Min absolute reference";
|
||||
protected static final String MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION =
|
||||
"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";
|
||||
protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
||||
protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
|
||||
"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";
|
||||
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
||||
"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 String MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
|
||||
"Prototype - Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
|
||||
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 boolean checkParamRefsOption = OPTION_DEFAULT_VALUE;
|
||||
protected boolean checkPointerParamRefsOption = POINTER_PARAM_OPTION_DEFAULT_VALUE;
|
||||
protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE;
|
||||
protected boolean trustWriteMemOption = TRUSTWRITEMEM_OPTION_DEFAULT_VALUE;
|
||||
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE;
|
||||
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||
protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||
protected boolean trustWriteMemOption = TRUST_WRITEMEM_OPTION_DEFAULT_VALUE;
|
||||
protected boolean createComplexDataFromPointers = CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE;
|
||||
|
||||
protected int maxThreadCount = MAX_THREAD_COUNT_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;
|
||||
|
||||
@ -105,6 +121,10 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
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.
|
||||
*
|
||||
@ -114,13 +134,25 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
handledProcessors.add(processorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to register a more specific analyzer.
|
||||
*
|
||||
* @param processorName
|
||||
*/
|
||||
static public boolean isClaimedProcessor(String processorName) {
|
||||
return handledProcessors.contains(processorName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
// Set the default for checking parameter passing
|
||||
// don't look for constant passing in things that have a small address space, or is segmented
|
||||
checkParamRefsOption = program.getDefaultPointerSize() > 2;
|
||||
checkParamRefsOption &=
|
||||
!(program.getAddressFactory().getDefaultAddressSpace() instanceof SegmentedAddressSpace);
|
||||
// unless there is a good data type at the location
|
||||
boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace();
|
||||
checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard;
|
||||
|
||||
checkParamRefsOption = !(program.getAddressFactory()
|
||||
.getDefaultAddressSpace() instanceof SegmentedAddressSpace);
|
||||
|
||||
if (processorName.equals("Basic")) {
|
||||
if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) {
|
||||
@ -129,8 +161,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
return true;
|
||||
}
|
||||
return program.getLanguage().getProcessor().equals(
|
||||
Processor.findOrPossiblyCreateProcessor(processorName));
|
||||
return program.getLanguage()
|
||||
.getProcessor()
|
||||
.equals(Processor.findOrPossiblyCreateProcessor(processorName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -138,7 +171,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
throws CancelledException {
|
||||
|
||||
AddressSet unanalyzedSet = new AddressSet(set);
|
||||
|
||||
|
||||
removeUninitializedBlocks(program, unanalyzedSet);
|
||||
|
||||
try {
|
||||
@ -434,6 +467,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
||||
symEval.setParamRefCheck(checkParamRefsOption);
|
||||
|
||||
symEval.setParamPointerRefCheck(checkPointerParamRefsOption);
|
||||
|
||||
symEval.setReturnRefCheck(checkParamRefsOption);
|
||||
symEval.setStoredRefCheck(checkStoredRefsOption);
|
||||
|
||||
@ -456,8 +492,12 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption,
|
||||
minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress);
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor)
|
||||
.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
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(STORED_OPTION_NAME, checkStoredRefsOption, null,
|
||||
STORED_OPTION_DESCRIPTION);
|
||||
options.registerOption(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption, null,
|
||||
TRUSTWRITEMEM_OPTION_DESCRIPTION);
|
||||
options.registerOption(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount, null,
|
||||
MAXTHREADCOUNT_OPTION_DESCRIPTION);
|
||||
options.registerOption(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption, null,
|
||||
TRUST_WRITEMEM_OPTION_DESCRIPTION);
|
||||
|
||||
options.registerOption(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null,
|
||||
MINKNOWNREFADDRESS_OPTION_DESCRIPTION);
|
||||
options.registerOption(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers, null,
|
||||
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();
|
||||
minSpeculativeRefAddress = size * 16;
|
||||
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
||||
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
||||
options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
||||
MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
|
||||
|
||||
maxSpeculativeRefAddress = size * 8;
|
||||
options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
|
||||
MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
||||
options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
|
||||
MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
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
|
||||
minStoreLoadRefAddress =
|
||||
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
||||
options.getLong(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
||||
minSpeculativeRefAddress =
|
||||
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
||||
options.getLong(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
||||
maxSpeculativeRefAddress =
|
||||
options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
|
||||
options.getLong(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,14 +15,24 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
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.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.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.util.ContextEvaluatorAdapter;
|
||||
import ghidra.program.util.VarnodeContext;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
* 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 {
|
||||
private static final int MAX_UNICODE_STRING_LEN = 200;
|
||||
private static final int MAX_CHAR_STRING__LEN = 100;
|
||||
protected AddressSet destSet = new AddressSet();
|
||||
private boolean trustMemoryWrite = false;
|
||||
private boolean createDataFromPointers = false;
|
||||
private long minStoreLoadOffset = 4;
|
||||
private long minSpeculativeOffset = 1024; // from the beginning 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
|
||||
*/
|
||||
public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) {
|
||||
public ConstantPropagationContextEvaluator(TaskMonitor monitor, boolean trustMemoryWrite) {
|
||||
this.monitor = monitor;
|
||||
this.trustMemoryWrite = trustMemoryWrite;
|
||||
}
|
||||
|
||||
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
|
||||
long minStoreLoadRefAddress, long minSpeculativeRefAddress,
|
||||
long maxSpeculativeRefAddress) {
|
||||
this(trustWriteMemOption);
|
||||
public ConstantPropagationContextEvaluator(TaskMonitor monitor,
|
||||
boolean trustWriteMemOption, long minStoreLoadRefAddress,
|
||||
long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
|
||||
this(monitor, trustWriteMemOption);
|
||||
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
||||
this.minSpeculativeOffset = minSpeculativeRefAddress;
|
||||
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.
|
||||
*
|
||||
@ -79,7 +153,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||
*/
|
||||
@Override
|
||||
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,
|
||||
// even if memory exists for those locations.
|
||||
@ -107,8 +181,8 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
// really there should be another callback when adding parameters
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -168,4 +475,60 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||
public boolean allowAccess(VarnodeContext context, Address addr) {
|
||||
return trustMemoryWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks at bytes at given address and converts to format String
|
||||
*
|
||||
* @param address Address of format String
|
||||
* @param pointer Pointer "type" of string
|
||||
* @return format String
|
||||
*/
|
||||
int getRestrictedStringLen(Program program, Address address, AbstractStringDataType dataType, int maxLength) {
|
||||
|
||||
maxLength = getMaxStringLength(program, address, maxLength);
|
||||
|
||||
MemoryBufferImpl memoryBuffer =
|
||||
new MemoryBufferImpl(program.getMemory(), address);
|
||||
|
||||
StringDataInstance stringDataInstance = dataType.getStringDataInstance(memoryBuffer, dataType.getDefaultSettings(), -1);
|
||||
stringDataInstance.getStringDataTypeGuess();
|
||||
|
||||
int detectedLength = stringDataInstance.getStringLength();
|
||||
if (detectedLength == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (detectedLength > maxLength) {
|
||||
detectedLength = maxLength;
|
||||
}
|
||||
|
||||
return detectedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes to the next reference, or the max length
|
||||
*
|
||||
* @param program
|
||||
* @param address
|
||||
* @return maximum length to create the string
|
||||
*/
|
||||
private int getMaxStringLength(Program program, Address address, int maxLen) {
|
||||
AddressIterator refIter = program.getReferenceManager().getReferenceDestinationIterator(address.next(), true);
|
||||
Address next = refIter.next();
|
||||
if (next == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long len = -1;
|
||||
try {
|
||||
len = next.subtract(address);
|
||||
if (len > maxLen) {
|
||||
len = maxLen;
|
||||
}
|
||||
return (int) len;
|
||||
} catch (IllegalArgumentException exc) {
|
||||
// bad address subtraction
|
||||
}
|
||||
return (int) len;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import ghidra.framework.options.Options;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
@ -144,7 +145,17 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
||||
pointerEnabled = 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
|
||||
int bitSize = defaultAddressSpace.getSize();
|
||||
return bitSize > 16;
|
||||
|
@ -16,6 +16,7 @@
|
||||
package ghidra.program.util;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
@ -56,12 +57,13 @@ public interface ContextEvaluator {
|
||||
* @param pcodeop the PcodeOp operation that is causing this reference
|
||||
* @param address address being referenced
|
||||
* @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)
|
||||
*
|
||||
* @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,
|
||||
RefType refType);
|
||||
DataType dataType, RefType refType);
|
||||
|
||||
/**
|
||||
* 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 constant constant value (in constant.getOffset() )
|
||||
* @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)
|
||||
*
|
||||
* @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
|
||||
* 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
|
||||
|
@ -16,6 +16,7 @@
|
||||
package ghidra.program.util;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
@ -40,13 +41,13 @@ public class ContextEvaluatorAdapter implements ContextEvaluator {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||
int size, RefType refType) {
|
||||
int size, DataType dataType, RefType refType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,13 @@ import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
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.Varnode;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.BigEndianDataConverter;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@ -62,6 +63,7 @@ public class SymbolicPropogator {
|
||||
protected boolean readExecutableAddress;
|
||||
protected VarnodeContext context;
|
||||
|
||||
protected AddressSet body; // body of processed instructions
|
||||
protected boolean hitCodeFlow = false; // no branching so far
|
||||
|
||||
protected boolean debug = false;
|
||||
@ -73,6 +75,8 @@ public class SymbolicPropogator {
|
||||
new NotFoundException("Divide by zero");
|
||||
|
||||
private long pointerMask;
|
||||
private int pointerSize;
|
||||
private DataType pointerSizedDT = null;
|
||||
|
||||
protected static final int MAX_EXACT_INSTRUCTIONS = 100;
|
||||
|
||||
@ -119,7 +123,9 @@ public class SymbolicPropogator {
|
||||
if (ptrSize > 8) {
|
||||
ptrSize = 8;
|
||||
}
|
||||
pointerSize = ptrSize;
|
||||
pointerMask = maskSize[ptrSize];
|
||||
pointerSizedDT = IntegerDataType.getUnsignedDataType(pointerSize, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -297,7 +303,7 @@ public class SymbolicPropogator {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
if (val.isConstant()) {
|
||||
if (context.isConstant(val)) {
|
||||
return new Value(val.getOffset());
|
||||
}
|
||||
AddressSpace space = val.getAddress().getAddressSpace();
|
||||
@ -390,6 +396,7 @@ public class SymbolicPropogator {
|
||||
protected int sameInstrCount = 0; // # of the same instructions
|
||||
|
||||
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 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,
|
||||
ContextEvaluator eval, VarnodeContext vContext, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
AddressSet body = new AddressSet();
|
||||
body = new AddressSet();
|
||||
AddressSet conflicts = new AddressSet();
|
||||
|
||||
// prime the context stack with the entry point address
|
||||
@ -762,7 +769,8 @@ public class SymbolicPropogator {
|
||||
}
|
||||
|
||||
Address minInstrAddress = instruction.getMinAddress();
|
||||
if (debug) {
|
||||
if (debug)
|
||||
{
|
||||
Msg.info(this, minInstrAddress + " " + instruction);
|
||||
}
|
||||
|
||||
@ -788,6 +796,7 @@ public class SymbolicPropogator {
|
||||
Varnode val1, val2, val3, result;
|
||||
long lval1, lval2;
|
||||
long lresult;
|
||||
boolean suspectOffset = false;
|
||||
Varnode vt;
|
||||
if (debug) {
|
||||
Msg.info(this, " " + pcodeOp);
|
||||
@ -798,8 +807,8 @@ public class SymbolicPropogator {
|
||||
case PcodeOp.COPY:
|
||||
if (in[0].isAddress() &&
|
||||
!in[0].getAddress().getAddressSpace().hasMappedRegisters()) {
|
||||
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0],
|
||||
RefType.READ, monitor);
|
||||
makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
|
||||
null, RefType.READ, ptype, true, monitor);
|
||||
}
|
||||
vContext.copy(out, in[0], mustClearAll, evaluator);
|
||||
break;
|
||||
@ -808,23 +817,35 @@ public class SymbolicPropogator {
|
||||
val1 = vContext.getValue(in[0], evaluator);
|
||||
val2 = vContext.getValue(in[1], evaluator);
|
||||
|
||||
suspectOffset = vContext.isSuspectConstant(val2);
|
||||
|
||||
vt = vContext.getVarnode(in[0], val2, out.getSize(), evaluator);
|
||||
|
||||
|
||||
// TODO: may need to use DATA refType in some cases
|
||||
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
|
||||
Varnode memVal = vContext.getValue(vt, evaluator);
|
||||
vContext.putValue(out, memVal, mustClearAll);
|
||||
|
||||
break;
|
||||
|
||||
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
|
||||
addLoadStoreReference(vContext, instruction, ptype, out, in[0], in[1],
|
||||
RefType.WRITE, monitor);
|
||||
RefType.WRITE, suspectOffset==false, monitor);
|
||||
|
||||
val3 = vContext.getValue(in[2], null);
|
||||
|
||||
@ -837,9 +858,11 @@ public class SymbolicPropogator {
|
||||
case PcodeOp.BRANCHIND:
|
||||
try {
|
||||
val1 = vContext.getValue(in[0], evaluator);
|
||||
suspectOffset = vContext.isSuspectConstant(val1);
|
||||
|
||||
vt = getConstantOrExternal(vContext, minInstrAddress, val1);
|
||||
makeReference(vContext, instruction, ptype, -1, vt,
|
||||
instruction.getFlowType(), monitor);
|
||||
makeReference(vContext, instruction, -1, vt, null,
|
||||
instruction.getFlowType(), ptype, !suspectOffset, monitor);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
// constant not found, ignore
|
||||
@ -873,7 +896,8 @@ public class SymbolicPropogator {
|
||||
|
||||
// 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)
|
||||
target = instruction.getAddress()
|
||||
.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
|
||||
if (refs.length <= 0 ||
|
||||
!refs[0].getToAddress().equals(target)) {
|
||||
makeReference(vContext, instruction, Reference.MNEMONIC,
|
||||
target = makeReference(vContext, instruction, Reference.MNEMONIC,
|
||||
// Use target in case location has shifted (external...)
|
||||
target.getAddressSpace().getSpaceID(),
|
||||
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:
|
||||
if (in[0].isAddress()) {
|
||||
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0],
|
||||
RefType.READ, monitor);
|
||||
makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
|
||||
null, RefType.READ, ptype, true, monitor);
|
||||
}
|
||||
val1 = vContext.extendValue(out, in, false, evaluator);
|
||||
vContext.putValue(out, val1, mustClearAll);
|
||||
@ -1112,8 +1137,8 @@ public class SymbolicPropogator {
|
||||
|
||||
case PcodeOp.INT_SEXT:
|
||||
if (in[0].isAddress()) {
|
||||
makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0],
|
||||
RefType.READ, monitor);
|
||||
makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
|
||||
null, RefType.READ, ptype, true, monitor);
|
||||
}
|
||||
val1 = vContext.extendValue(out, in, true, evaluator);
|
||||
vContext.putValue(out, val1, mustClearAll);
|
||||
@ -1453,17 +1478,18 @@ public class SymbolicPropogator {
|
||||
}
|
||||
return vt;
|
||||
}
|
||||
|
||||
private Varnode getStoredLocation(VarnodeContext vContext, Varnode[] in) {
|
||||
|
||||
private Varnode getStoredLocation(VarnodeContext vContext, Varnode space, Varnode offset, Varnode size) {
|
||||
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
|
||||
// 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) {
|
||||
// if can't get the value of the relative store location
|
||||
@ -1482,6 +1508,7 @@ public class SymbolicPropogator {
|
||||
}
|
||||
Address fallThruAddr = instruction.getFallThrough();
|
||||
// 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 ||
|
||||
target.getOffset() != fallThruAddr.getOffset()) {
|
||||
|
||||
@ -1490,7 +1517,7 @@ public class SymbolicPropogator {
|
||||
if (checkForParamRefs && evaluator != null &&
|
||||
evaluator.evaluateReference(context, instruction, PcodeOp.UNIMPLEMENTED,
|
||||
(target == null ? Address.NO_ADDRESS : target), 0,
|
||||
RefType.UNCONDITIONAL_CALL)) {
|
||||
null, RefType.UNCONDITIONAL_CALL)) {
|
||||
// put references on any register parameters with values in
|
||||
// them.
|
||||
addParamReferences(targetFunc, target, instruction, context, monitor);
|
||||
@ -1503,6 +1530,14 @@ public class SymbolicPropogator {
|
||||
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
|
||||
@ -1688,7 +1723,7 @@ public class SymbolicPropogator {
|
||||
ArrayList<Varnode> inputs = new ArrayList<Varnode>();
|
||||
for (int i = 1; i < ins.length; i++) {
|
||||
Varnode vval = context.getValue(ins[i], evaluator);
|
||||
if (!vval.isConstant()) {
|
||||
if (!context.isConstant(vval)) {
|
||||
return null;
|
||||
}
|
||||
inputs.add(vval);
|
||||
@ -1786,6 +1821,9 @@ public class SymbolicPropogator {
|
||||
int callStackMod = model.getExtrapop();
|
||||
int callStackShift = model.getStackshift();
|
||||
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;
|
||||
}
|
||||
if (depth == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
||||
@ -1825,7 +1863,7 @@ public class SymbolicPropogator {
|
||||
}
|
||||
|
||||
// don't check for params on external calls
|
||||
if ((callTarget != null) && callTarget.isExternalAddress()) {
|
||||
if (callTarget != null && callTarget.isExternalAddress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1847,29 +1885,58 @@ public class SymbolicPropogator {
|
||||
params = func.getParameters();
|
||||
signatureSource = func.getSignatureSource();
|
||||
}
|
||||
else if (checkForParamPointerRefs) {
|
||||
// no function chan't check for pointer types
|
||||
return;
|
||||
}
|
||||
|
||||
long callOffset = (callTarget == null ? -1 : callTarget.getOffset());
|
||||
|
||||
// If there are params defined or the params were specified (meaning it could be VOID params)
|
||||
boolean signatureAssigned = signatureSource != SourceType.DEFAULT;
|
||||
boolean trustSignature = signatureAssigned || params.length > 0;
|
||||
if (trustSignature) {
|
||||
if (trustSignature && !func.hasVarArgs()) {
|
||||
// Loop through defined parameters for a valid address value
|
||||
for (Parameter param : params) {
|
||||
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,
|
||||
p.getVariableStorage(), callOffset);
|
||||
// use the varnode to pull out the bytes from the varnode
|
||||
// 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
|
||||
VariableStorage[] vars = conv.getPotentialInputRegisterStorage(program);
|
||||
for (VariableStorage var : vars) {
|
||||
createVariableStorageReference(instruction, varnodeContext, monitor, var,
|
||||
callOffset);
|
||||
// only check the first seven param locations, if don't have a signature
|
||||
for (int pi=0; pi < 8; pi++) {
|
||||
// TODO Should cache the arg locations for each convention
|
||||
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;
|
||||
}
|
||||
|
||||
createVariableStorageReference(instruction, varnodeContext, monitor, returnLoc, 0);
|
||||
createVariableStorageReference(instruction, varnodeContext, monitor, null, returnLoc, null, 0);
|
||||
}
|
||||
|
||||
private void addLoadStoreReference(VarnodeContext vContext, Instruction instruction,
|
||||
int pcodeType, Varnode refLocation, Varnode targetSpaceID, Varnode assigningVarnode,
|
||||
RefType reftype, TaskMonitor monitor) {
|
||||
RefType reftype, boolean knownReference, TaskMonitor monitor) {
|
||||
|
||||
// no output or load
|
||||
if (refLocation == null) {
|
||||
@ -1906,7 +1973,7 @@ public class SymbolicPropogator {
|
||||
int opIndex = findOperandWithVarnodeAssignment(instruction, assigningVarnode);
|
||||
|
||||
if (instruction.getFlowType().isCall()) {
|
||||
makeReference(vContext, instruction, pcodeType, opIndex, refLocation, reftype, monitor);
|
||||
makeReference(vContext, instruction, opIndex, refLocation, null, reftype, pcodeType, knownReference, monitor);
|
||||
}
|
||||
else {
|
||||
int spaceID = refLocation.getSpace();
|
||||
@ -1915,35 +1982,25 @@ public class SymbolicPropogator {
|
||||
long offset = refLocation.getOffset();
|
||||
|
||||
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) {
|
||||
Address constant = program.getAddressFactory()
|
||||
.getAddress((int) targetSpaceID.getOffset(), offset);
|
||||
Address newTarget = evaluator.evaluateConstant(vContext, instruction,
|
||||
pcodeType, constant, 0, reftype);
|
||||
if (newTarget != null) {
|
||||
pcodeType, constant, 0, null, reftype);
|
||||
// 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,
|
||||
newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(), 0,
|
||||
reftype, pcodeType, false, monitor);
|
||||
null, reftype.DATA, pcodeType, false, false, monitor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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
|
||||
|
||||
if (!valueToStore.isConstant()) {
|
||||
if (!vContext.isConstant(valueToStore)) {
|
||||
return;
|
||||
}
|
||||
|
||||
long valueOffset = valueToStore.getOffset();
|
||||
|
||||
makeReference(vContext, instruction, -1, -1, valueOffset, 0, RefType.DATA, PcodeOp.STORE,
|
||||
false, monitor);
|
||||
makeReference(vContext, instruction, -1, -1, valueOffset, 0, null, RefType.DATA, PcodeOp.STORE,
|
||||
false, false, monitor);
|
||||
}
|
||||
|
||||
private void createVariableStorageReference(Instruction instruction,
|
||||
VarnodeContext varnodeContext, TaskMonitor monitor, VariableStorage storage,
|
||||
long callOffset) {
|
||||
VarnodeContext varnodeContext, TaskMonitor monitor, PrototypeModel conv, VariableStorage storage,
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
createRegisterStorageReference(instruction, varnodeContext, monitor, callOffset, rval);
|
||||
|
||||
makeVariableStorageReference(storage, instruction, varnodeContext, monitor, callOffset, dataType, lastSetAddr, bval);
|
||||
}
|
||||
|
||||
private void createRegisterStorageReference(Instruction instruction,
|
||||
VarnodeContext varnodeContext, TaskMonitor monitor, long callOffset,
|
||||
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();
|
||||
}
|
||||
}
|
||||
private void makeVariableStorageReference(VariableStorage storage, Instruction instruction, VarnodeContext varnodeContext,
|
||||
TaskMonitor monitor, long callOffset, DataType dataType, Address lastSetAddr, BigInteger bval) {
|
||||
|
||||
if (lastSetAddr == null) {
|
||||
lastSetAddr = instruction.getMaxAddress();
|
||||
}
|
||||
@ -2067,30 +2168,74 @@ public class SymbolicPropogator {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastSetAddr != null) {
|
||||
Instruction instr = instruction;
|
||||
// last setAddr could be in the base 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 (refAddr.getOffset() == addr.getOffset()) {
|
||||
found = true;
|
||||
break;
|
||||
if (lastSetAddr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the dataType is known, try to interpret it to an address given the
|
||||
// bytes in the storage location
|
||||
int knownSpaceID = -1;
|
||||
boolean knownReference = false;
|
||||
if (dataType != null) {
|
||||
if ((dataType instanceof TypeDef typedef && typedef.isPointer())) {
|
||||
// pointer type defs need to be handled specially they could be re-mapping to another space
|
||||
// or interpretting the value
|
||||
Object value = getPointerDataTypeValue(dataType, lastSetAddr, bval);
|
||||
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,
|
||||
PcodeOp.UNIMPLEMENTED, false, monitor);
|
||||
}
|
||||
|
||||
// last setAddr could be in the base instruction
|
||||
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
|
||||
*
|
||||
@ -2219,20 +2364,22 @@ public class SymbolicPropogator {
|
||||
* @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 refType - type of reference
|
||||
* @param knownReference true if this is a know good address, speculative otherwise
|
||||
* @param monitor to cancel
|
||||
* @return address that was marked up, null otherwise
|
||||
*/
|
||||
public void makeReference(VarnodeContext varnodeContext, Instruction instruction, int pcodeop,
|
||||
int opIndex, Varnode vt, RefType refType, TaskMonitor monitor) {
|
||||
public Address makeReference(VarnodeContext varnodeContext, Instruction instruction, int opIndex, Varnode vt, DataType dataType, RefType refType,
|
||||
int pcodeop, boolean knownReference, TaskMonitor monitor) {
|
||||
if (!vt.isAddress() && !varnodeContext.isExternalSpace(vt.getSpace())) {
|
||||
if (evaluator != null) {
|
||||
evaluator.evaluateSymbolicReference(varnodeContext, instruction, vt.getAddress());
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// offset must be word based to compute the reference correctly
|
||||
makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(),
|
||||
vt.getSize(), refType, pcodeop, true, monitor);
|
||||
return makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(),
|
||||
vt.getSize(), dataType, refType, pcodeop, knownReference, false, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2252,17 +2399,20 @@ public class SymbolicPropogator {
|
||||
* @param refType - type of reference
|
||||
* @param pcodeop - op that caused the reference
|
||||
* @param knownReference - true if reference is known to be a real reference, not speculative
|
||||
* @param preExisting preExisting reference
|
||||
* @param monitor - the task monitor
|
||||
* @return address that was marked up, null otherwise
|
||||
|
||||
*/
|
||||
public void makeReference(VarnodeContext vContext, Instruction instruction, int opIndex,
|
||||
long knownSpaceID, long wordOffset, int size, RefType refType, int pcodeop,
|
||||
boolean knownReference, TaskMonitor monitor) {
|
||||
public Address makeReference(VarnodeContext vContext, Instruction instruction, int opIndex,
|
||||
long knownSpaceID, long wordOffset, int size, DataType dataType, RefType refType, int pcodeop,
|
||||
boolean knownReference, boolean preExisting, TaskMonitor monitor) {
|
||||
|
||||
long spaceID = knownSpaceID;
|
||||
if (spaceID == -1) { // speculative reference - only offset is known
|
||||
spaceID = getReferenceSpaceID(instruction, wordOffset);
|
||||
if (spaceID == -1) {
|
||||
return; // don't make speculative reference
|
||||
return null; // don't make speculative reference
|
||||
}
|
||||
}
|
||||
|
||||
@ -2278,12 +2428,12 @@ public class SymbolicPropogator {
|
||||
else {
|
||||
// do checks that are actual memory, and not fabricated externals
|
||||
if (!space.isLoadedMemorySpace()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// 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)
|
||||
if (wordOffset == 0) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// wrap offset within address space
|
||||
@ -2301,7 +2451,7 @@ public class SymbolicPropogator {
|
||||
|
||||
// don't make references to registers
|
||||
if (space.hasMappedRegisters() && program.getRegister(target) != null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// normalize the address into this overlay space.
|
||||
@ -2312,38 +2462,24 @@ public class SymbolicPropogator {
|
||||
// it could be in a non-allocated memory space
|
||||
// TODO: Really at this point it should be a constant, and put on a list
|
||||
// to be considered later as a pointer.
|
||||
if (!program.getReferenceManager().hasReferencesTo(target)) {
|
||||
return;
|
||||
// allow flow references to memory not in program
|
||||
// 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 (refType.isCall() && !refType.isComputed()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// give evaluator a chance to stop or change the reference
|
||||
if (evaluator != null) {
|
||||
// if this was a speculative reference, pass to the evaluateConstant
|
||||
if (knownSpaceID == -1 || !knownReference) {
|
||||
Address constant = program.getAddressFactory().getConstantAddress(wordOffset);
|
||||
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;
|
||||
}
|
||||
}
|
||||
target = evaluateReference(vContext, instruction, knownSpaceID, wordOffset, size,
|
||||
dataType, refType, pcodeop, knownReference, target);
|
||||
if (target == null || preExisting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Pure data references need to be scrutinized
|
||||
@ -2351,7 +2487,7 @@ public class SymbolicPropogator {
|
||||
//
|
||||
if (refType.isData() &&
|
||||
!evaluatePureDataRef(instruction, wordOffset, refType, target)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
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
|
||||
Address[] flows = getInstructionFlows(instruction);
|
||||
if (flows.length > 1) {
|
||||
return;
|
||||
return target;
|
||||
}
|
||||
for (Address address : flows) {
|
||||
if (address.equals(target)) {
|
||||
return;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType);
|
||||
@ -2379,7 +2515,7 @@ public class SymbolicPropogator {
|
||||
if (!instruction.getFlowType().equals(refType)) {
|
||||
instruction = instruction.getNext();
|
||||
if (instruction == null) {
|
||||
return;
|
||||
return target;
|
||||
}
|
||||
opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType);
|
||||
}
|
||||
@ -2406,19 +2542,39 @@ public class SymbolicPropogator {
|
||||
else {
|
||||
instruction.addOperandReference(opIndex, target, refType, SourceType.ANALYSIS);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
if (refType.isData()) {
|
||||
createData(target, size);
|
||||
private Address evaluateReference(VarnodeContext vContext, Instruction instruction,
|
||||
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() &&
|
||||
!program.getMemory().isExternalBlockAddress(target)) {
|
||||
Data udata = program.getListing().getUndefinedDataAt(target);
|
||||
if (udata != null) {
|
||||
DisassembleCommand cmd = new DisassembleCommand(target, null, true);
|
||||
cmd.applyTo(program, monitor);
|
||||
// if this was a speculative reference, pass to the evaluateConstant
|
||||
if (knownSpaceID == -1 || !knownReference) {
|
||||
Address constant = program.getAddressFactory().getConstantAddress(wordOffset);
|
||||
Address newTarget = evaluator.evaluateConstant(vContext, instruction, pcodeop,
|
||||
constant, size, dataType, refType);
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
long wordOffset, RefType refType) {
|
||||
|
||||
@ -2648,6 +2778,16 @@ public class SymbolicPropogator {
|
||||
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
|
||||
*
|
||||
|
@ -19,11 +19,12 @@ import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Undefined;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
@ -38,8 +39,6 @@ import ghidra.util.exception.*;
|
||||
|
||||
public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
public static final int BAD_SPACE_ID_VALUE = 0xffff;
|
||||
|
||||
protected DisassemblerContextImpl offsetContext;
|
||||
protected DisassemblerContextImpl spaceContext;
|
||||
|
||||
@ -63,6 +62,10 @@ public class VarnodeContext implements ProcessorContext {
|
||||
protected VarnodeTranslator trans; // translator for varnodes<-->registers
|
||||
|
||||
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 Register stackReg = null;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
@ -92,8 +102,15 @@ public class VarnodeContext implements ProcessorContext {
|
||||
this.addrFactory = new OffsetAddressFactory(program);
|
||||
|
||||
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
|
||||
BAD_SPACE_ID_VALUE = BAD_ADDRESS.getAddressSpace().getSpaceID();
|
||||
|
||||
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;
|
||||
|
||||
@ -293,6 +310,48 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
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)
|
||||
throws NotFoundException {
|
||||
// for constant, return the constant value
|
||||
if (varnode.isConstant()) {
|
||||
if (isConstant(varnode)) {
|
||||
return varnode;
|
||||
}
|
||||
Varnode rvnode = null;
|
||||
@ -383,21 +442,26 @@ public class VarnodeContext implements ProcessorContext {
|
||||
if (bigVal != null) {
|
||||
|
||||
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());
|
||||
if (rvnode == null) {
|
||||
throw notFoundExc;
|
||||
}
|
||||
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
|
||||
if (debug) {
|
||||
Msg.info(this, " " + reg.getName() + " = " + print(rvnode));
|
||||
}
|
||||
|
||||
|
||||
if (debug) {
|
||||
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...
|
||||
}
|
||||
|
||||
@ -418,12 +482,6 @@ public class VarnodeContext implements ProcessorContext {
|
||||
if (debug) {
|
||||
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.
|
||||
// can't count on the offset staying the same.
|
||||
if (isSymbolicAddr) {
|
||||
@ -431,15 +489,9 @@ public class VarnodeContext implements ProcessorContext {
|
||||
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
|
||||
// figure out what register is used for stack values
|
||||
Register stackRegister = getStackRegister();
|
||||
if (!isStackSymbolicSpace(varnode)) {
|
||||
if (debug) {
|
||||
Msg.info(this,
|
||||
"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) {
|
||||
|
||||
// don't allow a zero/-1 constant pulled from a symbolic space.
|
||||
if (isConstant(lvalue) && (lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) {
|
||||
throw notFoundExc;
|
||||
}
|
||||
}
|
||||
@ -520,7 +572,8 @@ public class VarnodeContext implements ProcessorContext {
|
||||
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) {
|
||||
@ -642,9 +695,11 @@ public class VarnodeContext implements ProcessorContext {
|
||||
AddressSpace spc = addrFactory.getAddressSpace(spaceID);
|
||||
Address addr = null;
|
||||
|
||||
if (spaceID == BAD_SPACE_ID_VALUE || spc == null ||
|
||||
spc.equals(BAD_ADDRESS.getAddressSpace())) {
|
||||
if (spaceID == BAD_SPACE_ID_VALUE || spc == null) {
|
||||
addr = BAD_ADDRESS;
|
||||
} else if (spaceID == BAD_OFFSET_SPACEID) {
|
||||
// special case of unknown value + constant
|
||||
addr = spc.getTruncatedAddress(value, true);
|
||||
}
|
||||
else {
|
||||
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
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// don't ever store an unknown unique into a location
|
||||
if (result != null && result.isUnique()) {
|
||||
result = null;
|
||||
@ -715,6 +776,20 @@ public class VarnodeContext implements ProcessorContext {
|
||||
tempUniqueVals.put(out.getOffset(), result);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -907,7 +982,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
|
||||
public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException {
|
||||
if (!vnode.isConstant()) {
|
||||
if (!isConstant(vnode)) {
|
||||
if (evaluator == null) {
|
||||
throw notFoundExc;
|
||||
}
|
||||
@ -940,6 +1015,12 @@ public class VarnodeContext implements ProcessorContext {
|
||||
valbase = offset.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)) {
|
||||
if (evaluator == null) {
|
||||
throw notFoundExc;
|
||||
@ -1037,7 +1118,10 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1054,7 +1138,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
/**
|
||||
* 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 in varnode to copy from.
|
||||
@ -1067,8 +1151,10 @@ public class VarnodeContext implements ProcessorContext {
|
||||
Varnode val1 = null;
|
||||
val1 = getValue(in, evaluator);
|
||||
// if truncating a constant get a new constant of the proper size
|
||||
if (val1 != null && val1.isConstant() && in.getSize() > out.getSize()) {
|
||||
val1 = createConstantVarnode(val1.getOffset(), out.getSize());
|
||||
if (val1 != null && in.getSize() > out.getSize()) {
|
||||
if (isConstant(val1)) {
|
||||
val1 = createVarnode(val1.getOffset(), val1.getSpace(), out.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
if (!in.isRegister() || !out.isRegister()) {
|
||||
@ -1097,7 +1183,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
throws NotFoundException {
|
||||
|
||||
// try to make the constant value the addend.
|
||||
if (val1.isConstant() || val1.isAddress()) {
|
||||
if (isConstant(val1) || val1.isAddress()) {
|
||||
Varnode swap = val1;
|
||||
val1 = val2;
|
||||
val2 = swap;
|
||||
@ -1142,8 +1228,11 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (val1.isConstant()) {
|
||||
else if (isConstant(val1)) {
|
||||
valbase = val1.getOffset();
|
||||
if (!isSuspectConstant(val1)) {
|
||||
spaceID = val2.getSpace();
|
||||
}
|
||||
}
|
||||
else if (isSymbolicSpace(spaceID)) {
|
||||
Instruction instr = getCurrentInstruction(offsetContext.getAddress());
|
||||
@ -1181,7 +1270,6 @@ public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
throw notFoundExc;
|
||||
@ -1199,7 +1287,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
if (val1.equals(val2)) {
|
||||
return val1;
|
||||
}
|
||||
if (val1.isConstant() || val1.isAddress()) {
|
||||
if (isConstant(val1) || val1.isAddress()) {
|
||||
Varnode swap = val1;
|
||||
val1 = val2;
|
||||
val2 = swap;
|
||||
@ -1216,6 +1304,9 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
else if (val1.isConstant()) {
|
||||
valbase = val1.getOffset();
|
||||
if (!isSuspectConstant(val1)) {
|
||||
spaceID = val2.getSpace();
|
||||
}
|
||||
}
|
||||
else if (isSymbolicSpace(spaceID)) {
|
||||
valbase = val1.getOffset();
|
||||
@ -1244,25 +1335,29 @@ public class VarnodeContext implements ProcessorContext {
|
||||
return val1;
|
||||
}
|
||||
|
||||
if (val1.isConstant() || val1.isAddress()) {
|
||||
if (isConstant(val1) || val1.isAddress()) {
|
||||
Varnode swap = val1;
|
||||
val1 = val2;
|
||||
val2 = swap;
|
||||
}
|
||||
int spaceID = val1.getSpace();
|
||||
long val2Const = getConstant(val2, null);
|
||||
// got a constant from val2, (value | 0) == value, so just return value
|
||||
if (val2Const == 0) {
|
||||
return val1;
|
||||
if (!isSuspectConstant(val2)) {
|
||||
return val1;
|
||||
}
|
||||
spaceID = val2.getSpace();
|
||||
}
|
||||
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)
|
||||
throws NotFoundException {
|
||||
long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator);
|
||||
lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
|
||||
Varnode result = createConstantVarnode(lresult, val1.getSize());
|
||||
Varnode result = createVarnode(lresult, val1.getSpace(), val1.getSize());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1306,8 +1401,11 @@ public class VarnodeContext implements ProcessorContext {
|
||||
}
|
||||
int spaceID = val1.getSpace();
|
||||
long valbase = 0;
|
||||
if (val1.isConstant()) {
|
||||
if (isConstant(val1)) {
|
||||
valbase = val1.getOffset();
|
||||
if (!isSuspectConstant(val1)) {
|
||||
spaceID = val2.getSpace();
|
||||
}
|
||||
}
|
||||
else if (isRegister(val1)) {
|
||||
Register reg = trans.getRegister(val1);
|
||||
@ -1329,7 +1427,6 @@ public class VarnodeContext implements ProcessorContext {
|
||||
return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
throw notFoundExc;
|
||||
@ -1353,15 +1450,15 @@ public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
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
|
||||
if (vnodeVal.getSize() <= 8) {
|
||||
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 {
|
||||
// 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()) {
|
||||
@ -1414,7 +1511,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
Varnode regVnode = trans.getVarnode(register);
|
||||
try {
|
||||
Varnode value = this.getValue(regVnode, false, null);
|
||||
if (value.isConstant()) {
|
||||
if (isConstant(value)) {
|
||||
return new RegisterValue(register, BigInteger.valueOf(value.getOffset()));
|
||||
}
|
||||
}
|
||||
@ -1457,7 +1554,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||
Varnode regVnode = trans.getVarnode(register);
|
||||
try {
|
||||
Varnode value = this.getValue(regVnode, signed, null);
|
||||
if (value.isConstant()) {
|
||||
if (isConstant(value)) {
|
||||
return BigInteger.valueOf(value.getOffset());
|
||||
}
|
||||
}
|
||||
@ -1503,7 +1600,33 @@ public class VarnodeContext implements ProcessorContext {
|
||||
public boolean isRegister(Varnode varnode) {
|
||||
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
|
||||
*
|
||||
|
@ -98,18 +98,11 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
||||
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" +
|
||||
"af bc 00 10 3c 07 12 34 24 e7 45 67" +
|
||||
"ac a7 00 10 3c 06 0a 0b 24 c6 0c 0d" +
|
||||
"ae 06 00 10 8e 11 00 10 8c b1 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" +
|
||||
"3c 11 00 53" +
|
||||
"8e 51 00 10" +
|
||||
"03 e0 00 08" +
|
||||
"27 bd 00 20");
|
||||
"af bc 00 10 3c 07 12 34 24 e7 45 67 ac a7 00 10" +
|
||||
"3c 06 0a 0b 24 c6 0c 0d ae 06 00 10 8e 11 00 10" +
|
||||
"8c b1 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" +
|
||||
"3c 11 00 53 8e 51 00 10 03 e0 00 08 27 bd 00 20");
|
||||
|
||||
//00001000 lui gp,0x14
|
||||
//00001004 addiu gp,gp,-0x4ccc
|
||||
@ -153,7 +146,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true) {
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(TaskMonitor.DUMMY, true) {
|
||||
@Override
|
||||
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||
|
||||
@ -176,8 +169,92 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
||||
registerVarnode = regValue(context,"gp");
|
||||
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
||||
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;
|
||||
// TODO: more tests
|
||||
}
|
||||
return super.evaluateContext(context, instr);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.block.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
@ -364,7 +365,7 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
new ContextEvaluatorAdapter() {
|
||||
@Override
|
||||
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.
|
||||
if (refType.isComputed() && refType.isFlow() &&
|
||||
program.getMemory().contains(address)) {
|
||||
|
@ -21,9 +21,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.util.GhidraDataConverter;
|
||||
|
||||
/**
|
||||
* Simple byte buffer implementation of the memBuffer. Since there is no
|
||||
* actual memory object associated with this object, the getMemory method
|
||||
* is not implemented and all gets are limited to the bytes supplied during
|
||||
* Simple byte buffer implementation of the memBuffer. Even if a Memory is
|
||||
* provided, the available bytes will be limited to the bytes provided during
|
||||
* construction.
|
||||
*/
|
||||
public class ByteMemBufferImpl implements MemBuffer {
|
||||
@ -31,6 +30,7 @@ public class ByteMemBufferImpl implements MemBuffer {
|
||||
private final GhidraDataConverter converter;
|
||||
private byte[] bytes;
|
||||
private Address addr;
|
||||
private Memory mem;
|
||||
|
||||
/**
|
||||
* Construct a ByteMemBufferImpl object
|
||||
@ -39,9 +39,22 @@ public class ByteMemBufferImpl implements MemBuffer {
|
||||
* @param isBigEndian true for BigEndian, false for LittleEndian.
|
||||
*/
|
||||
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.bytes = bytes;
|
||||
this.converter = GhidraDataConverter.getInstance(isBigEndian);
|
||||
this.mem = memory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +80,7 @@ public class ByteMemBufferImpl implements MemBuffer {
|
||||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
return null;
|
||||
return mem;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +66,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ConstantPropagationContextEvaluator eval =
|
||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
@Override
|
||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||
String mnemonic = instr.getMnemonicString();
|
||||
@ -124,7 +124,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
@ -132,7 +132,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -153,6 +153,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||
|
||||
@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import ghidra.app.services.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
@ -190,7 +191,7 @@ public class AARCH64PltThunkAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||
int size, RefType refType) {
|
||||
int size, DataType dataType, RefType refType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ConstantPropagationContextEvaluator eval =
|
||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
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
|
||||
Varnode lrVal = context.getRegisterVarnodeValue(lrRegister);
|
||||
if (lrVal != null) {
|
||||
if (lrVal.isConstant()) {
|
||||
if (context.isConstant(lrVal)) {
|
||||
long target = lrVal.getAddress().getOffset();
|
||||
Address addr = instr.getMaxAddress().add(1);
|
||||
if (target == addr.getOffset() && !instr.getFlowType().isCall()) {
|
||||
@ -176,7 +176,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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() &&
|
||||
program.getMemory().contains(address) && address.getOffset() != 0) {
|
||||
if (instr.getMnemonicString().startsWith("tb")) {
|
||||
@ -184,24 +184,29 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
}
|
||||
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
||||
true, monitor);
|
||||
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
return !symEval.encounteredBranch();
|
||||
}
|
||||
if (refType.isData() && program.getMemory().contains(address)) {
|
||||
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);
|
||||
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
|
||||
SourceType.ANALYSIS);
|
||||
return false;
|
||||
if (numOperands <= 2) {
|
||||
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
|
||||
SourceType.ANALYSIS);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
|
||||
// must disassemble right now, because TB flag could get set back at end of blx
|
||||
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
||||
true, monitor);
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
|
||||
// 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();
|
||||
if (offset > 3 && offset != -1) {
|
||||
// need to override the return to a branch
|
||||
@ -236,6 +241,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||
|
||||
@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 (address == null) {
|
||||
|
@ -25,6 +25,7 @@ import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
@ -247,7 +248,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// 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 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
|
||||
Varnode raVal = context.getRegisterVarnodeValue(rareg);
|
||||
if (raVal != null) {
|
||||
if (raVal.isConstant()) {
|
||||
if (context.isConstant(raVal)) {
|
||||
long target = raVal.getAddress().getOffset();
|
||||
Address addr = instr.getMaxAddress();
|
||||
if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) {
|
||||
@ -317,22 +318,25 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
lastSetInstr = instructionAt;
|
||||
}
|
||||
}
|
||||
symEval.makeReference(context, lastSetInstr, -1,
|
||||
instr.getMinAddress().getAddressSpace().getSpaceID(),
|
||||
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
||||
monitor);
|
||||
if (localGPAssumptionValue == null) {
|
||||
program.getBookmarkManager().setBookmark(
|
||||
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
|
||||
"GP Global Register Set",
|
||||
"Global GP Register is set here.");
|
||||
}
|
||||
if (localGPAssumptionValue != null &&
|
||||
!localGPAssumptionValue.equals(gpRefAddr)) {
|
||||
localGPAssumptionValue = gp_assumption_value = null;
|
||||
}
|
||||
else {
|
||||
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
|
||||
// if an instruction actually set the GP
|
||||
if (lastSetAddr != null) {
|
||||
symEval.makeReference(context, lastSetInstr, -1,
|
||||
instr.getMinAddress().getAddressSpace().getSpaceID(),
|
||||
unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
||||
false, monitor);
|
||||
if (localGPAssumptionValue == null) {
|
||||
program.getBookmarkManager().setBookmark(
|
||||
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
|
||||
"GP Global Register Set",
|
||||
"Global GP Register is set here.");
|
||||
}
|
||||
if (localGPAssumptionValue != null &&
|
||||
!localGPAssumptionValue.equals(gpRefAddr)) {
|
||||
localGPAssumptionValue = gp_assumption_value = null;
|
||||
}
|
||||
else {
|
||||
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -372,9 +376,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
if (addr == Address.NO_ADDRESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
|
||||
// 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()) {
|
||||
addr = mipsExtDisassembly(program, instr, context, address, monitor);
|
||||
//addr = flowISA(program, instr, context, address);
|
||||
if (addr == null) {
|
||||
addr = address;
|
||||
}
|
||||
@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
context.clearRegister(reg);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
@ -497,6 +503,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
|
@ -20,6 +20,7 @@ import java.math.BigInteger;
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
@ -79,11 +80,11 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
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();
|
||||
|
||||
if (address.isExternalAddress()) {
|
||||
@ -97,7 +98,7 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
||||
if (refType.isComputed() && refType.isFlow() && isCodeSpace) {
|
||||
return true;
|
||||
}
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -146,6 +147,12 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
startNewBlock(program, flowStart);
|
||||
|
||||
AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||
|
@ -29,6 +29,7 @@ import ghidra.app.services.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
@ -264,7 +265,7 @@ public class PPC64CallStubAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||
int size, RefType refType) {
|
||||
int size, DataType dataType, RefType refType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ConstantPropagationContextEvaluator eval =
|
||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||
@ -224,7 +224,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
// for branching instructions, if we have a good target, mark it
|
||||
@ -259,7 +259,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
if (recoverSwitchTables) {
|
||||
@ -454,13 +460,13 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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!
|
||||
if (!((refType.isComputed() || refType.isConditional()) &&
|
||||
|
@ -99,7 +99,7 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
ConstantPropagationContextEvaluator eval =
|
||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
private boolean mustStopNow = false;
|
||||
|
||||
@Override
|
||||
@ -112,7 +112,13 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return mustStopNow;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
return resultSet;
|
||||
|
@ -76,7 +76,7 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||
@ -126,7 +126,13 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||
|
||||
return resultSet;
|
||||
|
@ -21,6 +21,7 @@ import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
@ -76,11 +77,11 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
return true;
|
||||
@ -98,7 +99,7 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
}
|
||||
|
||||
boolean doRef =
|
||||
super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||
if (!doRef) {
|
||||
return false;
|
||||
}
|
||||
@ -109,6 +110,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
return doRef;
|
||||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
|
@ -17,6 +17,7 @@ package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
@ -45,11 +46,11 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
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
|
||||
// used in the call for PIC calculations
|
||||
@ -67,7 +68,7 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
|
||||
|
||||
if (refType.isComputed()) {
|
||||
boolean doRef = super.evaluateReference(context, instr, pcodeop, address,
|
||||
size, refType);
|
||||
size, dataType, refType);
|
||||
if (!doRef) {
|
||||
return false;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.analysis;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
@ -48,7 +49,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||
@ -74,7 +75,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
@Override
|
||||
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.
|
||||
if (refType.isFlow() && !instr.getMemory().contains(address) &&
|
||||
@ -82,10 +83,16 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
||||
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);
|
||||
|
||||
return resultSet;
|
||||
|
Loading…
Reference in New Issue
Block a user