mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 05:46:00 +08:00
Merge remote-tracking branch 'origin/GP-3077_emteere_CrossedConstants--SQUASHED'
This commit is contained in:
@@ -46,6 +46,7 @@ import ghidra.app.script.GhidraScript;
|
|||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.block.CodeBlock;
|
import ghidra.program.model.block.CodeBlock;
|
||||||
import ghidra.program.model.block.PartitionCodeSubModel;
|
import ghidra.program.model.block.PartitionCodeSubModel;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
@@ -177,9 +178,9 @@ public class MultiInstructionMemReference extends GhidraScript {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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,
|
private boolean checkInstructionMatch(final int opIdx, boolean input,
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class PropagateConstantReferences extends GhidraScript {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// 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);
|
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import ghidra.app.plugin.core.disassembler.AddressTable;
|
|||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.block.*;
|
import ghidra.program.model.block.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.lang.RegisterValue;
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
@@ -88,7 +89,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
// Always trust values read from writable memory
|
// Always trust values read from writable memory
|
||||||
ConstantPropagationContextEvaluator eval =
|
ConstantPropagationContextEvaluator eval =
|
||||||
new ConstantPropagationContextEvaluator(true) {
|
new ConstantPropagationContextEvaluator(monitor, true) {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateDestination(VarnodeContext context,
|
public boolean evaluateDestination(VarnodeContext context,
|
||||||
Instruction instruction) {
|
Instruction instruction) {
|
||||||
@@ -131,10 +132,13 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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
|
return true; // just go ahead and mark up the instruction
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(true)
|
||||||
|
.setCreateComplexDataFromPointers(true);
|
||||||
|
|
||||||
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
|
SymbolicPropogator symEval = new SymbolicPropogator(currentProgram);
|
||||||
symEval.setParamRefCheck(true);
|
symEval.setParamRefCheck(true);
|
||||||
@@ -144,7 +148,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||||||
symEval.flowConstants(start, func.getBody(), eval, true, monitor);
|
symEval.flowConstants(start, func.getBody(), eval, true, monitor);
|
||||||
|
|
||||||
// now handle symbolic execution assuming values!
|
// now handle symbolic execution assuming values!
|
||||||
eval = new ConstantPropagationContextEvaluator() {
|
eval = new ConstantPropagationContextEvaluator(monitor) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
@@ -181,14 +185,14 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr,
|
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
|
// don't create any references from constants, only looking for flow refs
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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
|
// TODO: if ever loading from instructions in memory, must
|
||||||
// EXIT!
|
// EXIT!
|
||||||
if (!(instr.getFlowType().isComputed() &&
|
if (!(instr.getFlowType().isComputed() &&
|
||||||
@@ -220,6 +224,9 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(true)
|
||||||
|
.setCreateComplexDataFromPointers(true);
|
||||||
|
|
||||||
// now flow with the simple block of this branch....
|
// now flow with the simple block of this branch....
|
||||||
|
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
|
|||||||
Register syscallReg = program.getLanguage().getRegister(syscallRegister);
|
Register syscallReg = program.getLanguage().getRegister(syscallRegister);
|
||||||
for (Function func : funcsToCalls.keySet()) {
|
for (Function func : funcsToCalls.keySet()) {
|
||||||
Address start = func.getEntryPoint();
|
Address start = func.getEntryPoint();
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true);
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, true);
|
||||||
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
||||||
symEval.flowConstants(start, func.getBody(), eval, true, tMonitor);
|
symEval.flowConstants(start, func.getBody(), eval, true, tMonitor);
|
||||||
for (Address callSite : funcsToCalls.get(func)) {
|
for (Address callSite : funcsToCalls.get(func)) {
|
||||||
|
|||||||
+2
-1
@@ -32,6 +32,7 @@ import ghidra.program.model.block.CodeBlock;
|
|||||||
import ghidra.program.model.block.CodeBlockReference;
|
import ghidra.program.model.block.CodeBlockReference;
|
||||||
import ghidra.program.model.block.CodeBlockReferenceIterator;
|
import ghidra.program.model.block.CodeBlockReferenceIterator;
|
||||||
import ghidra.program.model.block.SimpleBlockModel;
|
import ghidra.program.model.block.SimpleBlockModel;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.lang.RegisterValue;
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
@@ -474,7 +475,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
|
|||||||
new ContextEvaluatorAdapter() {
|
new ContextEvaluatorAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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.
|
// go ahead and place the reference, since it is a constant.
|
||||||
if (refType.isComputed() && refType.isFlow() &&
|
if (refType.isComputed() && refType.isFlow() &&
|
||||||
program.getMemory().contains(address)) {
|
program.getMemory().contains(address)) {
|
||||||
|
|||||||
+99
-46
@@ -38,55 +38,71 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
private static final String NAME = " Constant Reference Analyzer";
|
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.";
|
" 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_NAME = "Function parameter/return Pointer analysis";
|
||||||
protected static final String OPTION_DESCRIPTION =
|
protected static final String OPTION_DESCRIPTION =
|
||||||
"Turn on to check if values passed as parameters or returned could be pointer references";
|
"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 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_NAME = "Stored Value Pointer analysis";
|
||||||
protected static final String STORED_OPTION_DESCRIPTION =
|
protected static final String STORED_OPTION_DESCRIPTION =
|
||||||
"Turn on to check if values stored into memory or the stack could be pointer references";
|
"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 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";
|
"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";
|
"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 MAX_THREAD_COUNT_OPTION_NAME = "Max Threads";
|
||||||
protected static final String MAXTHREADCOUNT_OPTION_DESCRIPTION =
|
protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION =
|
||||||
"Maximum threads for constant propagation. Too many threads causes thrashing in DB.";
|
"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 MIN_KNOWN_REFADDRESS_OPTION_NAME = "Min absolute reference";
|
||||||
protected static final String MINKNOWNREFADDRESS_OPTION_DESCRIPTION =
|
protected static final String MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION =
|
||||||
"Minimum address for calcuated constant store/load references";
|
"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";
|
"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";
|
"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";
|
"Speculative reference max";
|
||||||
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
protected static final String MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION =
|
||||||
"Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
|
"Prototype - 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 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 final static int NOTIFICATION_INTERVAL = 100;
|
||||||
|
|
||||||
protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE;
|
protected boolean checkParamRefsOption = OPTION_DEFAULT_VALUE;
|
||||||
|
protected boolean checkPointerParamRefsOption = POINTER_PARAM_OPTION_DEFAULT_VALUE;
|
||||||
protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE;
|
protected boolean checkStoredRefsOption = STORED_OPTION_DEFAULT_VALUE;
|
||||||
protected boolean trustWriteMemOption = TRUSTWRITEMEM_OPTION_DEFAULT_VALUE;
|
protected boolean trustWriteMemOption = TRUST_WRITEMEM_OPTION_DEFAULT_VALUE;
|
||||||
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE;
|
protected boolean createComplexDataFromPointers = CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_DEFAULT_VALUE;
|
||||||
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
|
|
||||||
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE;
|
||||||
protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_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;
|
protected boolean followConditional = false;
|
||||||
|
|
||||||
@@ -105,6 +121,10 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before().before().before().before());
|
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.
|
* Called to to register a more specific analyzer.
|
||||||
*
|
*
|
||||||
@@ -114,13 +134,25 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
handledProcessors.add(processorName);
|
handledProcessors.add(processorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to register a more specific analyzer.
|
||||||
|
*
|
||||||
|
* @param processorName
|
||||||
|
*/
|
||||||
|
static public boolean isClaimedProcessor(String processorName) {
|
||||||
|
return handledProcessors.contains(processorName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canAnalyze(Program program) {
|
public boolean canAnalyze(Program program) {
|
||||||
// Set the default for checking parameter passing
|
// Set the default for checking parameter passing
|
||||||
// don't look for constant passing in things that have a small address space, or is segmented
|
// don't look for constant passing in things that have a small address space, or is segmented
|
||||||
checkParamRefsOption = program.getDefaultPointerSize() > 2;
|
// unless there is a good data type at the location
|
||||||
checkParamRefsOption &=
|
boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace();
|
||||||
!(program.getAddressFactory().getDefaultAddressSpace() instanceof SegmentedAddressSpace);
|
checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard;
|
||||||
|
|
||||||
|
checkParamRefsOption = !(program.getAddressFactory()
|
||||||
|
.getDefaultAddressSpace() instanceof SegmentedAddressSpace);
|
||||||
|
|
||||||
if (processorName.equals("Basic")) {
|
if (processorName.equals("Basic")) {
|
||||||
if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) {
|
if (handledProcessors.contains(program.getLanguage().getProcessor().toString())) {
|
||||||
@@ -129,8 +161,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return program.getLanguage().getProcessor().equals(
|
return program.getLanguage()
|
||||||
Processor.findOrPossiblyCreateProcessor(processorName));
|
.getProcessor()
|
||||||
|
.equals(Processor.findOrPossiblyCreateProcessor(processorName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -138,7 +171,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
AddressSet unanalyzedSet = new AddressSet(set);
|
AddressSet unanalyzedSet = new AddressSet(set);
|
||||||
|
|
||||||
removeUninitializedBlocks(program, unanalyzedSet);
|
removeUninitializedBlocks(program, unanalyzedSet);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -434,6 +467,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
||||||
symEval.setParamRefCheck(checkParamRefsOption);
|
symEval.setParamRefCheck(checkParamRefsOption);
|
||||||
|
|
||||||
|
symEval.setParamPointerRefCheck(checkPointerParamRefsOption);
|
||||||
|
|
||||||
symEval.setReturnRefCheck(checkParamRefsOption);
|
symEval.setReturnRefCheck(checkParamRefsOption);
|
||||||
symEval.setStoredRefCheck(checkStoredRefsOption);
|
symEval.setStoredRefCheck(checkStoredRefsOption);
|
||||||
|
|
||||||
@@ -456,8 +492,12 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
|||||||
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
|
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption,
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor)
|
||||||
minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress);
|
.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
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(OPTION_NAME, checkParamRefsOption, null, OPTION_DESCRIPTION);
|
||||||
options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null,
|
options.registerOption(STORED_OPTION_NAME, checkStoredRefsOption, null,
|
||||||
STORED_OPTION_DESCRIPTION);
|
STORED_OPTION_DESCRIPTION);
|
||||||
options.registerOption(TRUSTWRITEMEM_OPTION_NAME, trustWriteMemOption, null,
|
options.registerOption(TRUST_WRITEMEM_OPTION_NAME, trustWriteMemOption, null,
|
||||||
TRUSTWRITEMEM_OPTION_DESCRIPTION);
|
TRUST_WRITEMEM_OPTION_DESCRIPTION);
|
||||||
options.registerOption(MAXTHREADCOUNT_OPTION_NAME, maxThreadCount, null,
|
|
||||||
MAXTHREADCOUNT_OPTION_DESCRIPTION);
|
|
||||||
|
|
||||||
options.registerOption(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null,
|
options.registerOption(CREATE_COMPLEX_DATA_FROM_POINTERS_OPTION_NAME, createComplexDataFromPointers, null,
|
||||||
MINKNOWNREFADDRESS_OPTION_DESCRIPTION);
|
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();
|
long size = program.getAddressFactory().getDefaultAddressSpace().getSize();
|
||||||
minSpeculativeRefAddress = size * 16;
|
minSpeculativeRefAddress = size * 16;
|
||||||
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
||||||
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
|
||||||
|
|
||||||
maxSpeculativeRefAddress = size * 8;
|
maxSpeculativeRefAddress = size * 8;
|
||||||
options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
|
options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
|
||||||
MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options, Program program) {
|
public void optionsChanged(Options options, Program program) {
|
||||||
checkParamRefsOption = options.getBoolean(OPTION_NAME, checkParamRefsOption);
|
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
|
// TODO: there should be a getAddress on option that validates and allows entry of addresses
|
||||||
minStoreLoadRefAddress =
|
minStoreLoadRefAddress =
|
||||||
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
options.getLong(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
||||||
minSpeculativeRefAddress =
|
minSpeculativeRefAddress =
|
||||||
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
options.getLong(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
||||||
maxSpeculativeRefAddress =
|
maxSpeculativeRefAddress =
|
||||||
options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
|
options.getLong(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+374
-11
@@ -15,14 +15,24 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.analysis;
|
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.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.pcode.PcodeOp;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.program.util.ContextEvaluatorAdapter;
|
import ghidra.program.util.ContextEvaluatorAdapter;
|
||||||
import ghidra.program.util.VarnodeContext;
|
import ghidra.program.util.VarnodeContext;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ConstantPropogatorEvaluator is used as the evaluator for the SymbolicPropagator when finding constant
|
* 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
|
* 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.
|
* 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 {
|
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();
|
protected AddressSet destSet = new AddressSet();
|
||||||
private boolean trustMemoryWrite = false;
|
private boolean trustMemoryWrite = false;
|
||||||
|
private boolean createDataFromPointers = false;
|
||||||
private long minStoreLoadOffset = 4;
|
private long minStoreLoadOffset = 4;
|
||||||
private long minSpeculativeOffset = 1024; // from the beginning of memory
|
private long minSpeculativeOffset = 1024; // from the beginning of memory
|
||||||
private long maxSpeculativeOffset = 256; // from the end 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
|
* @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;
|
this.trustMemoryWrite = trustMemoryWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
|
public ConstantPropagationContextEvaluator(TaskMonitor monitor,
|
||||||
long minStoreLoadRefAddress, long minSpeculativeRefAddress,
|
boolean trustWriteMemOption, long minStoreLoadRefAddress,
|
||||||
long maxSpeculativeRefAddress) {
|
long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
|
||||||
this(trustWriteMemOption);
|
this(monitor, trustWriteMemOption);
|
||||||
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
||||||
this.minSpeculativeOffset = minSpeculativeRefAddress;
|
this.minSpeculativeOffset = minSpeculativeRefAddress;
|
||||||
this.maxSpeculativeOffset = maxSpeculativeRefAddress;
|
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.
|
* 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
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
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,
|
// Constant references below minSpeculative or near the end of the address space are suspect,
|
||||||
// even if memory exists for those locations.
|
// even if memory exists for those locations.
|
||||||
@@ -107,8 +181,8 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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
|
// special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally
|
||||||
// really there should be another callback when adding parameters
|
// really there should be another callback when adding parameters
|
||||||
if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) {
|
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;
|
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.
|
* 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) {
|
public boolean allowAccess(VarnodeContext context, Address addr) {
|
||||||
return trustMemoryWrite;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -36,6 +36,7 @@ import ghidra.framework.options.Options;
|
|||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.lang.Processor;
|
||||||
import ghidra.program.model.lang.RegisterValue;
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
@@ -144,7 +145,17 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
|||||||
pointerEnabled = false;
|
pointerEnabled = false;
|
||||||
addressTablesEnabled = 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
|
// only analyze programs with address spaces > 16 bits
|
||||||
int bitSize = defaultAddressSpace.getSize();
|
int bitSize = defaultAddressSpace.getSize();
|
||||||
return bitSize > 16;
|
return bitSize > 16;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package ghidra.program.util;
|
package ghidra.program.util;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
@@ -56,12 +57,13 @@ public interface ContextEvaluator {
|
|||||||
* @param pcodeop the PcodeOp operation that is causing this reference
|
* @param pcodeop the PcodeOp operation that is causing this reference
|
||||||
* @param address address being referenced
|
* @param address address being referenced
|
||||||
* @param size size of the item being referenced (only non-zero if load or store of data)
|
* @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)
|
* @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)
|
* @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,
|
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
|
* 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 pcodeop the PcodeOp operation that is causing this potential constant
|
||||||
* @param constant constant value (in constant.getOffset() )
|
* @param constant constant value (in constant.getOffset() )
|
||||||
* @param size size of constant value in bytes
|
* @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)
|
* @param refType reference type (flow, data/read/write)
|
||||||
*
|
*
|
||||||
* @return the original address unchanged if it should be a reference
|
* @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
|
* a new address if the value should be a different address or address space
|
||||||
* Using something like instr.getProgram().getAddressFactory().getDefaultAddressSpace();
|
* 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
|
* Evaluate the instruction for an unknown destination
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package ghidra.program.util;
|
package ghidra.program.util;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
@@ -40,13 +41,13 @@ public class ContextEvaluatorAdapter implements ContextEvaluator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||||
int size, RefType refType) {
|
int size, DataType dataType, RefType refType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,11 +19,12 @@ import java.math.BigInteger;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.program.disassemble.DisassemblerContextImpl;
|
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.Undefined;
|
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
@@ -38,8 +39,6 @@ import ghidra.util.exception.*;
|
|||||||
|
|
||||||
public class VarnodeContext implements ProcessorContext {
|
public class VarnodeContext implements ProcessorContext {
|
||||||
|
|
||||||
public static final int BAD_SPACE_ID_VALUE = 0xffff;
|
|
||||||
|
|
||||||
protected DisassemblerContextImpl offsetContext;
|
protected DisassemblerContextImpl offsetContext;
|
||||||
protected DisassemblerContextImpl spaceContext;
|
protected DisassemblerContextImpl spaceContext;
|
||||||
|
|
||||||
@@ -63,6 +62,10 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
protected VarnodeTranslator trans; // translator for varnodes<-->registers
|
protected VarnodeTranslator trans; // translator for varnodes<-->registers
|
||||||
|
|
||||||
protected Varnode[] retVarnodes = null; // varnodes used to return values
|
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 Varnode stackVarnode = null; // varnode that represents the stack
|
||||||
protected Register stackReg = null;
|
protected Register stackReg = null;
|
||||||
private HashSet<String> validSymbolicStackNames = new HashSet<>(); // list of stack related register names
|
private HashSet<String> validSymbolicStackNames = new HashSet<>(); // list of stack related register names
|
||||||
@@ -72,6 +75,13 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
public final Address BAD_ADDRESS;
|
public final Address BAD_ADDRESS;
|
||||||
|
|
||||||
private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value;
|
private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value;
|
||||||
|
|
||||||
|
private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values
|
||||||
|
public final Address SUSPECT_ZERO_ADDRESS;
|
||||||
|
|
||||||
|
public final int BAD_SPACE_ID_VALUE;
|
||||||
|
|
||||||
|
private static final BigInteger BIG_NEGATIVE_ONE = BigInteger.ONE.negate();
|
||||||
|
|
||||||
protected boolean hitDest = false;
|
protected boolean hitDest = false;
|
||||||
|
|
||||||
@@ -92,8 +102,15 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
this.addrFactory = new OffsetAddressFactory(program);
|
this.addrFactory = new OffsetAddressFactory(program);
|
||||||
|
|
||||||
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
|
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
|
||||||
|
BAD_SPACE_ID_VALUE = BAD_ADDRESS.getAddressSpace().getSpaceID();
|
||||||
|
|
||||||
BAD_OFFSET_SPACEID = getAddressSpace("(Bad Address Offset)");
|
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;
|
this.programContext = programContext;
|
||||||
|
|
||||||
@@ -293,6 +310,48 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
return retVarnodes;
|
return retVarnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param targetFunc function to get killed varnodes for
|
||||||
|
*
|
||||||
|
* NOTE: this removes the return varnodes so they aren't duplicated
|
||||||
|
*
|
||||||
|
* @return varnode that represents where functions place their return value
|
||||||
|
*/
|
||||||
|
public Varnode[] getKilledVarnodes(Function targetFunc) {
|
||||||
|
// TODO: This doesn't handle full bonded yet!
|
||||||
|
PrototypeModel defaultCallingConvention =
|
||||||
|
program.getCompilerSpec().getDefaultCallingConvention();
|
||||||
|
|
||||||
|
if (targetFunc != null) {
|
||||||
|
// TODO handle custom calling convention killed by call when supported
|
||||||
|
PrototypeModel callingConvention = targetFunc.getCallingConvention();
|
||||||
|
|
||||||
|
if (callingConvention != null) {
|
||||||
|
return callingConvention.getKilledByCallList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no function, so get the default convention and use that.
|
||||||
|
if (killedVarnodes != null) {
|
||||||
|
return killedVarnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
killedVarnodes = defaultCallingConvention.getKilledByCallList();
|
||||||
|
|
||||||
|
// clean return varnodes out of list
|
||||||
|
Varnode[] returnVarnodes = getReturnVarnode(null);
|
||||||
|
ArrayList<Varnode> list = new ArrayList<Varnode>();
|
||||||
|
for (Varnode varnode : killedVarnodes) {
|
||||||
|
if (!ArrayUtils.contains(returnVarnodes, varnode)) {
|
||||||
|
list.add(varnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
killedVarnodes = list.toArray(new Varnode[list.size()]);
|
||||||
|
|
||||||
|
return killedVarnodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -356,7 +415,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator)
|
public Varnode getValue(Varnode varnode, boolean signed, ContextEvaluator evaluator)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
// for constant, return the constant value
|
// for constant, return the constant value
|
||||||
if (varnode.isConstant()) {
|
if (isConstant(varnode)) {
|
||||||
return varnode;
|
return varnode;
|
||||||
}
|
}
|
||||||
Varnode rvnode = null;
|
Varnode rvnode = null;
|
||||||
@@ -383,21 +442,26 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
if (bigVal != null) {
|
if (bigVal != null) {
|
||||||
|
|
||||||
BigInteger spaceVal = getTranslatedSpaceValue(reg);
|
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());
|
rvnode = createVarnode(bigVal, spaceVal, varnode.getSize());
|
||||||
if (rvnode == null) {
|
if (rvnode == null) {
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
}
|
}
|
||||||
if (!rvnode.getAddress().equals(BAD_ADDRESS)) {
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
Msg.info(this, " " + reg.getName() + " = " + print(rvnode));
|
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...
|
return varnode; // just return the register then, someone else will deal with it...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,12 +482,6 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
if (debug) {
|
if (debug) {
|
||||||
Msg.info(this, " " + varnode + " = " + print(lvalue));
|
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.
|
// 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.
|
// can't count on the offset staying the same.
|
||||||
if (isSymbolicAddr) {
|
if (isSymbolicAddr) {
|
||||||
@@ -431,15 +489,9 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
|
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
|
||||||
// figure out what register is used for stack values
|
// figure out what register is used for stack values
|
||||||
Register stackRegister = getStackRegister();
|
Register stackRegister = getStackRegister();
|
||||||
if (!isStackSymbolicSpace(varnode)) {
|
|
||||||
if (debug) {
|
// don't allow a zero/-1 constant pulled from a symbolic space.
|
||||||
Msg.info(this,
|
if (isConstant(lvalue) && (lvalue.getOffset() == 0 || lvalue.getOffset() == -1)) {
|
||||||
"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) {
|
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +572,8 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
value = (value << 8 * (8 - size)) >> 8 * (8 - size);
|
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) {
|
catch (MemoryAccessException e) {
|
||||||
@@ -642,9 +695,11 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
AddressSpace spc = addrFactory.getAddressSpace(spaceID);
|
AddressSpace spc = addrFactory.getAddressSpace(spaceID);
|
||||||
Address addr = null;
|
Address addr = null;
|
||||||
|
|
||||||
if (spaceID == BAD_SPACE_ID_VALUE || spc == null ||
|
if (spaceID == BAD_SPACE_ID_VALUE || spc == null) {
|
||||||
spc.equals(BAD_ADDRESS.getAddressSpace())) {
|
|
||||||
addr = BAD_ADDRESS;
|
addr = BAD_ADDRESS;
|
||||||
|
} else if (spaceID == BAD_OFFSET_SPACEID) {
|
||||||
|
// special case of unknown value + constant
|
||||||
|
addr = spc.getTruncatedAddress(value, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addr = spc.getTruncatedAddress(value, true);
|
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
|
// put the location on both the lastSet, and all locations set
|
||||||
addSetVarnodeToLastSetLocations(out, location);
|
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);
|
putMemoryValue(out, result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't ever store an unknown unique into a location
|
// don't ever store an unknown unique into a location
|
||||||
if (result != null && result.isUnique()) {
|
if (result != null && result.isUnique()) {
|
||||||
result = null;
|
result = null;
|
||||||
@@ -715,6 +776,20 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
tempUniqueVals.put(out.getOffset(), result);
|
tempUniqueVals.put(out.getOffset(), result);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
tempVals.put(out, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,7 +982,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException {
|
public long getConstant(Varnode vnode, ContextEvaluator evaluator) throws NotFoundException {
|
||||||
if (!vnode.isConstant()) {
|
if (!isConstant(vnode)) {
|
||||||
if (evaluator == null) {
|
if (evaluator == null) {
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
}
|
}
|
||||||
@@ -940,6 +1015,12 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
valbase = offset.getOffset();
|
valbase = offset.getOffset();
|
||||||
spaceID = (int) space.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)) {
|
else if (OffsetAddressFactory.isSymbolSpace(spaceID)) {
|
||||||
if (evaluator == null) {
|
if (evaluator == null) {
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
@@ -1037,7 +1118,10 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr);
|
BigInteger spaceVal = getTranslatedSpaceValue(reg, fromAddr, toAddr);
|
||||||
if (spaceVal != null) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1054,7 +1138,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy the varnode with as little manipulation as possible.
|
* 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 out varnode to put it in
|
||||||
* @param in varnode to copy from.
|
* @param in varnode to copy from.
|
||||||
@@ -1067,8 +1151,10 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
Varnode val1 = null;
|
Varnode val1 = null;
|
||||||
val1 = getValue(in, evaluator);
|
val1 = getValue(in, evaluator);
|
||||||
// if truncating a constant get a new constant of the proper size
|
// if truncating a constant get a new constant of the proper size
|
||||||
if (val1 != null && val1.isConstant() && in.getSize() > out.getSize()) {
|
if (val1 != null && in.getSize() > out.getSize()) {
|
||||||
val1 = createConstantVarnode(val1.getOffset(), out.getSize());
|
if (isConstant(val1)) {
|
||||||
|
val1 = createVarnode(val1.getOffset(), val1.getSpace(), out.getSize());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in.isRegister() || !out.isRegister()) {
|
if (!in.isRegister() || !out.isRegister()) {
|
||||||
@@ -1097,7 +1183,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
|
|
||||||
// try to make the constant value the addend.
|
// try to make the constant value the addend.
|
||||||
if (val1.isConstant() || val1.isAddress()) {
|
if (isConstant(val1) || val1.isAddress()) {
|
||||||
Varnode swap = val1;
|
Varnode swap = val1;
|
||||||
val1 = val2;
|
val1 = val2;
|
||||||
val2 = swap;
|
val2 = swap;
|
||||||
@@ -1142,8 +1228,11 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (val1.isConstant()) {
|
else if (isConstant(val1)) {
|
||||||
valbase = val1.getOffset();
|
valbase = val1.getOffset();
|
||||||
|
if (!isSuspectConstant(val1)) {
|
||||||
|
spaceID = val2.getSpace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (isSymbolicSpace(spaceID)) {
|
else if (isSymbolicSpace(spaceID)) {
|
||||||
Instruction instr = getCurrentInstruction(offsetContext.getAddress());
|
Instruction instr = getCurrentInstruction(offsetContext.getAddress());
|
||||||
@@ -1181,7 +1270,6 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
@@ -1199,7 +1287,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
if (val1.equals(val2)) {
|
if (val1.equals(val2)) {
|
||||||
return val1;
|
return val1;
|
||||||
}
|
}
|
||||||
if (val1.isConstant() || val1.isAddress()) {
|
if (isConstant(val1) || val1.isAddress()) {
|
||||||
Varnode swap = val1;
|
Varnode swap = val1;
|
||||||
val1 = val2;
|
val1 = val2;
|
||||||
val2 = swap;
|
val2 = swap;
|
||||||
@@ -1216,6 +1304,9 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
else if (val1.isConstant()) {
|
else if (val1.isConstant()) {
|
||||||
valbase = val1.getOffset();
|
valbase = val1.getOffset();
|
||||||
|
if (!isSuspectConstant(val1)) {
|
||||||
|
spaceID = val2.getSpace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (isSymbolicSpace(spaceID)) {
|
else if (isSymbolicSpace(spaceID)) {
|
||||||
valbase = val1.getOffset();
|
valbase = val1.getOffset();
|
||||||
@@ -1244,25 +1335,29 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
return val1;
|
return val1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val1.isConstant() || val1.isAddress()) {
|
if (isConstant(val1) || val1.isAddress()) {
|
||||||
Varnode swap = val1;
|
Varnode swap = val1;
|
||||||
val1 = val2;
|
val1 = val2;
|
||||||
val2 = swap;
|
val2 = swap;
|
||||||
}
|
}
|
||||||
|
int spaceID = val1.getSpace();
|
||||||
long val2Const = getConstant(val2, null);
|
long val2Const = getConstant(val2, null);
|
||||||
// got a constant from val2, (value | 0) == value, so just return value
|
// got a constant from val2, (value | 0) == value, so just return value
|
||||||
if (val2Const == 0) {
|
if (val2Const == 0) {
|
||||||
return val1;
|
if (!isSuspectConstant(val2)) {
|
||||||
|
return val1;
|
||||||
|
}
|
||||||
|
spaceID = val2.getSpace();
|
||||||
}
|
}
|
||||||
long lresult = getConstant(val1, evaluator) | val2Const;
|
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)
|
public Varnode left(Varnode val1, Varnode val2, ContextEvaluator evaluator)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator);
|
long lresult = getConstant(val1, evaluator) << getConstant(val2, evaluator);
|
||||||
lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
|
lresult = lresult & (0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
|
||||||
Varnode result = createConstantVarnode(lresult, val1.getSize());
|
Varnode result = createVarnode(lresult, val1.getSpace(), val1.getSize());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1306,8 +1401,11 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
}
|
}
|
||||||
int spaceID = val1.getSpace();
|
int spaceID = val1.getSpace();
|
||||||
long valbase = 0;
|
long valbase = 0;
|
||||||
if (val1.isConstant()) {
|
if (isConstant(val1)) {
|
||||||
valbase = val1.getOffset();
|
valbase = val1.getOffset();
|
||||||
|
if (!isSuspectConstant(val1)) {
|
||||||
|
spaceID = val2.getSpace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (isRegister(val1)) {
|
else if (isRegister(val1)) {
|
||||||
Register reg = trans.getRegister(val1);
|
Register reg = trans.getRegister(val1);
|
||||||
@@ -1329,7 +1427,6 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);
|
return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw notFoundExc;
|
throw notFoundExc;
|
||||||
@@ -1353,15 +1450,15 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
|
|
||||||
vnodeVal = getValue(in[0], signExtend, evaluator);
|
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
|
// TODO: Is there a better way to do this - it was not sign-extending temp values before
|
||||||
if (vnodeVal.getSize() <= 8) {
|
if (vnodeVal.getSize() <= 8) {
|
||||||
Scalar sVal = new Scalar(8 * vnodeVal.getSize(), vnodeVal.getOffset(), signExtend);
|
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 {
|
else {
|
||||||
// too big anyway,already extended as far as it will go.
|
// 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()) {
|
else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) {
|
||||||
@@ -1414,7 +1511,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
Varnode regVnode = trans.getVarnode(register);
|
Varnode regVnode = trans.getVarnode(register);
|
||||||
try {
|
try {
|
||||||
Varnode value = this.getValue(regVnode, false, null);
|
Varnode value = this.getValue(regVnode, false, null);
|
||||||
if (value.isConstant()) {
|
if (isConstant(value)) {
|
||||||
return new RegisterValue(register, BigInteger.valueOf(value.getOffset()));
|
return new RegisterValue(register, BigInteger.valueOf(value.getOffset()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1457,7 +1554,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
Varnode regVnode = trans.getVarnode(register);
|
Varnode regVnode = trans.getVarnode(register);
|
||||||
try {
|
try {
|
||||||
Varnode value = this.getValue(regVnode, signed, null);
|
Varnode value = this.getValue(regVnode, signed, null);
|
||||||
if (value.isConstant()) {
|
if (isConstant(value)) {
|
||||||
return BigInteger.valueOf(value.getOffset());
|
return BigInteger.valueOf(value.getOffset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1503,7 +1600,33 @@ public class VarnodeContext implements ProcessorContext {
|
|||||||
public boolean isRegister(Varnode varnode) {
|
public boolean isRegister(Varnode varnode) {
|
||||||
return varnode.isRegister() || trans.getRegister(varnode) != null;
|
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
|
* Check if varnode is in the stack space
|
||||||
*
|
*
|
||||||
|
|||||||
+91
-14
@@ -98,18 +98,11 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
|||||||
builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS);
|
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" +
|
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" +
|
"af bc 00 10 3c 07 12 34 24 e7 45 67 ac a7 00 10" +
|
||||||
"ac a7 00 10 3c 06 0a 0b 24 c6 0c 0d" +
|
"3c 06 0a 0b 24 c6 0c 0d ae 06 00 10 8e 11 00 10" +
|
||||||
"ae 06 00 10 8e 11 00 10 8c b1 00 10" +
|
"8c b1 00 10 8f b1 00 10 8e 51 00 10 ae 53 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" +
|
||||||
"8e 51 00 10" +
|
"3c 11 00 53 8e 51 00 10 03 e0 00 08 27 bd 00 20");
|
||||||
"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
|
//00001000 lui gp,0x14
|
||||||
//00001004 addiu gp,gp,-0x4ccc
|
//00001004 addiu gp,gp,-0x4ccc
|
||||||
@@ -153,7 +146,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(true) {
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(TaskMonitor.DUMMY, true) {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||||
|
|
||||||
@@ -176,8 +169,92 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
|||||||
registerVarnode = regValue(context,"gp");
|
registerVarnode = regValue(context,"gp");
|
||||||
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
||||||
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
|
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;
|
break;
|
||||||
// TODO: more tests
|
|
||||||
}
|
}
|
||||||
return super.evaluateContext(context, instr);
|
return super.evaluateContext(context, instr);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -31,6 +31,7 @@ import ghidra.app.util.importer.MessageLog;
|
|||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.block.*;
|
import ghidra.program.model.block.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
@@ -364,7 +365,7 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
|||||||
new ContextEvaluatorAdapter() {
|
new ContextEvaluatorAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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.
|
// go ahead and place the reference, since it is a constant.
|
||||||
if (refType.isComputed() && refType.isFlow() &&
|
if (refType.isComputed() && refType.isFlow() &&
|
||||||
program.getMemory().contains(address)) {
|
program.getMemory().contains(address)) {
|
||||||
|
|||||||
+17
-4
@@ -21,9 +21,8 @@ import ghidra.program.model.address.Address;
|
|||||||
import ghidra.util.GhidraDataConverter;
|
import ghidra.util.GhidraDataConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple byte buffer implementation of the memBuffer. Since there is no
|
* Simple byte buffer implementation of the memBuffer. Even if a Memory is
|
||||||
* actual memory object associated with this object, the getMemory method
|
* provided, the available bytes will be limited to the bytes provided during
|
||||||
* is not implemented and all gets are limited to the bytes supplied during
|
|
||||||
* construction.
|
* construction.
|
||||||
*/
|
*/
|
||||||
public class ByteMemBufferImpl implements MemBuffer {
|
public class ByteMemBufferImpl implements MemBuffer {
|
||||||
@@ -31,6 +30,7 @@ public class ByteMemBufferImpl implements MemBuffer {
|
|||||||
private final GhidraDataConverter converter;
|
private final GhidraDataConverter converter;
|
||||||
private byte[] bytes;
|
private byte[] bytes;
|
||||||
private Address addr;
|
private Address addr;
|
||||||
|
private Memory mem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a ByteMemBufferImpl object
|
* Construct a ByteMemBufferImpl object
|
||||||
@@ -39,9 +39,22 @@ public class ByteMemBufferImpl implements MemBuffer {
|
|||||||
* @param isBigEndian true for BigEndian, false for LittleEndian.
|
* @param isBigEndian true for BigEndian, false for LittleEndian.
|
||||||
*/
|
*/
|
||||||
public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) {
|
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.addr = addr;
|
||||||
this.bytes = bytes;
|
this.bytes = bytes;
|
||||||
this.converter = GhidraDataConverter.getInstance(isBigEndian);
|
this.converter = GhidraDataConverter.getInstance(isBigEndian);
|
||||||
|
this.mem = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +80,7 @@ public class ByteMemBufferImpl implements MemBuffer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Memory getMemory() {
|
public Memory getMemory() {
|
||||||
return null;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+11
-5
@@ -66,7 +66,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ConstantPropagationContextEvaluator eval =
|
ConstantPropagationContextEvaluator eval =
|
||||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
String mnemonic = instr.getMnemonicString();
|
String mnemonic = instr.getMnemonicString();
|
||||||
@@ -124,7 +124,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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()) {
|
if (instr.getFlowType().isJump()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,6 +153,12 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|
||||||
@@ -234,13 +240,13 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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)) {
|
if (targetList.contains(address)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -29,6 +29,7 @@ import ghidra.app.services.*;
|
|||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
@@ -190,7 +191,7 @@ public class AARCH64PltThunkAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||||
int size, RefType refType) {
|
int size, DataType dataType, RefType refType) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-11
@@ -81,7 +81,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ConstantPropagationContextEvaluator eval =
|
ConstantPropagationContextEvaluator eval =
|
||||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
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
|
// if LR is a constant and is set right after this, this is a call
|
||||||
Varnode lrVal = context.getRegisterVarnodeValue(lrRegister);
|
Varnode lrVal = context.getRegisterVarnodeValue(lrRegister);
|
||||||
if (lrVal != null) {
|
if (lrVal != null) {
|
||||||
if (lrVal.isConstant()) {
|
if (context.isConstant(lrVal)) {
|
||||||
long target = lrVal.getAddress().getOffset();
|
long target = lrVal.getAddress().getOffset();
|
||||||
Address addr = instr.getMaxAddress().add(1);
|
Address addr = instr.getMaxAddress().add(1);
|
||||||
if (target == addr.getOffset() && !instr.getFlowType().isCall()) {
|
if (target == addr.getOffset() && !instr.getFlowType().isCall()) {
|
||||||
@@ -176,7 +176,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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() &&
|
if (refType.isJump() && refType.isComputed() &&
|
||||||
program.getMemory().contains(address) && address.getOffset() != 0) {
|
program.getMemory().contains(address) && address.getOffset() != 0) {
|
||||||
if (instr.getMnemonicString().startsWith("tb")) {
|
if (instr.getMnemonicString().startsWith("tb")) {
|
||||||
@@ -184,24 +184,29 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
}
|
}
|
||||||
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
||||||
true, monitor);
|
true, monitor);
|
||||||
|
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
return !symEval.encounteredBranch();
|
return !symEval.encounteredBranch();
|
||||||
}
|
}
|
||||||
if (refType.isData() && program.getMemory().contains(address)) {
|
if (refType.isData() && program.getMemory().contains(address)) {
|
||||||
if (refType.isRead() || refType.isWrite()) {
|
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);
|
createData(program, address, size);
|
||||||
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
|
if (numOperands <= 2) {
|
||||||
SourceType.ANALYSIS);
|
instr.addOperandReference(instr.getNumOperands() - 1, address, refType,
|
||||||
return false;
|
SourceType.ANALYSIS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
|
else if (refType.isCall() && refType.isComputed() && !address.isExternalAddress()) {
|
||||||
// must disassemble right now, because TB flag could get set back at end of blx
|
// must disassemble right now, because TB flag could get set back at end of blx
|
||||||
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
doArmThumbDisassembly(program, instr, context, address, instr.getFlowType(),
|
||||||
true, monitor);
|
true, monitor);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -225,7 +230,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
|
public boolean evaluateReturn(Varnode retVN, VarnodeContext context, Instruction instruction) {
|
||||||
// check if a return is actually returning, or is branching with a constant PC
|
// 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();
|
long offset = retVN.getOffset();
|
||||||
if (offset > 3 && offset != -1) {
|
if (offset > 3 && offset != -1) {
|
||||||
// need to override the return to a branch
|
// need to override the return to a branch
|
||||||
@@ -236,6 +241,12 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|
||||||
@@ -361,13 +372,13 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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 ever see a reference to 0, something went wrong, stop the process
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
|
|||||||
+35
-23
@@ -25,6 +25,7 @@ import ghidra.app.util.importer.MessageLog;
|
|||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
@@ -247,7 +248,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// 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 Address localGPAssumptionValue = currentGPAssumptionValue;
|
||||||
|
|
||||||
private boolean mustStopNow = false; // if something discovered in processing, mustStop flag
|
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
|
// this was copylefted from the arm analyzer
|
||||||
Varnode raVal = context.getRegisterVarnodeValue(rareg);
|
Varnode raVal = context.getRegisterVarnodeValue(rareg);
|
||||||
if (raVal != null) {
|
if (raVal != null) {
|
||||||
if (raVal.isConstant()) {
|
if (context.isConstant(raVal)) {
|
||||||
long target = raVal.getAddress().getOffset();
|
long target = raVal.getAddress().getOffset();
|
||||||
Address addr = instr.getMaxAddress();
|
Address addr = instr.getMaxAddress();
|
||||||
if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) {
|
if (target == (addr.getOffset() + 1) && !instr.getFlowType().isCall()) {
|
||||||
@@ -317,22 +318,25 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
lastSetInstr = instructionAt;
|
lastSetInstr = instructionAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symEval.makeReference(context, lastSetInstr, -1,
|
// if an instruction actually set the GP
|
||||||
instr.getMinAddress().getAddressSpace().getSpaceID(),
|
if (lastSetAddr != null) {
|
||||||
unsignedValue, 1, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
symEval.makeReference(context, lastSetInstr, -1,
|
||||||
monitor);
|
instr.getMinAddress().getAddressSpace().getSpaceID(),
|
||||||
if (localGPAssumptionValue == null) {
|
unsignedValue, 1, null, RefType.DATA, PcodeOp.UNIMPLEMENTED, true,
|
||||||
program.getBookmarkManager().setBookmark(
|
false, monitor);
|
||||||
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
|
if (localGPAssumptionValue == null) {
|
||||||
"GP Global Register Set",
|
program.getBookmarkManager().setBookmark(
|
||||||
"Global GP Register is set here.");
|
lastSetInstr.getMinAddress(), BookmarkType.WARNING,
|
||||||
}
|
"GP Global Register Set",
|
||||||
if (localGPAssumptionValue != null &&
|
"Global GP Register is set here.");
|
||||||
!localGPAssumptionValue.equals(gpRefAddr)) {
|
}
|
||||||
localGPAssumptionValue = gp_assumption_value = null;
|
if (localGPAssumptionValue != null &&
|
||||||
}
|
!localGPAssumptionValue.equals(gpRefAddr)) {
|
||||||
else {
|
localGPAssumptionValue = gp_assumption_value = null;
|
||||||
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
|
}
|
||||||
|
else {
|
||||||
|
localGPAssumptionValue = gp_assumption_value = gpRefAddr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,9 +376,13 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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;
|
Address addr = address;
|
||||||
|
|
||||||
|
if (addr == Address.NO_ADDRESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
|
//if (instr.getFlowType().isJump() && !instr.getPrototype().hasDelaySlots()) {
|
||||||
// if this isn't straight code (thunk computation), let someone else lay down the reference
|
// 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()) & refType.isComputed()) {
|
||||||
//if (refType.isJump() || refType.isCall()) {
|
|
||||||
addr = mipsExtDisassembly(program, instr, context, address, monitor);
|
addr = mipsExtDisassembly(program, instr, context, address, monitor);
|
||||||
//addr = flowISA(program, instr, context, address);
|
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
addr = address;
|
addr = address;
|
||||||
}
|
}
|
||||||
@@ -412,7 +418,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
context.clearRegister(reg);
|
context.clearRegister(reg);
|
||||||
|
|
||||||
// need to add the reference here, register operand will no longer have a value
|
// 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);
|
SourceType.ANALYSIS);
|
||||||
|
|
||||||
// set the register value on the target address
|
// 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
|
@Override
|
||||||
@@ -497,6 +503,12 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||||
|
|
||||||
|
|||||||
+10
-3
@@ -20,6 +20,7 @@ import java.math.BigInteger;
|
|||||||
import ghidra.app.services.AnalysisPriority;
|
import ghidra.app.services.AnalysisPriority;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
@@ -79,11 +80,11 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
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();
|
AddressSpace space = address.getAddressSpace();
|
||||||
|
|
||||||
if (address.isExternalAddress()) {
|
if (address.isExternalAddress()) {
|
||||||
@@ -97,7 +98,7 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
if (refType.isComputed() && refType.isFlow() && isCodeSpace) {
|
if (refType.isComputed() && refType.isFlow() && isCodeSpace) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -146,6 +147,12 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
startNewBlock(program, flowStart);
|
startNewBlock(program, flowStart);
|
||||||
|
|
||||||
AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|||||||
+2
-1
@@ -29,6 +29,7 @@ import ghidra.app.services.*;
|
|||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
@@ -264,7 +265,7 @@ public class PPC64CallStubAnalyzer extends AbstractAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||||
int size, RefType refType) {
|
int size, DataType dataType, RefType refType) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -154,7 +154,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ConstantPropagationContextEvaluator eval =
|
ConstantPropagationContextEvaluator eval =
|
||||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||||
@@ -224,7 +224,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
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()) {
|
if (instr.getFlowType().isJump()) {
|
||||||
// for branching instructions, if we have a good target, mark it
|
// for branching instructions, if we have a good target, mark it
|
||||||
@@ -259,7 +259,7 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|
||||||
if (recoverSwitchTables) {
|
if (recoverSwitchTables) {
|
||||||
@@ -454,13 +460,13 @@ public class PowerPCAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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!
|
// TODO: if ever loading from instructions in memory, must EXIT!
|
||||||
if (!((refType.isComputed() || refType.isConditional()) &&
|
if (!((refType.isComputed() || refType.isConditional()) &&
|
||||||
|
|||||||
+8
-2
@@ -99,7 +99,7 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
ConstantPropagationContextEvaluator eval =
|
ConstantPropagationContextEvaluator eval =
|
||||||
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
private boolean mustStopNow = false;
|
private boolean mustStopNow = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,7 +112,13 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return mustStopNow;
|
return mustStopNow;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||||
|
|
||||||
return resultSet;
|
return resultSet;
|
||||||
|
|||||||
+8
-2
@@ -76,7 +76,7 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
@@ -126,7 +126,13 @@ public class SparcAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|
||||||
return resultSet;
|
return resultSet;
|
||||||
|
|||||||
+10
-3
@@ -21,6 +21,7 @@ import ghidra.app.util.importer.MessageLog;
|
|||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
@@ -76,11 +77,11 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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()) {
|
if (address.isExternalAddress()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -98,7 +99,7 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean doRef =
|
boolean doRef =
|
||||||
super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType);
|
||||||
if (!doRef) {
|
if (!doRef) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -109,6 +110,12 @@ public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
|||||||
return doRef;
|
return doRef;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eval.setTrustWritableMemory(trustWriteMemOption)
|
||||||
|
.setMinpeculativeOffset(minSpeculativeRefAddress)
|
||||||
|
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
|
||||||
|
.setMinStoreLoadOffset(minStoreLoadRefAddress)
|
||||||
|
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
|
||||||
|
|
||||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -17,6 +17,7 @@ package ghidra.app.plugin.core.analysis;
|
|||||||
|
|
||||||
import ghidra.app.services.AnalysisPriority;
|
import ghidra.app.services.AnalysisPriority;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
@@ -45,11 +46,11 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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
|
// if this is a call, some processors use the register value
|
||||||
// used in the call for PIC calculations
|
// used in the call for PIC calculations
|
||||||
@@ -67,7 +68,7 @@ public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
|
|||||||
|
|
||||||
if (refType.isComputed()) {
|
if (refType.isComputed()) {
|
||||||
boolean doRef = super.evaluateReference(context, instr, pcodeop, address,
|
boolean doRef = super.evaluateReference(context, instr, pcodeop, address,
|
||||||
size, refType);
|
size, dataType, refType);
|
||||||
if (!doRef) {
|
if (!doRef) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-4
@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.analysis;
|
|||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Processor;
|
import ghidra.program.model.lang.Processor;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
@@ -48,7 +49,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
@@ -74,7 +75,7 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
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.
|
// don't allow flow references to locations not in memory if the location is not external.
|
||||||
if (refType.isFlow() && !instr.getMemory().contains(address) &&
|
if (refType.isFlow() && !instr.getMemory().contains(address) &&
|
||||||
@@ -82,10 +83,16 @@ public class X86Analyzer extends ConstantPropagationAnalyzer {
|
|||||||
return false;
|
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);
|
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
|
||||||
return resultSet;
|
return resultSet;
|
||||||
|
|||||||
Reference in New Issue
Block a user