DBG: very basic function analysis
This commit is contained in:
parent
4429453728
commit
112f70de28
|
@ -0,0 +1,168 @@
|
|||
#include "functionanalysis.h"
|
||||
#include "console.h"
|
||||
#include "memory.h"
|
||||
#include "function.h"
|
||||
|
||||
FunctionAnalysis::FunctionAnalysis(uint base, uint size)
|
||||
{
|
||||
_base = base;
|
||||
_size = size;
|
||||
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
|
||||
MemRead((void*)_base, _data, _size, 0);
|
||||
}
|
||||
|
||||
FunctionAnalysis::~FunctionAnalysis()
|
||||
{
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
const unsigned char* FunctionAnalysis::TranslateAddress(uint addr)
|
||||
{
|
||||
return (addr >= _base && addr < _base + _size) ? _data + (addr - _base) : nullptr;
|
||||
}
|
||||
|
||||
void FunctionAnalysis::Analyse()
|
||||
{
|
||||
dputs("analysis started...");
|
||||
DWORD ticks = GetTickCount();
|
||||
|
||||
PopulateReferences();
|
||||
dprintf("%u called functions populated\n", _functions.size());
|
||||
AnalyseFunctions();
|
||||
|
||||
dprintf("analysis finished in %ums!\n", GetTickCount() - ticks);
|
||||
}
|
||||
|
||||
void FunctionAnalysis::SetMarkers()
|
||||
{
|
||||
FunctionDelRange(_base, _base + _size);
|
||||
for(auto & function : _functions)
|
||||
{
|
||||
if(!function.end)
|
||||
continue;
|
||||
FunctionAdd(function.start, function.end, false);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionAnalysis::SortCleanup()
|
||||
{
|
||||
//sort & remove duplicates
|
||||
std::sort(_functions.begin(), _functions.end());
|
||||
auto last = std::unique(_functions.begin(), _functions.end());
|
||||
_functions.erase(last, _functions.end());
|
||||
}
|
||||
|
||||
void FunctionAnalysis::PopulateReferences()
|
||||
{
|
||||
//linear immediate reference scan (call <addr>, push <addr>, mov [somewhere], <addr>)
|
||||
for(uint i = 0; i < _size;)
|
||||
{
|
||||
uint addr = _base + i;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
uint ref = GetReferenceOperand();
|
||||
if(ref)
|
||||
_functions.push_back({ ref, 0 });
|
||||
i += _cp.Size();
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
SortCleanup();
|
||||
}
|
||||
|
||||
void FunctionAnalysis::AnalyseFunctions()
|
||||
{
|
||||
for(size_t i = 0; i < _functions.size(); i++)
|
||||
{
|
||||
FunctionInfo & function = _functions[i];
|
||||
if(function.end) //skip already-analysed functions
|
||||
continue;
|
||||
uint maxaddr = _base + _size;
|
||||
if(i < _functions.size() - 1)
|
||||
maxaddr = _functions[i + 1].start;
|
||||
|
||||
//dprintf("analysing function %p-??? maxaddr: %p\n", function.start, maxaddr);
|
||||
uint end = FindFunctionEnd(function.start, maxaddr);
|
||||
if(end)
|
||||
function.end = end;
|
||||
}
|
||||
}
|
||||
|
||||
uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
|
||||
{
|
||||
//disassemble first instruction for some heuristics
|
||||
if(_cp.Disassemble(start, TranslateAddress(start), MAX_DISASM_BUFFER))
|
||||
{
|
||||
//JMP [123456] ; import
|
||||
if(_cp.InGroup(CS_GRP_JUMP) && _cp.x86().operands[0].type == X86_OP_MEM)
|
||||
return 0;
|
||||
}
|
||||
//linear search with some trickery
|
||||
uint end = 0;
|
||||
uint jumpback = 0;
|
||||
for(uint addr = start, newaddr = 0; addr < maxaddr;)
|
||||
{
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(addr + _cp.Size() > maxaddr) //we went past the maximum allowed address
|
||||
break;
|
||||
|
||||
//dprintf(" %p: %s %s\n", addr, _cp.GetInstr()->mnemonic, _cp.GetInstr()->op_str);
|
||||
const cs_x86_op & operand = _cp.x86().operands[0];
|
||||
if(_cp.InGroup(CS_GRP_JUMP) && operand.type == X86_OP_IMM) //jump
|
||||
{
|
||||
uint dest = (uint)operand.imm;
|
||||
|
||||
if(dest >= maxaddr) //jump across function boundaries (TODO: something with conditional jumps)
|
||||
{
|
||||
//add destination to function buffer?
|
||||
//end = addr;
|
||||
//break;
|
||||
}
|
||||
else if(dest > addr && dest > newaddr) //save the farthest jump
|
||||
{
|
||||
newaddr = dest;
|
||||
}
|
||||
else if(end && dest < end) //jump back to ret
|
||||
{
|
||||
jumpback = addr;
|
||||
}
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_RET)) //function end
|
||||
{
|
||||
end = addr;
|
||||
if(newaddr >= addr)
|
||||
{
|
||||
addr = newaddr;
|
||||
newaddr = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
addr += _cp.Size();
|
||||
}
|
||||
else
|
||||
addr++;
|
||||
}
|
||||
return end < jumpback ? jumpback : end;
|
||||
}
|
||||
|
||||
uint FunctionAnalysis::GetReferenceOperand()
|
||||
{
|
||||
for(int i = 0; i < _cp.x86().op_count; i++)
|
||||
{
|
||||
const cs_x86_op & operand = _cp.x86().operands[i];
|
||||
if(_cp.InGroup(CS_GRP_JUMP)) //skip jumps
|
||||
continue;
|
||||
if(operand.type == X86_OP_IMM) //we are looking for immediate references
|
||||
{
|
||||
uint dest = (uint)operand.imm;
|
||||
if(dest >= _base && dest < _base + _size)
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef _FUNCTIONANALYSIS_H
|
||||
#define _FUNCTIONANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
|
||||
class FunctionAnalysis
|
||||
{
|
||||
public:
|
||||
explicit FunctionAnalysis(uint base, uint size);
|
||||
FunctionAnalysis(const FunctionAnalysis & that) = delete;
|
||||
~FunctionAnalysis();
|
||||
const unsigned char* TranslateAddress(uint addr);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
uint start;
|
||||
uint end;
|
||||
|
||||
bool operator<(const FunctionInfo & b) const
|
||||
{
|
||||
return start < b.start;
|
||||
}
|
||||
|
||||
bool operator==(const FunctionInfo & b) const
|
||||
{
|
||||
return start == b.start;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
uint _base;
|
||||
uint _size;
|
||||
unsigned char* _data;
|
||||
std::vector<FunctionInfo> _functions;
|
||||
Capstone _cp;
|
||||
|
||||
void SortCleanup();
|
||||
void PopulateReferences();
|
||||
void AnalyseFunctions();
|
||||
uint FindFunctionEnd(uint start, uint maxaddr);
|
||||
uint GetReferenceOperand();
|
||||
};
|
||||
|
||||
#endif //_FUNCTIONANALYSIS_H
|
|
@ -1877,5 +1877,20 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
#include "functionanalysis.h"
|
||||
|
||||
CMDRESULT cbInstrAnalyse(int argc, char* argv[])
|
||||
{
|
||||
SELECTIONDATA sel;
|
||||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
uint size = 0;
|
||||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
FunctionAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
|
@ -67,5 +67,6 @@ CMDRESULT cbInstrYaramod(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrLog(int argc, char* argv[]);
|
||||
|
||||
CMDRESULT cbInstrCapstone(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
|
||||
|
||||
#endif // _INSTRUCTIONS_H
|
||||
|
|
|
@ -201,6 +201,7 @@ static void registercommands()
|
|||
dbgcmdnew("yara", cbInstrYara, true); //yara test command
|
||||
dbgcmdnew("yaramod", cbInstrYaramod, true); //yara rule on module
|
||||
dbgcmdnew("log", cbInstrLog, false); //log command with superawesome hax
|
||||
dbgcmdnew("analyse\1analyze\1anal", cbInstrAnalyse, true); //secret analysis command
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<ClCompile Include="error.cpp" />
|
||||
<ClCompile Include="exception.cpp" />
|
||||
<ClCompile Include="function.cpp" />
|
||||
<ClCompile Include="functionanalysis.cpp" />
|
||||
<ClCompile Include="instruction.cpp" />
|
||||
<ClCompile Include="label.cpp" />
|
||||
<ClCompile Include="loop.cpp" />
|
||||
|
@ -99,6 +100,7 @@
|
|||
<ClInclude Include="error.h" />
|
||||
<ClInclude Include="exception.h" />
|
||||
<ClInclude Include="function.h" />
|
||||
<ClInclude Include="functionanalysis.h" />
|
||||
<ClInclude Include="handle.h" />
|
||||
<ClInclude Include="instruction.h" />
|
||||
<ClInclude Include="jansson\jansson.h" />
|
||||
|
|
|
@ -76,6 +76,12 @@
|
|||
<Filter Include="Header Files\Third Party\capstone">
|
||||
<UniqueIdentifier>{1c3bf89b-90a5-4de7-a96f-e73e4250c274}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Analysis">
|
||||
<UniqueIdentifier>{3aba2399-cfdf-40be-9265-2062f983bbfd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Analysis">
|
||||
<UniqueIdentifier>{a2a92bf5-753d-4a01-be80-66cc61434fbf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
|
@ -210,6 +216,9 @@
|
|||
<ClCompile Include="capstone_wrapper.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="functionanalysis.cpp">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
@ -515,5 +524,8 @@
|
|||
<ClInclude Include="capstone\xcore.h">
|
||||
<Filter>Header Files\Third Party\capstone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="functionanalysis.h">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue