1
0
Fork 0

DBG: very basic function analysis

This commit is contained in:
Mr. eXoDia 2015-04-19 04:51:33 +02:00
parent 4429453728
commit 112f70de28
7 changed files with 246 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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