mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch 'origin/GP-3077_emteere_CrossedConstants--SQUASHED'
This commit is contained in:
commit
5b6a902c8c
27 changed files with 1258 additions and 392 deletions
|
@ -46,6 +46,7 @@ import ghidra.app.script.GhidraScript;
|
|||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.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,11 +132,14 @@ 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);
|
||||
symEval.setReturnRefCheck(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() &&
|
||||
|
@ -221,6 +225,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(true)
|
||||
.setCreateComplexDataFromPointers(true);
|
||||
|
||||
// now flow with the simple block of this branch....
|
||||
|
||||
// for each unknown branch destination,
|
||||
|
|
|
@ -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
|
||||
|
@ -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,12 +15,22 @@
|
|||
*/
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
public ConstantPropagationContextEvaluator() {
|
||||
protected TaskMonitor monitor;
|
||||
private final int NULL_TERMINATOR_PROBE = -1;
|
||||
|
||||
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,7 +181,7 @@ 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
|
||||
|
@ -137,9 +211,242 @@ 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.*;
|
||||
|
@ -145,6 +146,16 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||
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);
|
||||
|
@ -1454,16 +1479,17 @@ 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()) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
createVariableStorageReference(instruction, varnodeContext, monitor,
|
||||
p.getVariableStorage(), callOffset);
|
||||
// if undefined, or int/long could still be pointer
|
||||
if (!(Undefined.isUndefined(dataType) || dataType instanceof IntegerDataType)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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 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,24 +2061,65 @@ 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) {
|
||||
|
||||
if (!storage.isRegisterStorage()) {
|
||||
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 (!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();
|
||||
|
@ -2033,17 +2131,8 @@ public class SymbolicPropogator {
|
|||
return;
|
||||
}
|
||||
|
||||
createRegisterStorageReference(instruction, varnodeContext, monitor, callOffset, rval);
|
||||
}
|
||||
reg = rval.getRegister();
|
||||
|
||||
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
|
||||
|
@ -2055,6 +2144,18 @@ public class SymbolicPropogator {
|
|||
lastSetAddr = instruction.getMaxAddress();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
makeVariableStorageReference(storage, instruction, varnodeContext, monitor, callOffset, dataType, lastSetAddr, bval);
|
||||
}
|
||||
|
||||
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,9 +2168,30 @@ public class SymbolicPropogator {
|
|||
return;
|
||||
}
|
||||
|
||||
if (lastSetAddr != null) {
|
||||
Instruction instr = instruction;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last setAddr could be in the base instruction
|
||||
Instruction instr = instruction;
|
||||
if (!instr.contains(lastSetAddr)) {
|
||||
instr = getInstructionContaining(lastSetAddr);
|
||||
}
|
||||
|
@ -2078,19 +2200,42 @@ public class SymbolicPropogator {
|
|||
for (Reference ref : refs) {
|
||||
Address refAddr = ref.getToAddress();
|
||||
Address addr = refAddr.getAddressSpace().getTruncatedAddress(val, true);
|
||||
if (refAddr.getOffset() == addr.getOffset()) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
|
||||
RefType refType = (callOffset == 0 ? RefType.DATA : RefType.PARAM);
|
||||
makeReference(varnodeContext, instr, Reference.MNEMONIC, -1, val, 0, refType,
|
||||
PcodeOp.UNIMPLEMENTED, false, monitor);
|
||||
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);
|
||||
}
|
||||
|
@ -2407,18 +2543,38 @@ public class SymbolicPropogator {
|
|||
instruction.addOperandReference(opIndex, target, refType, SourceType.ANALYSIS);
|
||||
}
|
||||
|
||||
if (refType.isData()) {
|
||||
createData(target, size);
|
||||
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);
|
||||
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 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
|
||||
|
@ -73,6 +76,13 @@ public class VarnodeContext implements ProcessorContext {
|
|||
|
||||
private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value;
|
||||
|
||||
private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values
|
||||
public final Address SUSPECT_ZERO_ADDRESS;
|
||||
|
||||
public final int BAD_SPACE_ID_VALUE;
|
||||
|
||||
private static final BigInteger BIG_NEGATIVE_ONE = BigInteger.ONE.negate();
|
||||
|
||||
protected boolean hitDest = false;
|
||||
|
||||
protected AddressFactory addrFactory = null;
|
||||
|
@ -92,9 +102,16 @@ 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;
|
||||
|
||||
offsetContext = new DisassemblerContextImpl(programContext);
|
||||
|
@ -294,6 +311,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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Varnode that represents the stack register
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
// value is bad, just return original, someone else will deal with it
|
||||
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
|
||||
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) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -1504,6 +1601,32 @@ public class VarnodeContext implements ProcessorContext {
|
|||
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
|
||||
|
@ -154,6 +154,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
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);
|
||||
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
|
||||
|
@ -237,6 +242,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||
|
||||
if (recoverSwitchTables) {
|
||||
|
@ -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,10 +318,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
lastSetInstr = instructionAt;
|
||||
}
|
||||
}
|
||||
// if an instruction actually set the GP
|
||||
if (lastSetAddr != null) {
|
||||
symEval.makeReference(context, lastSetInstr, -1,
|
||||
instr.getMinAddress().getAddressSpace().getSpaceID(),
|
||||
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
||||
monitor);
|
||||
unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
||||
false, monitor);
|
||||
if (localGPAssumptionValue == null) {
|
||||
program.getBookmarkManager().setBookmark(
|
||||
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
|
||||
|
@ -338,6 +341,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mustStopNow;
|
||||
}
|
||||
|
||||
|
@ -372,10 +376,14 @@ 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
|
||||
// return !symEval.encounteredBranch();
|
||||
|
@ -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
|
||||
|
@ -498,6 +504,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
// Add in any addresses we should assume got covered
|
||||
|
|
|
@ -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
|
||||
|
@ -113,6 +113,12 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
|
@ -127,6 +127,12 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -110,6 +111,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
return resultSet;
|
||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue