mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
added RulePiecePathology
This commit is contained in:
parent
38b72df280
commit
ea83aa6d5c
6 changed files with 276 additions and 2 deletions
|
@ -8657,3 +8657,194 @@ Varnode *RulePopcountBoolXor::getBooleanResult(Varnode *vn,int4 bitPos,int4 &con
|
|||
}
|
||||
return (Varnode *)0; // Never reach here
|
||||
}
|
||||
|
||||
/// \brief Return \b true if concatenating with a SUBPIECE of the given Varnode is unusual
|
||||
///
|
||||
/// \param vn is the given Varnode
|
||||
/// \param data is the function containing the Varnode
|
||||
/// \return \b true if the configuration is a pathology
|
||||
bool RulePiecePathology::isPathology(Varnode *vn,Funcdata &data)
|
||||
|
||||
{
|
||||
vector<PcodeOp *> worklist;
|
||||
int4 pos = 0;
|
||||
int4 slot = 0;
|
||||
bool res = false;
|
||||
for(;;) {
|
||||
if (vn->isInput() && !vn->isPersist()) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
PcodeOp *op = vn->getDef();
|
||||
while(!res && op != (PcodeOp *)0) {
|
||||
switch(op->code()) {
|
||||
case CPUI_COPY:
|
||||
vn = op->getIn(0);
|
||||
op = vn->getDef();
|
||||
break;
|
||||
case CPUI_MULTIEQUAL:
|
||||
if (!op->isMark()) {
|
||||
op->setMark();
|
||||
worklist.push_back(op);
|
||||
}
|
||||
op = (PcodeOp *)0;
|
||||
break;
|
||||
case CPUI_INDIRECT:
|
||||
if (op->getIn(1)->getSpace()->getType() == IPTR_IOP) {
|
||||
PcodeOp *callOp = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
|
||||
if (callOp->isCall()) {
|
||||
FuncCallSpecs *fspec = data.getCallSpecs(callOp);
|
||||
if (fspec != (FuncCallSpecs *) 0 && !fspec->isOutputActive()) {
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
op = (PcodeOp *)0;
|
||||
break;
|
||||
case CPUI_CALL:
|
||||
case CPUI_CALLIND:
|
||||
{
|
||||
FuncCallSpecs *fspec = data.getCallSpecs(op);
|
||||
if (fspec != (FuncCallSpecs *)0 && !fspec->isOutputActive()) {
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
op = (PcodeOp *)0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res) break;
|
||||
if (pos >= worklist.size()) break;
|
||||
op = worklist[pos];
|
||||
if (slot < op->numInput()) {
|
||||
vn = op->getIn(slot);
|
||||
slot += 1;
|
||||
}
|
||||
else {
|
||||
pos += 1;
|
||||
if (pos >= worklist.size()) break;
|
||||
vn = worklist[pos]->getIn(0);
|
||||
slot = 1;
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<worklist.size();++i)
|
||||
worklist[i]->clearMark();
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \brief Given a known pathological concatenation, trace it forward to CALLs and RETURNs
|
||||
///
|
||||
/// If the pathology reaches a CALL or RETURN, it is noted, through the FuncProto or FuncCallSpecs
|
||||
/// object, that the parameter or return value is only partially consumed. The subvariable flow
|
||||
/// rules can then decide whether or not to truncate this part of the data-flow.
|
||||
/// \param op is CPUI_PIECE op that is the pathological concatenation
|
||||
/// \param data is the function containing the data-flow
|
||||
/// \return a non-zero value if new bytes are labeled as unconsumed
|
||||
int4 RulePiecePathology::tracePathologyForward(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
int4 count = 0;
|
||||
const FuncCallSpecs *fProto;
|
||||
vector<PcodeOp *> worklist;
|
||||
int4 pos = 0;
|
||||
op->setMark();
|
||||
worklist.push_back(op);
|
||||
while(pos < worklist.size()) {
|
||||
PcodeOp *curOp = worklist[pos];
|
||||
pos += 1;
|
||||
Varnode *outVn = curOp->getOut();
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
list<PcodeOp *>::const_iterator enditer = outVn->endDescend();
|
||||
for(iter=outVn->beginDescend();iter!=enditer;++iter) {
|
||||
curOp = *iter;
|
||||
switch(curOp->code()) {
|
||||
case CPUI_COPY:
|
||||
case CPUI_INDIRECT:
|
||||
case CPUI_MULTIEQUAL:
|
||||
if (!curOp->isMark()) {
|
||||
curOp->setMark();
|
||||
worklist.push_back(curOp);
|
||||
}
|
||||
break;
|
||||
case CPUI_CALL:
|
||||
case CPUI_CALLIND:
|
||||
fProto = data.getCallSpecs(curOp);
|
||||
if (fProto != (FuncProto *)0 && !fProto->isInputActive() && !fProto->isInputLocked()) {
|
||||
int4 bytesConsumed = op->getIn(1)->getSize();
|
||||
for(int4 i=1;i<curOp->numInput();++i) {
|
||||
if (curOp->getIn(i) == outVn) {
|
||||
if (fProto->setInputBytesConsumed(i, bytesConsumed))
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CPUI_RETURN:
|
||||
if (!data.getFuncProto().isOutputLocked()) {
|
||||
if (data.getFuncProto().setReturnBytesConsumed(op->getIn(1)->getSize()))
|
||||
count += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<worklist.size();++i)
|
||||
worklist[i]->clearMark();
|
||||
return count;
|
||||
}
|
||||
|
||||
/// \class RulePiecePathology
|
||||
/// \brief Search for concatenations with unlikely things to inform return/parameter consumption calculation
|
||||
///
|
||||
/// For that can read/write part of a general purpose register, a small return value can get concatenated
|
||||
/// with unrelated data when the function writes directly to part of the return register. This searches
|
||||
/// for a characteristic pathology:
|
||||
/// \code
|
||||
/// retreg = CALL();
|
||||
/// ...
|
||||
/// retreg = CONCAT(SUBPIECE(retreg,#4),smallval);
|
||||
/// \endcode
|
||||
void RulePiecePathology::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
oplist.push_back(CPUI_PIECE);
|
||||
}
|
||||
|
||||
int4 RulePiecePathology::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *vn = op->getIn(0);
|
||||
if (!vn->isWritten()) return 0;
|
||||
PcodeOp *subOp = vn->getDef();
|
||||
|
||||
// Make sure we are concatenating the most significant bytes of a truncation
|
||||
OpCode opc = subOp->code();
|
||||
if (opc == CPUI_SUBPIECE) {
|
||||
if (subOp->getIn(1)->getOffset() == 0) return 0;
|
||||
if (!isPathology(subOp->getIn(0),data)) return 0;
|
||||
}
|
||||
else if (opc == CPUI_INDIRECT) {
|
||||
if (!subOp->isIndirectCreation()) return 0;
|
||||
Varnode *retVn = op->getIn(1);
|
||||
if (!retVn->isWritten()) return 0;
|
||||
PcodeOp *callOp = retVn->getDef();
|
||||
if (!callOp->isCall()) return 0;
|
||||
FuncCallSpecs *fc = data.getCallSpecs(callOp);
|
||||
if (fc == (FuncCallSpecs *)0) return 0;
|
||||
if (!fc->isOutputLocked()) return 0;
|
||||
Address addr = retVn->getAddr();
|
||||
if (addr.getSpace()->isBigEndian())
|
||||
addr = addr - vn->getSize();
|
||||
else
|
||||
addr = addr + retVn->getSize();
|
||||
if (addr != vn->getAddr()) return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return tracePathologyForward(op, data);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue