Add AutomatedPlanner skeleton class

This commit is contained in:
nemerle 2016-05-04 14:22:28 +02:00
parent 29353111ac
commit c8fd3a01df
12 changed files with 130 additions and 50 deletions

View File

@ -97,6 +97,8 @@ set(dcc_LIB_SOURCES
src/Loaders.h src/Loaders.h
src/FollowControlFlow.cpp src/FollowControlFlow.cpp
src/FollowControlFlow.h src/FollowControlFlow.h
src/AutomatedPlanner
) )
set(dcc_UI_SOURCES set(dcc_UI_SOURCES
src/ui/DccMainWindow.ui src/ui/DccMainWindow.ui

View File

@ -151,7 +151,7 @@ enum DecompilationStep : uint32_t {
//eStackTracing, // tracing stack depth across function calls //eStackTracing, // tracing stack depth across function calls
}; };
struct Function : public std::enable_shared_from_this<Function> class Function : public std::enable_shared_from_this<Function>
{ {
typedef llvm::iplist<BB> BasicBlockListType; typedef llvm::iplist<BB> BasicBlockListType;
// BasicBlock iterators... // BasicBlock iterators...
@ -216,6 +216,7 @@ public:
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;} // bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;} bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
void markDoNotDecompile() { flg |= PROC_ISLIB; } void markDoNotDecompile() { flg |= PROC_ISLIB; }
bool doNotDecompile() const { return isLibrary(); }
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;} bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
void compoundCond(); void compoundCond();
void writeProcComments(); void writeProcComments();

45
src/AutomatedPlanner.cpp Normal file
View File

@ -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);
}

20
src/AutomatedPlanner.h Normal file
View File

@ -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

View File

@ -25,7 +25,7 @@ public:
} }
Project *m_project; Project *m_project;
PtrFunction *m_func; PtrFunction m_func;
QVector<QPair<Command *,QString>> m_failures; QVector<QPair<Command *,QString>> m_failures;
void reset(); void reset();
}; };

View File

@ -1,11 +1,16 @@
#include "FollowControlFlow.h" #include "FollowControlFlow.h"
#include "project.h"
QString FollowControlFlow::instanceDescription() const 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) 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; return false;
} }

View File

@ -3,11 +3,13 @@
#include "Command.h" #include "Command.h"
#include "state.h"
class FollowControlFlow : public Command class FollowControlFlow : public Command
{ {
uint32_t m_address; STATE m_start_state;
public: 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 // Command interface
public: public:

View File

@ -7,6 +7,7 @@
#include "CallGraph.h" #include "CallGraph.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "chklib.h" #include "chklib.h"
#include "FollowControlFlow.h"
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
@ -116,6 +117,7 @@ ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
* using a depth first search. */ * using a depth first search. */
void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
{ {
Project *project(Project::get());
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */ ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
SYM * psym; SYM * psym;
@ -187,8 +189,8 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
pstate->JCond.regi = 0; pstate->JCond.regi = 0;
/* This sets up range check for indexed JMPs hopefully /* 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))) if (ip > 0 and prev.ll()->getOpcode() == iCMP and (prev.ll()->testFlags(I)))
{ {
pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2(); pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2();
@ -201,7 +203,7 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
StCopy = *pstate; StCopy = *pstate;
/* Straight line code */ /* Straight line code */
this->FollowCtrl (pcallGraph, &StCopy); // recurrent ? project->addCommand(shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ?
if (fBranch) /* Do branching code */ 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]); StCopy.IP = cs + LH(&prog.image()[i]);
iICODE last_current_insn = (++Icode.rbegin()).base(); 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; // incremented here because FollowCtrl might have adde more instructions after the Jmp
last_current_insn->ll()->caseEntry = k++; 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; uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
iICODE last_current_insn = (++Icode.rbegin()).base(); 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;
last_current_insn->ll()->caseEntry = i; last_current_insn->ll()->caseEntry = i;
last_current_insn->ll()->setFlags(CASE); 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; uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
iICODE last_current_insn = (++Icode.rbegin()).base(); 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;
last_current_insn->ll()->caseEntry = i; last_current_insn->ll()->caseEntry = i;
last_current_insn->ll()->setFlags(CASE); 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(); iICODE last_current_insn = (++Icode.rbegin()).base();
//ip = Icode.size(); //ip = Icode.size();
FollowCtrl (pcallGraph, &StCopy); Project::get()->addCommand(shared_from_this(),new FollowControlFlow(StCopy));
++last_current_insn; ++last_current_insn;
last_current_insn->ll()->caseEntry = k++; last_current_insn->ll()->caseEntry = k++;
last_current_insn->ll()->setFlags(CASE); 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 |= PROC_IJMP;
flg &= ~TERMINATES; flg &= ~TERMINATES;
// TODO: consider adding a new user-interactive command ResolveControlFlowFailure ?
interactDis(shared_from_this(), Icode.size()-1); interactDis(shared_from_this(), Icode.size()-1);
return true; return true;
} }
@ -777,7 +781,7 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
pcallGraph->insertCallGraph (this->shared_from_this(), iter); pcallGraph->insertCallGraph (this->shared_from_this(), iter);
/* Process new procedure */ /* Process new procedure */
x.FollowCtrl (pcallGraph, pstate); Project::get()->addCommand(iter,new FollowControlFlow(*pstate));
/* Restore segment registers & IP from localState */ /* Restore segment registers & IP from localState */
pstate->IP = localState.IP; pstate->IP = localState.IP;

