diff --git a/x64_dbg_dbg/analysis.h b/x64_dbg_dbg/analysis.h index d5bf6cd4..8e8535c3 100644 --- a/x64_dbg_dbg/analysis.h +++ b/x64_dbg_dbg/analysis.h @@ -9,7 +9,7 @@ class Analysis public: explicit Analysis(uint base, uint size); Analysis(const Analysis & that) = delete; - ~Analysis(); + virtual ~Analysis(); virtual void Analyse() = 0; virtual void SetMarkers() = 0; diff --git a/x64_dbg_dbg/controlflowanalysis.cpp b/x64_dbg_dbg/controlflowanalysis.cpp index b64aa59f..c7dbcf4b 100644 --- a/x64_dbg_dbg/controlflowanalysis.cpp +++ b/x64_dbg_dbg/controlflowanalysis.cpp @@ -11,9 +11,17 @@ void ControlFlowAnalysis::Analyse() DWORD ticks = GetTickCount(); BasicBlockStarts(); - BasicBlocks(); + dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks); + ticks = GetTickCount(); - dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); + BasicBlocks(); + dprintf("Basick blocks in %ums!\n", GetTickCount() - ticks); + ticks = GetTickCount(); + + Functions(); + dprintf("Functions in %ums!\n", GetTickCount() - ticks); + + dprintf("Analysis finished!\n"); } void ControlFlowAnalysis::SetMarkers() @@ -21,14 +29,16 @@ void ControlFlowAnalysis::SetMarkers() dprintf("digraph ControlFlow {\n"); int i = 0; std::map nodeMap; - for(auto block : _blocks) + for(const auto & it : _blocks) { + const auto & block = it.second; nodeMap.insert({ block.start, i }); - dprintf(" node%u [label=\"start=%p, end=%p\"];\n", i, block.start, block.end); + dprintf(" node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function); i++; } - for(auto block : _blocks) + for(auto it : _blocks) { + const auto & block = it.second; int startNode = nodeMap[block.start]; if(block.left) { @@ -65,26 +75,26 @@ void ControlFlowAnalysis::BasicBlockStarts() uint addr = _base + i; if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) { - if(bSkipFilling) //handle filling skip mode + if(bSkipFilling) //handle filling skip mode { - if(!_cp.IsFilling()) //do nothing until the filling stopped + if(!_cp.IsFilling()) //do nothing until the filling stopped { bSkipFilling = false; _blockStarts.insert(addr); } } - else if(_cp.InGroup(CS_GRP_RET) || _cp.InGroup(CS_GRP_INT)) //RET/INT break control flow + else if(_cp.InGroup(CS_GRP_RET) || _cp.InGroup(CS_GRP_INT)) //RET/INT break control flow { bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow) } - else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches + else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches { uint dest1 = GetBranchOperand(); uint dest2 = 0; - if(_cp.GetId() != X86_INS_JMP) //unconditional jump + if(_cp.GetId() != X86_INS_JMP) //unconditional jump dest2 = addr + _cp.Size(); - if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted) + if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted) bSkipFilling = true; if(dest1) _blockStarts.insert(dest1); @@ -128,29 +138,153 @@ void ControlFlowAnalysis::BasicBlocks() { if(_cp.InGroup(CS_GRP_RET)) { - _blocks.push_back(BasicBlock(start, addr, 0, 0)); //leaf block + insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block break; } else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) { uint dest1 = GetBranchOperand(); uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0; - _blocks.push_back(BasicBlock(start, addr, dest1, dest2)); + insertBlock(BasicBlock(start, addr, dest1, dest2)); + insertParent(dest1, start); + insertParent(dest2, start); break; } addr += _cp.Size(); } else addr++; - if(addr == nextStart) //special case handling overlapping blocks + if(addr == nextStart) //special case handling overlapping blocks { - _blocks.push_back(BasicBlock(start, prevaddr, 0, nextStart)); + insertBlock(BasicBlock(start, prevaddr, 0, nextStart)); + insertParent(nextStart, start); break; } } } } +void ControlFlowAnalysis::Functions() +{ + typedef std::pair DelayedBlock; + std::vector delayedBlocks; + for(auto & it : _blocks) + { + BasicBlock* block = &it.second; + UintSet* parents = findParents(block->start); + if(!block->function) + { + if(!parents) //no parents = function start + { + uint functionStart = block->start; + block->function = functionStart; + UintSet functionBlocks; + functionBlocks.insert(functionStart); + _functions[functionStart] = functionBlocks; + } + else //in function + { + uint function = findFunctionStart(block, parents); + if(!function) //this happens with loops sometimes + delayedBlocks.push_back(DelayedBlock(block, parents)); + else + block->function = function; + } + } + else + DebugBreak(); //this should not happen + } + dprintf("%u/%u delayed blocks...\n", delayedBlocks.size(), _blocks.size()); + for(auto & delayedBlock : delayedBlocks) + { + BasicBlock* block = delayedBlock.first; + UintSet* parents = delayedBlock.second; + uint function = findFunctionStart(block, parents); + if(!function) + { + dprintf("unresolved block %s\n", blockToString(block).c_str()); + if(parents) + { + dprintf("parents:\n"); + for(auto parent : *parents) + dprintf(" %s\n", blockToString(findBlock(parent)).c_str()); + } + else + dprintf("parents: null"); + dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str()); + dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str()); + return; + } + block->function = function; + } +} + +void ControlFlowAnalysis::insertBlock(BasicBlock block) +{ + if(_blocks.find(block.start) != _blocks.end()) + DebugBreak(); + _blocks[block.start] = block; +} + +ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(uint start) +{ + if(!start) + return nullptr; + auto found = _blocks.find(start); + return found != _blocks.end() ? &found->second : nullptr; +} + +void ControlFlowAnalysis::insertParent(uint child, uint parent) +{ + if(!child || !parent) + return; + auto found = _parentMap.find(child); + if(found == _parentMap.end()) + { + UintSet parents; + parents.insert(parent); + _parentMap[child] = parents; + } + else + found->second.insert(parent); +} + +ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(uint child) +{ + if(!child) + return nullptr; + auto found = _parentMap.find(child); + return found != _parentMap.end() ? &found->second : nullptr; +} + +uint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents) +{ + if(!block) + return 0; + if(block->function) + return block->function; + BasicBlock* left = findBlock(block->left); + if(left && left->function) + return left->function; + BasicBlock* right = findBlock(block->right); + if(right && right->function) + return right->function; + for(auto start : *parents) + { + BasicBlock* parent = findBlock(start); + if(parent->function) + return parent->function; + } + return 0; +} + +String ControlFlowAnalysis::blockToString(BasicBlock* block) +{ + if(!block) + return String("null"); + return block->toString(); +} + uint ControlFlowAnalysis::GetBranchOperand() { for(int i = 0; i < _cp.x86().op_count; i++) diff --git a/x64_dbg_dbg/controlflowanalysis.h b/x64_dbg_dbg/controlflowanalysis.h index 5d4545d8..15a6cb11 100644 --- a/x64_dbg_dbg/controlflowanalysis.h +++ b/x64_dbg_dbg/controlflowanalysis.h @@ -2,15 +2,15 @@ #define _CONTROLFLOWANALYSIS_H #include "_global.h" -#include "capstone_wrapper.h" #include "analysis.h" +#include "addrinfo.h" class ControlFlowAnalysis : public Analysis { public: explicit ControlFlowAnalysis(uint base, uint size); - void Analyse(); - void SetMarkers(); + void Analyse() override; + void SetMarkers() override; private: struct BasicBlock @@ -19,6 +19,7 @@ private: uint end; uint left; uint right; + uint function; BasicBlock() { @@ -26,6 +27,7 @@ private: this->end = 0; this->left = 0; this->right = 0; + this->function = 0; } BasicBlock(uint start, uint end, uint left, uint right) @@ -34,14 +36,31 @@ private: this->end = end; this->left = min(left, right); this->right = max(left, right); + this->function = 0; + } + + String toString() + { + return StringUtils::sprintf("start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function); } }; - std::set _blockStarts; - std::vector _blocks; + typedef std::set UintSet; + + UintSet _blockStarts; + std::map _blocks; //start of block -> block + std::map _parentMap; //start child -> parents + std::map _functions; //function start -> function block starts void BasicBlockStarts(); void BasicBlocks(); + void Functions(); + void insertBlock(BasicBlock block); + BasicBlock* findBlock(uint start); + void insertParent(uint child, uint parent); + UintSet* findParents(uint child); + uint findFunctionStart(BasicBlock* block, UintSet* parents); + String blockToString(BasicBlock* block); uint GetBranchOperand(); }; diff --git a/x64_dbg_dbg/functionanalysis.h b/x64_dbg_dbg/functionanalysis.h index 96a22460..42bf126b 100644 --- a/x64_dbg_dbg/functionanalysis.h +++ b/x64_dbg_dbg/functionanalysis.h @@ -2,15 +2,14 @@ #define _FUNCTIONANALYSIS_H #include "_global.h" -#include "capstone_wrapper.h" #include "analysis.h" class FunctionAnalysis : public Analysis { public: explicit FunctionAnalysis(uint base, uint size); - void Analyse(); - void SetMarkers(); + void Analyse() override; + void SetMarkers() override; private: struct FunctionInfo diff --git a/x64_dbg_dbg/instruction.cpp b/x64_dbg_dbg/instruction.cpp index effbacea..0ff9870a 100644 --- a/x64_dbg_dbg/instruction.cpp +++ b/x64_dbg_dbg/instruction.cpp @@ -1930,7 +1930,7 @@ CMDRESULT cbInstrCfanalyse(int argc, char* argv[]) uint base = MemFindBaseAddr(sel.start, &size); ControlFlowAnalysis anal(base, size); anal.Analyse(); - anal.SetMarkers(); + //anal.SetMarkers(); GuiUpdateAllViews(); return STATUS_CONTINUE; }