1
0
Fork 0

DBG: more fixes in analysis + added ExceptionDirectoryAnalysis class

This commit is contained in:
Mr. eXoDia 2015-07-13 03:51:54 +02:00
parent 4a9ad61280
commit d5c7c6f6a0
12 changed files with 310 additions and 49 deletions

View File

@ -98,6 +98,8 @@ bool FunctionPass::Analyse()
std::sort(funcs.begin(), funcs.end());
funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end());
dprintf("%u functions\n", funcs.size());
FunctionClear();
for(auto & func : funcs)
{
@ -168,6 +170,7 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector<FunctionDef>
void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector<FunctionDef>* Blocks)
{
return;
const uint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart;
const uint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd;

View File

@ -1,28 +1,81 @@
#include "controlflowanalysis.h"
#include "console.h"
#include "module.h"
#include "TitanEngine/TitanEngine.h"
#include "memory.h"
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size)
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size)
{
}
_functionInfoData = nullptr;
#ifdef _WIN64
// This will only be valid if the address range is within a loaded module
_moduleBase = ModBaseFromAddr(base);
void ControlFlowAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
if(exceptionDirectory && _moduleBase != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
BasicBlockStarts();
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
BasicBlocks();
dprintf("Basick blocks in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
Functions();
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
dprintf("Analysis finished!\n");
}
ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
_functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
_functionInfoData = emalloc(_functionInfoSize);
if(_functionInfoData)
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
}
}
}
#endif //_WIN64
}
ControlFlowAnalysis::~ControlFlowAnalysis()
{
if(_functionInfoData)
efree(_functionInfoData);
}
void ControlFlowAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
BasicBlockStarts();
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
BasicBlocks();
dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
Functions();
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
dprintf("Analysis finished!\n");
}
void ControlFlowAnalysis::SetMarkers()
{
@ -83,7 +136,7 @@ void ControlFlowAnalysis::BasicBlockStarts()
_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.GetId() == X86_INS_INT3) //RET/INT3 break control flow
{
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
}
@ -139,7 +192,7 @@ void ControlFlowAnalysis::BasicBlocks()
prevaddr = addr;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(_cp.InGroup(CS_GRP_RET))
if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3)
{
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
break;
@ -166,6 +219,23 @@ void ControlFlowAnalysis::BasicBlocks()
}
}
_blockStarts.clear();
#ifdef _WIN64
int count = 0;
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const uint funcAddr = _moduleBase + Function->BeginAddress;
const uint funcEnd = _moduleBase + Function->EndAddress;
// If within limits...
if(funcAddr >= _base && funcAddr < _base + _size)
_functionStarts.insert(funcAddr);
count++;
return true;
});
dprintf("%u functions from the exception directory...\n", count);
#endif // _WIN64
dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size());
}
@ -309,4 +379,23 @@ uint ControlFlowAnalysis::GetReferenceOperand()
}
}
return 0;
}
}
#ifdef _WIN64
void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
{
if(!_functionInfoData)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#endif // _WIN64

View File

@ -4,11 +4,13 @@
#include "_global.h"
#include "analysis.h"
#include "addrinfo.h"
#include <functional>
class ControlFlowAnalysis : public Analysis
{
public:
explicit ControlFlowAnalysis(uint base, uint size);
explicit ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory);
~ControlFlowAnalysis();
void Analyse() override;
void SetMarkers() override;
@ -47,6 +49,10 @@ private:
typedef std::set<uint> UintSet;
uint _moduleBase;
uint _functionInfoSize;
void* _functionInfoData;
UintSet _blockStarts;
UintSet _functionStarts;
std::map<uint, BasicBlock> _blocks; //start of block -> block
@ -63,6 +69,9 @@ private:
uint findFunctionStart(BasicBlock* block, UintSet* parents);
String blockToString(BasicBlock* block);
uint GetReferenceOperand();
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};
#endif //_CONTROLFLOWANALYSIS_H

View File

