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

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

View File

@ -46,6 +46,7 @@ import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.*;
import ghidra.program.model.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,

View File

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

View File

@ -31,6 +31,7 @@ import ghidra.app.plugin.core.disassembler.AddressTable;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*;
@ -88,7 +89,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
// use context to fill out addresses on certain instructions
// Always trust values read from writable memory
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(true) {
new ConstantPropagationContextEvaluator(monitor, true) {
@Override
public boolean evaluateDestination(VarnodeContext context,
Instruction instruction) {
@ -131,10 +132,13 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
return true; // just go ahead and mark up the instruction
}
};
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
symEval.setParamRefCheck(true);
@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
symEval.flowConstants(start, func.getBody(), eval, true, monitor);
// now handle symbolic execution assuming values!
eval = new ConstantPropagationContextEvaluator() {
eval = new ConstantPropagationContextEvaluator(monitor) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr,
int pcodeop, Address constant, int size, RefType refType) {
int pcodeop, Address constant, int size, DataType dataType, RefType refType) {
// don't create any references from constants, only looking for flow refs
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
// TODO: if ever loading from instructions in memory, must
// EXIT!
if (!(instr.getFlowType().isComputed() &&
@ -220,6 +224,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
return true;
}
};
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
// now flow with the simple block of this branch....

View File

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

View File

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

View File

@ -38,55 +38,71 @@ import ghidra.util.task.TaskMonitor;
public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
private static final String NAME = " Constant Reference Analyzer";
private static final String DESCRIPTION =
static final String DESCRIPTION =
" Constant Propagation Analyzer for constant references computed with multiple instructions.";
protected static final String OPTION_NAME = "Function parameter/return Pointer analysis";
protected static final String OPTION_DESCRIPTION =
"Turn on to check if values passed as parameters or returned could be pointer references";
protected static final boolean OPTION_DEFAULT_VALUE = true;
protected static final String POINTER_PARAM_OPTION_NAME = "Require pointer param data type";
protected static final String POINTER_PARAM_OPTION_DESCRIPTION =
"Turn on to require values passed as parameters or returned to be a known pointer data type";
protected static final boolean POINTER_PARAM_OPTION_DEFAULT_VALUE = false;
protected static final String STORED_OPTION_NAME = "Stored Value Pointer analysis";
protected static final String STORED_OPTION_DESCRIPTION =
"Turn on to check if values stored into memory or the stack could be pointer references";
protected static final boolean STORED_OPTION_DEFAULT_VALUE = true;
protected static final String TRUSTWRITEMEM_OPTION_NAME =
protected static final String TRUST_WRITEMEM_OPTION_NAME =
"Trust values read from writable memory";
protected static final String TRUSTWRITEMEM_OPTION_DESCRIPTION =
protected static final String TRUST_WRITEMEM_OPTION_DESCRIPTION =
"Turn on to trust values read from writable memory";
protected static final boolean TRUSTWRITEMEM_OPTION_DEFAULT_VALUE = true;
protected static final boolean TRUST_WRITEMEM_OPTION_DEFAULT_VALUE = true;
protected static final String MAXTHREADCOUNT_OPTION_NAME = "Max Threads";
protected static final String MAXTHREADCOUNT_OPTION_DESCRIPTION =
protected static final String MAX_THREAD_COUNT_OPTION_NAME = "Max Threads";
protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION =
"Maximum threads for constant propagation. Too many threads causes thrashing in DB.";
protected static final int MAXTHREADCOUNT_OPTION_DEFAULT_VALUE = 2;
protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2;
protected static final String MINKNOWNREFADDRESS_OPTION_NAME = "Min absolute reference";
protected static final String MINKNOWNREFADDRESS_OPTION_DESCRIPTION =
protected static final String MIN_KNOWN_REFADDRESS_OPTION_NAME = "Min absolute reference";
protected static final String MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION =
"Minimum address for calcuated constant store/load references";
protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4;
protected static final int MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE = 4;
protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME =
protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_NAME =
"Speculative reference min";
protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
"Minimum speculative reference address for offsets and parameters";
protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024;
protected static final int MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 1024;
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_NAME =
protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_NAME =
"Speculative reference max";
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
"Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
protected static final int MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 256;
protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
"Prototype - Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
protected static final int MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 256;
protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME =
"Create Data from pointer";
protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION =
"Create complex data types from pointers if the data type is known, currently from function parameters.";
protected static final boolean CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE = false;
protected final static int NOTIFICATION_INTERVAL = 100;
protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE;
protected boolean checkPointerParamRefsOption = POINTER_PARAM_OPTION_DEFAULT_VALUE;
protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE;
protected boolean trustWriteMemOption = TRUSTWRITEMEM_OPTION_DEFAULT_VALUE;
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE;
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
protected boolean trustWriteMemOption = TRUST_WRITEMEM_OPTION_DEFAULT_VALUE;
protected boolean createComplexDataFromPointers = CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE;
protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE;
protected long minStoreLoadRefAddress = MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE;
protected long minSpeculativeRefAddress = MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE;
protected long maxSpeculativeRefAddress = MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE;
protected boolean followConditional = false;
@ -105,6 +121,10 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before().before().before().before());
}
public ConstantPropagationAnalyzer(String processorName, AnalyzerType type) {
super(processorName + NAME, processorName + DESCRIPTION, type);
}
/**
* Called to to register a more specific analyzer.
*
@ -114,13 +134,25 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
handledProcessors.add(processorName);
}
/**
* Called to register a more specific analyzer.
*
* @param processorName
*/
static public boolean isClaimedProcessor(String processorName) {
return handledProcessors.contains(processorName);
}
@Override
public boolean canAnalyze(Program program) {
// Set the default for checking parameter passing
// don't look for constant passing in things that have a small address space, or is segmented
checkParamRefsOption = program.getDefaultPointerSize() > 2;
checkParamRefsOption &=
!(program.getAddressFactory().getDefaultAddressSpace() instanceof SegmentedAddressSpace);
// unless there is a good data type at the location
boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace();
checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard;
checkParamRefsOption = !(program.getAddressFactory()
.getDefaultAddressSpace() instanceof SegmentedAddressSpace);
if (processorName.equals("Basic")) {
if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) {
@ -129,8 +161,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
return true;
}
return program.getLanguage().getProcessor().equals(
Processor.findOrPossiblyCreateProcessor(processorName));
return program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor(processorName));
}
@Override
@ -138,7 +171,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
throws CancelledException {
AddressSet unanalyzedSet = new AddressSet(set);
removeUninitializedBlocks(program, unanalyzedSet);
try {
@ -434,6 +467,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
SymbolicPropogator symEval = new SymbolicPropogator(program);
symEval.setParamRefCheck(checkParamRefsOption);
symEval.setParamPointerRefCheck(checkPointerParamRefsOption);
symEval.setReturnRefCheck(checkParamRefsOption);
symEval.setStoredRefCheck(checkStoredRefsOption);
@ -456,8 +492,12 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
throws CancelledException {
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption,
minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress);
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor)
.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
}
@ -515,39 +555,52 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
options.registerOption(OPTION_NAME, checkParamRefsOption, null, OPTION_DESCRIPTION);
options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null,
STORED_OPTION_DESCRIPTION);
options.registerOption(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption, null,
TRUSTWRITEMEM_OPTION_DESCRIPTION);
options.registerOption(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount, null,
MAXTHREADCOUNT_OPTION_DESCRIPTION);
options.registerOption(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption, null,
TRUST_WRITEMEM_OPTION_DESCRIPTION);
options.registerOption(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null,
MINKNOWNREFADDRESS_OPTION_DESCRIPTION);
options.registerOption(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers, null,
CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION);
options.registerOption(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption, null,
POINTER_PARAM_OPTION_DESCRIPTION);
options.registerOption(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount, null,
MAX_THREAD_COUNT_OPTION_DESCRIPTION);
options.registerOption(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null,
MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION);
long size = program.getAddressFactory().getDefaultAddressSpace().getSize();
minSpeculativeRefAddress = size * 16;
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
maxSpeculativeRefAddress = size * 8;
options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
}
@Override
public void optionsChanged(Options options, Program program) {
checkParamRefsOption = options.getBoolean(OPTION_NAME, checkParamRefsOption);
checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption);
trustWriteMemOption = options.getBoolean(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption);
maxThreadCount = options.getInt(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount);
checkPointerParamRefsOption =
options.getBoolean(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption);
checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption);
trustWriteMemOption = options.getBoolean(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption);
createComplexDataFromPointers = options.getBoolean(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers);
maxThreadCount = options.getInt(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount);
// TODO: there should be a getAddress on option that validates and allows entry of addresses
minStoreLoadRefAddress =
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
options.getLong(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
minSpeculativeRefAddress =
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
options.getLong(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
maxSpeculativeRefAddress =
options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
options.getLong(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
}
}

View File

@ -15,14 +15,24 @@
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.cmd.function.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.PseudoDisassembler;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBufferImpl;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.program.util.ContextEvaluatorAdapter;
import ghidra.program.util.VarnodeContext;
import ghidra.util.task.TaskMonitor;
/**
/**
* The ConstantPropogatorEvaluator is used as the evaluator for the SymbolicPropagator when finding constant
* references and laying them down for a generic processor. Extend this class to add additional checks
* and behaviors necessary for a unique processor such as the PowerPC.
@ -39,31 +49,95 @@ import ghidra.program.util.VarnodeContext;
*/
public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter {
private static final int MAX_UNICODE_STRING_LEN = 200;
private static final int MAX_CHAR_STRING__LEN = 100;
protected AddressSet destSet = new AddressSet();
private boolean trustMemoryWrite = false;
private boolean createDataFromPointers = false;
private long minStoreLoadOffset = 4;
private long minSpeculativeOffset = 1024; // from the beginning of memory
private long maxSpeculativeOffset = 256; // from the end of memory
protected TaskMonitor monitor;
private final int NULL_TERMINATOR_PROBE = -1;
public ConstantPropagationContextEvaluator() {
public ConstantPropagationContextEvaluator(TaskMonitor monitor) {
this.monitor = monitor;
}
/**
* @param monitor TODO
* @param trustMemoryWrite - true to trust values read from memory that is marked writable
*/
public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) {
public ConstantPropagationContextEvaluator(TaskMonitor monitor, boolean trustMemoryWrite) {
this.monitor = monitor;
this.trustMemoryWrite = trustMemoryWrite;
}
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
long minStoreLoadRefAddress, long minSpeculativeRefAddress,
long maxSpeculativeRefAddress) {
this(trustWriteMemOption);
public ConstantPropagationContextEvaluator(TaskMonitor monitor,
boolean trustWriteMemOption, long minStoreLoadRefAddress,
long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
this(monitor, trustWriteMemOption);
this.minStoreLoadOffset = minStoreLoadRefAddress;
this.minSpeculativeOffset = minSpeculativeRefAddress;
this.maxSpeculativeOffset = maxSpeculativeRefAddress;
}
/**
* Set option to trust reads from memory that is marked writeable
*
* @param trustWriteableMemOption true to trust values read from memory that is marked writable
* @return this
*/
public ConstantPropagationContextEvaluator setTrustWritableMemory(boolean trustWriteableMemOption) {
trustMemoryWrite = trustWriteableMemOption;
return this;
}
/**
* Set mimimum speculative memory offset for references
*
* @param minSpeculativeRefAddress minimum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMinpeculativeOffset(long minSpeculativeRefAddress) {
minSpeculativeOffset = minSpeculativeRefAddress;
return this;
}
/**
* Set maximum speculative memory offset for references
*
* @param maxSpeculativeRefAddress maximum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMaxSpeculativeOffset(long maxSpeculativeRefAddress) {
maxSpeculativeOffset = maxSpeculativeRefAddress;
return this;
}
/**
* Set maximum speculative memory offset for references
*
* @param minStoreLoadRefAddress maximum address offset
* @return this
*/
public ConstantPropagationContextEvaluator setMinStoreLoadOffset(long minStoreLoadRefAddress) {
maxSpeculativeOffset = minStoreLoadRefAddress;
return this;
}
/**
* Set option to create complex data for pointers if the datatype is known
*
* @param doCreateData true to create complex data types if the data type is known
* @return this
*/
public ConstantPropagationContextEvaluator setCreateComplexDataFromPointers(boolean doCreateData) {
createDataFromPointers = doCreateData;
return this;
}
/**
* The computed destination set is useful if follow on switch analysis is to be done.
*
@ -79,7 +153,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
*/
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) {
Address constant, int size, DataType dataType, RefType refType) {
// Constant references below minSpeculative or near the end of the address space are suspect,
// even if memory exists for those locations.
@ -107,8 +181,8 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
*/
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
// special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally
// really there should be another callback when adding parameters
if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) {
@ -137,8 +211,241 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
}
}
Program program = instr.getProgram();
AutoAnalysisManager aMgr= AutoAnalysisManager.getAnalysisManager(program);
// if data reference, handle data
if (refType.isData()) {
createPointedToData(aMgr, program, address, refType, dataType, size);
}
// if flowing to an address, disassemble it
if (refType.isFlow() && !refType.isIndirect() &&
!program.getMemory().isExternalBlockAddress(address)) {
Data udata = program.getListing().getUndefinedDataAt(address);
if (udata != null) {
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(program, monitor);
}
//
// TODO: need to kick analysis if the target is a function and non-returning
// Function functionAt = program.getFunctionManager().getFunctionAt(address);
// if (functionAt != null && functionAt.hasNoReturn()) {
// aMgr.functionModifierChanged(address);
// }
}
return true;
}
private int createPointedToData(AutoAnalysisManager aMgr, Program program, Address address, RefType refType, DataType dataType, int size) {
// don't do in external memory
if (program.getMemory().isExternalBlockAddress(address) || address.isExternalAddress()) {
return 0;
}
// don't create if not in real memory
if (!program.getMemory().contains(address)) {
return 0;
}
// Get the data type that is pointed to, strip off pointer, or pointer typedef
DataType pointedToDT = null;
if (dataType instanceof Pointer ptr) {
pointedToDT = ptr.getDataType();
}
else if ((dataType instanceof TypeDef typeDef && typeDef.getBaseDataType() instanceof Pointer ptr)) {
pointedToDT = ptr.getDataType();
}
// if this is a function pointer, create the code/function/signature
if (pointedToDT instanceof FunctionDefinition funcDefn) {
createFunctionApplySignature(aMgr, program, address, funcDefn);
return dataType.getLength();
}
// otherwise it is data
if (dataType != null) {
// System.out.println("@ " + address + " Data Type - " + dataType);
}
return createData(program, address, pointedToDT, size);
}
/**
* Create Data at an address in the program
*
* @param program the program
* @param address location to create data
* @param dataType dataType if known
* @param size size of the data type (from a read/write)
* @return size of the data item created, or 0 if none created
*/
private int createData(Program program, Address address, DataType dataType, int size) {
// defined data (that isn't an undefined) don't do anything
Data data = program.getListing().getDataAt(address);
if (data == null || !Undefined.isUndefined(data.getDataType())) {
return 0;
}
// get a default undefined data type of the right size for the access
DataType dt = Undefined.getUndefinedDataType(size);
int maxLen = -1;
if (createDataFromPointers && dataType != null) {
DataType originalDT = dataType;
// if typedef, get the base type
if (dataType instanceof TypeDef typeDef) {
dataType = typeDef.getBaseDataType();
}
if (dataType instanceof CharDataType) {
// Use Terminated in case strings are referenced offcut
maxLen = getRestrictedStringLen(program, address, TerminatedStringDataType.dataType, MAX_CHAR_STRING__LEN);
if (maxLen > 0) {
dt = TerminatedStringDataType.dataType;
}
} else if (dataType instanceof WideCharDataType) {
maxLen = getRestrictedStringLen(program, address, TerminatedUnicodeDataType.dataType, MAX_UNICODE_STRING_LEN);
if (maxLen > 0) {
dt = TerminatedUnicodeDataType.dataType;
}
} else if (dataType instanceof Composite comp) {
// create empty structures, they can get filled out later
// if they don't fit later because they grow, then there will be an error at the location
dt = originalDT; // original might have been a typedef, use original
} else if (dataType instanceof VoidDataType) {
// ptr to void should be ignored
return 0;
} else if (dataType instanceof AbstractFloatDataType) {
dt = dataType;
} else {
// don't do any other types other than above for now
return 0;
}
} else if (size < 1 || size > 8) {
return 0;
}
try {
// create data at the location so that we record the access size
// the data is undefined, and SHOULD be overwritten if something
// else knows better about the location.
if (maxLen > 0) {
data = DataUtilities.createData(program, address, dt, maxLen,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
} else {
data = DataUtilities.createData(program, address, dt, -1,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
}
return data.getLength();
}
catch (CodeUnitInsertionException e) {
// couldn't create data
}
return 0;
}
/**
* Create a function/code at a location and apply the
*
* @param aMgr auto analysis manager
* @param program the program
* @param address location to create function
* @param funcDefn function definition if known
*/
private void createFunctionApplySignature(AutoAnalysisManager aMgr, Program program,
Address address, FunctionDefinition funcDefn) {
// System.out.println("@ " + address + " - Typedef Function " + ((FunctionDefinition)ptrToDT).getPrototypeString());
Listing listing = program.getListing();
// defined data (that isn't an undefined) don't do anything
Data data = listing.getDefinedDataContaining(address);
if (data != null) {
return;
}
// if memory is undefined bytes, don't disassemble or create function
MemoryBlock block = program.getMemory().getBlock(address);
if (block == null || !block.isInitialized()) {
return;
}
// normalize the address to where code should start (ARM and MIPS can be offset by one)
Address normalizedAddr = PseudoDisassembler.getNormalizedDisassemblyAddress(program, address);
if (!listing.isUndefined(normalizedAddr, normalizedAddr)) {
// if not undefined, must be an instruction to continue
Instruction instr = listing.getInstructionAt(normalizedAddr);
if (instr == null) {
return;
}
} else {
// if nothing defined here, disassemble
address = PseudoDisassembler.setTargeContextForDisassembly(program, address);
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(program, monitor);
}
// see if there is an existing function
FunctionManager funcMgr = program.getFunctionManager();
Function func = funcMgr.getFunctionAt(address);
// if no function at the address, make sure not in the middle of a function
if (func == null) {
func = funcMgr.getFunctionContaining(address);
// don't create a function in the middle of another
if (func != null) {
return;
}
}
if (func != null) {
if (func.isThunk()) {
return;
}
SourceType mostTrusted = getMostTrustedParameterSource(func);
if (SourceType.ANALYSIS.isLowerPriorityThan(mostTrusted)) {
return;
}
} else {
CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(address, false);
aMgr.schedule(createFunctionCmd, AnalysisPriority.FUNCTION_ANALYSIS.priority());
}
// only apply the signature if actually creating data, the function/code has already been created
if (!createDataFromPointers) {
return;
}
// if no arguments, could be an opaque function pointer, don't apply arguments
ParameterDefinition[] arguments = funcDefn.getArguments();
DataType returnType = funcDefn.getReturnType();
if (arguments == null || (arguments.length == 0 && (returnType==null || Undefined.isUndefined(returnType)))) {
return;
}
// applying function signatures considered data
// don't change name, even default name
ApplyFunctionSignatureCmd applyFunctionSignatureCmd = new ApplyFunctionSignatureCmd(address, funcDefn, SourceType.ANALYSIS, true, FunctionRenameOption.NO_CHANGE);
aMgr.schedule(applyFunctionSignatureCmd, AnalysisPriority.FUNCTION_ANALYSIS.after().priority());
}
private SourceType getMostTrustedParameterSource(Function func) {
SourceType highestSource = func.getSignatureSource();
Parameter[] parameters = func.getParameters();
for (Parameter parameter : parameters) {
SourceType paramSource = parameter.getSource();
if (paramSource.isHigherPriorityThan(highestSource)) {
highestSource = paramSource;
}
}
return highestSource;
}
/**
* Add instructions to destination set for unknown computed branches.
@ -168,4 +475,60 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
public boolean allowAccess(VarnodeContext context, Address addr) {
return trustMemoryWrite;
}
/**
* Looks at bytes at given address and converts to format String
*
* @param address Address of format String
* @param pointer Pointer "type" of string
* @return format String
*/
int getRestrictedStringLen(Program program, Address address, AbstractStringDataType dataType, int maxLength) {
maxLength = getMaxStringLength(program, address, maxLength);
MemoryBufferImpl memoryBuffer =
new MemoryBufferImpl(program.getMemory(), address);
StringDataInstance stringDataInstance = dataType.getStringDataInstance(memoryBuffer, dataType.getDefaultSettings(), -1);
stringDataInstance.getStringDataTypeGuess();
int detectedLength = stringDataInstance.getStringLength();
if (detectedLength == -1) {
return 0;
}
if (detectedLength > maxLength) {
detectedLength = maxLength;
}
return detectedLength;
}
/**
* Get the number of bytes to the next reference, or the max length
*
* @param program
* @param address
* @return maximum length to create the string
*/
private int getMaxStringLength(Program program, Address address, int maxLen) {
AddressIterator refIter = program.getReferenceManager().getReferenceDestinationIterator(address.next(), true);
Address next = refIter.next();
if (next == null) {
return -1;
}
long len = -1;
try {
len = next.subtract(address);
if (len > maxLen) {
len = maxLen;
}
return (int) len;
} catch (IllegalArgumentException exc) {
// bad address subtraction
}
return (int) len;
}
}

View File

@ -36,6 +36,7 @@ import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
@ -144,7 +145,17 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
pointerEnabled = false;
addressTablesEnabled = false;
}
boolean isArm = program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor("ARM"));
// if arm, turn off reference to pointer analysis
if (isArm) {
pointerEnabled = false;
addressTablesEnabled = false;
}
// only analyze programs with address spaces > 16 bits
int bitSize = defaultAddressSpace.getSize();
return bitSize > 16;

