5 Commits
Author SHA1 Message Date
tr4ceflow 6c138af356 speedup the analysis process due autocomments
The new version cef97919f87d999c4b5c14be0f61edc5000639f5 of x64_dbg provides DbgSetAutoComments as in Issue #2.
2014-07-02 20:32:20 +02:00
tr4ceflow 84f82f725a Merge branch 'master' of https://github.com/tr4ceflow/x64dbg-StaticAnalysis 2014-07-02 20:21:53 +02:00
tr4ceflow f64cfaa7ca fix module name and label name convention
the new version of x64dbg uses '&' as a prefix in front of label names. This version fixes this issue by removing the first character iff it is '&'
2014-07-02 20:21:07 +02:00
tr4ceflow b38053609d Update README.md 2014-06-22 16:39:28 +02:00
tr4ceflow c840e9fcd2 Update README.md 2014-06-19 20:42:11 +02:00
14 changed files with 62 additions and 266 deletions

No files matched your search

+8 -48
View File
@@ -35,32 +35,14 @@ void AnalysisRunner::start(){
_plugin_logputs("[StaticAnalysis] analysis finished ...");
}
unsigned int AnalysisRunner::getInstruction(const duint bytesOffset,DISASM* disasm ){
memset(&disasm, 0, sizeof(disasm));
if(currentEIP + bytesOffset > mSize)
return UNKNOWN_OPCODE;
duint baseaddr = mBaseAddress;
duint size = mSize;
#ifdef _WIN64
disasm.Archi=64;
#endif // _WIN64
disasm->EIP=currentEIP + bytesOffset;
disasm->VirtualAddr=currentVirtualAddr + bytesOffset;
return (int) Disasm(disasm);
const duint AnalysisRunner::baseAddress() const{
return mBaseAddress;
}
void AnalysisRunner::run()
{
EIPdata = new unsigned char[mSize];
if(!DbgMemRead(mBaseAddress, EIPdata, mSize))
unsigned char* data = new unsigned char[mSize];
if(!DbgMemRead(mBaseAddress, data, mSize))
{
//ERROR
_plugin_logputs("[StaticAnalysis] could not read memory ...");
@@ -77,30 +59,24 @@ void AnalysisRunner::run()
#ifdef _WIN64
disasm.Archi=64;
#endif // _WIN64
currentEIP = (UIntPtr)EIPdata;
disasm.EIP=currentEIP;
currentVirtualAddr = (UInt64)baseaddr;
disasm.VirtualAddr=currentVirtualAddr;
disasm.EIP=(UIntPtr)data;
disasm.VirtualAddr=(UInt64)baseaddr;
duint i=0;
while(i<size)
{
int len=Disasm(&disasm);
if(len!=UNKNOWN_OPCODE)
{
emulateStack(&disasm);
see(&disasm);
}
else{
unknownOpCode(&disasm);
len=1;
}
currentEIP += len;
currentVirtualAddr += len;
disasm.EIP=currentEIP;
disasm.VirtualAddr=currentVirtualAddr;
disasm.EIP+=len;
disasm.VirtualAddr+=len;
i+=len;
}
delete EIPdata;
}
void AnalysisRunner::clear( )
{
@@ -134,19 +110,3 @@ void AnalysisRunner::setDB( ApiDB *api )
{
mDb = api;
}
void AnalysisRunner::emulateStack( DISASM* disasm )
{
/* track all events:
- sub/add esp
- mov [esp+x], ???
- push/pop
- ret
*/
if ((disasm->Argument1.AccessMode == WRITE)
&& (disasm->Argument1.ArgType & MEMORY_TYPE)
&& (disasm->Argument1.Memory.BaseRegister & REG4)) {
}
}
+1 -4
View File
@@ -28,9 +28,6 @@ class AnalysisRunner
S_IntermodularCalls *_Calls;
ApiDB *mDb;
unsigned char* EIPdata;
UIntPtr currentEIP;
UInt64 currentVirtualAddr;
public:
@@ -49,6 +46,6 @@ public:
void clear( );
void think( );
void initialise();
unsigned int getInstruction(const duint bytesOffset, DISASM* disasm );
const duint baseAddress() const;
};
+3 -1
View File
@@ -86,10 +86,12 @@ ApiDB::~ApiDB(void)
APIFunction ApiDB::find( std::string name )
{
if(name[0]=='&')
name.erase (0,1);
APIFunction f;
f.invalid = true;
//_plugin_logprintf("[StaticAnalysis:IntermodularCalls] search data %s \n",name.c_str() );
std::list<APIFunction>::iterator it = mInfo.begin();
while(it!=mInfo.end()){
+1 -6
View File
@@ -1,5 +1,5 @@
#include "ICommand.h"
#include "AnalysisRunner.h"
ICommand::ICommand(AnalysisRunner *parent) : mParent(parent)
{
@@ -15,8 +15,3 @@ void ICommand::initialise( const duint Base,const duint Size )
mBase = Base;
mSize = Size;
}
unsigned int ICommand::getInstruction( const duint bytesOffset, DISASM* disasm )
{
return mParent->getInstruction(bytesOffset,disasm);
}
-1
View File
@@ -19,7 +19,6 @@ protected:
duint mBase;
duint mSize;
AnalysisRunner *mParent;
unsigned int getInstruction(const duint bytesOffset, DISASM* disasm );
public:
-11
View File
@@ -1,11 +0,0 @@
#include "S_IntermodularCallsX64.h"
S_IntermodularCalls::S_IntermodularCalls(void)
{
}
S_IntermodularCalls::~S_IntermodularCalls(void)
{
}
-21
View File
@@ -1,21 +0,0 @@
#pragma once
/* calling convention
1. arg -> RCX (floating point: XMM0)
2. arg -> RDX (floating point: XMM1)
3. arg -> R8 (floating point: XMM2)
4. arg -> R9 (floating point: XMM3)
additional arguments are pushed onto the stack (right to left)
*/
class S_IntermodularCalls
{
public:
S_IntermodularCalls(void);
~S_IntermodularCalls(void);
};
+43 -52
View File
@@ -6,9 +6,6 @@
#include "AnalysisRunner.h"
#include "meta.h"
/*#define _isPush(disasm) (QString(disasm->Instruction.Mnemonic).trimmed().toLower() == "push")
#define _isCall(disasm) ((disasm->Instruction.BranchType == CallType) && !(disasm->Argument1.ArgType &REGISTER_TYPE))))*/
#define _isPush(disasm) ((strcmp(disasm->Instruction.Mnemonic ,"push ") == 0) )
#define _isCall(disasm) ((disasm->Instruction.Opcode == 0xE8) && (disasm->Instruction.BranchType) && (disasm->Instruction.BranchType!=RetType) && !(disasm->Argument1.ArgType &REGISTER_TYPE))
@@ -36,60 +33,24 @@ void S_IntermodularCalls::see(const DISASM* disasm )
{
// no part of api-call
mCurrent.clear();
//_plugin_logprintf("[StaticAnalysis:IntermodularCalls] found 0xFF : %x and mne (%s)\n", disasm->Instruction.Opcode,disasm->Instruction.Mnemonic);
char labelText[MAX_LABEL_SIZE];
bool hasLabel = DbgGetLabelAt(disasm->Argument1.Memory.Displacement, SEG_DEFAULT, labelText);
if(hasLabel){
// api calls have 0xFF-jumps as target addresses, we need to remember them
_JumpFF j;
j.RVA = disasm->VirtualAddr;
j.RelativeAddressValue = disasm->Argument1.Memory.Displacement;
strcpy(j.label,labelText);
mApiJumps.insert(j);
}
}else {
if(_isCall(disasm))
{
// set missing informations
mCurrent.RVA = disasm->VirtualAddr ;
mCurrent.RelativeAddressValue = disasm->Instruction.AddrValue ;
// retrieve label from the instratuction at "addrValue"
DISASM target_instr;
int len = getInstruction(disasm->Instruction.AddrValue-disasm->VirtualAddr,&target_instr);
if(len != UNKNOWN_OPCODE){
// it is a jump to a dll
if(target_instr.Instruction.Opcode == 0xFF){
mCurrent.isApiCall = true;
// prepare gathering labelText
char labelText[MAX_LABEL_SIZE];
bool hasLabel = DbgGetLabelAt(target_instr.Argument1.Memory.Displacement, SEG_DEFAULT, labelText);
if(hasLabel){
// we have a label from TitanEngine --> look up function header in database
APIFunction f;
f = mParent->db()->find(labelText);
if(!f.invalid){
// found!
// yeah we know everything about the api-call!
std::string functionComment;
functionComment = f.ReturnType + " " + f.Name + "(...)";
DbgSetCommentAt(disasm->VirtualAddr ,functionComment.c_str());
int pos=0;
// set comments for the arguments
if( (f.Arguments.size() > 0) && (mCurrent.arguments.size() > 0) ){
for(std::list<duint>::reverse_iterator a= mCurrent.arguments.rbegin();a!=mCurrent.arguments.rend();a++)
{
// more push" instructions than arguments
if(pos >=f.Arguments.size())
break;
std::string ArgComment = f.arg(pos).Type + " "+ f.arg(pos).Name;
DbgSetCommentAt((*a) ,ArgComment.c_str());
pos++;
}
}
}
}
}
}
// copy structure
_Call t = mCurrent;
mCalls.push_back(t);
@@ -114,8 +75,38 @@ bool S_IntermodularCalls::think()
// iterate all calls
for (std::list<_Call>::iterator c = mCalls.begin();c != mCalls.end();c++)
{
if(c->isApiCall)
bool is_api = false;
_JumpFF findJump;
findJump.RVA = c->RelativeAddressValue;
std::set<_JumpFF>::iterator j = mApiJumps.find(findJump);
if(j != mApiJumps.end()){
// having a label we can look in our database to get the arguments list
APIFunction f;
f = mParent->db()->find(j->label);
if(!f.invalid){
// yeah we know everything about the api-call!
std::string functionComment;
functionComment = f.ReturnType + " " + f.Name + "(...)";
DbgSetAutoCommentAt(c->RVA ,functionComment.c_str());
//_plugin_logprintf("[StaticAnalysis:IntermodularCalls] found %s at %X\n",functionComment , c->RVA);
int pos=0;
// set comments for the arguments
if( (f.Arguments.size() > 0) && (c->arguments.size() > 0) ){
for(std::list<duint>::reverse_iterator a= c->arguments.rbegin();a!=c->arguments.rend();a++)
{
// more push" instructions than arguments
if(pos >=f.Arguments.size())
break;
std::string ArgComment = f.arg(pos).Type + " "+ f.arg(pos).Name;
DbgSetAutoCommentAt((*a) ,ArgComment.c_str());
pos++;
}
}
}
is_api = true;
numberOfApiCalls++;
}
}
_plugin_logprintf("[StaticAnalysis:IntermodularCalls] of which are %i intermodular calls\n", numberOfApiCalls);
+1 -1
View File
@@ -44,7 +44,7 @@ class S_IntermodularCalls : public ICommand
}
bool operator<(const _JumpFF& rhs) const
{
return RVA < rhs.RVA;
return (RVA < rhs.RVA);
}
};
-78
View File
@@ -1,78 +0,0 @@
/* plugin: (StaticAnalysis) for x64dbg <http://www.x64dbg.com>
* author: [email protected] <http://blog.traceflow.com>
* license: GLPv3
*/
#include "StackEmulator.h"
StackEmulator::StackEmulator( void) : mStackpointer(0)
{
for (unsigned int i=0;i<MAX_STACKSIZE;i++)
mStack[i]=0;
}
StackEmulator::~StackEmulator(void)
{
}
/*
0x01234: mov [esp+C], eax
--> modifyFrom(0xC,0x01234)
*/
void StackEmulator::modifyFrom(int relative_offset,duint addr){
const unsigned int internal_pointer = pointerByOffset(-1*relative_offset);
mStack[internal_pointer] = addr;
}
/*
0x01234: pop eax
--> popFrom(0x01234), because it is:
mov eax, [esp]
add esp, -1 ; one to the past
*/
void StackEmulator::popFrom( duint addr )
{
moveStackpointer(+1);
}
/*
0x01234: push eax
--> pushFrom(0x01234), because it is:
add esp, +1
mov [esp], eax ; one to the future
*/
void StackEmulator::pushFrom( duint addr )
{
mStack[mStackpointer] = addr;
moveStackpointer(-1);
}
/*
0x01234: add esp, 0xA
--> moveStackpointer(0xA)
offset = offset to the past
*/
void StackEmulator::moveStackpointer( int offset )
{
mStackpointer = pointerByOffset(-offset);
}
unsigned int StackEmulator::pointerByOffset(int offset){
return (mStackpointer + ((offset+MAX_STACKSIZE) %MAX_STACKSIZE) + MAX_STACKSIZE) %MAX_STACKSIZE;
}
/* returns addr from last access
0x155: mov [esp+8], eax
lastAccessAt(0x8) would be 0x155
*/
duint StackEmulator::lastAccessAt(int offset){
int p = pointerByOffset(-offset);
return mStack[p];
}
-38
View File
@@ -1,38 +0,0 @@
/* plugin: (StaticAnalysis) for x64dbg <http://www.x64dbg.com>
* author: [email protected] <http://blog.traceflow.com>
* license: GLPv3
*/
#pragma once
#include "meta.h"
/* since some compilers don't use "push" to change the stack for arguments (see MingGW)
we have to track all modifications to the stack for better analysis
therefore we emulate the stack by only storing the virtual address from the last write-access
-> advantage: we can track all modifications of the register for better placing of comments
*/
const unsigned int MAX_STACKSIZE = 50;
class StackEmulator
{
duint mStack[MAX_STACKSIZE];
unsigned int mStackpointer;
public:
StackEmulator(void);
~StackEmulator(void);
void pushFrom(duint addr);
void popFrom(duint addr);
void modifyFrom(int relative_offset,duint addr);
void moveStackpointer(int offset);
unsigned int pointerByOffset(int offset);
duint lastAccessAt(int offset);
};
Binary file not shown.
+5 -5
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64_dbg_analysisplugin", "x64_dbg_analysisplugin.vcxproj", "{CB859ADC-243D-4B05-E4EA-4A9CD1F318A2}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64_dbg_analysisplugin", "x64_dbg_analysisplugin.vcxproj", "{56EC1214-EF57-5BB5-8D3B-E74ED52F6386}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -9,10 +9,10 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CB859ADC-243D-4B05-E4EA-4A9CD1F318A2}.Release|Win32.ActiveCfg = Release|Win32
{CB859ADC-243D-4B05-E4EA-4A9CD1F318A2}.Release|Win32.Build.0 = Release|Win32
{CB859ADC-243D-4B05-E4EA-4A9CD1F318A2}.Release|x64.ActiveCfg = Release|x64
{CB859ADC-243D-4B05-E4EA-4A9CD1F318A2}.Release|x64.Build.0 = Release|x64
{56EC1214-EF57-5BB5-8D3B-E74ED52F6386}.Release|Win32.ActiveCfg = Release|Win32
{56EC1214-EF57-5BB5-8D3B-E74ED52F6386}.Release|Win32.Build.0 = Release|Win32
{56EC1214-EF57-5BB5-8D3B-E74ED52F6386}.Release|x64.ActiveCfg = Release|x64
{56EC1214-EF57-5BB5-8D3B-E74ED52F6386}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Binary file not shown.