@ -0,0 +1,106 @@
#include "exceptiondirectoryanalysis.h"
#include "module.h"
#include "TitanEngine/TitanEngine.h"
#include "memory.h"
#include "console.h"
#include "function.h"
ExceptionDirectoryAnalysis::ExceptionDirectoryAnalysis(uint base, uint size) : Analysis(base, size)
{
_functionInfoData = nullptr;
#ifdef _WIN64
// This will only be valid if the address range is within a loaded module
_moduleBase = ModBaseFromAddr(base);
if(_moduleBase != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
_functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
_functionInfoData = emalloc(_functionInfoSize);
if(_functionInfoData)
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
}
}
}
#endif //_WIN64
}
ExceptionDirectoryAnalysis::~ExceptionDirectoryAnalysis()
{
if(_functionInfoData)
efree(_functionInfoData);
}
void ExceptionDirectoryAnalysis::Analyse()
{
#ifdef _WIN64
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const uint funcAddr = _moduleBase + Function->BeginAddress;
const uint funcEnd = _moduleBase + Function->EndAddress;
// If within limits...
if(funcAddr >= _base && funcAddr < _base + _size)
_functions.push_back({ funcAddr, funcEnd });
return true;
});
dprintf("%u functions discovered!\n", _functions.size());
#else //x32
dprintf("This kind of analysis doesn't work on x32 executables...\n");
#endif // _WIN64
}
void ExceptionDirectoryAnalysis::SetMarkers()
{
FunctionDelRange(_base, _base + _size);
for(const auto & function : _functions)
FunctionAdd(function.first, function.second, false);
}
#ifdef _WIN64
void ExceptionDirectoryAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
{
if(!_functionInfoData)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(uint i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#endif // _WIN64

View File

@ -0,0 +1,26 @@
#ifndef _EXCEPTIONDIRECTORYANALYSIS_H
#define _EXCEPTIONDIRECTORYANALYSIS_H
#include "analysis.h"
#include <functional>
class ExceptionDirectoryAnalysis : public Analysis
{
public:
explicit ExceptionDirectoryAnalysis(uint base, uint size);
~ExceptionDirectoryAnalysis();
void Analyse() override;
void SetMarkers() override;
private:
uint _moduleBase;
uint _functionInfoSize;
void* _functionInfoData;
std::vector<std::pair<uint, uint>> _functions;
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};
#endif //_EXCEPTIONDIRECTORYANALYSIS_H

View File

@ -26,9 +26,10 @@
#include "module.h"
#include "stringformat.h"
#include "filereader.h"
#include "functionanalysis.h"
#include "linearanalysis.h"
#include "controlflowanalysis.h"
#include "analysis_nukem.h"
#include "exceptiondirectoryanalysis.h"
static bool bRefinit = false;
@ -1865,6 +1866,7 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
const cs_x86 & x86 = cp.x86();
int argcount = x86.op_count;
dprintf("%s %s\n", instr->mnemonic, instr->op_str);
dprintf("%d, NOP=%d\n", cp.GetId(), X86_INS_NOP);
for(int i = 0; i < argcount; i++)
{
const cs_x86_op & op = x86.operands[i];
@ -1915,7 +1917,7 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
uint size = 0;
uint base = MemFindBaseAddr(sel.start, &size);
FunctionAnalysis anal(base, size);
LinearAnalysis anal(base, size);
anal.Analyse();
anal.SetMarkers();
GuiUpdateAllViews();
@ -1924,17 +1926,33 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
{
bool exceptionDirectory = false;
if(argc > 1)
exceptionDirectory = true;
SELECTIONDATA sel;
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
uint size = 0;
uint base = MemFindBaseAddr(sel.start, &size);
ControlFlowAnalysis anal(base, size);
ControlFlowAnalysis anal(base, size, exceptionDirectory);
anal.Analyse();
//anal.SetMarkers();
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbInstrExanalyse(int argc, char* argv[])
{
SELECTIONDATA sel;
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
uint size = 0;
uint base = MemFindBaseAddr(sel.start, &size);
ExceptionDirectoryAnalysis anal(base, size);
anal.Analyse();
anal.SetMarkers();
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbInstrVisualize(int argc, char* argv[])
{
if(argc < 3)

View File

@ -72,5 +72,6 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
CMDRESULT cbInstrVisualize(int argc, char* argv[]);
CMDRESULT cbInstrMeminfo(int argc, char* argv[]);
CMDRESULT cbInstrCfanalyse(int argc, char* argv[]);
CMDRESULT cbInstrExanalyse(int argc, char* argv[]);
#endif // _INSTRUCTIONS_H

View File

@ -1,13 +1,13 @@
#include "functionanalysis.h"
#include "linearanalysis.h"
#include "console.h"
#include "memory.h"
#include "function.h"
FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size)
LinearAnalysis::LinearAnalysis(uint base, uint size) : Analysis(base, size)
{
}
void FunctionAnalysis::Analyse()
void LinearAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
@ -19,7 +19,7 @@ void FunctionAnalysis::Analyse()
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
}
void FunctionAnalysis::SetMarkers()
void LinearAnalysis::SetMarkers()
{
FunctionDelRange(_base, _base + _size);
for(auto & function : _functions)
@ -30,7 +30,7 @@ void FunctionAnalysis::SetMarkers()
}
}
void FunctionAnalysis::SortCleanup()
void LinearAnalysis::SortCleanup()
{
//sort & remove duplicates
std::sort(_functions.begin(), _functions.end());
@ -38,7 +38,7 @@ void FunctionAnalysis::SortCleanup()
_functions.erase(last, _functions.end());
}
void FunctionAnalysis::PopulateReferences()
void LinearAnalysis::PopulateReferences()
{
//linear immediate reference scan (call <addr>, push <addr>, mov [somewhere], <addr>)
for(uint i = 0; i < _size;)
@ -57,7 +57,7 @@ void FunctionAnalysis::PopulateReferences()
SortCleanup();
}
void FunctionAnalysis::AnalyseFunctions()
void LinearAnalysis::AnalyseFunctions()
{
for(size_t i = 0; i < _functions.size(); i++)
{
@ -79,7 +79,7 @@ void FunctionAnalysis::AnalyseFunctions()
}
}
uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
uint LinearAnalysis::FindFunctionEnd(uint start, uint maxaddr)
{
//disassemble first instruction for some heuristics
if(_cp.Disassemble(start, TranslateAddress(start), MAX_DISASM_BUFFER))
@ -132,7 +132,7 @@ uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
return end < jumpback ? jumpback : end;
}
uint FunctionAnalysis::GetReferenceOperand()
uint LinearAnalysis::GetReferenceOperand()
{
for(int i = 0; i < _cp.x86().op_count; i++)
{

View File

@ -1,13 +1,13 @@
#ifndef _FUNCTIONANALYSIS_H
#define _FUNCTIONANALYSIS_H
#ifndef _LINEARANALYSIS_H
#define _LINEARANALYSIS_H
#include "_global.h"
#include "analysis.h"
class FunctionAnalysis : public Analysis
class LinearAnalysis : public Analysis
{
public:
explicit FunctionAnalysis(uint base, uint size);
explicit LinearAnalysis(uint base, uint size);
void Analyse() override;
void SetMarkers() override;
@ -37,4 +37,4 @@ private:
uint GetReferenceOperand();
};
#endif //_FUNCTIONANALYSIS_H
#endif //_LINEARANALYSIS_H

View File

@ -189,7 +189,6 @@ static void registercommands()
dbgcmdnew("yara", cbInstrYara, true); //yara test command
dbgcmdnew("yaramod", cbInstrYaramod, true); //yara rule on module
dbgcmdnew("analyse\1analyze\1anal", cbInstrAnalyse, true); //secret analysis command
dbgcmdnew("analyse_nukem\1analyze_nukem\1anal_nukem", cbInstrAnalyseNukem, true); //secret analysis command #2
//undocumented
dbgcmdnew("bench", cbDebugBenchmark, true); //benchmark test (readmem etc)
@ -202,6 +201,8 @@ static void registercommands()
dbgcmdnew("visualize", cbInstrVisualize, true); //visualize analysis
dbgcmdnew("meminfo", cbInstrMeminfo, true); //command to debug memory map bugs
dbgcmdnew("cfanal\1cfanalyse\1cfanalyze", cbInstrCfanalyse, true); //control flow analysis
dbgcmdnew("analyse_nukem\1analyze_nukem\1anal_nukem", cbInstrAnalyseNukem, true); //secret analysis command #2
dbgcmdnew("exanal\1exanalyse\1exanalyze", cbInstrExanalyse, true); //exception directory analysis
}
static bool cbCommandProvider(char* cmd, int maxlen)

View File

@ -40,10 +40,11 @@
<ClCompile Include="disasm_helper.cpp" />
<ClCompile Include="error.cpp" />
<ClCompile Include="exception.cpp" />
<ClCompile Include="exceptiondirectoryanalysis.cpp" />
<ClCompile Include="expressionparser.cpp" />
<ClCompile Include="filereader.cpp" />
<ClCompile Include="function.cpp" />
<ClCompile Include="functionanalysis.cpp" />
<ClCompile Include="linearanalysis.cpp" />
<ClCompile Include="FunctionPass.cpp" />
<ClCompile Include="instruction.cpp" />
<ClCompile Include="Int3CoagulatorPass.cpp" />
@ -119,10 +120,11 @@
<ClInclude Include="dynamicmem.h" />
<ClInclude Include="error.h" />
<ClInclude Include="exception.h" />
<ClInclude Include="exceptiondirectoryanalysis.h" />
<ClInclude Include="expressionparser.h" />
<ClInclude Include="filereader.h" />
<ClInclude Include="function.h" />
<ClInclude Include="functionanalysis.h" />
<ClInclude Include="linearanalysis.h" />
<ClInclude Include="FunctionPass.h" />
<ClInclude Include="handle.h" />
<ClInclude Include="instruction.h" />

View File

@ -216,9 +216,6 @@
<ClCompile Include="capstone_wrapper.cpp">
<Filter>Source Files\Utilities</Filter>
</ClCompile>
<ClCompile Include="functionanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="filereader.cpp">
<Filter>Source Files\Utilities</Filter>
</ClCompile>
@ -276,6 +273,12 @@
<ClCompile Include="controlflowanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="exceptiondirectoryanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="linearanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64_dbg.h">
@ -566,9 +569,6 @@
<ClInclude Include="capstone\xcore.h">
<Filter>Header Files\Third Party\capstone</Filter>
</ClInclude>
<ClInclude Include="functionanalysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="filereader.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
@ -632,5 +632,11 @@
<ClInclude Include="_scriptapi_misc.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
</ClInclude>
<ClInclude Include="exceptiondirectoryanalysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="linearanalysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
</ItemGroup>
</Project>