View File

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

View File

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

View File

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

View File

@ -19,11 +19,12 @@ import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;
import org.apache.commons.lang3.ArrayUtils;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException;
@ -38,8 +39,6 @@ import ghidra.util.exception.*;
public class VarnodeContext implements ProcessorContext {
public static final int BAD_SPACE_ID_VALUE = 0xffff;
protected DisassemblerContextImpl offsetContext;
protected DisassemblerContextImpl spaceContext;
@ -63,6 +62,10 @@ public class VarnodeContext implements ProcessorContext {
protected VarnodeTranslator trans; // translator for varnodes<-->registers
protected Varnode[] retVarnodes = null; // varnodes used to return values
protected Varnode[] killedVarnodes = null; // varnodes killed by default calling convention
protected Varnode stackVarnode = null; // varnode that represents the stack
protected Register stackReg = null;
private HashSet<String> validSymbolicStackNames = new HashSet<>(); // list of stack related register names
@ -72,6 +75,13 @@ public class VarnodeContext implements ProcessorContext {
public final Address BAD_ADDRESS;
private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value;
private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values
public final Address SUSPECT_ZERO_ADDRESS;
public final int BAD_SPACE_ID_VALUE;
private static final BigInteger BIG_NEGATIVE_ONE = BigInteger.ONE.negate();
protected boolean hitDest = false;
@ -92,8 +102,15 @@ public class VarnodeContext implements ProcessorContext {
this.addrFactory = new OffsetAddressFactory(program);
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
BAD_SPACE_ID_VALUE = BAD_ADDRESS.getAddressSpace().getSpaceID();
BAD_OFFSET_SPACEID = getAddressSpace("(Bad Address Offset)");
/* Suspect constants act like constants, but are in a SuspectConst
* address space instead of the constant space.
*/
SUSPECT_ZERO_ADDRESS = addrFactory.getAddress(getAddressSpace("SuspectConst"), 0);
SUSPECT_OFFSET_SPACEID = SUSPECT_ZERO_ADDRESS.getAddressSpace().getSpaceID();
this.programContext = programContext;
@ -293,6 +310,48 @@ public class VarnodeContext implements ProcessorContext {
}
return retVarnodes;
}
/**
*
* @param targetFunc function to get killed varnodes for
*
* NOTE: this removes the return varnodes so they aren't duplicated
*
* @return varnode that represents where functions place their return value
*/
public Varnode[] getKilledVarnodes(Function targetFunc) {
// TODO: This doesn't handle full bonded yet!
PrototypeModel defaultCallingConvention =
program.getCompilerSpec().getDefaultCallingConvention();
if (targetFunc != null) {
// TODO handle custom calling convention killed by call when supported
PrototypeModel callingConvention = targetFunc.getCallingConvention();
if (callingConvention != null) {
return callingConvention.getKilledByCallList();
}
}
// no function, so get the default convention and use that.
if (killedVarnodes != null) {
return killedVarnodes;
}
killedVarnodes = defaultCallingConvention.getKilledByCallList();
// clean return varnodes out of list
Varnode[] returnVarnodes = getReturnVarnode(null);
ArrayList<Varnode> list = new ArrayList<Varnode>();
for (Varnode varnode : killedVarnodes) {
if (!ArrayUtils.contains(returnVarnodes, varnode)) {
list.add(varnode);
}
}
killedVarnodes = list.toArray(new Varnode[list.size()]);
return killedVarnodes;
}
/**
*
@ -356,7 +415,7 @@ public class VarnodeContext implements ProcessorContext {
public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator)
throws NotFoundException {
// for constant, return the constant value
if (varnode.isConstant()) {
if (isConstant(varnode)) {
return varnode;
}
Varnode rvnode = null;
@ -383,21 +442,26 @@ public class VarnodeContext implements ProcessorContext {
if (bigVal != null) {
BigInteger spaceVal = getTranslatedSpaceValue(reg);
// -1 and zero constants pulled from a register are suspect
if (spaceVal == null && (bigVal.equals(BIG_NEGATIVE_ONE) || bigVal.equals(BigInteger.ZERO))) {
spaceVal = BigInteger.valueOf(SUSPECT_OFFSET_SPACEID);
}
rvnode = createVarnode(bigVal, spaceVal, varnode.getSize());
if (rvnode == null) {
throw notFoundExc;
}
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
if (debug) {
Msg.info(this, " " + reg.getName() + " = " + print(rvnode));
}
if (debug) {
Msg.info(this, " " + reg.getName() + " = " + print(rvnode));
}
// value is bad, just return original, someone else will deal with it
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
return rvnode;
}
return rvnode;
}
}
// TODO: should this return a new space at offset 0?
return varnode; // just return the register then, someone else will deal with it...
}
@ -418,12 +482,6 @@ public class VarnodeContext implements ProcessorContext {
if (debug) {
Msg.info(this, " " + varnode + " = " + print(lvalue));
}
if (isSymbolicSpace(lvalue.getSpace())) {
if (debug) {
Msg.info(this, " out " + varnode + " = " + print(lvalue));
}
throw notFoundExc;
}
// if this is an offset reference, ONLY allow it to be offset into the stack, no other register offset.
// can't count on the offset staying the same.
if (isSymbolicAddr) {
@ -431,15 +489,9 @@ public class VarnodeContext implements ProcessorContext {
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
// figure out what register is used for stack values
Register stackRegister = getStackRegister();
if (!isStackSymbolicSpace(varnode)) {
if (debug) {
Msg.info(this,
"Don't Trust value from " + varnode + " = " + print(lvalue));
}
throw notFoundExc;
}
// don't allow a zero constant pulled from a symbolic space.
if (lvalue.isConstant() && lvalue.getOffset() == 0) {
// don't allow a zero/-1 constant pulled from a symbolic space.
if (isConstant(lvalue) && (lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) {
throw notFoundExc;
}
}
@ -520,7 +572,8 @@ public class VarnodeContext implements ProcessorContext {
value = (value << 8 * (8 - size)) >> 8 * (8 - size);
}
return createConstantVarnode(value, size);
// constants pulled from memory are always suspect
return createVarnode(value, SUSPECT_OFFSET_SPACEID, size);
}
catch (MemoryAccessException e) {
@ -642,9 +695,11 @@ public class VarnodeContext implements ProcessorContext {
AddressSpace spc = addrFactory.getAddressSpace(spaceID);
Address addr = null;
if (spaceID == BAD_SPACE_ID_VALUE || spc == null ||
spc.equals(BAD_ADDRESS.getAddressSpace())) {
if (spaceID == BAD_SPACE_ID_VALUE || spc == null) {
addr = BAD_ADDRESS;
} else if (spaceID == BAD_OFFSET_SPACEID) {
// special case of unknown value + constant
addr = spc.getTruncatedAddress(value, true);
}
else {
addr = spc.getTruncatedAddress(value, true);
@ -700,10 +755,16 @@ public class VarnodeContext implements ProcessorContext {
// put the location on both the lastSet, and all locations set
addSetVarnodeToLastSetLocations(out, location);
// don't put a value into a bad address space
// could get values pulled from a different badd address offset
if (isSymbolicAddr && out.getAddress().getAddressSpace().getSpaceID() == BAD_OFFSET_SPACEID) {
return;
}
putMemoryValue(out, result);
return;
}
}
// don't ever store an unknown unique into a location
if (result != null && result.isUnique()) {
result = null;
@ -715,6 +776,20 @@ public class VarnodeContext implements ProcessorContext {
tempUniqueVals.put(out.getOffset(), result);
}
else {
// if storing a bad address, need to create a new register/address
// relative symbolic space
if (result != null && result.getAddress()==BAD_ADDRESS) {
String spaceName = out.getAddress().getAddressSpace().getName();
Register register = getRegister(out);
if (register == null) {
spaceName = out.toString();
} else {
spaceName = register.getName();
}
int newRegSpaceID = getAddressSpace(spaceName+"-"+currentAddress);
result = createVarnode(0, newRegSpaceID, out.getSize());
}
tempVals.put(out, result);
}
@ -907,7 +982,7 @@ public class VarnodeContext implements ProcessorContext {
}
public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException {
if (!vnode.isConstant()) {
if (!isConstant(vnode)) {
if (evaluator == null) {
throw notFoundExc;
}
@ -940,6 +1015,12 @@ public class VarnodeContext implements ProcessorContext {
valbase = offset.getOffset();
spaceID = (int) space.getOffset();
}
else if (isSuspectConstant(offset)) {
// constant suspicious don't let if fall into symbolic
// handle same as normal constant but keep suspicious space
valbase = offset.getOffset();
spaceID = (int) space.getOffset();
}
else if (OffsetAddressFactory.isSymbolSpace(spaceID)) {
if (evaluator == null) {
throw notFoundExc;
@ -1037,7 +1118,10 @@ public class VarnodeContext implements ProcessorContext {
}
BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr);
if (spaceVal != null) {
if (addrFactory.getConstantSpace().getSpaceID() != spaceVal.intValue()) {
int spaceID = spaceVal.intValue();
// check normal constant and suspect constants
if (spaceID != addrFactory.getConstantSpace().getSpaceID() &&
spaceID != SUSPECT_OFFSET_SPACEID) {
return null;
}
}
@ -1054,7 +1138,7 @@ public class VarnodeContext implements ProcessorContext {
/**
* Copy the varnode with as little manipulation as possible.
* Try to keep whatever partical state there is intact if a real value isn't required.
* Try to keep whatever partial state there is intact if a real value isn't required.
*
* @param out varnode to put it in
* @param in varnode to copy from.
@ -1067,8 +1151,10 @@ public class VarnodeContext implements ProcessorContext {
Varnode val1 = null;
val1 = getValue(in, evaluator);
// if truncating a constant get a new constant of the proper size
if (val1 != null && val1.isConstant() && in.getSize() > out.getSize()) {
val1 = createConstantVarnode(val1.getOffset(), out.getSize());
if (val1 != null && in.getSize() > out.getSize()) {
if (isConstant(val1)) {
val1 = createVarnode(val1.getOffset(), val1.getSpace(), out.getSize());
}
}
if (!in.isRegister() || !out.isRegister()) {
@ -1097,7 +1183,7 @@ public class VarnodeContext implements ProcessorContext {
throws NotFoundException {
// try to make the constant value the addend.
if (val1.isConstant() || val1.isAddress()) {
if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1;
val1 = val2;
val2 = swap;
@ -1142,8 +1228,11 @@ public class VarnodeContext implements ProcessorContext {
}
}
}
else if (val1.isConstant()) {
else if (isConstant(val1)) {
valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
}
else if (isSymbolicSpace(spaceID)) {
Instruction instr = getCurrentInstruction(offsetContext.getAddress());
@ -1181,7 +1270,6 @@ public class VarnodeContext implements ProcessorContext {
}
}
}
else {
throw notFoundExc;
@ -1199,7 +1287,7 @@ public class VarnodeContext implements ProcessorContext {
if (val1.equals(val2)) {
return val1;
}
if (val1.isConstant() || val1.isAddress()) {
if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1;
val1 = val2;
val2 = swap;
@ -1216,6 +1304,9 @@ public class VarnodeContext implements ProcessorContext {
}
else if (val1.isConstant()) {
valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
}
else if (isSymbolicSpace(spaceID)) {
valbase = val1.getOffset();
@ -1244,25 +1335,29 @@ public class VarnodeContext implements ProcessorContext {
return val1;
}
if (val1.isConstant() || val1.isAddress()) {
if (isConstant(val1) || val1.isAddress()) {
Varnode swap = val1;
val1 = val2;
val2 = swap;
}
int spaceID = val1.getSpace();
long val2Const = getConstant(val2, null);
// got a constant from val2, (value | 0) == value, so just return value
if (val2Const == 0) {
return val1;
if (!isSuspectConstant(val2)) {
return val1;
}
spaceID = val2.getSpace();
}
long lresult = getConstant(val1, evaluator) | val2Const;
return createConstantVarnode(lresult, val1.getSize());
return createVarnode(lresult, spaceID, val1.getSize());
}
public Varnode left(Varnode val1, Varnode val2, ContextEvaluator evaluator)
throws NotFoundException {
long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator);
lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
Varnode result = createConstantVarnode(lresult, val1.getSize());
Varnode result = createVarnode(lresult, val1.getSpace(), val1.getSize());
return result;
}
@ -1306,8 +1401,11 @@ public class VarnodeContext implements ProcessorContext {
}
int spaceID = val1.getSpace();
long valbase = 0;
if (val1.isConstant()) {
if (isConstant(val1)) {
valbase = val1.getOffset();
if (!isSuspectConstant(val1)) {
spaceID = val2.getSpace();
}
}
else if (isRegister(val1)) {
Register reg = trans.getRegister(val1);
@ -1329,7 +1427,6 @@ public class VarnodeContext implements ProcessorContext {
return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);
}
}
}
else {
throw notFoundExc;
@ -1353,15 +1450,15 @@ public class VarnodeContext implements ProcessorContext {
vnodeVal = getValue(in[0], signExtend, evaluator);
if (vnodeVal.isConstant() && in[0].getSize() < out.getSize()) {
if (isConstant(vnodeVal) && in[0].getSize() < out.getSize()) {
// TODO: Is there a better way to do this - it was not sign-extending temp values before
if (vnodeVal.getSize() <= 8) {
Scalar sVal = new Scalar(8 * vnodeVal.getSize(), vnodeVal.getOffset(), signExtend);
vnodeVal = createConstantVarnode(sVal.getValue(), out.getSize());
vnodeVal = createVarnode(sVal.getValue(), vnodeVal.getSpace(), out.getSize());
}
else {
// too big anyway,already extended as far as it will go.
vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize());
vnodeVal = createVarnode(vnodeVal.getOffset(), vnodeVal.getSpace(), out.getSize());
}
}
else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) {
@ -1414,7 +1511,7 @@ public class VarnodeContext implements ProcessorContext {
Varnode regVnode = trans.getVarnode(register);
try {
Varnode value = this.getValue(regVnode, false, null);
if (value.isConstant()) {
if (isConstant(value)) {
return new RegisterValue(register, BigInteger.valueOf(value.getOffset()));
}
}
@ -1457,7 +1554,7 @@ public class VarnodeContext implements ProcessorContext {
Varnode regVnode = trans.getVarnode(register);
try {
Varnode value = this.getValue(regVnode, signed, null);
if (value.isConstant()) {
if (isConstant(value)) {
return BigInteger.valueOf(value.getOffset());
}
}
@ -1503,7 +1600,33 @@ public class VarnodeContext implements ProcessorContext {
public boolean isRegister(Varnode varnode) {
return varnode.isRegister() || trans.getRegister(varnode) != null;
}
/**
* Check if this is a constant, or a suspect constant
*
* @param varnode to check
* @return true if should be treated as a constant for most purposes
*/
public boolean isConstant(Varnode varnode) {
if (varnode.isConstant()) {
return true;
}
return isSuspectConstant(varnode);
}
/**
* Check if the constant is a suspect constant
* It shouldn't be trusted in certain cases.
* Suspect constants act like constants, but are in a Suspicious
* address space instead of the constant space.
*
* @param val1 varnode to check
* @return true if varnode is a suspect constant
*/
public boolean isSuspectConstant(Varnode val1) {
return val1.getSpace() == SUSPECT_OFFSET_SPACEID;
}
/**
* Check if varnode is in the stack space
*

View File

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

View File

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

View File

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

View File

@ -66,7 +66,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
String mnemonic = instr.getMnemonicString();
@ -124,7 +124,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
if (instr.getFlowType().isJump()) {
return false;
}
@ -132,7 +132,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
return false;
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
}
@Override
@ -153,6 +153,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
return false;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) {
Address constant, int size, DataType dataType, RefType refType) {
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
if (targetList.contains(address)) {
return false;
}

View File

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

View File

@ -81,7 +81,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@ -104,7 +104,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
// if LR is a constant and is set right after this, this is a call
Varnode lrVal = context.getRegisterVarnodeValue(lrRegister);
if (lrVal != null) {
if (lrVal.isConstant()) {
if (context.isConstant(lrVal)) {
long target = lrVal.getAddress().getOffset();
Address addr = instr.getMaxAddress().add(1);
if (target == addr.getOffset() && !instr.getFlowType().isCall()) {
@ -176,7 +176,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
if (refType.isJump() && refType.isComputed() &&
program.getMemory().contains(address) && address.getOffset() != 0) {
if (instr.getMnemonicString().startsWith("tb")) {
@ -184,24 +184,29 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
}
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor);
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
return !symEval.encounteredBranch();
}
if (refType.isData() && program.getMemory().contains(address)) {
if (refType.isRead() || refType.isWrite()) {
int numOperands = instr.getNumOperands();
// if two operands, then all read/write refs go on the 2nd operand
createData(program, address, size);
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
SourceType.ANALYSIS);
return false;
if (numOperands <= 2) {
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
SourceType.ANALYSIS);
return false;
}
return true;
}
}
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
// must disassemble right now, because TB flag could get set back at end of blx
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor);
return false;
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
}
@Override
@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
// check if a return is actually returning, or is branching with a constant PC
if (retVN != null && retVN.isConstant()) {
if (retVN != null && context.isConstant(retVN)) {
long offset = retVN.getOffset();
if (offset > 3 && offset != -1) {
// need to override the return to a branch
@ -236,6 +241,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
return false;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) {
Address constant, int size, DataType dataType, RefType refType) {
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
// if ever see a reference to 0, something went wrong, stop the process
if (address == null) {

View File

@ -25,6 +25,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
@ -247,7 +248,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
private Address localGPAssumptionValue = currentGPAssumptionValue;
private boolean mustStopNow = false; // if something discovered in processing, mustStop flag
@ -267,7 +268,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
// this was copylefted from the arm analyzer
Varnode raVal = context.getRegisterVarnodeValue(rareg);
if (raVal != null) {
if (raVal.isConstant()) {
if (context.isConstant(raVal)) {
long target = raVal.getAddress().getOffset();
Address addr = instr.getMaxAddress();
if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) {
@ -317,22 +318,25 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
lastSetInstr = instructionAt;
}
}
symEval.makeReference(context, lastSetInstr, -1,
instr.getMinAddress().getAddressSpace().getSpaceID(),
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
monitor);
if (localGPAssumptionValue == null) {
program.getBookmarkManager().setBookmark(
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
"GP Global Register Set",
"Global GP Register is set here.");
}
if (localGPAssumptionValue != null &&
!localGPAssumptionValue.equals(gpRefAddr)) {
localGPAssumptionValue = gp_assumption_value = null;
}
else {
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
// if an instruction actually set the GP
if (lastSetAddr != null) {
symEval.makeReference(context, lastSetInstr, -1,
instr.getMinAddress().getAddressSpace().getSpaceID(),
unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
false, monitor);
if (localGPAssumptionValue == null) {
program.getBookmarkManager().setBookmark(
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
"GP Global Register Set",
"Global GP Register is set here.");
}
if (localGPAssumptionValue != null &&
!localGPAssumptionValue.equals(gpRefAddr)) {
localGPAssumptionValue = gp_assumption_value = null;
}
else {
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
}
}
}
}
@ -372,9 +376,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
Address addr = address;
if (addr == Address.NO_ADDRESS) {
return false;
}
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
// if this isn't straight code (thunk computation), let someone else lay down the reference
@ -386,9 +394,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
if ((refType.isJump() || refType.isCall()) & refType.isComputed()) {
//if (refType.isJump() || refType.isCall()) {
addr = mipsExtDisassembly(program, instr, context, address, monitor);
//addr = flowISA(program, instr, context, address);
if (addr == null) {
addr = address;
}
@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
context.clearRegister(reg);
// need to add the reference here, register operand will no longer have a value
instr.addOperandReference(0, addr, refType,
instr.addOperandReference(0, addr, instr.getFlowType(),
SourceType.ANALYSIS);
// set the register value on the target address
@ -433,7 +439,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
}
@Override
@ -497,6 +503,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
return null;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);

View File

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

View File

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

View File

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

View File

@ -99,7 +99,7 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
private boolean mustStopNow = false;
@Override
@ -112,7 +112,13 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
return mustStopNow;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
return resultSet;

View File

@ -76,7 +76,7 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@ -126,7 +126,13 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
return false;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
return resultSet;

View File

@ -21,6 +21,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.PcodeOp;
@ -76,11 +77,11 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
if (address.isExternalAddress()) {
return true;
@ -98,7 +99,7 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
}
boolean doRef =
super.evaluateReference(context, instr, pcodeop, address, size, refType);
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
if (!doRef) {
return false;
}
@ -109,6 +110,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
return doRef;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);

View File

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

View File

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