View File

@ -1,6 +1,7 @@
#include "CommandQueueView.h" #include "CommandQueueView.h"
#include "project.h" #include "project.h"
#include "../AutomatedPlanner.h"
#include "ui_CommandQueueView.h" #include "ui_CommandQueueView.h"
@ -43,3 +44,10 @@ void CommandQueueView::on_btnStep_clicked()
Project &project(*Project::get()); Project &project(*Project::get());
project.processCommands(1); 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);
}

View File

@ -24,6 +24,8 @@ protected:
private slots: private slots:
void on_btnStep_clicked(); void on_btnStep_clicked();
void on_btnPlan_clicked();
private: private:
Ui::CommandQueueView *ui; Ui::CommandQueueView *ui;
}; };

View File

@ -15,16 +15,40 @@
</property> </property>
<widget class="QWidget" name="dockWidgetContents"> <widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Planned actions:</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QListWidget" name="lstQueuedCommands"/> <widget class="QListWidget" name="lstQueuedCommands"/>
</item> </item>
<item>
<widget class="QPushButton" name="btnPlan">
<property name="text">
<string>Plan</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="btnStep"> <widget class="QPushButton" name="btnStep">
<property name="text"> <property name="text">
<string>Step</string> <string>Execute</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Completed actions:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="lstCompletedCommands"/>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>

View File

@ -11,12 +11,12 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>DockWidget</string> <string>Doc&amp;kWidget</string>
</property> </property>
<widget class="QWidget" name="dockWidgetContents"> <widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QTableView" name="m_func_list_view"> <widget class="QTreeView" name="m_func_list_view">
<property name="editTriggers"> <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set> <set>QAbstractItemView::NoEditTriggers</set>
</property> </property>
@ -32,40 +32,7 @@
</widget> </widget>
</widget> </widget>
<resources/> <resources/>
<connections> <connections/>
<connection>
<sender>m_func_list_view</sender>
<signal>activated(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>displayRequest(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>161</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>149</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_func_list_view</sender>
<signal>clicked(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>functionSelected(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>161</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>149</y>
</hint>
</hints>
</connection>
</connections>
<slots> <slots>
<signal>displayRequested()</signal> <signal>displayRequested()</signal>
<slot>displayRequest(QModelIndex)</slot> <slot>displayRequest(QModelIndex)</slot>