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

This commit is contained in:
Ryan Kurtz 2023-05-01 06:25:01 -04:00
commit 5b6a902c8c
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,11 +132,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
return true; // just go ahead and mark up the instruction
}
};
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
symEval.setParamRefCheck(true);
symEval.setReturnRefCheck(true);
@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
symEval.flowConstants(start, func.getBody(), eval, true, monitor);
// now handle symbolic execution assuming values!
eval = new ConstantPropagationContextEvaluator() {
eval = new ConstantPropagationContextEvaluator(monitor) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr,
int pcodeop, Address constant, int size, RefType refType) {
int pcodeop, Address constant, int size, DataType dataType, RefType refType) {
// don't create any references from constants, only looking for flow refs
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, RefType refType) {
int pcodeop, Address address, int size, DataType dataType, RefType refType) {
// TODO: if ever loading from instructions in memory, must
// EXIT!
if (!(instr.getFlowType().isComputed() &&
@ -221,6 +225,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
}
};
eval.setTrustWritableMemory(true)
.setCreateComplexDataFromPointers(true);
// now flow with the simple block of this branch....
// for each unknown branch destination,

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

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.*;
@ -145,6 +146,16 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
addressTablesEnabled = false;
}
boolean isArm = program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor("ARM"));
// if arm, turn off reference to pointer analysis
if (isArm) {
pointerEnabled = false;
addressTablesEnabled = false;
}
// only analyze programs with address spaces > 16 bits
int bitSize = defaultAddressSpace.getSize();
return bitSize > 16;

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

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

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
@ -154,6 +154,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
//
@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) {
Address constant, int size, DataType dataType, RefType refType) {
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
if (targetList.contains(address)) {
return false;
}

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);
if (numOperands <= 2) {
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
SourceType.ANALYSIS);
return false;
}
return true;
}
}
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
// must disassemble right now, because TB flag could get set back at end of blx
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
true, monitor);
return false;
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
}
@Override
@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
// check if a return is actually returning, or is branching with a constant PC
if (retVN != null && retVN.isConstant()) {
if (retVN != null && context.isConstant(retVN)) {
long offset = retVN.getOffset();
if (offset > 3 && offset != -1) {
// need to override the return to a branch
@ -237,6 +242,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
if (recoverSwitchTables) {
@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
@Override
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
Address constant, int size, RefType refType) {
Address constant, int size, DataType dataType, RefType refType) {
return null;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
// if ever see a reference to 0, something went wrong, stop the process
if (address == null) {

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,10 +318,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
lastSetInstr = instructionAt;
}
}
// if an instruction actually set the GP
if (lastSetAddr != null) {
symEval.makeReference(context, lastSetInstr, -1,
instr.getMinAddress().getAddressSpace().getSpaceID(),
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
monitor);
unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
false, monitor);
if (localGPAssumptionValue == null) {
program.getBookmarkManager().setBookmark(
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
@ -338,6 +341,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
}
}
}
return mustStopNow;
}
@ -372,10 +376,14 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
Address address, int size, RefType refType) {
Address address, int size, DataType dataType, RefType refType) {
Address addr = address;
if (addr == Address.NO_ADDRESS) {
return false;
}
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
// if this isn't straight code (thunk computation), let someone else lay down the reference
// return !symEval.encounteredBranch();
@ -386,9 +394,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
if ((refType.isJump() || refType.isCall()) & refType.isComputed()) {
//if (refType.isJump() || refType.isCall()) {
addr = mipsExtDisassembly(program, instr, context, address, monitor);
//addr = flowISA(program, instr, context, address);
if (addr == null) {
addr = address;
}
@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
context.clearRegister(reg);
// need to add the reference here, register operand will no longer have a value
instr.addOperandReference(0, addr, refType,
instr.addOperandReference(0, addr, instr.getFlowType(),
SourceType.ANALYSIS);
// set the register value on the target address
@ -433,7 +439,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
}
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
}
@Override
@ -498,6 +504,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
// Add in any addresses we should assume got covered

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
@ -113,6 +113,12 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
return resultSet;

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) {
@ -127,6 +127,12 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
return resultSet;

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;
}
@ -110,6 +111,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
return resultSet;

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;