Move JMP processing from Function class
Add MarkAsSwitchCase command
This commit is contained in:
parent
ae27258e3c
commit
9c6dfd676e
@ -232,7 +232,6 @@ public:
|
||||
void markImpure();
|
||||
void findImmedDom();
|
||||
void process_operands(ICODE &pIcode, STATE *pstate);
|
||||
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void freeCFG();
|
||||
void codeGen(QIODevice & fs);
|
||||
@ -285,10 +284,6 @@ protected:
|
||||
bool findDerivedSeq(derSeq &derivedGi);
|
||||
bool nextOrderGraph(derSeq &derivedGi);
|
||||
void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll);
|
||||
|
||||
private:
|
||||
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
};
|
||||
|
||||
typedef std::list<PtrFunction> FunctionListType;
|
||||
|
||||
@ -16,3 +16,34 @@ bool FollowControlFlow::execute(CommandContext *ctx)
|
||||
FollowCtrl(*scanned_func,proj.callGraph, &m_start_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MarkAsSwitchCase::instanceDescription() const
|
||||
{
|
||||
return name() + QString(" 0x%1 -> 0x%2 ; case %3")
|
||||
.arg(m_src_addr,8,16,QChar('0'))
|
||||
.arg(m_dst_addr,8,16,QChar('0'))
|
||||
.arg(m_case_label);
|
||||
|
||||
}
|
||||
|
||||
bool MarkAsSwitchCase::execute(CommandContext * ctx)
|
||||
{
|
||||
//TODO: record code/data referneces in project for navigation UI purposes ?
|
||||
auto switch_insn = ctx->m_func->Icode.labelSrch(m_src_addr);
|
||||
if(switch_insn==ctx->m_func->Icode.end()) {
|
||||
ctx->recordFailure(this,QString("switch instruction @ 0x%1 not found in procedure's instructions ?")
|
||||
.arg(m_src_addr,8,16,QChar('0')));
|
||||
return false;
|
||||
}
|
||||
auto insn = ctx->m_func->Icode.labelSrch(m_dst_addr);
|
||||
if(insn==ctx->m_func->Icode.end()) {
|
||||
ctx->recordFailure(this,QString("switch target instruction 0x%1 not found in procedure's instructions ?")
|
||||
.arg(m_dst_addr,8,16,QChar('0')));
|
||||
return false;
|
||||
}
|
||||
insn->ll()->caseEntry = m_case_label;
|
||||
insn->ll()->setFlags(CASE);
|
||||
switch_insn->ll()->caseTbl2.push_back( m_dst_addr );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@ -16,5 +16,24 @@ public:
|
||||
QString instanceDescription() const override;
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
// mark instruction at address m_dst_addr as a case m_case_label of switch located at m_src_addr
|
||||
class MarkAsSwitchCase : public Command
|
||||
{
|
||||
uint32_t m_src_addr;
|
||||
uint32_t m_dst_addr;
|
||||
int m_case_label;
|
||||
public:
|
||||
MarkAsSwitchCase(uint32_t src_addr,uint32_t dst_addr,int lab) :
|
||||
Command("Mark as switch case",eFunction),
|
||||
m_src_addr(src_addr),
|
||||
m_dst_addr(dst_addr),
|
||||
m_case_label(lab)
|
||||
{}
|
||||
|
||||
// Command interface
|
||||
public:
|
||||
QString instanceDescription() const override;
|
||||
bool execute(CommandContext *ctx) override;
|
||||
|
||||
};
|
||||
#endif // FOLLOWCONTROLFLOW_H
|
||||
|
||||
132
src/parser.cpp
132
src/parser.cpp
@ -32,7 +32,8 @@ using namespace std;
|
||||
//static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
|
||||
static void setBits(int16_t type, uint32_t start, uint32_t len);
|
||||
static void process_MOV(LLInst &ll, STATE * pstate);
|
||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph);
|
||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||
//void interactDis(Function * initProc, int ic);
|
||||
|
||||
/* Returns the size of the string pointed by sym and delimited by delim.
|
||||
@ -277,13 +278,13 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
/* Next icode. Note: not the same as GetLastIcode() because of the call to FollowCtrl() */
|
||||
pIcode = func.Icode.GetIcode(ip);
|
||||
/* do the jump path */
|
||||
done = func.process_JMP (*pIcode, pstate, pcallGraph);
|
||||
done = process_JMP(func.shared_from_this(),*pIcode, pstate, pcallGraph);
|
||||
break;
|
||||
}
|
||||
/*** Jumps ***/
|
||||
case iJMP:
|
||||
case iJMPF: /* Returns true if we've run into a loop */
|
||||
done = func.process_JMP (*pIcode, pstate, pcallGraph);
|
||||
done = process_JMP (func.shared_from_this(),*pIcode, pstate, pcallGraph);
|
||||
break;
|
||||
|
||||
/*** Calls ***/
|
||||
@ -401,7 +402,7 @@ bool Function::followAllTableEntries(JumpTable &table, uint32_t cs, ICODE& pIcod
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
// mov cx,NUM_CASES
|
||||
@ -418,9 +419,9 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
|
||||
// jmp word ptr [bx+2*NUM_CASES]
|
||||
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
|
||||
|
||||
if(Icode.size()<8)
|
||||
if(func->Icode.size()<8)
|
||||
return false;
|
||||
if(&Icode.back()!=&pIcode) // not the last insn in the list skip it
|
||||
if(&func->Icode.back()!=&pIcode) // not the last insn in the list skip it
|
||||
return false;
|
||||
if(pIcode.ll()->src().regi != INDEX_BX) {
|
||||
return false;
|
||||
@ -428,7 +429,7 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
|
||||
// find address-wise predecessors of the icode
|
||||
std::deque<ICODE *> matched;
|
||||
QMap<uint32_t,ICODE *> addrmap;
|
||||
for(ICODE & ic : Icode) {
|
||||
for(ICODE & ic : func->Icode) {
|
||||
addrmap[ic.ll()->GetLlLabel()] = ⁣
|
||||
}
|
||||
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
|
||||
@ -478,16 +479,12 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
|
||||
STATE StCopy = *pstate;
|
||||
uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
|
||||
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy));
|
||||
++last_current_insn;
|
||||
last_current_insn->ll()->caseEntry = i;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
// mov cx,NUM_CASES
|
||||
@ -508,9 +505,9 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
|
||||
// jmp word ptr [bx+2*NUM_CASES]
|
||||
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
|
||||
|
||||
if(Icode.size()<12)
|
||||
if(func->Icode.size()<12)
|
||||
return false;
|
||||
if(&Icode.back() != &pIcode) // not the last insn in the list skip it
|
||||
if(&func->Icode.back() != &pIcode) // not the last insn in the list skip it
|
||||
return false;
|
||||
if(pIcode.ll()->src().regi != INDEX_BX) {
|
||||
return false;
|
||||
@ -518,7 +515,7 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
|
||||
// find address-wise predecessors of the icode
|
||||
std::deque<ICODE *> matched;
|
||||
QMap<uint32_t,ICODE *> addrmap;
|
||||
for(ICODE & ic : Icode) {
|
||||
for(ICODE & ic : func->Icode) {
|
||||
addrmap[ic.ll()->GetLlLabel()] = ⁣
|
||||
}
|
||||
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
|
||||
@ -564,41 +561,19 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
|
||||
STATE StCopy = *pstate;
|
||||
uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
|
||||
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy));
|
||||
++last_current_insn;
|
||||
last_current_insn->ll()->caseEntry = i;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
/* Look for switch() stmt. idiom of the form
|
||||
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
|
||||
static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *pstate) {
|
||||
const static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
|
||||
|
||||
uint32_t seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
|
||||
PROG &prog(Project::get()->prog);
|
||||
static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
|
||||
ICODE _Icode;
|
||||
uint32_t cs, offTable, endTable;
|
||||
uint32_t i, k, seg, target;
|
||||
|
||||
if (pIcode.ll()->testFlags(I))
|
||||
{
|
||||
if (pIcode.ll()->getOpcode() == iJMPF)
|
||||
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
|
||||
pstate->IP = pIcode.ll()->src().getImm2();
|
||||
int64_t i = pIcode.ll()->src().getImm2();
|
||||
if (i < 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Return true if jump target is already parsed */
|
||||
return Icode.alreadyDecoded(i);
|
||||
}
|
||||
/* We've got an indirect JMP - look for switch() stmt. idiom of the form
|
||||
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
|
||||
seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
|
||||
|
||||
/* Ensure we have a uint16_t offset & valid seg */
|
||||
if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and
|
||||
@ -608,8 +583,9 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
|
||||
pIcode.ll()->src().regi == INDEX_BX))
|
||||
{
|
||||
|
||||
offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
|
||||
|
||||
uint32_t offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
|
||||
uint32_t endTable;
|
||||
uint32_t i;
|
||||
/* Firstly look for a leading range check of the form:-
|
||||
* CMP {BX | SI | DI}, immed
|
||||
* JA | JAE | JB | JBE
|
||||
@ -630,10 +606,10 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
|
||||
/* Now do some heuristic pruning. Look for ptrs. into the table
|
||||
* and for addresses that don't appear to point to valid code.
|
||||
*/
|
||||
cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
|
||||
uint32_t cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
|
||||
for (i = offTable; i < endTable; i += 2)
|
||||
{
|
||||
target = cs + LH(&prog.image()[i]);
|
||||
uint32_t target = cs + LH(&prog.image()[i]);
|
||||
if (target < endTable and target >= offTable)
|
||||
endTable = target;
|
||||
else if (target >= (uint32_t)prog.cbImage)
|
||||
@ -642,10 +618,10 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
|
||||
|
||||
for (i = offTable; i < endTable; i += 2)
|
||||
{
|
||||
target = cs + LH(&prog.image()[i]);
|
||||
uint32_t target = cs + LH(&prog.image()[i]);
|
||||
/* Be wary of 00 00 as code - it's probably data */
|
||||
if (not (prog.image()[target] or prog.image()[target+1]) or
|
||||
scan(target, _Icode))
|
||||
ICODE _Icode;
|
||||
if (not (prog.image()[target] or prog.image()[target+1]) or scan(target, _Icode)!=NO_ERR)
|
||||
endTable = i;
|
||||
}
|
||||
|
||||
@ -661,39 +637,55 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
|
||||
setBits(BM_DATA, offTable, endTable - offTable);
|
||||
|
||||
pIcode.ll()->setFlags(SWITCH);
|
||||
//pIcode.ll()->caseTbl2.numEntries = (endTable - offTable) / 2;
|
||||
|
||||
uint32_t k;
|
||||
for (i = offTable, k = 0; i < endTable; i += 2)
|
||||
{
|
||||
StCopy = *pstate;
|
||||
StCopy.IP = cs + LH(&prog.image()[i]);
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
//ip = Icode.size();
|
||||
|
||||
Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy));
|
||||
|
||||
++last_current_insn;
|
||||
last_current_insn->ll()->caseEntry = k++;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,k++));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(decodeIndirectJMP(pIcode,pstate,pcallGraph)) {
|
||||
return false;
|
||||
}
|
||||
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
if (pIcode.ll()->testFlags(I))
|
||||
{
|
||||
if (pIcode.ll()->getOpcode() == iJMPF)
|
||||
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
|
||||
pstate->IP = pIcode.ll()->src().getImm2();
|
||||
int64_t i = pIcode.ll()->src().getImm2();
|
||||
if (i < 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Return true if jump target is already parsed */
|
||||
return func->Icode.alreadyDecoded(i);
|
||||
}
|
||||
/* We've got an indirect JMP */
|
||||
if(decodeIndirectJMP0(func,pIcode,pstate)) {
|
||||
return true;
|
||||
}
|
||||
if(decodeIndirectJMP2(pIcode,pstate,pcallGraph)) {
|
||||
if(decodeIndirectJMP(func,pIcode,pstate)) {
|
||||
return true;
|
||||
}
|
||||
if(decodeIndirectJMP2(func,pIcode,pstate)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Can't do anything with this jump */
|
||||
|
||||
flg |= PROC_IJMP;
|
||||
flg &= ~TERMINATES;
|
||||
func->flg |= PROC_IJMP;
|
||||
func->flg &= ~TERMINATES;
|
||||
// TODO: consider adding a new user-interactive command ResolveControlFlowFailure ?
|
||||
interactDis(shared_from_this(), Icode.size()-1);
|
||||
interactDis(func, func->Icode.size()-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user