mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
solving stack STOREs
This commit is contained in:
parent
2a73bca9ac
commit
ec9bfa86a7
5 changed files with 112 additions and 44 deletions
|
@ -232,7 +232,8 @@ public:
|
|||
/// \return \b true if the Varnode is fully linked
|
||||
bool isHeritaged(Varnode *vn) { return (heritage.heritagePass(vn->getAddr())>=0); }
|
||||
|
||||
const list<LoadGuard> &getLoadGuards(void) const { return heritage.getLoadGuards(); }
|
||||
const list<LoadGuard> &getLoadGuards(void) const { return heritage.getLoadGuards(); } ///< Get the list of guarded LOADs
|
||||
const list<LoadGuard> &getStoreGuards(void) const { return heritage.getStoreGuards(); } ///< Get the list of guarded STOREs
|
||||
|
||||
// Function prototype and call specification routines
|
||||
int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function
|
||||
|
|
|
@ -656,18 +656,35 @@ void LoadGuard::finalizeRange(const ValueSetRead &valueSet)
|
|||
void Heritage::analyzeNewLoadGuards(void)
|
||||
|
||||
{
|
||||
if (loadGuard.empty()) return;
|
||||
if (loadGuard.back().analysisState != 0) return; // Nothing new
|
||||
list<LoadGuard>::iterator startIter = loadGuard.end();
|
||||
bool nothingToDo = true;
|
||||
if (!loadGuard.empty()) {
|
||||
if (loadGuard.back().analysisState == 0) // Check if unanalyzed
|
||||
nothingToDo = false;
|
||||
}
|
||||
if (!storeGuard.empty()) {
|
||||
if (storeGuard.back().analysisState == 0)
|
||||
nothingToDo = false;
|
||||
}
|
||||
if (nothingToDo) return;
|
||||
|
||||
vector<Varnode *> sinks;
|
||||
vector<PcodeOp *> reads;
|
||||
while(startIter != loadGuard.begin()) {
|
||||
--startIter;
|
||||
LoadGuard &guard( *startIter );
|
||||
list<LoadGuard>::iterator loadIter = loadGuard.end();
|
||||
while(loadIter != loadGuard.begin()) {
|
||||
--loadIter;
|
||||
LoadGuard &guard( *loadIter );
|
||||
if (guard.analysisState != 0) break;
|
||||
reads.push_back(guard.op);
|
||||
sinks.push_back(guard.op->getIn(1)); // The CPUI_LOAD pointer
|
||||
}
|
||||
list<LoadGuard>::iterator storeIter = storeGuard.end();
|
||||
while(storeIter != storeGuard.begin()) {
|
||||
--storeIter;
|
||||
LoadGuard &guard( *storeIter );
|
||||
if (guard.analysisState != 0) break;
|
||||
reads.push_back(guard.op);
|
||||
sinks.push_back(guard.op->getIn(1)); // The CPUI_STORE pointer
|
||||
}
|
||||
AddrSpace *stackSpc = fd->getArch()->getStackSpace();
|
||||
Varnode *stackReg = (Varnode *)0;
|
||||
if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0)
|
||||
|
@ -678,7 +695,13 @@ void Heritage::analyzeNewLoadGuards(void)
|
|||
vsSolver.solve(10000,widener);
|
||||
list<LoadGuard>::iterator iter;
|
||||
bool runFullAnalysis = false;
|
||||
for(iter=startIter;iter!=loadGuard.end(); ++iter) {
|
||||
for(iter=loadIter;iter!=loadGuard.end(); ++iter) {
|
||||
LoadGuard &guard( *iter );
|
||||
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
||||
if (guard.analysisState == 0)
|
||||
runFullAnalysis = true;
|
||||
}
|
||||
for(iter=storeIter;iter!=storeGuard.end(); ++iter) {
|
||||
LoadGuard &guard( *iter );
|
||||
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
||||
if (guard.analysisState == 0)
|
||||
|
@ -687,7 +710,11 @@ void Heritage::analyzeNewLoadGuards(void)
|
|||
if (runFullAnalysis) {
|
||||
WidenerFull fullWidener;
|
||||
vsSolver.solve(10000, fullWidener);
|
||||
for (iter = startIter; iter != loadGuard.end(); ++iter) {
|
||||
for (iter = loadIter; iter != loadGuard.end(); ++iter) {
|
||||
LoadGuard &guard(*iter);
|
||||
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
||||
}
|
||||
for (iter = storeIter; iter != storeGuard.end(); ++iter) {
|
||||
LoadGuard &guard(*iter);
|
||||
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
||||
}
|
||||
|
@ -708,6 +735,20 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
|
|||
loadGuard.back().set(op,spc,node.offset);
|
||||
}
|
||||
|
||||
/// \brief Generate a guard record given an indexed STORE to a stack space
|
||||
///
|
||||
/// Record the STORE op and the (likely) range of addresses in the stack space that
|
||||
/// might be stored to.
|
||||
/// \param node is the path element containing the constructed Address
|
||||
/// \param op is the STORE PcodeOp
|
||||
/// \param spc is the stack space
|
||||
void Heritage::generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
|
||||
|
||||
{
|
||||
storeGuard.push_back(LoadGuard());
|
||||
storeGuard.back().set(op,spc,node.offset);
|
||||
}
|
||||
|
||||
/// \brief Trace input stackpointer to any indexed loads
|
||||
///
|
||||
/// Look for expressions of the form val = *(SP(i) + vn + #c), where the base stack
|
||||
|
@ -715,7 +756,7 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
|
|||
/// value is loaded from the resulting address. The LOAD operations are added to the list
|
||||
/// of ops that potentially need to be guarded during a heritage pass.
|
||||
/// \param spc is the particular address space with a stackpointer (into it)
|
||||
void Heritage::discoverIndexedStackLoads(AddrSpace *spc)
|
||||
void Heritage::discoverIndexedStackPointers(AddrSpace *spc)
|
||||
|
||||
{
|
||||
// We need to be careful of exponential ladders, so we mark Varnodes independently of
|
||||
|
@ -791,6 +832,13 @@ void Heritage::discoverIndexedStackLoads(AddrSpace *spc)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CPUI_STORE:
|
||||
{
|
||||
if (curNode.traversals != 0) {
|
||||
generateStoreGuard(curNode, op, spc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2039,7 +2087,7 @@ void Heritage::heritage(void)
|
|||
if (pass < info->delay) continue; // It is too soon to heritage this space
|
||||
if (!info->loadGuardSearch) {
|
||||
info->loadGuardSearch = true;
|
||||
discoverIndexedStackLoads(info->space);
|
||||
discoverIndexedStackPointers(info->space);
|
||||
}
|
||||
needwarning = false;
|
||||
iter = fd->beginLoc(space);
|
||||
|
@ -2205,6 +2253,7 @@ void Heritage::clear(void)
|
|||
merge.clear();
|
||||
clearInfoList();
|
||||
loadGuard.clear();
|
||||
storeGuard.clear();
|
||||
maxdepth = -1;
|
||||
pass = 0;
|
||||
}
|
||||
|
|
|
@ -204,6 +204,7 @@ class Heritage {
|
|||
vector<FlowBlock *> merge; ///< Calculate merge points (blocks containing phi-nodes)
|
||||
vector<HeritageInfo> infolist; ///< Heritage status for individual address spaces
|
||||
list<LoadGuard> loadGuard; ///< List of LOAD operations that need to be guarded
|
||||
list<LoadGuard> storeGuard; ///< List of STORE operations taking an indexed pointer to the stack
|
||||
vector<PcodeOp *> loadCopyOps; ///< List of COPY ops generated by load guards
|
||||
void clearInfoList(void); ///< Reset heritage status for all address spaces
|
||||
|
||||
|
@ -231,7 +232,8 @@ class Heritage {
|
|||
void handleNewLoadCopies(void);
|
||||
void analyzeNewLoadGuards(void);
|
||||
void generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
|
||||
void discoverIndexedStackLoads(AddrSpace *spc);
|
||||
void generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
|
||||
void discoverIndexedStackPointers(AddrSpace *spc);
|
||||
void guard(const Address &addr,int4 size,vector<Varnode *> &read,vector<Varnode *> &write,vector<Varnode *> &inputvars);
|
||||
void guardInput(const Address &addr,int4 size,vector<Varnode *> &input);
|
||||
void guardCalls(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
|
||||
|
@ -270,6 +272,7 @@ public:
|
|||
void clear(void); ///< Reset all analysis of heritage
|
||||
void heritage(void); ///< Perform one pass of heritage
|
||||
const list<LoadGuard> &getLoadGuards(void) const { return loadGuard; } ///< Get list of LOAD ops that are guarded
|
||||
const list<LoadGuard> &getStoreGuards(void) const { return storeGuard; } ///< Get list of STORE ops that are guarded
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -796,6 +796,44 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,i
|
|||
#endif
|
||||
}
|
||||
|
||||
/// The given LoadGuard, which may be a LOAD or STORE is converted into an appropriate
|
||||
/// RangeHint, attempting to make use of any data-type or index information.
|
||||
/// \param guard is the given LoadGuard
|
||||
/// \param typeFactory is used to manufacture a data-type for the hint if necessary
|
||||
void MapState::addGuard(const LoadGuard &guard,TypeFactory *typeFactory)
|
||||
|
||||
{
|
||||
if (!guard.isValid()) return;
|
||||
int4 step = guard.getStep();
|
||||
if (step == 0) return; // No definitive sign of array access
|
||||
Datatype *ct = guard.getOp()->getIn(1)->getType();
|
||||
if (ct->getMetatype() == TYPE_PTR) {
|
||||
ct = ((TypePointer *) ct)->getPtrTo();
|
||||
while (ct->getMetatype() == TYPE_ARRAY)
|
||||
ct = ((TypeArray *) ct)->getBase();
|
||||
}
|
||||
int4 outSize = guard.getOp()->getOut()->getSize();
|
||||
if (outSize != step) {
|
||||
// LOAD size doesn't match step: field in array of structures or something more unusual
|
||||
if (outSize > step || (step % outSize) != 0)
|
||||
return;
|
||||
// Since the LOAD size divides the step and we want to preserve the arrayness
|
||||
// we pretend we have an array of LOAD's size
|
||||
step = outSize;
|
||||
}
|
||||
if (ct->getSize() != step) { // Make sure data-type matches our step size
|
||||
if (step > 8)
|
||||
return; // Don't manufacture primitives bigger than 8-bytes
|
||||
ct = typeFactory->getBase(step, TYPE_UNKNOWN);
|
||||
}
|
||||
if (guard.isRangeLocked()) {
|
||||
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
|
||||
addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
|
||||
}
|
||||
else
|
||||
addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
|
||||
}
|
||||
|
||||
/// Run through all Symbols in the given map and create a corresponding RangeHint
|
||||
/// to \b this collection for each Symbol.
|
||||
/// \param rangemap is the given map of Symbols
|
||||
|
@ -922,39 +960,14 @@ void MapState::gatherOpen(const Funcdata &fd)
|
|||
addRange(offset,ct,0,RangeHint::open,minItems);
|
||||
}
|
||||
|
||||
TypeFactory *typeFactory = fd.getArch()->types;
|
||||
const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
|
||||
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) {
|
||||
const LoadGuard &guard( *iter );
|
||||
if (!guard.isValid()) continue;
|
||||
int4 step = guard.getStep();
|
||||
if (step == 0) continue; // No definitive sign of array access
|
||||
Datatype *ct = guard.getOp()->getIn(1)->getType();
|
||||
if (ct->getMetatype() == TYPE_PTR) {
|
||||
ct = ((TypePointer *) ct)->getPtrTo();
|
||||
while (ct->getMetatype() == TYPE_ARRAY)
|
||||
ct = ((TypeArray *) ct)->getBase();
|
||||
}
|
||||
int4 outSize = guard.getOp()->getOut()->getSize();
|
||||
if (outSize != step) {
|
||||
// LOAD size doesn't match step: field in array of structures or something more unusual
|
||||
if (outSize > step || (step % outSize) != 0)
|
||||
continue;
|
||||
// Since the LOAD size divides the step and we want to preserve the arrayness
|
||||
// we pretend we have an array of LOAD's size
|
||||
step = outSize;
|
||||
}
|
||||
if (ct->getSize() != step) { // Make sure data-type matches our step size
|
||||
if (step > 8)
|
||||
continue; // Don't manufacture primitives bigger than 8-bytes
|
||||
ct = fd.getArch()->types->getBase(step, TYPE_UNKNOWN);
|
||||
}
|
||||
if (guard.isRangeLocked()) {
|
||||
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
|
||||
addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
|
||||
}
|
||||
else
|
||||
addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
|
||||
}
|
||||
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter)
|
||||
addGuard(*iter,typeFactory);
|
||||
|
||||
const list<LoadGuard> &storeGuard( fd.getStoreGuards() );
|
||||
for(list<LoadGuard>::const_iterator iter=storeGuard.begin();iter!=storeGuard.end();++iter)
|
||||
addGuard(*iter,typeFactory);
|
||||
}
|
||||
|
||||
/// Define stack Symbols based on Varnodes.
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
};
|
||||
|
||||
class ProtoModel;
|
||||
class LoadGuard;
|
||||
|
||||
/// \brief A light-weight class for analyzing pointers and aliasing on the stack
|
||||
///
|
||||
|
@ -126,6 +127,7 @@ class MapState {
|
|||
vector<RangeHint *>::iterator iter; ///< The current iterator into the RangeHints
|
||||
Datatype *defaultType; ///< The default data-type to use for RangeHints
|
||||
AliasChecker checker; ///< A collection of pointer Varnodes into our address space
|
||||
void addGuard(const LoadGuard &guard,TypeFactory *typeFactory); ///< Add LoadGuard record as a hint to the collection
|
||||
void addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi); ///< Add a hint to the collection
|
||||
public:
|
||||
#ifdef OPACTION_DEBUG
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue