diff --git a/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java b/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java index d7df2aff8d..04dc9c79fa 100644 --- a/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java +++ b/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java @@ -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, diff --git a/Ghidra/Features/Base/ghidra_scripts/PropagateConstantReferences.java b/Ghidra/Features/Base/ghidra_scripts/PropagateConstantReferences.java index ed529a0cfb..0c6bd32aa6 100644 --- a/Ghidra/Features/Base/ghidra_scripts/PropagateConstantReferences.java +++ b/Ghidra/Features/Base/ghidra_scripts/PropagateConstantReferences.java @@ -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); diff --git a/Ghidra/Features/Base/ghidra_scripts/PropagateX86ConstantReferences.java b/Ghidra/Features/Base/ghidra_scripts/PropagateX86ConstantReferences.java index 6d4379c26a..c45cae374f 100644 --- a/Ghidra/Features/Base/ghidra_scripts/PropagateX86ConstantReferences.java +++ b/Ghidra/Features/Base/ghidra_scripts/PropagateX86ConstantReferences.java @@ -31,6 +31,7 @@ import ghidra.app.plugin.core.disassembler.AddressTable; import ghidra.app.script.GhidraScript; import ghidra.program.model.address.*; import ghidra.program.model.block.*; +import ghidra.program.model.data.DataType; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; @@ -88,7 +89,7 @@ public class PropagateX86ConstantReferences extends GhidraScript { // use context to fill out addresses on certain instructions // Always trust values read from writable memory ConstantPropagationContextEvaluator eval = - new ConstantPropagationContextEvaluator(true) { + new ConstantPropagationContextEvaluator(monitor, true) { @Override public boolean evaluateDestination(VarnodeContext context, Instruction instruction) { @@ -131,10 +132,13 @@ public class PropagateX86ConstantReferences extends GhidraScript { @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, - int pcodeop, Address address, int size, RefType refType) { + int pcodeop, Address address, int size, DataType dataType, RefType refType) { return true; // just go ahead and mark up the instruction } }; + + eval.setTrustWritableMemory(true) + .setCreateComplexDataFromPointers(true); SymbolicPropogator symEval = new SymbolicPropogator(currentProgram); symEval.setParamRefCheck(true); @@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript { symEval.flowConstants(start, func.getBody(), eval, true, monitor); // now handle symbolic execution assuming values! - eval = new ConstantPropagationContextEvaluator() { + eval = new ConstantPropagationContextEvaluator(monitor) { @Override public boolean evaluateContext(VarnodeContext context, Instruction instr) { @@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript { @Override public Address evaluateConstant(VarnodeContext context, Instruction instr, - int pcodeop, Address constant, int size, RefType refType) { + int pcodeop, Address constant, int size, DataType dataType, RefType refType) { // don't create any references from constants, only looking for flow refs return null; } @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, - int pcodeop, Address address, int size, RefType refType) { + int pcodeop, Address address, int size, DataType dataType, RefType refType) { // TODO: if ever loading from instructions in memory, must // EXIT! if (!(instr.getFlowType().isComputed() && @@ -220,6 +224,9 @@ public class PropagateX86ConstantReferences extends GhidraScript { return true; } }; + + eval.setTrustWritableMemory(true) + .setCreateComplexDataFromPointers(true); // now flow with the simple block of this branch.... diff --git a/Ghidra/Features/Base/ghidra_scripts/ResolveX86orX64LinuxSyscallsScript.java b/Ghidra/Features/Base/ghidra_scripts/ResolveX86orX64LinuxSyscallsScript.java index 633b446c2f..536008e3db 100644 --- a/Ghidra/Features/Base/ghidra_scripts/ResolveX86orX64LinuxSyscallsScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/ResolveX86orX64LinuxSyscallsScript.java @@ -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)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index f83c33521a..79d704577d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -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)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java index 79496bfa78..c8c1b0f931 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java @@ -38,55 +38,71 @@ import ghidra.util.task.TaskMonitor; public class ConstantPropagationAnalyzer extends AbstractAnalyzer { private static final String NAME = " Constant Reference Analyzer"; - private static final String DESCRIPTION = + + static final String DESCRIPTION = " Constant Propagation Analyzer for constant references computed with multiple instructions."; + protected static final String OPTION_NAME = "Function parameter/return Pointer analysis"; protected static final String OPTION_DESCRIPTION = "Turn on to check if values passed as parameters or returned could be pointer references"; protected static final boolean OPTION_DEFAULT_VALUE = true; + protected static final String POINTER_PARAM_OPTION_NAME = "Require pointer param data type"; + protected static final String POINTER_PARAM_OPTION_DESCRIPTION = + "Turn on to require values passed as parameters or returned to be a known pointer data type"; + protected static final boolean POINTER_PARAM_OPTION_DEFAULT_VALUE = false; + protected static final String STORED_OPTION_NAME = "Stored Value Pointer analysis"; protected static final String STORED_OPTION_DESCRIPTION = "Turn on to check if values stored into memory or the stack could be pointer references"; protected static final boolean STORED_OPTION_DEFAULT_VALUE = true; - protected static final String TRUSTWRITEMEM_OPTION_NAME = + protected static final String TRUST_WRITEMEM_OPTION_NAME = "Trust values read from writable memory"; - protected static final String TRUSTWRITEMEM_OPTION_DESCRIPTION = + protected static final String TRUST_WRITEMEM_OPTION_DESCRIPTION = "Turn on to trust values read from writable memory"; - protected static final boolean TRUSTWRITEMEM_OPTION_DEFAULT_VALUE = true; + protected static final boolean TRUST_WRITEMEM_OPTION_DEFAULT_VALUE = true; - protected static final String MAXTHREADCOUNT_OPTION_NAME = "Max Threads"; - protected static final String MAXTHREADCOUNT_OPTION_DESCRIPTION = + protected static final String MAX_THREAD_COUNT_OPTION_NAME = "Max Threads"; + protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION = "Maximum threads for constant propagation. Too many threads causes thrashing in DB."; - protected static final int MAXTHREADCOUNT_OPTION_DEFAULT_VALUE = 2; + protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2; - protected static final String MINKNOWNREFADDRESS_OPTION_NAME = "Min absolute reference"; - protected static final String MINKNOWNREFADDRESS_OPTION_DESCRIPTION = + protected static final String MIN_KNOWN_REFADDRESS_OPTION_NAME = "Min absolute reference"; + protected static final String MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION = "Minimum address for calcuated constant store/load references"; - protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4; + protected static final int MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE = 4; - protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME = + protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_NAME = "Speculative reference min"; - protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = + protected static final String MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION = "Minimum speculative reference address for offsets and parameters"; - protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024; + protected static final int MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 1024; - protected static final String MAXSPECULATIVEREFADDRESS_OPTION_NAME = + protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_NAME = "Speculative reference max"; - protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = - "Maxmimum speculative reference address offset from the end of memory for offsets and parameters"; - protected static final int MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 256; + protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION = + "Prototype - Maxmimum speculative reference address offset from the end of memory for offsets and parameters"; + protected static final int MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE = 256; + + protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME = + "Create Data from pointer"; + protected static final String CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION = + "Create complex data types from pointers if the data type is known, currently from function parameters."; + protected static final boolean CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE = false; protected final static int NOTIFICATION_INTERVAL = 100; protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE; + protected boolean checkPointerParamRefsOption = POINTER_PARAM_OPTION_DEFAULT_VALUE; protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE; - protected boolean trustWriteMemOption = TRUSTWRITEMEM_OPTION_DEFAULT_VALUE; - protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE; - protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE; - protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; - protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; + protected boolean trustWriteMemOption = TRUST_WRITEMEM_OPTION_DEFAULT_VALUE; + protected boolean createComplexDataFromPointers = CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE; + + protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE; + protected long minStoreLoadRefAddress = MIN_KNOWN_REFADDRESS_OPTION_DEFAULT_VALUE; + protected long minSpeculativeRefAddress = MIN_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE; + protected long maxSpeculativeRefAddress = MAX_SPECULATIVE_REFADDRESS_OPTION_DEFAULT_VALUE; protected boolean followConditional = false; @@ -105,6 +121,10 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before().before().before().before()); } + public ConstantPropagationAnalyzer(String processorName, AnalyzerType type) { + super(processorName + NAME, processorName + DESCRIPTION, type); + } + /** * Called to to register a more specific analyzer. * @@ -114,13 +134,25 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { handledProcessors.add(processorName); } + /** + * Called to register a more specific analyzer. + * + * @param processorName + */ + static public boolean isClaimedProcessor(String processorName) { + return handledProcessors.contains(processorName); + } + @Override public boolean canAnalyze(Program program) { // Set the default for checking parameter passing // don't look for constant passing in things that have a small address space, or is segmented - checkParamRefsOption = program.getDefaultPointerSize() > 2; - checkParamRefsOption &= - !(program.getAddressFactory().getDefaultAddressSpace() instanceof SegmentedAddressSpace); + // unless there is a good data type at the location + boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace(); + checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard; + + checkParamRefsOption = !(program.getAddressFactory() + .getDefaultAddressSpace() instanceof SegmentedAddressSpace); if (processorName.equals("Basic")) { if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) { @@ -129,8 +161,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { return true; } - return program.getLanguage().getProcessor().equals( - Processor.findOrPossiblyCreateProcessor(processorName)); + return program.getLanguage() + .getProcessor() + .equals(Processor.findOrPossiblyCreateProcessor(processorName)); } @Override @@ -138,7 +171,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { throws CancelledException { AddressSet unanalyzedSet = new AddressSet(set); - + removeUninitializedBlocks(program, unanalyzedSet); try { @@ -434,6 +467,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { SymbolicPropogator symEval = new SymbolicPropogator(program); symEval.setParamRefCheck(checkParamRefsOption); + + symEval.setParamPointerRefCheck(checkPointerParamRefsOption); + symEval.setReturnRefCheck(checkParamRefsOption); symEval.setStoredRefCheck(checkStoredRefsOption); @@ -456,8 +492,12 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor) throws CancelledException { - ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption, - minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress); + ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor) + .setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); return symEval.flowConstants(flowStart, flowSet, eval, true, monitor); } @@ -515,39 +555,52 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { options.registerOption(OPTION_NAME, checkParamRefsOption, null, OPTION_DESCRIPTION); options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null, STORED_OPTION_DESCRIPTION); - options.registerOption(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption, null, - TRUSTWRITEMEM_OPTION_DESCRIPTION); - options.registerOption(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount, null, - MAXTHREADCOUNT_OPTION_DESCRIPTION); + options.registerOption(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption, null, + TRUST_WRITEMEM_OPTION_DESCRIPTION); - options.registerOption(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null, - MINKNOWNREFADDRESS_OPTION_DESCRIPTION); + options.registerOption(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers, null, + CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DESCRIPTION); + + options.registerOption(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption, null, + POINTER_PARAM_OPTION_DESCRIPTION); + + options.registerOption(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount, null, + MAX_THREAD_COUNT_OPTION_DESCRIPTION); + + options.registerOption(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null, + MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION); long size = program.getAddressFactory().getDefaultAddressSpace().getSize(); minSpeculativeRefAddress = size * 16; - options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null, - MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); + options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null, + MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION); maxSpeculativeRefAddress = size * 8; - options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null, - MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); + options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null, + MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION); } @Override public void optionsChanged(Options options, Program program) { checkParamRefsOption = options.getBoolean(OPTION_NAME, checkParamRefsOption); - checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption); - trustWriteMemOption = options.getBoolean(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption); - maxThreadCount = options.getInt(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount); + checkPointerParamRefsOption = + options.getBoolean(POINTER_PARAM_OPTION_NAME, checkPointerParamRefsOption); + + checkStoredRefsOption = options.getBoolean(STORED_OPTION_NAME, checkStoredRefsOption); + trustWriteMemOption = options.getBoolean(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption); + + createComplexDataFromPointers = options.getBoolean(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers); + + maxThreadCount = options.getInt(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount); // TODO: there should be a getAddress on option that validates and allows entry of addresses minStoreLoadRefAddress = - options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress); + options.getLong(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress); minSpeculativeRefAddress = - options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress); + options.getLong(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress); maxSpeculativeRefAddress = - options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress); + options.getLong(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java index 33443be8b1..21b6150e86 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java @@ -15,14 +15,24 @@ */ package ghidra.app.plugin.core.analysis; +import ghidra.app.cmd.function.*; +import ghidra.app.cmd.disassemble.DisassembleCommand; +import ghidra.app.services.AnalysisPriority; +import ghidra.app.util.PseudoDisassembler; import ghidra.program.model.address.*; -import ghidra.program.model.listing.Instruction; +import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.mem.MemoryBufferImpl; import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.util.ContextEvaluatorAdapter; import ghidra.program.util.VarnodeContext; +import ghidra.util.task.TaskMonitor; -/** +/** * The ConstantPropogatorEvaluator is used as the evaluator for the SymbolicPropagator when finding constant * references and laying them down for a generic processor. Extend this class to add additional checks * and behaviors necessary for a unique processor such as the PowerPC. @@ -39,31 +49,95 @@ import ghidra.program.util.VarnodeContext; */ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter { + private static final int MAX_UNICODE_STRING_LEN = 200; + private static final int MAX_CHAR_STRING__LEN = 100; protected AddressSet destSet = new AddressSet(); private boolean trustMemoryWrite = false; + private boolean createDataFromPointers = false; private long minStoreLoadOffset = 4; private long minSpeculativeOffset = 1024; // from the beginning of memory private long maxSpeculativeOffset = 256; // from the end of memory + + protected TaskMonitor monitor; + private final int NULL_TERMINATOR_PROBE = -1; - public ConstantPropagationContextEvaluator() { + public ConstantPropagationContextEvaluator(TaskMonitor monitor) { + this.monitor = monitor; } /** + * @param monitor TODO * @param trustMemoryWrite - true to trust values read from memory that is marked writable */ - public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) { + public ConstantPropagationContextEvaluator(TaskMonitor monitor, boolean trustMemoryWrite) { + this.monitor = monitor; this.trustMemoryWrite = trustMemoryWrite; } - public ConstantPropagationContextEvaluator(boolean trustWriteMemOption, - long minStoreLoadRefAddress, long minSpeculativeRefAddress, - long maxSpeculativeRefAddress) { - this(trustWriteMemOption); + public ConstantPropagationContextEvaluator(TaskMonitor monitor, + boolean trustWriteMemOption, long minStoreLoadRefAddress, + long minSpeculativeRefAddress, long maxSpeculativeRefAddress) { + this(monitor, trustWriteMemOption); this.minStoreLoadOffset = minStoreLoadRefAddress; this.minSpeculativeOffset = minSpeculativeRefAddress; this.maxSpeculativeOffset = maxSpeculativeRefAddress; } + + /** + * Set option to trust reads from memory that is marked writeable + * + * @param trustWriteableMemOption true to trust values read from memory that is marked writable + * @return this + */ + public ConstantPropagationContextEvaluator setTrustWritableMemory(boolean trustWriteableMemOption) { + trustMemoryWrite = trustWriteableMemOption; + return this; + } + /** + * Set mimimum speculative memory offset for references + * + * @param minSpeculativeRefAddress minimum address offset + * @return this + */ + public ConstantPropagationContextEvaluator setMinpeculativeOffset(long minSpeculativeRefAddress) { + minSpeculativeOffset = minSpeculativeRefAddress; + return this; + } + + /** + * Set maximum speculative memory offset for references + * + * @param maxSpeculativeRefAddress maximum address offset + * @return this + */ + public ConstantPropagationContextEvaluator setMaxSpeculativeOffset(long maxSpeculativeRefAddress) { + maxSpeculativeOffset = maxSpeculativeRefAddress; + return this; + } + + /** + * Set maximum speculative memory offset for references + * + * @param minStoreLoadRefAddress maximum address offset + * @return this + */ + public ConstantPropagationContextEvaluator setMinStoreLoadOffset(long minStoreLoadRefAddress) { + maxSpeculativeOffset = minStoreLoadRefAddress; + return this; + } + + /** + * Set option to create complex data for pointers if the datatype is known + * + * @param doCreateData true to create complex data types if the data type is known + * @return this + */ + public ConstantPropagationContextEvaluator setCreateComplexDataFromPointers(boolean doCreateData) { + createDataFromPointers = doCreateData; + return this; + } + /** * The computed destination set is useful if follow on switch analysis is to be done. * @@ -79,7 +153,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter */ @Override public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, - Address constant, int size, RefType refType) { + Address constant, int size, DataType dataType, RefType refType) { // Constant references below minSpeculative or near the end of the address space are suspect, // even if memory exists for those locations. @@ -107,8 +181,8 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter */ @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, - Address address, int size, RefType refType) { - + Address address, int size, DataType dataType, RefType refType) { + // special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally // really there should be another callback when adding parameters if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) { @@ -137,8 +211,241 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter } } + Program program = instr.getProgram(); + AutoAnalysisManager aMgr= AutoAnalysisManager.getAnalysisManager(program); + + // if data reference, handle data + if (refType.isData()) { + createPointedToData(aMgr, program, address, refType, dataType, size); + } + + // if flowing to an address, disassemble it + if (refType.isFlow() && !refType.isIndirect() && + !program.getMemory().isExternalBlockAddress(address)) { + Data udata = program.getListing().getUndefinedDataAt(address); + if (udata != null) { + DisassembleCommand cmd = new DisassembleCommand(address, null, true); + cmd.applyTo(program, monitor); + } + // + // TODO: need to kick analysis if the target is a function and non-returning + // Function functionAt = program.getFunctionManager().getFunctionAt(address); + // if (functionAt != null && functionAt.hasNoReturn()) { + // aMgr.functionModifierChanged(address); + // } + } + return true; } + + private int createPointedToData(AutoAnalysisManager aMgr, Program program, Address address, RefType refType, DataType dataType, int size) { + // don't do in external memory + if (program.getMemory().isExternalBlockAddress(address) || address.isExternalAddress()) { + return 0; + } + + // don't create if not in real memory + if (!program.getMemory().contains(address)) { + return 0; + } + + // Get the data type that is pointed to, strip off pointer, or pointer typedef + DataType pointedToDT = null; + if (dataType instanceof Pointer ptr) { + pointedToDT = ptr.getDataType(); + } + else if ((dataType instanceof TypeDef typeDef && typeDef.getBaseDataType() instanceof Pointer ptr)) { + pointedToDT = ptr.getDataType(); + } + + // if this is a function pointer, create the code/function/signature + if (pointedToDT instanceof FunctionDefinition funcDefn) { + createFunctionApplySignature(aMgr, program, address, funcDefn); + return dataType.getLength(); + } + + // otherwise it is data + + if (dataType != null) { + // System.out.println("@ " + address + " Data Type - " + dataType); + } + + return createData(program, address, pointedToDT, size); + } + + /** + * Create Data at an address in the program + * + * @param program the program + * @param address location to create data + * @param dataType dataType if known + * @param size size of the data type (from a read/write) + * @return size of the data item created, or 0 if none created + */ + private int createData(Program program, Address address, DataType dataType, int size) { + // defined data (that isn't an undefined) don't do anything + Data data = program.getListing().getDataAt(address); + if (data == null || !Undefined.isUndefined(data.getDataType())) { + return 0; + } + + // get a default undefined data type of the right size for the access + DataType dt = Undefined.getUndefinedDataType(size); + + int maxLen = -1; + if (createDataFromPointers && dataType != null) { + DataType originalDT = dataType; + + // if typedef, get the base type + if (dataType instanceof TypeDef typeDef) { + dataType = typeDef.getBaseDataType(); + } + + if (dataType instanceof CharDataType) { + // Use Terminated in case strings are referenced offcut + maxLen = getRestrictedStringLen(program, address, TerminatedStringDataType.dataType, MAX_CHAR_STRING__LEN); + if (maxLen > 0) { + dt = TerminatedStringDataType.dataType; + } + } else if (dataType instanceof WideCharDataType) { + maxLen = getRestrictedStringLen(program, address, TerminatedUnicodeDataType.dataType, MAX_UNICODE_STRING_LEN); + if (maxLen > 0) { + dt = TerminatedUnicodeDataType.dataType; + } + } else if (dataType instanceof Composite comp) { + // create empty structures, they can get filled out later + // if they don't fit later because they grow, then there will be an error at the location + dt = originalDT; // original might have been a typedef, use original + } else if (dataType instanceof VoidDataType) { + // ptr to void should be ignored + return 0; + } else if (dataType instanceof AbstractFloatDataType) { + dt = dataType; + } else { + // don't do any other types other than above for now + return 0; + } + } else if (size < 1 || size > 8) { + return 0; + } + + try { + // create data at the location so that we record the access size + // the data is undefined, and SHOULD be overwritten if something + // else knows better about the location. + if (maxLen > 0) { + data = DataUtilities.createData(program, address, dt, maxLen, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + } else { + data = DataUtilities.createData(program, address, dt, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + } + return data.getLength(); + } + catch (CodeUnitInsertionException e) { + // couldn't create data + } + + return 0; + } + + /** + * Create a function/code at a location and apply the + * + * @param aMgr auto analysis manager + * @param program the program + * @param address location to create function + * @param funcDefn function definition if known + */ + private void createFunctionApplySignature(AutoAnalysisManager aMgr, Program program, + Address address, FunctionDefinition funcDefn) { + + // System.out.println("@ " + address + " - Typedef Function " + ((FunctionDefinition)ptrToDT).getPrototypeString()); + + Listing listing = program.getListing(); + + // defined data (that isn't an undefined) don't do anything + Data data = listing.getDefinedDataContaining(address); + if (data != null) { + return; + } + + // if memory is undefined bytes, don't disassemble or create function + MemoryBlock block = program.getMemory().getBlock(address); + if (block == null || !block.isInitialized()) { + return; + } + + // normalize the address to where code should start (ARM and MIPS can be offset by one) + Address normalizedAddr = PseudoDisassembler.getNormalizedDisassemblyAddress(program, address); + if (!listing.isUndefined(normalizedAddr, normalizedAddr)) { + // if not undefined, must be an instruction to continue + Instruction instr = listing.getInstructionAt(normalizedAddr); + if (instr == null) { + return; + } + } else { + // if nothing defined here, disassemble + address = PseudoDisassembler.setTargeContextForDisassembly(program, address); + DisassembleCommand cmd = new DisassembleCommand(address, null, true); + cmd.applyTo(program, monitor); + } + + // see if there is an existing function + FunctionManager funcMgr = program.getFunctionManager(); + Function func = funcMgr.getFunctionAt(address); + // if no function at the address, make sure not in the middle of a function + if (func == null) { + func = funcMgr.getFunctionContaining(address); + // don't create a function in the middle of another + if (func != null) { + return; + } + } + + if (func != null) { + if (func.isThunk()) { + return; + } + + SourceType mostTrusted = getMostTrustedParameterSource(func); + if (SourceType.ANALYSIS.isLowerPriorityThan(mostTrusted)) { + return; + } + } else { + CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(address, false); + aMgr.schedule(createFunctionCmd, AnalysisPriority.FUNCTION_ANALYSIS.priority()); + } + + // only apply the signature if actually creating data, the function/code has already been created + if (!createDataFromPointers) { + return; + } + + // if no arguments, could be an opaque function pointer, don't apply arguments + ParameterDefinition[] arguments = funcDefn.getArguments(); + DataType returnType = funcDefn.getReturnType(); + if (arguments == null || (arguments.length == 0 && (returnType==null || Undefined.isUndefined(returnType)))) { + return; + } + + // applying function signatures considered data + // don't change name, even default name + ApplyFunctionSignatureCmd applyFunctionSignatureCmd = new ApplyFunctionSignatureCmd(address, funcDefn, SourceType.ANALYSIS, true, FunctionRenameOption.NO_CHANGE); + aMgr.schedule(applyFunctionSignatureCmd, AnalysisPriority.FUNCTION_ANALYSIS.after().priority()); + } + + private SourceType getMostTrustedParameterSource(Function func) { + SourceType highestSource = func.getSignatureSource(); + Parameter[] parameters = func.getParameters(); + for (Parameter parameter : parameters) { + SourceType paramSource = parameter.getSource(); + if (paramSource.isHigherPriorityThan(highestSource)) { + highestSource = paramSource; + } + } + return highestSource; + } /** * Add instructions to destination set for unknown computed branches. @@ -168,4 +475,60 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter public boolean allowAccess(VarnodeContext context, Address addr) { return trustMemoryWrite; } + + /** + * Looks at bytes at given address and converts to format String + * + * @param address Address of format String + * @param pointer Pointer "type" of string + * @return format String + */ + int getRestrictedStringLen(Program program, Address address, AbstractStringDataType dataType, int maxLength) { + + maxLength = getMaxStringLength(program, address, maxLength); + + MemoryBufferImpl memoryBuffer = + new MemoryBufferImpl(program.getMemory(), address); + + StringDataInstance stringDataInstance = dataType.getStringDataInstance(memoryBuffer, dataType.getDefaultSettings(), -1); + stringDataInstance.getStringDataTypeGuess(); + + int detectedLength = stringDataInstance.getStringLength(); + if (detectedLength == -1) { + return 0; + } + + if (detectedLength > maxLength) { + detectedLength = maxLength; + } + + return detectedLength; + } + + /** + * Get the number of bytes to the next reference, or the max length + * + * @param program + * @param address + * @return maximum length to create the string + */ + private int getMaxStringLength(Program program, Address address, int maxLen) { + AddressIterator refIter = program.getReferenceManager().getReferenceDestinationIterator(address.next(), true); + Address next = refIter.next(); + if (next == null) { + return -1; + } + + long len = -1; + try { + len = next.subtract(address); + if (len > maxLen) { + len = maxLen; + } + return (int) len; + } catch (IllegalArgumentException exc) { + // bad address subtraction + } + return (int) len; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java index 133c3ca89a..b87685ff9c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java @@ -36,6 +36,7 @@ import ghidra.framework.options.Options; import ghidra.program.disassemble.Disassembler; import ghidra.program.model.address.*; import ghidra.program.model.data.*; +import ghidra.program.model.lang.Processor; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; import ghidra.program.model.mem.*; @@ -144,7 +145,17 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer { pointerEnabled = false; addressTablesEnabled = false; } + + boolean isArm = program.getLanguage() + .getProcessor() + .equals(Processor.findOrPossiblyCreateProcessor("ARM")); + // if arm, turn off reference to pointer analysis + if (isArm) { + pointerEnabled = false; + addressTablesEnabled = false; + } + // only analyze programs with address spaces > 16 bits int bitSize = defaultAddressSpace.getSize(); return bitSize > 16; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluator.java index 4e2347d75f..3babb2d55e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluator.java @@ -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 diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluatorAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluatorAdapter.java index bd33885910..89ac3a9e36 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluatorAdapter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ContextEvaluatorAdapter.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 78071a27d2..437bbef8eb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -27,12 +27,13 @@ import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; -import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.*; import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.*; import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.BigEndianDataConverter; import ghidra.util.Msg; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; @@ -62,6 +63,7 @@ public class SymbolicPropogator { protected boolean readExecutableAddress; protected VarnodeContext context; + protected AddressSet body; // body of processed instructions protected boolean hitCodeFlow = false; // no branching so far protected boolean debug = false; @@ -73,6 +75,8 @@ public class SymbolicPropogator { new NotFoundException("Divide by zero"); private long pointerMask; + private int pointerSize; + private DataType pointerSizedDT = null; protected static final int MAX_EXACT_INSTRUCTIONS = 100; @@ -119,7 +123,9 @@ public class SymbolicPropogator { if (ptrSize > 8) { ptrSize = 8; } + pointerSize = ptrSize; pointerMask = maskSize[ptrSize]; + pointerSizedDT = IntegerDataType.getUnsignedDataType(pointerSize, null); } /** @@ -297,7 +303,7 @@ public class SymbolicPropogator { if (val == null) { return null; } - if (val.isConstant()) { + if (context.isConstant(val)) { return new Value(val.getOffset()); } AddressSpace space = val.getAddress().getAddressSpace(); @@ -390,6 +396,7 @@ public class SymbolicPropogator { protected int sameInstrCount = 0; // # of the same instructions private boolean checkForParamRefs = true; // true if params to functions should be checked for references + private boolean checkForParamPointerRefs = true; // true if param must be a marked pointer data type private boolean checkForReturnRefs = true; // true if return values from functions should be checked for references private boolean checkForStoredRefs = true; // true if stored values should be checked for references @@ -402,7 +409,7 @@ public class SymbolicPropogator { public AddressSet flowConstants(Address fromAddr, Address startAddr, AddressSetView restrictSet, ContextEvaluator eval, VarnodeContext vContext, TaskMonitor monitor) throws CancelledException { - AddressSet body = new AddressSet(); + body = new AddressSet(); AddressSet conflicts = new AddressSet(); // prime the context stack with the entry point address @@ -762,7 +769,8 @@ public class SymbolicPropogator { } Address minInstrAddress = instruction.getMinAddress(); - if (debug) { + if (debug) + { Msg.info(this, minInstrAddress + " " + instruction); } @@ -788,6 +796,7 @@ public class SymbolicPropogator { Varnode val1, val2, val3, result; long lval1, lval2; long lresult; + boolean suspectOffset = false; Varnode vt; if (debug) { Msg.info(this, " " + pcodeOp); @@ -798,8 +807,8 @@ public class SymbolicPropogator { case PcodeOp.COPY: if (in[0].isAddress() && !in[0].getAddress().getAddressSpace().hasMappedRegisters()) { - makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], - RefType.READ, monitor); + makeReference(vContext, instruction, Reference.MNEMONIC, in[0], + null, RefType.READ, ptype, true, monitor); } vContext.copy(out, in[0], mustClearAll, evaluator); break; @@ -808,23 +817,35 @@ public class SymbolicPropogator { val1 = vContext.getValue(in[0], evaluator); val2 = vContext.getValue(in[1], evaluator); + suspectOffset = vContext.isSuspectConstant(val2); + vt = vContext.getVarnode(in[0], val2, out.getSize(), evaluator); - + // TODO: may need to use DATA refType in some cases addLoadStoreReference(vContext, instruction, ptype, vt, in[0], in[1], - RefType.READ, monitor); + RefType.READ, suspectOffset==false, monitor); // If vt is a bad varnode (bad space, no memory, no value in varnode) you won't get a value Varnode memVal = vContext.getValue(vt, evaluator); vContext.putValue(out, memVal, mustClearAll); + break; case PcodeOp.STORE: - out = getStoredLocation(vContext, in); + Varnode offs = null; + try { + offs = vContext.getValue(in[1], true, evaluator); + suspectOffset = vContext.isSuspectConstant(offs); + out = getStoredLocation(vContext, in[0], offs, in[2]); + } catch (NotFoundException e) { + // if can't get the value of the relative store location + // this isn't an exception, the output will be null/unknown + } + // TODO: may need to use DATA refType in some cases addLoadStoreReference(vContext, instruction, ptype, out, in[0], in[1], - RefType.WRITE, monitor); + RefType.WRITE, suspectOffset==false, monitor); val3 = vContext.getValue(in[2], null); @@ -837,9 +858,11 @@ public class SymbolicPropogator { case PcodeOp.BRANCHIND: try { val1 = vContext.getValue(in[0], evaluator); + suspectOffset = vContext.isSuspectConstant(val1); + vt = getConstantOrExternal(vContext, minInstrAddress, val1); - makeReference(vContext, instruction, ptype, -1, vt, - instruction.getFlowType(), monitor); + makeReference(vContext, instruction, -1, vt, null, + instruction.getFlowType(), ptype, !suspectOffset, monitor); } catch (NotFoundException e) { // constant not found, ignore @@ -873,7 +896,8 @@ public class SymbolicPropogator { // TODO: Revisit handling of external functions... - if (val1.isConstant()) { + if (vContext.isConstant(val1)) { + suspectOffset = vContext.isSuspectConstant(val1); // indirect target - assume single code space (same as instruction) target = instruction.getAddress() .getNewTruncatedAddress(val1.getOffset(), true); @@ -893,11 +917,12 @@ public class SymbolicPropogator { // make sure we aren't replacing a read ref with a call to the same place if (refs.length <= 0 || !refs[0].getToAddress().equals(target)) { - makeReference(vContext, instruction, Reference.MNEMONIC, + target = makeReference(vContext, instruction, Reference.MNEMONIC, // Use target in case location has shifted (external...) target.getAddressSpace().getSpaceID(), target.getAddressableWordOffset(), val1.getSize(), - instruction.getFlowType(), ptype, true, monitor); + null, + instruction.getFlowType(), ptype, !suspectOffset, false, monitor); } } @@ -1103,8 +1128,8 @@ public class SymbolicPropogator { case PcodeOp.INT_ZEXT: if (in[0].isAddress()) { - makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], - RefType.READ, monitor); + makeReference(vContext, instruction, Reference.MNEMONIC, in[0], + null, RefType.READ, ptype, true, monitor); } val1 = vContext.extendValue(out, in, false, evaluator); vContext.putValue(out, val1, mustClearAll); @@ -1112,8 +1137,8 @@ public class SymbolicPropogator { case PcodeOp.INT_SEXT: if (in[0].isAddress()) { - makeReference(vContext, instruction, ptype, Reference.MNEMONIC, in[0], - RefType.READ, monitor); + makeReference(vContext, instruction, Reference.MNEMONIC, in[0], + null, RefType.READ, ptype, true, monitor); } val1 = vContext.extendValue(out, in, true, evaluator); vContext.putValue(out, val1, mustClearAll); @@ -1453,17 +1478,18 @@ public class SymbolicPropogator { } return vt; } - - private Varnode getStoredLocation(VarnodeContext vContext, Varnode[] in) { + + private Varnode getStoredLocation(VarnodeContext vContext, Varnode space, Varnode offset, Varnode size) { Varnode out = null; - Varnode val; - try { - // first create the ref, even if don't know the value to be stored - val = vContext.getValue(in[1], true, evaluator); + if (offset == null) { + return null; + } + + try { // out is a calculated location for store. If got to here, need to set out // because it might need to be cleared by a bad value access! - out = vContext.getVarnode(in[0], val, in[2].getSize(), evaluator); + out = vContext.getVarnode(space, offset, size.getSize(), evaluator); } catch (NotFoundException e) { // if can't get the value of the relative store location @@ -1482,6 +1508,7 @@ public class SymbolicPropogator { } Address fallThruAddr = instruction.getFallThrough(); // if the call is right below this routine, ignore the call + // otherwise clear out the return and killed by call variables if (fallThruAddr == null || target == null || target.getOffset() != fallThruAddr.getOffset()) { @@ -1490,7 +1517,7 @@ public class SymbolicPropogator { if (checkForParamRefs && evaluator != null && evaluator.evaluateReference(context, instruction, PcodeOp.UNIMPLEMENTED, (target == null ? Address.NO_ADDRESS : target), 0, - RefType.UNCONDITIONAL_CALL)) { + null, RefType.UNCONDITIONAL_CALL)) { // put references on any register parameters with values in // them. addParamReferences(targetFunc, target, instruction, context, monitor); @@ -1503,6 +1530,14 @@ public class SymbolicPropogator { context.putValue(varnode, context.createBadVarnode(), false); } } + + // clear out any killed by call variables + Varnode killedVarnodes[] = context.getKilledVarnodes(targetFunc); + if (killedVarnodes != null) { + for (Varnode varnode : killedVarnodes) { + context.putValue(varnode, context.createBadVarnode(), false); + } + } } // inlined function, don't worry about it's function effects @@ -1688,7 +1723,7 @@ public class SymbolicPropogator { ArrayList inputs = new ArrayList(); 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 if will be correct so should use it! + // Need to make sure that is happening in the program before accepting return callStackShift; } if (depth == Function.UNKNOWN_STACK_DEPTH_CHANGE || @@ -1825,7 +1863,7 @@ public class SymbolicPropogator { } // don't check for params on external calls - if ((callTarget != null) && callTarget.isExternalAddress()) { + if (callTarget != null && callTarget.isExternalAddress()) { return; } @@ -1847,29 +1885,58 @@ public class SymbolicPropogator { params = func.getParameters(); signatureSource = func.getSignatureSource(); } + else if (checkForParamPointerRefs) { + // no function chan't check for pointer types + return; + } long callOffset = (callTarget == null ? -1 : callTarget.getOffset()); // If there are params defined or the params were specified (meaning it could be VOID params) boolean signatureAssigned = signatureSource != SourceType.DEFAULT; boolean trustSignature = signatureAssigned || params.length > 0; - if (trustSignature) { + if (trustSignature && !func.hasVarArgs()) { // Loop through defined parameters for a valid address value for (Parameter param : params) { Parameter p = param; - if (!p.isRegisterVariable()) { - continue; + + // check if known pointer DT. + // construct pointer of the right type, given the constant + // if not a pointer && flag must be pointer, don't add pointer + DataType dataType = p.getDataType(); + + if (!(dataType instanceof Pointer || + (dataType instanceof TypeDef && ((TypeDef) dataType).isPointer()))) { + // wasn't a pointer immediately + if (checkForParamPointerRefs) { + continue; + } + // if undefined, or int/long could still be pointer + if (!(Undefined.isUndefined(dataType) || dataType instanceof IntegerDataType)) { + continue; + } } - createVariableStorageReference(instruction, varnodeContext, monitor, - p.getVariableStorage(), callOffset); + // use the varnode to pull out the bytes from the varnode + // only use constants, not symbolic? + // put the bytes in a membuffer + // Hand bytes to data type to decode as if in memory + // get pointer out + createVariableStorageReference(instruction, varnodeContext, monitor, conv, + p.getVariableStorage(), dataType, callOffset); } } - else { + else if (!checkForParamPointerRefs) { // loop through potential params, since none defined, to find a potential pointer - VariableStorage[] vars = conv.getPotentialInputRegisterStorage(program); - for (VariableStorage var : vars) { - createVariableStorageReference(instruction, varnodeContext, monitor, var, - callOffset); + // only check the first seven param locations, if don't have a signature + for (int pi=0; pi < 8; pi++) { + // TODO Should cache the arg locations for each convention + VariableStorage var = conv.getArgLocation(pi, null, pointerSizedDT, program); + // can't trust stack storage if params aren't known + if (var.isStackStorage()) { + continue; + } + createVariableStorageReference(instruction, varnodeContext, monitor, conv, var, + null, callOffset); } } } @@ -1891,12 +1958,12 @@ public class SymbolicPropogator { return; } - createVariableStorageReference(instruction, varnodeContext, monitor, returnLoc, 0); + createVariableStorageReference(instruction, varnodeContext, monitor, null, returnLoc, null, 0); } private void addLoadStoreReference(VarnodeContext vContext, Instruction instruction, int pcodeType, Varnode refLocation, Varnode targetSpaceID, Varnode assigningVarnode, - RefType reftype, TaskMonitor monitor) { + RefType reftype, boolean knownReference, TaskMonitor monitor) { // no output or load if (refLocation == null) { @@ -1906,7 +1973,7 @@ public class SymbolicPropogator { int opIndex = findOperandWithVarnodeAssignment(instruction, assigningVarnode); if (instruction.getFlowType().isCall()) { - makeReference(vContext, instruction, pcodeType, opIndex, refLocation, reftype, monitor); + makeReference(vContext, instruction, opIndex, refLocation, null, reftype, pcodeType, knownReference, monitor); } else { int spaceID = refLocation.getSpace(); @@ -1915,35 +1982,25 @@ public class SymbolicPropogator { long offset = refLocation.getOffset(); if (evaluator != null) { - // symbolic spaces will have the name of the symbolic space be the register space -// String spaceName = refLocation.getAddress().getAddressSpace().getName(); -// Register register = vContext.getRegister(spaceName); - // never make an offset onto the stack -// if (register != null) { -// if (!register.equals(vContext.getStackRegister())) { -// // need to get the register, because we want to find the last place the register -// // was set to this value so that we can create a reference. -// RegisterValue rval = new RegisterValue(register,BigInteger.valueOf(offset)); -// createRegisterStorageReference(instruction, vContext, monitor, 0, rval); -// } -// } else - if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) { Address constant = program.getAddressFactory() .getAddress((int) targetSpaceID.getOffset(), offset); Address newTarget = evaluator.evaluateConstant(vContext, instruction, - pcodeType, constant, 0, reftype); - if (newTarget != null) { + pcodeType, constant, 0, null, reftype); + // TODO: This is speculative, should not be doing here + // need to check if there is a memory/label at the other end, or some other + // corroborating evidence very late in analysis + if (newTarget != null ) { makeReference(vContext, instruction, Reference.MNEMONIC, newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(), 0, - reftype, pcodeType, false, monitor); + null, reftype.DATA, pcodeType, false, false, monitor); return; } } } } // even if this is symbolic space, give the evaluator a chance to do something with the symbolic value - makeReference(vContext, instruction, pcodeType, opIndex, refLocation, reftype, monitor); + makeReference(vContext, instruction, opIndex, refLocation, null, reftype, pcodeType, knownReference, monitor); } } @@ -2004,57 +2061,101 @@ public class SymbolicPropogator { // TODO: this could be a calculated OFFSET reference with a base address - if (!valueToStore.isConstant()) { + if (!vContext.isConstant(valueToStore)) { return; } long valueOffset = valueToStore.getOffset(); - makeReference(vContext, instruction, -1, -1, valueOffset, 0, RefType.DATA, PcodeOp.STORE, - false, monitor); + makeReference(vContext, instruction, -1, -1, valueOffset, 0, null, RefType.DATA, PcodeOp.STORE, + false, false, monitor); } private void createVariableStorageReference(Instruction instruction, - VarnodeContext varnodeContext, TaskMonitor monitor, VariableStorage storage, - long callOffset) { + VarnodeContext varnodeContext, TaskMonitor monitor, PrototypeModel conv, VariableStorage storage, + DataType dataType, long callOffset) { + + Address lastSetAddr; + BigInteger bval; + + // TODO: need to handle memory + // TODO: need to handle multi-piece variables and re-assemble + // + + if (storage.isStackStorage()) { + if (conv == null) { + return; + } + Varnode sVnode = storage.getFirstVarnode(); + + // translate the variable relative to the current stackpointer symbolic value + Varnode stackVarnode = varnodeContext.getStackVarnode(); + Varnode stackVal = null; + try { + stackVal = varnodeContext.getValue(stackVarnode, null); + if (stackVal == null) { + return; + } + } catch (NotFoundException e) { + return; + } + Varnode realSPVarnode = varnodeContext.createVarnode(stackVal.getOffset() + sVnode.getOffset(), + stackVal.getSpace(), sVnode.getAddress().getAddressSpace().getPointerSize()); + + Varnode value = null; + try { + value = varnodeContext.getValue(realSPVarnode,evaluator); + } + catch (NotFoundException e) { + return; + } - if (!storage.isRegisterStorage()) { + if (!varnodeContext.isConstant(value)) { + return; + } + bval = BigInteger.valueOf(value.getOffset()); + + lastSetAddr = varnodeContext.getLastSetLocation(realSPVarnode, bval); + + // TODO: What if last set location is in a delayslot? + } + else if (storage.isRegisterStorage()) { + // TODO: need to handle compound register storage (e.g., two registers + // used) + Register reg = storage.getRegister(); + + // RegisterValue rval = + // context.getRegisterValue(reg,instruction.getMinAddress()); + RegisterValue rval = varnodeContext.getRegisterValue(reg); + if (rval == null || !rval.hasValue()) { + return; + } + + reg = rval.getRegister(); + + bval = rval.getUnsignedValue(); + lastSetAddr = varnodeContext.getLastSetLocation(reg, bval); + // if instruction has a delay slot, carefully check the location of the + // lastSetAddr Value + // to make sure it matches. If it doesn't, use this instruction + if (lastSetAddr != null && instruction.getPrototype().hasDelaySlots()) { + RegisterValue lastRval = varnodeContext.getRegisterValue(reg, lastSetAddr); + if (lastRval == null || !lastRval.hasAnyValue() || !lastRval.equals(rval)) { + lastSetAddr = instruction.getMaxAddress(); + } + } + + } + else { return; } - - // TODO: need to handle compound register storage (e.g., two registers - // used) - Register reg = storage.getRegister(); - - // RegisterValue rval = - // context.getRegisterValue(reg,instruction.getMinAddress()); - RegisterValue rval = varnodeContext.getRegisterValue(reg); - if (rval == null || !rval.hasValue()) { - return; - } - - createRegisterStorageReference(instruction, varnodeContext, monitor, callOffset, rval); + + makeVariableStorageReference(storage, instruction, varnodeContext, monitor, callOffset, dataType, lastSetAddr, bval); } - private void createRegisterStorageReference(Instruction instruction, - VarnodeContext varnodeContext, TaskMonitor monitor, long callOffset, - RegisterValue rval) { - Address lastSetAddr; - - Register reg = rval.getRegister(); - - BigInteger bval; - bval = rval.getUnsignedValue(); - lastSetAddr = varnodeContext.getLastSetLocation(reg, bval); - // if instruction has a delay slot, carefully check the location of the - // lastSetAddr Value - // to make sure it matches. If it doesn't, use this instruction - if (lastSetAddr != null && instruction.getPrototype().hasDelaySlots()) { - RegisterValue lastRval = varnodeContext.getRegisterValue(reg, lastSetAddr); - if (lastRval == null || !lastRval.hasAnyValue() || !lastRval.equals(rval)) { - lastSetAddr = instruction.getMaxAddress(); - } - } + private void makeVariableStorageReference(VariableStorage storage, Instruction instruction, VarnodeContext varnodeContext, + TaskMonitor monitor, long callOffset, DataType dataType, Address lastSetAddr, BigInteger bval) { + if (lastSetAddr == null) { lastSetAddr = instruction.getMaxAddress(); } @@ -2067,30 +2168,74 @@ public class SymbolicPropogator { return; } - if (lastSetAddr != null) { - Instruction instr = instruction; - // last setAddr could be in the base instruction - if (!instr.contains(lastSetAddr)) { - instr = getInstructionContaining(lastSetAddr); - } - Reference[] refs = instr.getReferencesFrom(); - boolean found = false; - for (Reference ref : refs) { - Address refAddr = ref.getToAddress(); - Address addr = refAddr.getAddressSpace().getTruncatedAddress(val, true); - if (refAddr.getOffset() == addr.getOffset()) { - found = true; - break; + if (lastSetAddr == null) { + return; + } + + // if the dataType is known, try to interpret it to an address given the + // bytes in the storage location + int knownSpaceID = -1; + boolean knownReference = false; + if (dataType != null) { + if ((dataType instanceof TypeDef typedef && typedef.isPointer())) { + // pointer type defs need to be handled specially they could be re-mapping to another space + // or interpretting the value + Object value = getPointerDataTypeValue(dataType, lastSetAddr, bval); + if (value instanceof Address) { + Address addrVal = (Address) value; + val = addrVal.getAddressableWordOffset(); + knownSpaceID = addrVal.getAddressSpace().getSpaceID(); + knownReference = true; } } - if (!found) { - RefType refType = (callOffset == 0 ? RefType.DATA : RefType.PARAM); - makeReference(varnodeContext, instr, Reference.MNEMONIC, -1, val, 0, refType, - PcodeOp.UNIMPLEMENTED, false, monitor); + } + + // last setAddr could be in the base instruction + Instruction instr = instruction; + if (!instr.contains(lastSetAddr)) { + instr = getInstructionContaining(lastSetAddr); + } + Reference[] refs = instr.getReferencesFrom(); + boolean found = false; + for (Reference ref : refs) { + Address refAddr = ref.getToAddress(); + Address addr = refAddr.getAddressSpace().getTruncatedAddress(val, true); + if (ref.getReferenceType() == RefType.PARAM && !body.contains(ref.getFromAddress())) { + // if reference address is not in body yet, this is the first time at this location + // get rid of the reference, reference could be changed to new AddressSpace or value + instr.removeOperandReference(ref.getOperandIndex(), refAddr); + } else if (refAddr.getOffset() == addr.getOffset()) { + found = true; } } + + RefType refType = (callOffset == 0 ? RefType.DATA : RefType.PARAM); + makeReference(varnodeContext, instr, Reference.MNEMONIC, knownSpaceID, val, 0, dataType, refType, + PcodeOp.UNIMPLEMENTED, knownReference, found, monitor); } + private Object getPointerDataTypeValue(DataType dataType, Address lastSetAddr, + BigInteger bval) { + + int len = dataType.getLength(); + byte[] byteArray = new byte[len]; + + BigEndianDataConverter.INSTANCE.putBigInteger(byteArray, 0, len, bval); + + MemBuffer buf = + new ByteMemBufferImpl(program.getMemory(), lastSetAddr, byteArray, true); + + // if not enough bytes for data type, can't do it + if (len > byteArray.length) { + return null; + } + + Object value = dataType.getValue(buf, dataType.getDefaultSettings(), len); + + return value; + } + + /** * get the return variable storage location for this function * @@ -2219,20 +2364,22 @@ public class SymbolicPropogator { * @param opIndex - operand it should be placed on, or -1 if unknown * @param vt - place to reference, could be a full address, or just a constant * @param refType - type of reference + * @param knownReference true if this is a know good address, speculative otherwise * @param monitor to cancel + * @return address that was marked up, null otherwise */ - public void makeReference(VarnodeContext varnodeContext, Instruction instruction, int pcodeop, - int opIndex, Varnode vt, RefType refType, TaskMonitor monitor) { + public Address makeReference(VarnodeContext varnodeContext, Instruction instruction, int opIndex, Varnode vt, DataType dataType, RefType refType, + int pcodeop, boolean knownReference, TaskMonitor monitor) { if (!vt.isAddress() && !varnodeContext.isExternalSpace(vt.getSpace())) { if (evaluator != null) { evaluator.evaluateSymbolicReference(varnodeContext, instruction, vt.getAddress()); } - return; + return null; } // offset must be word based to compute the reference correctly - makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(), - vt.getSize(), refType, pcodeop, true, monitor); + return makeReference(varnodeContext, instruction, opIndex, vt.getSpace(), vt.getWordOffset(), + vt.getSize(), dataType, refType, pcodeop, knownReference, false, monitor); } /** @@ -2252,17 +2399,20 @@ public class SymbolicPropogator { * @param refType - type of reference * @param pcodeop - op that caused the reference * @param knownReference - true if reference is known to be a real reference, not speculative + * @param preExisting preExisting reference * @param monitor - the task monitor + * @return address that was marked up, null otherwise + */ - public void makeReference(VarnodeContext vContext, Instruction instruction, int opIndex, - long knownSpaceID, long wordOffset, int size, RefType refType, int pcodeop, - boolean knownReference, TaskMonitor monitor) { + public Address makeReference(VarnodeContext vContext, Instruction instruction, int opIndex, + long knownSpaceID, long wordOffset, int size, DataType dataType, RefType refType, int pcodeop, + boolean knownReference, boolean preExisting, TaskMonitor monitor) { long spaceID = knownSpaceID; if (spaceID == -1) { // speculative reference - only offset is known spaceID = getReferenceSpaceID(instruction, wordOffset); if (spaceID == -1) { - return; // don't make speculative reference + return null; // don't make speculative reference } } @@ -2278,12 +2428,12 @@ public class SymbolicPropogator { else { // do checks that are actual memory, and not fabricated externals if (!space.isLoadedMemorySpace()) { - return; + return null; } // for now, don't mark up this area of memory. // Memory at too low an offset could be from a bad calculation (use of zero or other small number) if (wordOffset == 0) { - return; + return null; } // wrap offset within address space @@ -2301,7 +2451,7 @@ public class SymbolicPropogator { // don't make references to registers if (space.hasMappedRegisters() && program.getRegister(target) != null) { - return; + return null; } // normalize the address into this overlay space. @@ -2312,38 +2462,24 @@ public class SymbolicPropogator { // it could be in a non-allocated memory space // TODO: Really at this point it should be a constant, and put on a list // to be considered later as a pointer. - if (!program.getReferenceManager().hasReferencesTo(target)) { - return; + // allow flow references to memory not in program + // program could be located in the wrong place, or other flow issues + if (!refType.isFlow() && !program.getReferenceManager().hasReferencesTo(target)) { + return null; } } } // if the refType is a call, and it isn't computed, we shouldn't be here if (refType.isCall() && !refType.isComputed()) { - return; + return null; } // give evaluator a chance to stop or change the reference - if (evaluator != null) { - // if this was a speculative reference, pass to the evaluateConstant - if (knownSpaceID == -1 || !knownReference) { - Address constant = program.getAddressFactory().getConstantAddress(wordOffset); - Address newTarget = evaluator.evaluateConstant(vContext, instruction, pcodeop, - constant, size, refType); - if (newTarget == null) { - return; - } - if (newTarget != constant) { - target = newTarget; // updated the target, if same, then don't update to constant - // since the target address was already computed. - } - } - else { - if (!evaluator.evaluateReference(vContext, instruction, pcodeop, target, size, - refType)) { - return; - } - } + target = evaluateReference(vContext, instruction, knownSpaceID, wordOffset, size, + dataType, refType, pcodeop, knownReference, target); + if (target == null || preExisting) { + return null; } // Pure data references need to be scrutinized @@ -2351,7 +2487,7 @@ public class SymbolicPropogator { // if (refType.isData() && !evaluatePureDataRef(instruction, wordOffset, refType, target)) { - return; + return null; } if (refType.isJump() && refType.isComputed()) { @@ -2359,17 +2495,17 @@ public class SymbolicPropogator { // if there are more than one reference, don't do the jump here Address[] flows = getInstructionFlows(instruction); if (flows.length > 1) { - return; + return target; } for (Address address : flows) { if (address.equals(target)) { - return; + return target; } } } } catch (AddressOutOfBoundsException e) { - return; + return null; } opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType); @@ -2379,7 +2515,7 @@ public class SymbolicPropogator { if (!instruction.getFlowType().equals(refType)) { instruction = instruction.getNext(); if (instruction == null) { - return; + return target; } opIndex = findOpIndexForRef(vContext, instruction, opIndex, wordOffset, refType); } @@ -2406,19 +2542,39 @@ public class SymbolicPropogator { else { instruction.addOperandReference(opIndex, target, refType, SourceType.ANALYSIS); } + + return target; + } - if (refType.isData()) { - createData(target, size); + private Address evaluateReference(VarnodeContext vContext, Instruction instruction, + long knownSpaceID, long wordOffset, int size, DataType dataType, RefType refType, + int pcodeop, boolean knownReference, Address target) { + if (evaluator == null) { + return target; } - if (refType.isFlow() && !refType.isIndirect() && - !program.getMemory().isExternalBlockAddress(target)) { - Data udata = program.getListing().getUndefinedDataAt(target); - if (udata != null) { - DisassembleCommand cmd = new DisassembleCommand(target, null, true); - cmd.applyTo(program, monitor); + // if this was a speculative reference, pass to the evaluateConstant + if (knownSpaceID == -1 || !knownReference) { + Address constant = program.getAddressFactory().getConstantAddress(wordOffset); + Address newTarget = evaluator.evaluateConstant(vContext, instruction, pcodeop, + constant, size, dataType, refType); + if (newTarget == null) { + return null; + } + if (newTarget != constant) { + target = newTarget; // updated the target, if same, then don't update to constant + // since the target address was already computed. } } + + // was a known reference, or constant evalutator allowed the reference and + // didn't handle it + if (!evaluator.evaluateReference(vContext, instruction, pcodeop, target, size, + dataType, refType)) { + return null; + } + + return target; } /** @@ -2476,32 +2632,6 @@ public class SymbolicPropogator { return true; } - private int createData(Address address, int size) { - if (program.getMemory().isExternalBlockAddress(address) || - !program.getListing().isUndefined(address, address)) { - return 0; - } - - if (size < 1 || size > 8) { - return 0; - } - DataType dt = Undefined.getUndefinedDataType(size); - - try { - // create data at the location so that we record the access size - // the data is undefined, and SHOULD be overwritten if something - // else knows better about the location. - // This should only be done on references that are know good read/write, not data - program.getListing().createData(address, dt); - } - catch (CodeUnitInsertionException e) { - program.getListing().getDefinedDataAt(address); - } - int addrByteSize = dt.getLength(); - - return addrByteSize; - } - private int findOpIndexForRef(VarnodeContext vcontext, Instruction instruction, int opIndex, long wordOffset, RefType refType) { @@ -2648,6 +2778,16 @@ public class SymbolicPropogator { checkForParamRefs = checkParamRefsOption; } + /** + * enable/disable creating param references for constants + * only if the function parameter is specified as a known pointer + * + * @param checkParamRefsOption true to enable + */ + public void setParamPointerRefCheck(boolean checkParamRefsOption) { + checkForParamPointerRefs = checkParamRefsOption; + } + /** * enable/disable checking return for constant references * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java index 7b52045b86..c4c0d16b89 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java @@ -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 validSymbolicStackNames = new HashSet<>(); // list of stack related register names @@ -72,6 +75,13 @@ public class VarnodeContext implements ProcessorContext { public final Address BAD_ADDRESS; private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value; + + private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values + public final Address SUSPECT_ZERO_ADDRESS; + + public final int BAD_SPACE_ID_VALUE; + + private static final BigInteger BIG_NEGATIVE_ONE = BigInteger.ONE.negate(); protected boolean hitDest = false; @@ -92,8 +102,15 @@ public class VarnodeContext implements ProcessorContext { this.addrFactory = new OffsetAddressFactory(program); BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0); + BAD_SPACE_ID_VALUE = BAD_ADDRESS.getAddressSpace().getSpaceID(); BAD_OFFSET_SPACEID = getAddressSpace("(Bad Address Offset)"); + + /* Suspect constants act like constants, but are in a SuspectConst + * address space instead of the constant space. + */ + SUSPECT_ZERO_ADDRESS = addrFactory.getAddress(getAddressSpace("SuspectConst"), 0); + SUSPECT_OFFSET_SPACEID = SUSPECT_ZERO_ADDRESS.getAddressSpace().getSpaceID(); this.programContext = programContext; @@ -293,6 +310,48 @@ public class VarnodeContext implements ProcessorContext { } return retVarnodes; } + + /** + * + * @param targetFunc function to get killed varnodes for + * + * NOTE: this removes the return varnodes so they aren't duplicated + * + * @return varnode that represents where functions place their return value + */ + public Varnode[] getKilledVarnodes(Function targetFunc) { + // TODO: This doesn't handle full bonded yet! + PrototypeModel defaultCallingConvention = + program.getCompilerSpec().getDefaultCallingConvention(); + + if (targetFunc != null) { + // TODO handle custom calling convention killed by call when supported + PrototypeModel callingConvention = targetFunc.getCallingConvention(); + + if (callingConvention != null) { + return callingConvention.getKilledByCallList(); + } + } + + // no function, so get the default convention and use that. + if (killedVarnodes != null) { + return killedVarnodes; + } + + killedVarnodes = defaultCallingConvention.getKilledByCallList(); + + // clean return varnodes out of list + Varnode[] returnVarnodes = getReturnVarnode(null); + ArrayList list = new ArrayList(); + for (Varnode varnode : killedVarnodes) { + if (!ArrayUtils.contains(returnVarnodes, varnode)) { + list.add(varnode); + } + } + killedVarnodes = list.toArray(new Varnode[list.size()]); + + return killedVarnodes; + } /** * @@ -356,7 +415,7 @@ public class VarnodeContext implements ProcessorContext { public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator) throws NotFoundException { // for constant, return the constant value - if (varnode.isConstant()) { + if (isConstant(varnode)) { return varnode; } Varnode rvnode = null; @@ -383,21 +442,26 @@ public class VarnodeContext implements ProcessorContext { if (bigVal != null) { BigInteger spaceVal = getTranslatedSpaceValue(reg); + // -1 and zero constants pulled from a register are suspect + if (spaceVal == null && (bigVal.equals(BIG_NEGATIVE_ONE) || bigVal.equals(BigInteger.ZERO))) { + spaceVal = BigInteger.valueOf(SUSPECT_OFFSET_SPACEID); + } rvnode = createVarnode(bigVal, spaceVal, varnode.getSize()); if (rvnode == null) { throw notFoundExc; } - if (!rvnode.getAddress().equals(BAD_ADDRESS)) { - if (debug) { - Msg.info(this, " " + reg.getName() + " = " + print(rvnode)); - } - + + if (debug) { + Msg.info(this, " " + reg.getName() + " = " + print(rvnode)); + } + + // value is bad, just return original, someone else will deal with it + if (!rvnode.getAddress().equals(BAD_ADDRESS)) { + return rvnode; } - return rvnode; } } - // TODO: should this return a new space at offset 0? return varnode; // just return the register then, someone else will deal with it... } @@ -418,12 +482,6 @@ public class VarnodeContext implements ProcessorContext { if (debug) { Msg.info(this, " " + varnode + " = " + print(lvalue)); } - if (isSymbolicSpace(lvalue.getSpace())) { - if (debug) { - Msg.info(this, " out " + varnode + " = " + print(lvalue)); - } - throw notFoundExc; - } // if this is an offset reference, ONLY allow it to be offset into the stack, no other register offset. // can't count on the offset staying the same. if (isSymbolicAddr) { @@ -431,15 +489,9 @@ public class VarnodeContext implements ProcessorContext { AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace()); // figure out what register is used for stack values Register stackRegister = getStackRegister(); - if (!isStackSymbolicSpace(varnode)) { - if (debug) { - Msg.info(this, - "Don't Trust value from " + varnode + " = " + print(lvalue)); - } - throw notFoundExc; - } - // don't allow a zero constant pulled from a symbolic space. - if (lvalue.isConstant() && lvalue.getOffset() == 0) { + + // don't allow a zero/-1 constant pulled from a symbolic space. + if (isConstant(lvalue) && (lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) { throw notFoundExc; } } @@ -520,7 +572,8 @@ public class VarnodeContext implements ProcessorContext { value = (value << 8 * (8 - size)) >> 8 * (8 - size); } - return createConstantVarnode(value, size); + // constants pulled from memory are always suspect + return createVarnode(value, SUSPECT_OFFSET_SPACEID, size); } catch (MemoryAccessException e) { @@ -642,9 +695,11 @@ public class VarnodeContext implements ProcessorContext { AddressSpace spc = addrFactory.getAddressSpace(spaceID); Address addr = null; - if (spaceID == BAD_SPACE_ID_VALUE || spc == null || - spc.equals(BAD_ADDRESS.getAddressSpace())) { + if (spaceID == BAD_SPACE_ID_VALUE || spc == null) { addr = BAD_ADDRESS; + } else if (spaceID == BAD_OFFSET_SPACEID) { + // special case of unknown value + constant + addr = spc.getTruncatedAddress(value, true); } else { addr = spc.getTruncatedAddress(value, true); @@ -700,10 +755,16 @@ public class VarnodeContext implements ProcessorContext { // put the location on both the lastSet, and all locations set addSetVarnodeToLastSetLocations(out, location); + // don't put a value into a bad address space + // could get values pulled from a different badd address offset + if (isSymbolicAddr && out.getAddress().getAddressSpace().getSpaceID() == BAD_OFFSET_SPACEID) { + return; + } putMemoryValue(out, result); return; } } + // don't ever store an unknown unique into a location if (result != null && result.isUnique()) { result = null; @@ -715,6 +776,20 @@ public class VarnodeContext implements ProcessorContext { tempUniqueVals.put(out.getOffset(), result); } else { + // if storing a bad address, need to create a new register/address + // relative symbolic space + if (result != null && result.getAddress()==BAD_ADDRESS) { + + String spaceName = out.getAddress().getAddressSpace().getName(); + Register register = getRegister(out); + if (register == null) { + spaceName = out.toString(); + } else { + spaceName = register.getName(); + } + int newRegSpaceID = getAddressSpace(spaceName+"-"+currentAddress); + result = createVarnode(0, newRegSpaceID, out.getSize()); + } tempVals.put(out, result); } @@ -907,7 +982,7 @@ public class VarnodeContext implements ProcessorContext { } public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException { - if (!vnode.isConstant()) { + if (!isConstant(vnode)) { if (evaluator == null) { throw notFoundExc; } @@ -940,6 +1015,12 @@ public class VarnodeContext implements ProcessorContext { valbase = offset.getOffset(); spaceID = (int) space.getOffset(); } + else if (isSuspectConstant(offset)) { + // constant suspicious don't let if fall into symbolic + // handle same as normal constant but keep suspicious space + valbase = offset.getOffset(); + spaceID = (int) space.getOffset(); + } else if (OffsetAddressFactory.isSymbolSpace(spaceID)) { if (evaluator == null) { throw notFoundExc; @@ -1037,7 +1118,10 @@ public class VarnodeContext implements ProcessorContext { } BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr); if (spaceVal != null) { - if (addrFactory.getConstantSpace().getSpaceID() != spaceVal.intValue()) { + int spaceID = spaceVal.intValue(); + // check normal constant and suspect constants + if (spaceID != addrFactory.getConstantSpace().getSpaceID() && + spaceID != SUSPECT_OFFSET_SPACEID) { return null; } } @@ -1054,7 +1138,7 @@ public class VarnodeContext implements ProcessorContext { /** * Copy the varnode with as little manipulation as possible. - * Try to keep whatever partical state there is intact if a real value isn't required. + * Try to keep whatever partial state there is intact if a real value isn't required. * * @param out varnode to put it in * @param in varnode to copy from. @@ -1067,8 +1151,10 @@ public class VarnodeContext implements ProcessorContext { Varnode val1 = null; val1 = getValue(in, evaluator); // if truncating a constant get a new constant of the proper size - if (val1 != null && val1.isConstant() && in.getSize() > out.getSize()) { - val1 = createConstantVarnode(val1.getOffset(), out.getSize()); + if (val1 != null && in.getSize() > out.getSize()) { + if (isConstant(val1)) { + val1 = createVarnode(val1.getOffset(), val1.getSpace(), out.getSize()); + } } if (!in.isRegister() || !out.isRegister()) { @@ -1097,7 +1183,7 @@ public class VarnodeContext implements ProcessorContext { throws NotFoundException { // try to make the constant value the addend. - if (val1.isConstant() || val1.isAddress()) { + if (isConstant(val1) || val1.isAddress()) { Varnode swap = val1; val1 = val2; val2 = swap; @@ -1142,8 +1228,11 @@ public class VarnodeContext implements ProcessorContext { } } } - else if (val1.isConstant()) { + else if (isConstant(val1)) { valbase = val1.getOffset(); + if (!isSuspectConstant(val1)) { + spaceID = val2.getSpace(); + } } else if (isSymbolicSpace(spaceID)) { Instruction instr = getCurrentInstruction(offsetContext.getAddress()); @@ -1181,7 +1270,6 @@ public class VarnodeContext implements ProcessorContext { } } - } else { throw notFoundExc; @@ -1199,7 +1287,7 @@ public class VarnodeContext implements ProcessorContext { if (val1.equals(val2)) { return val1; } - if (val1.isConstant() || val1.isAddress()) { + if (isConstant(val1) || val1.isAddress()) { Varnode swap = val1; val1 = val2; val2 = swap; @@ -1216,6 +1304,9 @@ public class VarnodeContext implements ProcessorContext { } else if (val1.isConstant()) { valbase = val1.getOffset(); + if (!isSuspectConstant(val1)) { + spaceID = val2.getSpace(); + } } else if (isSymbolicSpace(spaceID)) { valbase = val1.getOffset(); @@ -1244,25 +1335,29 @@ public class VarnodeContext implements ProcessorContext { return val1; } - if (val1.isConstant() || val1.isAddress()) { + if (isConstant(val1) || val1.isAddress()) { Varnode swap = val1; val1 = val2; val2 = swap; } + int spaceID = val1.getSpace(); long val2Const = getConstant(val2, null); // got a constant from val2, (value | 0) == value, so just return value if (val2Const == 0) { - return val1; + if (!isSuspectConstant(val2)) { + return val1; + } + spaceID = val2.getSpace(); } long lresult = getConstant(val1, evaluator) | val2Const; - return createConstantVarnode(lresult, val1.getSize()); + return createVarnode(lresult, spaceID, val1.getSize()); } public Varnode left(Varnode val1, Varnode val2, ContextEvaluator evaluator) throws NotFoundException { long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator); lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8)); - Varnode result = createConstantVarnode(lresult, val1.getSize()); + Varnode result = createVarnode(lresult, val1.getSpace(), val1.getSize()); return result; } @@ -1306,8 +1401,11 @@ public class VarnodeContext implements ProcessorContext { } int spaceID = val1.getSpace(); long valbase = 0; - if (val1.isConstant()) { + if (isConstant(val1)) { valbase = val1.getOffset(); + if (!isSuspectConstant(val1)) { + spaceID = val2.getSpace(); + } } else if (isRegister(val1)) { Register reg = trans.getRegister(val1); @@ -1329,7 +1427,6 @@ public class VarnodeContext implements ProcessorContext { return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator); } } - } else { throw notFoundExc; @@ -1353,15 +1450,15 @@ public class VarnodeContext implements ProcessorContext { vnodeVal = getValue(in[0], signExtend, evaluator); - if (vnodeVal.isConstant() && in[0].getSize() < out.getSize()) { + if (isConstant(vnodeVal) && in[0].getSize() < out.getSize()) { // TODO: Is there a better way to do this - it was not sign-extending temp values before if (vnodeVal.getSize() <= 8) { Scalar sVal = new Scalar(8 * vnodeVal.getSize(), vnodeVal.getOffset(), signExtend); - vnodeVal = createConstantVarnode(sVal.getValue(), out.getSize()); + vnodeVal = createVarnode(sVal.getValue(), vnodeVal.getSpace(), out.getSize()); } else { // too big anyway,already extended as far as it will go. - vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize()); + vnodeVal = createVarnode(vnodeVal.getOffset(), vnodeVal.getSpace(), out.getSize()); } } else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) { @@ -1414,7 +1511,7 @@ public class VarnodeContext implements ProcessorContext { Varnode regVnode = trans.getVarnode(register); try { Varnode value = this.getValue(regVnode, false, null); - if (value.isConstant()) { + if (isConstant(value)) { return new RegisterValue(register, BigInteger.valueOf(value.getOffset())); } } @@ -1457,7 +1554,7 @@ public class VarnodeContext implements ProcessorContext { Varnode regVnode = trans.getVarnode(register); try { Varnode value = this.getValue(regVnode, signed, null); - if (value.isConstant()) { + if (isConstant(value)) { return BigInteger.valueOf(value.getOffset()); } } @@ -1503,7 +1600,33 @@ public class VarnodeContext implements ProcessorContext { public boolean isRegister(Varnode varnode) { return varnode.isRegister() || trans.getRegister(varnode) != null; } + + /** + * Check if this is a constant, or a suspect constant + * + * @param varnode to check + * @return true if should be treated as a constant for most purposes + */ + public boolean isConstant(Varnode varnode) { + if (varnode.isConstant()) { + return true; + } + return isSuspectConstant(varnode); + } + /** + * Check if the constant is a suspect constant + * It shouldn't be trusted in certain cases. + * Suspect constants act like constants, but are in a Suspicious + * address space instead of the constant space. + * + * @param val1 varnode to check + * @return true if varnode is a suspect constant + */ + public boolean isSuspectConstant(Varnode val1) { + return val1.getSpace() == SUSPECT_OFFSET_SPACEID; + } + /** * Check if varnode is in the stack space * diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java index 5641f65d45..be44e4fc69 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java @@ -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); } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java index 0de049e40e..438214b5c0 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java @@ -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)) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java index 3fc065c4b9..d49e3167c5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java @@ -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 diff --git a/Ghidra/Processors/68000/src/main/java/ghidra/app/plugin/core/analysis/Motorola68KAnalyzer.java b/Ghidra/Processors/68000/src/main/java/ghidra/app/plugin/core/analysis/Motorola68KAnalyzer.java index 3ea80b712e..4a2afba3d2 100644 --- a/Ghidra/Processors/68000/src/main/java/ghidra/app/plugin/core/analysis/Motorola68KAnalyzer.java +++ b/Ghidra/Processors/68000/src/main/java/ghidra/app/plugin/core/analysis/Motorola68KAnalyzer.java @@ -66,7 +66,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context // use context to fill out addresses on certain instructions ConstantPropagationContextEvaluator eval = - new ConstantPropagationContextEvaluator(trustWriteMemOption) { + new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { @Override public boolean evaluateContext(VarnodeContext context, Instruction instr) { String mnemonic = instr.getMnemonicString(); @@ -124,7 +124,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer { @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, - int pcodeop, Address address, int size, RefType refType) { + int pcodeop, Address address, int size, DataType dataType, RefType refType) { if (instr.getFlowType().isJump()) { return false; } @@ -132,7 +132,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer { return false; } - return super.evaluateReference(context, instr, pcodeop, address, size, refType); + return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); } @Override @@ -153,6 +153,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer { return false; } }; + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); @@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer { @Override public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, - Address constant, int size, RefType refType) { + Address constant, int size, DataType dataType, RefType refType) { return null; } @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, - Address address, int size, RefType refType) { + Address address, int size, DataType dataType, RefType refType) { if (targetList.contains(address)) { return false; } diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java index 0024f4f95e..df8ec480d6 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java @@ -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; } diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/plugin/core/analysis/ArmAnalyzer.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/plugin/core/analysis/ArmAnalyzer.java index 77d783f939..dafa363158 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/plugin/core/analysis/ArmAnalyzer.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/plugin/core/analysis/ArmAnalyzer.java @@ -81,7 +81,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context // use context to fill out addresses on certain instructions ConstantPropagationContextEvaluator eval = - new ConstantPropagationContextEvaluator(trustWriteMemOption) { + new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { @Override public boolean evaluateContext(VarnodeContext context, Instruction instr) { @@ -104,7 +104,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { // if LR is a constant and is set right after this, this is a call Varnode lrVal = context.getRegisterVarnodeValue(lrRegister); if (lrVal != null) { - if (lrVal.isConstant()) { + if (context.isConstant(lrVal)) { long target = lrVal.getAddress().getOffset(); Address addr = instr.getMaxAddress().add(1); if (target == addr.getOffset() && !instr.getFlowType().isCall()) { @@ -176,7 +176,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, - int pcodeop, Address address, int size, RefType refType) { + int pcodeop, Address address, int size, DataType dataType, RefType refType) { if (refType.isJump() && refType.isComputed() && program.getMemory().contains(address) && address.getOffset() != 0) { if (instr.getMnemonicString().startsWith("tb")) { @@ -184,24 +184,29 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { } doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(), true, monitor); + super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); return !symEval.encounteredBranch(); } if (refType.isData() && program.getMemory().contains(address)) { if (refType.isRead() || refType.isWrite()) { + int numOperands = instr.getNumOperands(); + // if two operands, then all read/write refs go on the 2nd operand createData(program, address, size); - instr.addOperandReference(instr.getNumOperands() - 1, address, refType, - SourceType.ANALYSIS); - return false; + if (numOperands <= 2) { + instr.addOperandReference(instr.getNumOperands() - 1, address, refType, + SourceType.ANALYSIS); + return false; + } + return true; } } else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) { // must disassemble right now, because TB flag could get set back at end of blx doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(), true, monitor); - return false; } - return super.evaluateReference(context, instr, pcodeop, address, size, refType); + return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); } @Override @@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) { // check if a return is actually returning, or is branching with a constant PC - if (retVN != null && retVN.isConstant()) { + if (retVN != null && context.isConstant(retVN)) { long offset = retVN.getOffset(); if (offset > 3 && offset != -1) { // need to override the return to a branch @@ -236,6 +241,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { return false; } }; + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); @@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer { @Override public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, - Address constant, int size, RefType refType) { + Address constant, int size, DataType dataType, RefType refType) { return null; } @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, - Address address, int size, RefType refType) { + Address address, int size, DataType dataType, RefType refType) { // if ever see a reference to 0, something went wrong, stop the process if (address == null) { diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/plugin/core/analysis/MipsAddressAnalyzer.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/plugin/core/analysis/MipsAddressAnalyzer.java index 2751dd0967..c6b4e6defe 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/plugin/core/analysis/MipsAddressAnalyzer.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/plugin/core/analysis/MipsAddressAnalyzer.java @@ -25,6 +25,7 @@ import ghidra.app.util.importer.MessageLog; import ghidra.framework.options.Options; import ghidra.program.disassemble.Disassembler; import ghidra.program.model.address.*; +import ghidra.program.model.data.DataType; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; @@ -247,7 +248,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context // use context to fill out addresses on certain instructions - ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { + ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { private Address localGPAssumptionValue = currentGPAssumptionValue; private boolean mustStopNow = false; // if something discovered in processing, mustStop flag @@ -267,7 +268,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { // this was copylefted from the arm analyzer Varnode raVal = context.getRegisterVarnodeValue(rareg); if (raVal != null) { - if (raVal.isConstant()) { + if (context.isConstant(raVal)) { long target = raVal.getAddress().getOffset(); Address addr = instr.getMaxAddress(); if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) { @@ -317,22 +318,25 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { lastSetInstr = instructionAt; } } - symEval.makeReference(context, lastSetInstr, -1, - instr.getMinAddress().getAddressSpace().getSpaceID(), - unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true, - monitor); - if (localGPAssumptionValue == null) { - program.getBookmarkManager().setBookmark( - lastSetInstr.getMinAddress(), BookmarkType.WARNING, - "GP Global Register Set", - "Global GP Register is set here."); - } - if (localGPAssumptionValue != null && - !localGPAssumptionValue.equals(gpRefAddr)) { - localGPAssumptionValue = gp_assumption_value = null; - } - else { - localGPAssumptionValue = gp_assumption_value = gpRefAddr; + // if an instruction actually set the GP + if (lastSetAddr != null) { + symEval.makeReference(context, lastSetInstr, -1, + instr.getMinAddress().getAddressSpace().getSpaceID(), + unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true, + false, monitor); + if (localGPAssumptionValue == null) { + program.getBookmarkManager().setBookmark( + lastSetInstr.getMinAddress(), BookmarkType.WARNING, + "GP Global Register Set", + "Global GP Register is set here."); + } + if (localGPAssumptionValue != null && + !localGPAssumptionValue.equals(gpRefAddr)) { + localGPAssumptionValue = gp_assumption_value = null; + } + else { + localGPAssumptionValue = gp_assumption_value = gpRefAddr; + } } } } @@ -372,9 +376,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, - Address address, int size, RefType refType) { + Address address, int size, DataType dataType, RefType refType) { Address addr = address; + + if (addr == Address.NO_ADDRESS) { + return false; + } //if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) { // if this isn't straight code (thunk computation), let someone else lay down the reference @@ -386,9 +394,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { } if ((refType.isJump() || refType.isCall()) & refType.isComputed()) { - //if (refType.isJump() || refType.isCall()) { addr = mipsExtDisassembly(program, instr, context, address, monitor); - //addr = flowISA(program, instr, context, address); if (addr == null) { addr = address; } @@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { context.clearRegister(reg); // need to add the reference here, register operand will no longer have a value - instr.addOperandReference(0, addr, refType, + instr.addOperandReference(0, addr, instr.getFlowType(), SourceType.ANALYSIS); // set the register value on the target address @@ -433,7 +439,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { } } - return super.evaluateReference(context, instr, pcodeop, address, size, refType); + return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); } @Override @@ -497,6 +503,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer { return null; } }; + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java index 2a097f2b92..9d9527bbb9 100644 --- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java +++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java @@ -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); diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PPC64CallStubAnalyzer.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PPC64CallStubAnalyzer.java index 842c6a9a0b..8b33f7943c 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PPC64CallStubAnalyzer.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PPC64CallStubAnalyzer.java @@ -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; } diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PowerPCAddressAnalyzer.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PowerPCAddressAnalyzer.java index 98a955331c..335fd05be3 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PowerPCAddressAnalyzer.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/plugin/core/analysis/PowerPCAddressAnalyzer.java @@ -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()) && diff --git a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/plugin/core/analysis/RISCVAddressAnalyzer.java b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/plugin/core/analysis/RISCVAddressAnalyzer.java index 99cd2df5c6..c8aefb30fc 100644 --- a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/plugin/core/analysis/RISCVAddressAnalyzer.java +++ b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/plugin/core/analysis/RISCVAddressAnalyzer.java @@ -99,7 +99,7 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context ConstantPropagationContextEvaluator eval = - new ConstantPropagationContextEvaluator(trustWriteMemOption) { + new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { private boolean mustStopNow = false; @Override @@ -112,7 +112,13 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer { return mustStopNow; } }; - + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); + AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); return resultSet; diff --git a/Ghidra/Processors/Sparc/src/main/java/ghidra/app/plugin/core/analysis/SparcAnalyzer.java b/Ghidra/Processors/Sparc/src/main/java/ghidra/app/plugin/core/analysis/SparcAnalyzer.java index ba8933132b..ba510cb388 100644 --- a/Ghidra/Processors/Sparc/src/main/java/ghidra/app/plugin/core/analysis/SparcAnalyzer.java +++ b/Ghidra/Processors/Sparc/src/main/java/ghidra/app/plugin/core/analysis/SparcAnalyzer.java @@ -76,7 +76,7 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context // use context to fill out addresses on certain instructions - ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { + ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { @Override public boolean evaluateContext(VarnodeContext context, Instruction instr) { @@ -126,7 +126,13 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer { return false; } }; - + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); + AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); return resultSet; diff --git a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4AddressAnalyzer.java b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4AddressAnalyzer.java index 7110dc2cff..9b2e217aa7 100644 --- a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4AddressAnalyzer.java +++ b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4AddressAnalyzer.java @@ -21,6 +21,7 @@ import ghidra.app.util.importer.MessageLog; import ghidra.framework.options.Options; import ghidra.program.disassemble.Disassembler; import ghidra.program.model.address.*; +import ghidra.program.model.data.DataType; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.pcode.PcodeOp; @@ -76,11 +77,11 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer { // follow all flows building up context // use context to fill out addresses on certain instructions - ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) { + ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { @Override public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, - Address address, int size, RefType refType) { + Address address, int size, DataType dataType, RefType refType) { if (address.isExternalAddress()) { return true; @@ -98,7 +99,7 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer { } boolean doRef = - super.evaluateReference(context, instr, pcodeop, address, size, refType); + super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); if (!doRef) { return false; } @@ -109,6 +110,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer { return doRef; } }; + + eval.setTrustWritableMemory(trustWriteMemOption) + .setMinpeculativeOffset(minSpeculativeRefAddress) + .setMaxSpeculativeOffset(maxSpeculativeRefAddress) + .setMinStoreLoadOffset(minStoreLoadRefAddress) + .setCreateComplexDataFromPointers(createComplexDataFromPointers); AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor); diff --git a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4EarlyAddressAnalyzer.java b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4EarlyAddressAnalyzer.java index 64703d78e0..86d681e82b 100644 --- a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4EarlyAddressAnalyzer.java +++ b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/plugin/core/analysis/SH4EarlyAddressAnalyzer.java @@ -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; } diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/plugin/core/analysis/X86Analyzer.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/plugin/core/analysis/X86Analyzer.java index 8ef0143bd1..4a4bfbfa67 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/plugin/core/analysis/X86Analyzer.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/plugin/core/analysis/X86Analyzer.java @@ -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;