diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dbf102..0f01e99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,8 @@ set(dcc_LIB_SOURCES src/Loaders.h src/FollowControlFlow.cpp src/FollowControlFlow.h + + src/AutomatedPlanner ) set(dcc_UI_SOURCES src/ui/DccMainWindow.ui diff --git a/include/Procedure.h b/include/Procedure.h index ea51735..fe737c0 100644 --- a/include/Procedure.h +++ b/include/Procedure.h @@ -151,7 +151,7 @@ enum DecompilationStep : uint32_t { //eStackTracing, // tracing stack depth across function calls }; -struct Function : public std::enable_shared_from_this +class Function : public std::enable_shared_from_this { typedef llvm::iplist BasicBlockListType; // BasicBlock iterators... @@ -216,6 +216,7 @@ public: // bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;} bool hasRegArgs() const { return (flg & REG_ARGS)!=0;} void markDoNotDecompile() { flg |= PROC_ISLIB; } + bool doNotDecompile() const { return isLibrary(); } bool isLibrary() const { return (flg & PROC_ISLIB)!=0;} void compoundCond(); void writeProcComments(); diff --git a/src/AutomatedPlanner.cpp b/src/AutomatedPlanner.cpp new file mode 100644 index 0000000..c954dd6 --- /dev/null +++ b/src/AutomatedPlanner.cpp @@ -0,0 +1,45 @@ +#include "AutomatedPlanner.h" + +#include "project.h" +#include "FollowControlFlow.h" + +/** + * @class AutomatedPlanner + * @brief Class responsible for building command lists + * + * The goal for top level [Project] plan is to build a fully decompiled representation of source binaries + */ + +AutomatedPlanner::AutomatedPlanner() +{ + +} +/** + * @brief Given a state of a project, add actions that will advance the decompilation + * @param project + */ +void AutomatedPlanner::planFor(Project &project) { + // TODO: For now this logic is sprinkled all over the place, should move it here + // IF NO BINARY IMAGE LOADED - > add SelectImage/SelectProject command + // IF NO LOADER SELECTED -> add SelectLoader command + // ... +} + +void AutomatedPlanner::planFor(Function & func) { + if(func.doNotDecompile()) + return; // for functions marked as non-decompileable we don't add any commands + switch(func.nStep) { + case eNotDecoded: + addAction(func,new FollowControlFlow(func.state)); + } +} + +void AutomatedPlanner::addAction(Function & func, Command * cmd) +{ + Project::get()->addCommand(func.shared_from_this(),cmd); +} + +void AutomatedPlanner::addAction(Project & func, Command * cmd) +{ + func.addCommand(cmd); +} diff --git a/src/AutomatedPlanner.h b/src/AutomatedPlanner.h new file mode 100644 index 0000000..bb907bd --- /dev/null +++ b/src/AutomatedPlanner.h @@ -0,0 +1,20 @@ +#ifndef AUTOMATEDPLANNER_H +#define AUTOMATEDPLANNER_H + +class Project; +class Function; +class Command; + +class AutomatedPlanner +{ +public: + AutomatedPlanner(); + + void planFor(Project & project); + void planFor(Function & func); +protected: + void addAction(Function &func,Command *cmd); + void addAction(Project &func,Command *cmd); +}; + +#endif // AUTOMATEDPLANNER_H diff --git a/src/Command.h b/src/Command.h index 71d6a81..5d552bc 100644 --- a/src/Command.h +++ b/src/Command.h @@ -25,7 +25,7 @@ public: } Project *m_project; - PtrFunction *m_func; + PtrFunction m_func; QVector> m_failures; void reset(); }; diff --git a/src/FollowControlFlow.cpp b/src/FollowControlFlow.cpp index f59f3db..893cb74 100644 --- a/src/FollowControlFlow.cpp +++ b/src/FollowControlFlow.cpp @@ -1,11 +1,16 @@ #include "FollowControlFlow.h" +#include "project.h" + QString FollowControlFlow::instanceDescription() const { - return name() + " @ 0x"+QString::number(m_address,16); + return name() + " @ 0x"+QString::number(m_start_state.IP,16); } bool FollowControlFlow::execute(CommandContext *ctx) { + Project &proj(*ctx->m_project); + PtrFunction scanned_func(ctx->m_func); + scanned_func->FollowCtrl(proj.callGraph, &m_start_state); return false; } diff --git a/src/FollowControlFlow.h b/src/FollowControlFlow.h index 2e7e063..fb34b80 100644 --- a/src/FollowControlFlow.h +++ b/src/FollowControlFlow.h @@ -3,11 +3,13 @@ #include "Command.h" +#include "state.h" + class FollowControlFlow : public Command { - uint32_t m_address; + STATE m_start_state; public: - FollowControlFlow(uint32_t addr) : Command("Follow control flow",eFunction),m_address(addr) {} + FollowControlFlow(STATE addr) : Command("Follow control flow",eFunction),m_start_state(addr) {} // Command interface public: diff --git a/src/parser.cpp b/src/parser.cpp index de3cd66..f197241 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -7,6 +7,7 @@ #include "CallGraph.h" #include "msvc_fixes.h" #include "chklib.h" +#include "FollowControlFlow.h" #include #include @@ -116,6 +117,7 @@ ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode) * using a depth first search. */ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) { + Project *project(Project::get()); PROG &prog(Project::get()->prog); ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */ SYM * psym; @@ -187,8 +189,8 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) pstate->JCond.regi = 0; /* This sets up range check for indexed JMPs hopefully - * Handles JA/JAE for fall through and JB/JBE on branch - */ + * Handles JA/JAE for fall through and JB/JBE on branch + */ if (ip > 0 and prev.ll()->getOpcode() == iCMP and (prev.ll()->testFlags(I))) { pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2(); @@ -201,7 +203,7 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) StCopy = *pstate; /* Straight line code */ - this->FollowCtrl (pcallGraph, &StCopy); // recurrent ? + project->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ? if (fBranch) /* Do branching code */ { @@ -359,7 +361,7 @@ bool Function::followAllTableEntries(JumpTable &table, uint32_t cs, ICODE& pIcod StCopy.IP = cs + LH(&prog.image()[i]); iICODE last_current_insn = (++Icode.rbegin()).base(); - FollowCtrl (pcallGraph, &StCopy); + Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); ++last_current_insn; // incremented here because FollowCtrl might have adde more instructions after the Jmp last_current_insn->ll()->caseEntry = k++; @@ -446,7 +448,7 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca 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(); - FollowCtrl (pcallGraph, &StCopy); + Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); ++last_current_insn; last_current_insn->ll()->caseEntry = i; last_current_insn->ll()->setFlags(CASE); @@ -532,7 +534,7 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc 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(); - FollowCtrl (pcallGraph, &StCopy); + Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); ++last_current_insn; last_current_insn->ll()->caseEntry = i; last_current_insn->ll()->setFlags(CASE); @@ -637,7 +639,8 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra iICODE last_current_insn = (++Icode.rbegin()).base(); //ip = Icode.size(); - FollowCtrl (pcallGraph, &StCopy); + Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); + ++last_current_insn; last_current_insn->ll()->caseEntry = k++; last_current_insn->ll()->setFlags(CASE); @@ -658,6 +661,7 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra flg |= PROC_IJMP; flg &= ~TERMINATES; + // TODO: consider adding a new user-interactive command ResolveControlFlowFailure ? interactDis(shared_from_this(), Icode.size()-1); return true; } @@ -777,7 +781,7 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta pcallGraph->insertCallGraph (this->shared_from_this(), iter); /* Process new procedure */ - x.FollowCtrl (pcallGraph, pstate); + Project::get()->addCommand(iter,new FollowControlFlow(*pstate)); /* Restore segment registers & IP from localState */ pstate->IP = localState.IP; diff --git a/src/ui/CommandQueueView.cpp b/src/ui/CommandQueueView.cpp index 1179e21..00b867e 100644 --- a/src/ui/CommandQueueView.cpp +++ b/src/ui/CommandQueueView.cpp @@ -1,6 +1,7 @@ #include "CommandQueueView.h" #include "project.h" +#include "../AutomatedPlanner.h" #include "ui_CommandQueueView.h" @@ -43,3 +44,10 @@ void CommandQueueView::on_btnStep_clicked() Project &project(*Project::get()); project.processCommands(1); } + +void CommandQueueView::on_btnPlan_clicked() +{ + AutomatedPlanner planner; + // TODO: Use some kind of UI context to retrieve currently selected function + //planner.planFor(func); +} diff --git a/src/ui/CommandQueueView.h b/src/ui/CommandQueueView.h index d66645e..c5c49e1 100644 --- a/src/ui/CommandQueueView.h +++ b/src/ui/CommandQueueView.h @@ -24,6 +24,8 @@ protected: private slots: void on_btnStep_clicked(); + void on_btnPlan_clicked(); + private: Ui::CommandQueueView *ui; }; diff --git a/src/ui/CommandQueueView.ui b/src/ui/CommandQueueView.ui index 6665699..2615da0 100644 --- a/src/ui/CommandQueueView.ui +++ b/src/ui/CommandQueueView.ui @@ -15,16 +15,40 @@ + + + + Planned actions: + + + + + + + Plan + + + - Step + Execute + + + + Completed actions: + + + + + + diff --git a/src/ui/FunctionListDockWidget.ui b/src/ui/FunctionListDockWidget.ui index 702f93b..50efeb7 100644 --- a/src/ui/FunctionListDockWidget.ui +++ b/src/ui/FunctionListDockWidget.ui @@ -11,12 +11,12 @@ - DockWidget + Doc&kWidget - + QAbstractItemView::NoEditTriggers @@ -32,40 +32,7 @@ - - - m_func_list_view - activated(QModelIndex) - FunctionListDockWidget - displayRequest(QModelIndex) - - - 199 - 161 - - - 199 - 149 - - - - - m_func_list_view - clicked(QModelIndex) - FunctionListDockWidget - functionSelected(QModelIndex) - - - 199 - 161 - - - 199 - 149 - - - - + displayRequested() displayRequest(QModelIndex)