DBG: integrate analysisplugin for out-of-the-box analysis
This is the last version of this analysis code. The next will contain a program-flow-graph for further analysis. It currently supports: - detect Api-Calls and add comments for the parameter (x86/x64) - detect function-bodies (x86) you have to download the "api.dat" from the static analysis plugin
This commit is contained in:
parent
e028ccf680
commit
d1943dc3d1
|
|
@ -634,7 +634,8 @@ typedef enum
|
|||
GUI_REPAINT_TABLE_VIEW, // param1=unused, param2=unused
|
||||
GUI_UPDATE_PATCHES, // param1=unused, param2=unused
|
||||
GUI_UPDATE_CALLSTACK, // param1=unused, param2=unused
|
||||
GUI_SYMBOL_REFRESH_CURRENT // param1=unused, param2=unused
|
||||
GUI_SYMBOL_REFRESH_CURRENT, // param1=unused, param2=unused
|
||||
GUI_ANALYSE_CODE // param1=int_t Base, param2=int_t Size
|
||||
} GUIMSG;
|
||||
|
||||
//GUI structures
|
||||
|
|
@ -708,6 +709,7 @@ BRIDGE_IMPEXP void GuiUpdateSideBar();
|
|||
BRIDGE_IMPEXP void GuiRepaintTableView();
|
||||
BRIDGE_IMPEXP void GuiUpdatePatches();
|
||||
BRIDGE_IMPEXP void GuiUpdateCallStack();
|
||||
BRIDGE_IMPEXP void GuiAnalyseCode(duint base, duint size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
#include "AnalysisRunner.h"
|
||||
#include "../_global.h"
|
||||
#include "../console.h"
|
||||
#include "meta.h"
|
||||
#include "IntermodularCalls.h"
|
||||
#include "FunctionDetector.h"
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
AnalysisRunner::AnalysisRunner(duint BaseAddress, duint Size)
|
||||
{
|
||||
// store all given information
|
||||
mBaseAddress = BaseAddress;
|
||||
mSize = Size;
|
||||
|
||||
_Calls = new IntermodularCalls(this);
|
||||
_Func = new CallDetector(this);
|
||||
|
||||
initialise();
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
AnalysisRunner::~AnalysisRunner(void)
|
||||
{
|
||||
}
|
||||
|
||||
void AnalysisRunner::start()
|
||||
{
|
||||
// do we have information about the function prototypes?
|
||||
if(!mApiDb->ok())
|
||||
return;
|
||||
dputs("[StaticAnalysis] analysis started ...");
|
||||
// remove all temp information
|
||||
clear();
|
||||
run();
|
||||
// see every instructions once
|
||||
publishInstructions();
|
||||
// do some magic
|
||||
think();
|
||||
dputs("[StaticAnalysis] analysis finished ...");
|
||||
}
|
||||
|
||||
void AnalysisRunner::publishInstructions()
|
||||
{
|
||||
StackEmulator Stack;
|
||||
RegisterEmulator Register;
|
||||
// show every sub-plugin the current instruction
|
||||
for each(auto currentInstruction in mInstructionsBuffer)
|
||||
{
|
||||
see(¤tInstruction.second, &Stack, &Register);
|
||||
Stack.emulate(¤tInstruction.second.BeaStruct);
|
||||
Register.emulate(¤tInstruction.second.BeaStruct);
|
||||
}
|
||||
}
|
||||
|
||||
void AnalysisRunner::run()
|
||||
{
|
||||
// this function will be run once
|
||||
|
||||
// copy the code section
|
||||
mCodeMemory = new unsigned char[mSize];
|
||||
if(!DbgMemRead(mBaseAddress, mCodeMemory, mSize))
|
||||
{
|
||||
//ERROR: copying did not work
|
||||
dputs("[StaticAnalysis] could not read memory ...");
|
||||
return;
|
||||
}
|
||||
|
||||
//loop over all instructions
|
||||
DISASM disasm;
|
||||
|
||||
duint baseaddr = mBaseAddress;
|
||||
duint size = mSize;
|
||||
|
||||
memset(&disasm, 0, sizeof(disasm));
|
||||
|
||||
#ifdef _WIN64
|
||||
disasm.Archi = 64;
|
||||
#endif // _WIN64
|
||||
|
||||
currentEIP = (UIntPtr)mCodeMemory;
|
||||
disasm.EIP = currentEIP;
|
||||
currentVirtualAddr = (UInt64)baseaddr;
|
||||
disasm.VirtualAddr = currentVirtualAddr;
|
||||
duint i = 0;
|
||||
|
||||
for(duint i = 0; i < size;)
|
||||
{
|
||||
// disassemble instruction
|
||||
int len = Disasm(&disasm);
|
||||
// everything ok?
|
||||
if(len != UNKNOWN_OPCODE)
|
||||
{
|
||||
Instruction_t instr(&disasm, len);
|
||||
mInstructionsBuffer.insert(std::pair<UInt64, Instruction_t>(disasm.VirtualAddr, instr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// something went wrong --> notify every subplugin
|
||||
unknownOpCode(&disasm);
|
||||
len = 1;
|
||||
}
|
||||
// we do not know if the struct DISASM gets destroyed on unkown opcodes --> use variables
|
||||
currentEIP += len;
|
||||
currentVirtualAddr += len;
|
||||
|
||||
disasm.EIP = currentEIP;
|
||||
disasm.VirtualAddr = currentVirtualAddr;
|
||||
// move memory pointer
|
||||
i += len;
|
||||
}
|
||||
|
||||
|
||||
delete mCodeMemory;
|
||||
}
|
||||
void AnalysisRunner::clear()
|
||||
{
|
||||
mInstructionsBuffer.clear();
|
||||
// forward to all sub-plugin
|
||||
_Calls->clear();
|
||||
_Func->clear();
|
||||
}
|
||||
void AnalysisRunner::think()
|
||||
{
|
||||
// forward to all sub-plugin
|
||||
_Calls->think();
|
||||
_Func->think();
|
||||
}
|
||||
void AnalysisRunner::see(const Instruction_t* disasm, const StackEmulator* stack, const RegisterEmulator* regState)
|
||||
{
|
||||
// forward to all sub-plugin
|
||||
_Calls->see(disasm, stack, regState);
|
||||
_Func->see(disasm, stack, regState);
|
||||
}
|
||||
|
||||
void AnalysisRunner::unknownOpCode(const DISASM* disasm)
|
||||
{
|
||||
// forward to all sub-plugin
|
||||
_Calls->unknownOpCode(disasm);
|
||||
_Func->unknownOpCode(disasm);
|
||||
}
|
||||
|
||||
void AnalysisRunner::initialise()
|
||||
{
|
||||
// forward to all sub-plugin
|
||||
_Calls->initialise(mBaseAddress, mSize);
|
||||
_Func->initialise(mBaseAddress, mSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ApiDB* AnalysisRunner::FunctionInformation() const
|
||||
{
|
||||
return mApiDb;
|
||||
}
|
||||
|
||||
|
||||
void AnalysisRunner::setFunctionInformation(ApiDB* api)
|
||||
{
|
||||
mApiDb = api;
|
||||
}
|
||||
|
||||
// return instruction of address - if possible
|
||||
int AnalysisRunner::instruction(UInt64 va, Instruction_t* instr) const
|
||||
{
|
||||
if(tr4ce::contains(mInstructionsBuffer, va))
|
||||
{
|
||||
*instr = mInstructionsBuffer.at(va);
|
||||
return instr->Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UNKNOWN_OPCODE;
|
||||
}
|
||||
}
|
||||
std::map<UInt64, Instruction_t>::const_iterator AnalysisRunner::instructionIter(UInt64 va) const
|
||||
{
|
||||
return mInstructionsBuffer.find(va);
|
||||
}
|
||||
std::map<UInt64, Instruction_t>::const_iterator AnalysisRunner::lastInstruction() const
|
||||
{
|
||||
return mInstructionsBuffer.end();
|
||||
}
|
||||
|
||||
duint AnalysisRunner::base() const
|
||||
{
|
||||
return mBaseAddress;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
#include "../_global.h"
|
||||
#include <map>
|
||||
#include "Meta.h"
|
||||
#include "StackEmulator.h"
|
||||
#include "RegisterEmulator.h"
|
||||
#include "ApiDB.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
class IntermodularCalls;
|
||||
class CallDetector;
|
||||
|
||||
|
||||
class AnalysisRunner
|
||||
{
|
||||
std::map<UInt64, Instruction_t> mInstructionsBuffer;
|
||||
duint mBaseAddress;
|
||||
duint mSize;
|
||||
|
||||
IntermodularCalls* _Calls;
|
||||
CallDetector* _Func;
|
||||
ApiDB* mApiDb;
|
||||
|
||||
|
||||
unsigned char* mCodeMemory;
|
||||
UIntPtr currentEIP;
|
||||
UInt64 currentVirtualAddr;
|
||||
|
||||
protected:
|
||||
// forwarding
|
||||
void see(const Instruction_t* disasm, const StackEmulator* stack, const RegisterEmulator* regState);
|
||||
void clear();
|
||||
void think();
|
||||
void initialise();
|
||||
void unknownOpCode(const DISASM* disasm);
|
||||
|
||||
private:
|
||||
void run();
|
||||
void publishInstructions();
|
||||
|
||||
public:
|
||||
|
||||
ApiDB* FunctionInformation() const;
|
||||
void setFunctionInformation(ApiDB* api);
|
||||
|
||||
AnalysisRunner(duint BaseAddress, duint Size);
|
||||
~AnalysisRunner(void);
|
||||
|
||||
void start();
|
||||
|
||||
|
||||
|
||||
int instruction(UInt64 va, Instruction_t* instr) const;
|
||||
std::map<UInt64, Instruction_t>::const_iterator instructionIter(UInt64 va) const;
|
||||
std::map<UInt64, Instruction_t>::const_iterator lastInstruction() const;
|
||||
|
||||
duint base() const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/* plugin: (StaticAnalysis) for x64dbg <http://www.x64dbg.com>
|
||||
* author: tr4ceflow@gmail.com <http://blog.traceflow.com>
|
||||
* license: GLPv3
|
||||
*/
|
||||
#include "../console.h"
|
||||
#include "ApiDB.h"
|
||||
#include "Meta.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
// http://stackoverflow.com/a/22923239/1392416
|
||||
std::vector<std::string> split(const std::string & string, const char* del)
|
||||
{
|
||||
size_t first = 0, second = 0;
|
||||
size_t end = string.size();
|
||||
size_t len = strlen(del);
|
||||
std::vector<std::string> tokens;
|
||||
while((second = string.find(del, first)) != (std::string::npos))
|
||||
{
|
||||
size_t dif = second - first;
|
||||
if(dif)
|
||||
{
|
||||
tokens.push_back(string.substr(first, dif));
|
||||
}
|
||||
first = second + len;
|
||||
}
|
||||
if(first != end)
|
||||
{
|
||||
tokens.push_back(string.substr(first));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
namespace tr4ce
|
||||
{
|
||||
ApiDB::ApiDB(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
mValid = true;
|
||||
|
||||
std::ifstream helpFile;
|
||||
std::string rawLine;
|
||||
helpFile.open("api.dat");
|
||||
if(!helpFile)
|
||||
{
|
||||
dputs("[StaticAnalysis] api help file not found ...");
|
||||
}
|
||||
else
|
||||
{
|
||||
dputs("[StaticAnalysis] load api help file ...");
|
||||
while(!helpFile.eof())
|
||||
{
|
||||
helpFile >> rawLine;
|
||||
std::vector<std::string> tokens = split(rawLine, ";");
|
||||
|
||||
if(tokens.size() > 3)
|
||||
{
|
||||
FunctionInfo_t f;
|
||||
f.DLLName = tokens.at(0);
|
||||
f.ReturnType = tokens.at(1);
|
||||
f.Name = tokens.at(2);
|
||||
|
||||
for(unsigned int j = 3; j < tokens.size() - 1; j += 2)
|
||||
{
|
||||
ArgumentInfo_t a;
|
||||
a.Type = tokens.at(j);
|
||||
a.Name = tokens.at(j + 1);
|
||||
f.Arguments.push_back(a);
|
||||
}
|
||||
|
||||
|
||||
mInfo.push_back(f);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
dprintf("[StaticAnalysis] loaded %i functions signatures from helpfile\n", i);
|
||||
helpFile.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ApiDB::~ApiDB(void)
|
||||
{
|
||||
}
|
||||
|
||||
FunctionInfo_t ApiDB::find(std::string name)
|
||||
{
|
||||
if(name[0] == '&')
|
||||
name.erase(0, 1);
|
||||
FunctionInfo_t f;
|
||||
f.invalid = true;
|
||||
|
||||
//_plugin_logprintf("[StaticAnalysis:IntermodularCalls] search data %s \n",name.c_str() );
|
||||
std::list<FunctionInfo_t>::iterator it = mInfo.begin();
|
||||
|
||||
while(it != mInfo.end())
|
||||
{
|
||||
if(it->Name == name)
|
||||
{
|
||||
f = *it;
|
||||
f.invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
const bool ApiDB::ok() const
|
||||
{
|
||||
return mValid;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "Meta.h"
|
||||
#include <list>
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
class ApiDB
|
||||
{
|
||||
private:
|
||||
bool mValid; // "database" ok ?
|
||||
public:
|
||||
ApiDB(void);
|
||||
~ApiDB(void);
|
||||
|
||||
const bool ok() const;
|
||||
|
||||
FunctionInfo_t find(std::string name);
|
||||
|
||||
std::list<FunctionInfo_t> mInfo;
|
||||
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#include "BeaInterpreter.h"
|
||||
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BeaInterpreter::BeaInterpreter(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
BeaInterpreter::~BeaInterpreter(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "Meta.h"
|
||||
#include "../BeaEngine/BeaEngine.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
|
||||
|
||||
class BeaInterpreter
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
BeaInterpreter(void);
|
||||
~BeaInterpreter(void);
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#include "IntermodularCalls.h"
|
||||
#include "AnalysisRunner.h"
|
||||
#include "../console.h"
|
||||
#include "FunctionDetector.h"
|
||||
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#define _isCall(disasm) ((disasm.Instruction.Opcode == 0xE8) && (disasm.Instruction.BranchType) && (disasm.Instruction.BranchType!=RetType) && !(disasm.Argument1.ArgType ®ISTER_TYPE))
|
||||
#else
|
||||
#define _isCall(disasm) ((disasm.Instruction.BranchType==CallType) && (disasm.Instruction.BranchType!=RetType) && !(disasm.Argument1.ArgType ®ISTER_TYPE))
|
||||
#endif
|
||||
|
||||
|
||||
CallDetector::CallDetector(AnalysisRunner* parent) : ICommand(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CallDetector::clear()
|
||||
{
|
||||
numberOfFunctions = 0;
|
||||
}
|
||||
#ifndef _WIN64
|
||||
void CallDetector::see(const Instruction_t* currentInstruction, const StackEmulator* stackState, const RegisterEmulator* regState)
|
||||
{
|
||||
|
||||
if((currentInstruction->BeaStruct.Instruction.Opcode != 0xFF) && (_isCall(currentInstruction->BeaStruct)))
|
||||
{
|
||||
Instruction_t callTarget;
|
||||
int len = mParent->instruction(currentInstruction->BeaStruct.Instruction.AddrValue, &callTarget);
|
||||
if(len != UNKNOWN_OPCODE)
|
||||
{
|
||||
if((callTarget.BeaStruct.Instruction.Opcode != 0xFF) && (currentInstruction->BeaStruct.Instruction.AddrValue != mParent->base())){
|
||||
dprintf("[StaticAnalysis:CallDetector] call at %x \n",currentInstruction->BeaStruct.VirtualAddr);
|
||||
dprintf("[StaticAnalysis:CallDetector] call to %x \n",currentInstruction->BeaStruct.Instruction.AddrValue);
|
||||
Call_t c(0);
|
||||
c.startAddress = currentInstruction->BeaStruct.Instruction.AddrValue;
|
||||
mCalls.insert(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void CallDetector::see(const Instruction_t* currentInstruction, const StackEmulator* stackState, const RegisterEmulator* regState)
|
||||
{
|
||||
|
||||
// if((_isCall(currentInstruction->BeaStruct)))
|
||||
// {
|
||||
// char labelText[MAX_LABEL_SIZE];
|
||||
// bool hasLabel = DbgGetLabelAt(currentInstruction->BeaStruct.Instruction.AddrValue, SEG_DEFAULT, labelText);
|
||||
// if(hasLabel)
|
||||
// {
|
||||
// // we have NO label from TitanEngine --> custom call
|
||||
// FunctionInfo_t f = mParent->FunctionInformation()->find(labelText);
|
||||
// if(f.invalid)
|
||||
// {
|
||||
// numberOfFunctions++;
|
||||
// dprintf("[StaticAnalysis:CallDetector] call at %x \n",currentInstruction->BeaStruct.VirtualAddr);
|
||||
// dprintf("[StaticAnalysis:CallDetector] call to %x \n",currentInstruction->BeaStruct.Instruction.AddrValue);
|
||||
// Call_t c(0);
|
||||
// c.startAddress = currentInstruction->BeaStruct.Instruction.AddrValue;
|
||||
// mCalls.insert(c);
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
||||
}
|
||||
#endif // _WIN64
|
||||
bool CallDetector::think()
|
||||
{
|
||||
#ifndef _WIN64
|
||||
const int RETOPCODE = 0xC2;
|
||||
#else
|
||||
const int RETOPCODE = 0xC3;
|
||||
#endif
|
||||
|
||||
for each(Call_t c in mCalls){
|
||||
dprintf("[StaticAnalysis:CallDetector] think about %x \n",c.startAddress);
|
||||
Instruction_t t;
|
||||
|
||||
std::map<UInt64, Instruction_t>::const_iterator code = mParent->instructionIter(c.startAddress);
|
||||
|
||||
while(code->second.BeaStruct.Instruction.Opcode != RETOPCODE){
|
||||
code++;
|
||||
}
|
||||
|
||||
DbgSetAutoFunctionAt(c.startAddress,code->second.BeaStruct.VirtualAddr);
|
||||
}
|
||||
|
||||
dprintf("[StaticAnalysis:CallDetector] found %i functions\n", numberOfFunctions);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallDetector::unknownOpCode(const DISASM* disasm)
|
||||
{
|
||||
// current instruction wasn't correctly disassembled, so assuming worst-case
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "ICommand.h"
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "Meta.h"
|
||||
#include "StackEmulator.h"
|
||||
#include "RegisterEmulator.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
class CallDetector : public ICommand
|
||||
{
|
||||
|
||||
|
||||
unsigned int numberOfFunctions;
|
||||
std::set<Call_t> mCalls;
|
||||
|
||||
public:
|
||||
|
||||
CallDetector(AnalysisRunner* parent);
|
||||
|
||||
void clear();
|
||||
void see(const Instruction_t* disasm, const StackEmulator* stack, const RegisterEmulator* regState);
|
||||
bool think();
|
||||
void unknownOpCode(const DISASM* disasm);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#include "ICommand.h"
|
||||
#include "AnalysisRunner.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
ICommand::ICommand(AnalysisRunner* parent) : mParent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ICommand::~ICommand(void)
|
||||
{
|
||||
}
|
||||
|
||||
void ICommand::initialise(const uint Base, const uint Size)
|
||||
{
|
||||
mBase = Base;
|
||||
mSize = Size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/* plugin: (StaticAnalysis) for x64dbg <http://www.x64dbg.com>
|
||||
* author: tr4ceflow@gmail.com <http://blog.traceflow.com>
|
||||
* license: GLPv3
|
||||
*/
|
||||
#pragma once
|
||||
#include "../BeaEngine/BeaEngine.h"
|
||||
#include "../_global.h"
|
||||
|
||||
#include "Meta.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
class AnalysisRunner;
|
||||
class StackEmulator;
|
||||
class RegisterEmulator;
|
||||
|
||||
class ICommand
|
||||
{
|
||||
public:
|
||||
ICommand(AnalysisRunner* parent);
|
||||
virtual ~ICommand(void);
|
||||
|
||||
|
||||
protected:
|
||||
uint mBase;
|
||||
uint mSize;
|
||||
AnalysisRunner* mParent;
|
||||
|
||||
public:
|
||||
|
||||
// initialization before any analysis
|
||||
void initialise(const uint Base, const uint Size);
|
||||
// clear all extracted informations
|
||||
virtual void clear() = 0;
|
||||
// each sub-plugin will get a simulated flow (it gets an instruction and the state of the stack)
|
||||
virtual void see(const Instruction_t* disasm, const StackEmulator* stack, const RegisterEmulator* regState) = 0;
|
||||
// this methods process all gathered informations
|
||||
virtual bool think() = 0;
|
||||
|
||||
void unknownOpCode(const DISASM* disasm);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include "ICommand.h"
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "meta.h"
|
||||
#include "StackEmulator.h"
|
||||
#include "RegisterEmulator.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
|
||||
|
||||
class IntermodularCalls : public ICommand
|
||||
{
|
||||
unsigned int numberOfCalls;
|
||||
unsigned int numberOfApiCalls;
|
||||
|
||||
public:
|
||||
|
||||
IntermodularCalls(AnalysisRunner* parent);
|
||||
|
||||
void clear();
|
||||
void see(const Instruction_t* disasm, const StackEmulator* stack, const RegisterEmulator* regState);
|
||||
bool think();
|
||||
void unknownOpCode(const DISASM* disasm);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#ifdef _WIN64
|
||||
|
||||
|
||||
#include "IntermodularCalls.h"
|
||||
#include "AnalysisRunner.h"
|
||||
#include "../console.h"
|
||||
namespace tr4ce
|
||||
{
|
||||
#define _isCall(disasm) ((disasm.Instruction.BranchType==CallType) && (disasm.Instruction.BranchType!=RetType) && !(disasm.Argument1.ArgType ®ISTER_TYPE))
|
||||
|
||||
|
||||
IntermodularCalls::IntermodularCalls(AnalysisRunner* parent) : ICommand(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntermodularCalls::clear()
|
||||
{
|
||||
numberOfApiCalls = 0;
|
||||
numberOfCalls = 0;
|
||||
}
|
||||
|
||||
void IntermodularCalls::see(const Instruction_t* currentInstruction, const StackEmulator* stackState, const RegisterEmulator* regState)
|
||||
{
|
||||
|
||||
if((_isCall(currentInstruction->BeaStruct)))
|
||||
{
|
||||
// current instructions contains a call
|
||||
// extract from "call 0x123" --> instruction at 0x123
|
||||
|
||||
|
||||
// the opcode 0xFF "jmp" tells us that the current call is a call to a dll-function
|
||||
|
||||
numberOfCalls++;
|
||||
// does the TitanEngine provides us a label?
|
||||
char labelText[MAX_LABEL_SIZE];
|
||||
bool hasLabel = DbgGetLabelAt(currentInstruction->BeaStruct.Instruction.AddrValue, SEG_DEFAULT, labelText);
|
||||
if(hasLabel)
|
||||
{
|
||||
|
||||
// we have a label from TitanEngine --> look up function header in database
|
||||
FunctionInfo_t f = mParent->FunctionInformation()->find(labelText);
|
||||
if(!f.invalid)
|
||||
{
|
||||
numberOfApiCalls++;
|
||||
// yeah we know everything about the dll-call!
|
||||
std::string functionComment;
|
||||
functionComment = f.ReturnType + " " + f.Name + "(...)";
|
||||
DbgSetAutoCommentAt(currentInstruction->BeaStruct.VirtualAddr, functionComment.c_str());
|
||||
|
||||
if(f.Arguments.size() > 0)
|
||||
{
|
||||
std::string ArgComment = f.arg(0).Type + " " + f.arg(0).Name;
|
||||
DbgSetAutoCommentAt(regState->rcx(), ArgComment.c_str());
|
||||
}
|
||||
if(f.Arguments.size() > 1)
|
||||
{
|
||||
std::string ArgComment = f.arg(1).Type + " " + f.arg(1).Name;
|
||||
DbgSetCommentAt(regState->rdx(), ArgComment.c_str());
|
||||
}
|
||||
if(f.Arguments.size() > 2)
|
||||
{
|
||||
std::string ArgComment = f.arg(2).Type + " " + f.arg(2).Name;
|
||||
DbgSetAutoCommentAt(regState->r8(), ArgComment.c_str());
|
||||
}
|
||||
if(f.Arguments.size() > 3)
|
||||
{
|
||||
std::string ArgComment = f.arg(3).Type + " " + f.arg(3).Name;
|
||||
DbgSetAutoCommentAt(regState->r9(), ArgComment.c_str());
|
||||
}
|
||||
if(f.Arguments.size() > 4)
|
||||
{
|
||||
// set comments for the arguments
|
||||
for(auto i = 4; i < f.Arguments.size(); i++)
|
||||
{
|
||||
std::string ArgComment = f.arg(i).Type + " " + f.arg(i).Name;
|
||||
uint commentAddr = stackState->lastAccessAtOffset(f.Arguments.size() - i - 1);
|
||||
if(commentAddr != STACK_ERROR)
|
||||
{
|
||||
DbgSetAutoCommentAt(commentAddr, ArgComment.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have more arguments in the function descriptions than parameters on the stack
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IntermodularCalls::think()
|
||||
{
|
||||
StackEmulator stack;
|
||||
|
||||
dprintf("[StaticAnalysis:IntermodularCalls] found %i calls\n", numberOfCalls);
|
||||
dprintf("[StaticAnalysis:IntermodularCalls] of which are %i intermodular calls\n", numberOfApiCalls);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntermodularCalls::unknownOpCode(const DISASM* disasm)
|
||||
{
|
||||
// current instruction wasn't correctly disassembled, so assuming worst-case
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // _WIN64
|
||||
|
||||
|
||||
/* new calling convention in x64
|
||||
|
||||
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)
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef _WIN64
|
||||
|
||||
|
||||
#include "IntermodularCalls.h"
|
||||
#include "AnalysisRunner.h"
|
||||
#include "../console.h"
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
#define _isCall(disasm) ((disasm.Instruction.Opcode == 0xE8) && (disasm.Instruction.BranchType) && (disasm.Instruction.BranchType!=RetType) && !(disasm.Argument1.ArgType ®ISTER_TYPE))
|
||||
|
||||
|
||||
IntermodularCalls::IntermodularCalls(AnalysisRunner* parent) : ICommand(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntermodularCalls::clear()
|
||||
{
|
||||
numberOfApiCalls = 0;
|
||||
numberOfCalls = 0;
|
||||
}
|
||||
|
||||
void IntermodularCalls::see(const Instruction_t* currentInstruction, const StackEmulator* stackState, const RegisterEmulator* regState)
|
||||
{
|
||||
|
||||
if((currentInstruction->BeaStruct.Instruction.Opcode != 0xFF) && (_isCall(currentInstruction->BeaStruct)))
|
||||
{
|
||||
// current instructions contains a call
|
||||
// extract from "call 0x123" --> instruction at 0x123
|
||||
Instruction_t callTarget;
|
||||
int len = mParent->instruction(currentInstruction->BeaStruct.Instruction.AddrValue, &callTarget);
|
||||
if(len != UNKNOWN_OPCODE)
|
||||
{
|
||||
// call target was correctly disassembled before
|
||||
if(callTarget.BeaStruct.Instruction.Opcode == 0xFF)
|
||||
{
|
||||
|
||||
// the opcode 0xFF "jmp" tells us that the current call is a call to a dll-function
|
||||
numberOfApiCalls++;
|
||||
numberOfCalls++;
|
||||
// does the TitanEngine provides us a label?
|
||||
char labelText[MAX_LABEL_SIZE];
|
||||
bool hasLabel = DbgGetLabelAt(callTarget.BeaStruct.Argument1.Memory.Displacement, SEG_DEFAULT, labelText);
|
||||
if(hasLabel)
|
||||
{
|
||||
|
||||
// we have a label from TitanEngine --> look up function header in database
|
||||
FunctionInfo_t f = mParent->FunctionInformation()->find(labelText);
|
||||
if(!f.invalid)
|
||||
{
|
||||
// yeah we know everything about the dll-call!
|
||||
std::string functionComment;
|
||||
functionComment = f.ReturnType + " " + f.Name + "(...)";
|
||||
DbgSetAutoCommentAt(currentInstruction->BeaStruct.VirtualAddr, functionComment.c_str());
|
||||
|
||||
|
||||
// set comments for the arguments
|
||||
for(auto i = 0; i < f.Arguments.size(); i++)
|
||||
{
|
||||
std::string ArgComment = f.arg(i).Type + " " + f.arg(i).Name;
|
||||
uint commentAddr = stackState->lastAccessAtOffset(f.Arguments.size() - i - 1);
|
||||
if(commentAddr != STACK_ERROR)
|
||||
{
|
||||
DbgSetAutoCommentAt(commentAddr, ArgComment.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have more arguments in the function descriptions than parameters on the stack
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numberOfCalls++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IntermodularCalls::think()
|
||||
{
|
||||
StackEmulator stack;
|
||||
|
||||
dprintf("[StaticAnalysis:IntermodularCalls] found %i calls\n", numberOfCalls);
|
||||
dprintf("[StaticAnalysis:IntermodularCalls] of which are %i intermodular calls\n", numberOfApiCalls);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntermodularCalls::unknownOpCode(const DISASM* disasm)
|
||||
{
|
||||
// current instruction wasn't correctly disassembled, so assuming worst-case
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // _WIN64
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
#include "../BeaEngine/BeaEngine.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
struct Call_t
|
||||
{
|
||||
UInt64 startAddress;
|
||||
UInt64 endAddress;
|
||||
|
||||
Call_t(UInt64 a)
|
||||
{
|
||||
startAddress = a;
|
||||
}
|
||||
|
||||
bool operator==(const Call_t & rhs) const
|
||||
{
|
||||
return static_cast<bool>(startAddress == rhs.startAddress);
|
||||
}
|
||||
bool operator<(const Call_t & rhs) const
|
||||
{
|
||||
return static_cast<bool>(startAddress < rhs.startAddress);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
struct Instruction_t
|
||||
{
|
||||
DISASM BeaStruct;
|
||||
unsigned int Length;
|
||||
|
||||
Instruction_t(DISASM* dis, unsigned int len)
|
||||
{
|
||||
BeaStruct = *dis;
|
||||
Length = len;
|
||||
}
|
||||
|
||||
Instruction_t()
|
||||
{
|
||||
Length = UNKNOWN_OPCODE;
|
||||
}
|
||||
};
|
||||
|
||||
struct ArgumentInfo_t
|
||||
{
|
||||
std::string Type;
|
||||
std::string Name;
|
||||
|
||||
ArgumentInfo_t(std::string t, std::string n)
|
||||
{
|
||||
Type = t;
|
||||
Name = n;
|
||||
}
|
||||
|
||||
ArgumentInfo_t() {}
|
||||
};
|
||||
|
||||
struct FunctionInfo_t
|
||||
{
|
||||
std::string DLLName;
|
||||
std::string ReturnType;
|
||||
std::string Name;
|
||||
std::vector<ArgumentInfo_t> Arguments;
|
||||
bool invalid;
|
||||
|
||||
FunctionInfo_t()
|
||||
{
|
||||
invalid = false;
|
||||
}
|
||||
|
||||
FunctionInfo_t(std::string dll, std::string ret, std::string name, std::vector<ArgumentInfo_t> args)
|
||||
{
|
||||
DLLName = dll;
|
||||
ReturnType = ret;
|
||||
Name = name;
|
||||
Arguments = args;
|
||||
invalid = false;
|
||||
}
|
||||
|
||||
bool operator==(const FunctionInfo_t & rhs) const
|
||||
{
|
||||
return static_cast<bool>((_strcmpi(Name.c_str(), rhs.Name.c_str()) < 0));
|
||||
}
|
||||
bool operator<(const FunctionInfo_t & rhs) const
|
||||
{
|
||||
return static_cast<bool>(_strcmpi(Name.c_str(), rhs.Name.c_str()));
|
||||
}
|
||||
|
||||
ArgumentInfo_t arg(int i)
|
||||
{
|
||||
return Arguments.at(i);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename D>
|
||||
bool contains(std::map<T, D> s, T key)
|
||||
{
|
||||
std::map<T, D>::iterator it = s.find(key);
|
||||
return (it != s.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN64
|
||||
#define REGISTER_SIZE 8
|
||||
#else
|
||||
#define REGISTER_SIZE 4
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/*namespace std{
|
||||
|
||||
template<typename T, typename D>
|
||||
bool contains(std::map<T,D> s, T key)
|
||||
{
|
||||
std::map<T,D>::iterator it = s.find(key);
|
||||
return (it != s.end());
|
||||
}
|
||||
}*/
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#include "RegisterEmulator.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
#define _SAME(a,b) ((strcmp(a ,b) == 0) )
|
||||
|
||||
RegisterEmulator::RegisterEmulator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RegisterEmulator::~RegisterEmulator()
|
||||
{
|
||||
}
|
||||
|
||||
void RegisterEmulator::emulate(const DISASM* BeaStruct)
|
||||
{
|
||||
if((BeaStruct->Argument1.AccessMode == WRITE) && ((BeaStruct->Argument1.ArgType & GENERAL_REG)))
|
||||
{
|
||||
// Unfortunately there is a bug in BeaEngine, so we cannot use
|
||||
// "if (BeaStruct->Argument1.ArgType & REG?)"
|
||||
if(_SAME(BeaStruct->Argument1.ArgMnemonic, "cl") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "ch") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "cx") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "ecx") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "rcx")
|
||||
)
|
||||
{
|
||||
mRCX = BeaStruct->VirtualAddr;
|
||||
}
|
||||
else if(_SAME(BeaStruct->Argument1.ArgMnemonic, "dl") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "dh") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "dx") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "edx") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "rdx")
|
||||
)
|
||||
{
|
||||
mRDX = BeaStruct->VirtualAddr;
|
||||
}
|
||||
else if(_SAME(BeaStruct->Argument1.ArgMnemonic, "r8") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r8d") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r8w") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r8b")
|
||||
)
|
||||
{
|
||||
mR8 = BeaStruct->VirtualAddr;
|
||||
}
|
||||
else if(_SAME(BeaStruct->Argument1.ArgMnemonic, "r9") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r9d") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r9w") ||
|
||||
_SAME(BeaStruct->Argument1.ArgMnemonic, "r9b")
|
||||
)
|
||||
{
|
||||
mR9 = BeaStruct->VirtualAddr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const uint RegisterEmulator::rcx() const
|
||||
{
|
||||
return mRCX;
|
||||
}
|
||||
|
||||
const uint RegisterEmulator::rdx() const
|
||||
{
|
||||
return mRDX;
|
||||
}
|
||||
|
||||
const uint RegisterEmulator::r8() const
|
||||
{
|
||||
return mR8;
|
||||
}
|
||||
|
||||
const uint RegisterEmulator::r9() const
|
||||
{
|
||||
return mR9;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "meta.h"
|
||||
#include "../_global.h"
|
||||
namespace tr4ce
|
||||
{
|
||||
class RegisterEmulator
|
||||
{
|
||||
UInt64 mRCX;
|
||||
UInt64 mRDX;
|
||||
UInt64 mR8;
|
||||
UInt64 mR9;
|
||||
public:
|
||||
RegisterEmulator();
|
||||
~RegisterEmulator();
|
||||
|
||||
void emulate(const DISASM* BeaStruct);
|
||||
|
||||
const uint rcx() const;
|
||||
const uint rdx() const;
|
||||
const uint r8() const;
|
||||
const uint r9() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#include "StackEmulator.h"
|
||||
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
#define _isPush(disasm) ((strcmp((disasm)->Instruction.Mnemonic ,"push ") == 0) )
|
||||
#define _isPop(disasm) ((strcmp((disasm)->Instruction.Mnemonic ,"pop ") == 0) )
|
||||
#define _isSub(disasm) ((strcmp((disasm)->Instruction.Mnemonic ,"sub ") == 0) )
|
||||
#define _isAdd(disasm) ((strcmp((disasm)->Instruction.Mnemonic ,"add ") == 0) )
|
||||
|
||||
|
||||
|
||||
|
||||
StackEmulator::StackEmulator(void) : mStackpointer(0)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_STACKSIZE; i++)
|
||||
mStack[i] = STACK_ERROR;
|
||||
}
|
||||
|
||||
|
||||
StackEmulator::~StackEmulator(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
0x01234: mov [esp+C], eax
|
||||
--> modifyFrom(0xC,0x01234)
|
||||
*/
|
||||
void StackEmulator::modifyFrom(int relative_offset, UInt64 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(UInt64 addr)
|
||||
{
|
||||
moveStackpointerBack(+1);
|
||||
}
|
||||
/*
|
||||
0x01234: push eax
|
||||
--> pushFrom(0x01234), because it is:
|
||||
|
||||
add esp, +1
|
||||
mov [esp], eax ; one to the future
|
||||
*/
|
||||
void StackEmulator::pushFrom(UInt64 addr)
|
||||
{
|
||||
moveStackpointerBack(-1);
|
||||
mStack[mStackpointer] = addr;
|
||||
}
|
||||
/*
|
||||
0x01234: add esp, 0xA
|
||||
--> moveStackpointer(0xA)
|
||||
|
||||
offset = offset to the past
|
||||
*/
|
||||
void StackEmulator::moveStackpointerBack(int offset)
|
||||
{
|
||||
mStackpointer = pointerByOffset(-offset);
|
||||
}
|
||||
|
||||
unsigned int StackEmulator::pointerByOffset(int offset) const
|
||||
{
|
||||
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
|
||||
|
||||
*/
|
||||
UInt64 StackEmulator::lastAccessAtOffset(int offset) const
|
||||
{
|
||||
int p = pointerByOffset(-offset);
|
||||
return mStack[p];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StackEmulator::emulate(const DISASM* BeaStruct)
|
||||
{
|
||||
/* track all events:
|
||||
- sub/add esp
|
||||
- mov [esp+x], ???
|
||||
- push/pop
|
||||
*/
|
||||
//
|
||||
|
||||
const UInt64 addr = BeaStruct->VirtualAddr; // --> 00401301
|
||||
|
||||
if(_isPush(BeaStruct))
|
||||
{
|
||||
// "0x123 push eax" --> remember 0x123
|
||||
pushFrom(addr);
|
||||
}
|
||||
else if(_isPop(BeaStruct))
|
||||
{
|
||||
// "0x125 pop ebp" --> remember 0x125
|
||||
popFrom(addr);
|
||||
}
|
||||
else if(_isSub(BeaStruct))
|
||||
{
|
||||
|
||||
if((strcmp(BeaStruct->Argument1.ArgMnemonic, "esp ") == 0))
|
||||
{
|
||||
// "sub esp, ???"
|
||||
moveStackpointerBack(BeaStruct->Instruction.Immediat / REGISTER_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
else if(_isAdd(BeaStruct))
|
||||
{
|
||||
|
||||
if((strcmp(BeaStruct->Argument1.ArgMnemonic, "esp ") == 0))
|
||||
{
|
||||
// "add esp, ???"
|
||||
moveStackpointerBack(BeaStruct->Instruction.Immediat / -REGISTER_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// "00401301: mov dword ptr ss:[esp+04h], 0040400Eh"
|
||||
if((BeaStruct->Argument1.AccessMode == WRITE)
|
||||
&& (BeaStruct->Argument1.ArgType & MEMORY_TYPE)
|
||||
&& (BeaStruct->Argument1.Memory.BaseRegister & REG4)
|
||||
&& (BeaStruct->Argument1.SegmentReg & SSReg)
|
||||
)
|
||||
{
|
||||
int offset = BeaStruct->Argument1.Memory.Displacement; // --> 04h
|
||||
uint addr = BeaStruct->VirtualAddr; // --> 00401301
|
||||
|
||||
modifyFrom(offset / REGISTER_SIZE, addr);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include "Meta.h"
|
||||
#include "../_global.h"
|
||||
|
||||
namespace tr4ce
|
||||
{
|
||||
|
||||
/* 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;
|
||||
|
||||
#define STACK_ERROR -1
|
||||
|
||||
class StackEmulator
|
||||
{
|
||||
|
||||
UInt64 mStack[MAX_STACKSIZE];
|
||||
unsigned int mStackpointer;
|
||||
|
||||
public:
|
||||
StackEmulator(void);
|
||||
~StackEmulator(void);
|
||||
|
||||
|
||||
void pushFrom(UInt64 addr);
|
||||
void popFrom(UInt64 addr);
|
||||
void modifyFrom(int relative_offset, UInt64 addr);
|
||||
|
||||
void moveStackpointerBack(int offset);
|
||||
unsigned int pointerByOffset(int offset) const;
|
||||
UInt64 lastAccessAtOffset(int offset) const;
|
||||
|
||||
void emulate(const DISASM* disasm);
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -10,6 +10,8 @@
|
|||
#include "plugin_loader.h"
|
||||
#include "simplescript.h"
|
||||
#include "symbolinfo.h"
|
||||
#include "Analysis/AnalysisRunner.h"
|
||||
#include "Analysis/ApiDB.h"
|
||||
|
||||
static bool bScyllaLoaded = false;
|
||||
|
||||
|
|
@ -995,6 +997,35 @@ CMDRESULT cbDebugBcDll(int argc, char* argv[])
|
|||
dputs("dll breakpoint removed!");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
CMDRESULT cbDebugAnalyse(int argc, char* argv[])
|
||||
{
|
||||
dputs("start analysis");
|
||||
uint addr = GetContextData(UE_CIP);
|
||||
if(argc > 1 and !valfromstring(argv[1], &addr))
|
||||
{
|
||||
dprintf("invalid address \"%s\"!\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf("valid cip "fhex"!\n", addr);
|
||||
uint size;
|
||||
uint base = memfindbaseaddr(addr, &size);
|
||||
if(!base)
|
||||
{
|
||||
dprintf("invalid address "fhex"!\n", addr);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf("valid base "fhex"!\n", base);
|
||||
dprintf("valid size "fhex"!\n", size);
|
||||
|
||||
tr4ce::ApiDB* db = new tr4ce::ApiDB();
|
||||
tr4ce::AnalysisRunner AR(base, size);
|
||||
AR.setFunctionInformation(db);
|
||||
AR.start();
|
||||
|
||||
|
||||
//GuiAnalyseCode(base, size);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSwitchthread(int argc, char* argv[])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,5 +55,6 @@ CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[]);
|
|||
CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugAnalyse(int argc, char* argv[]);
|
||||
|
||||
#endif //_DEBUGGER_COMMANDS_H
|
||||
|
|
@ -206,6 +206,7 @@ static void registercommands()
|
|||
dbgcmdnew("getstr\1strget", cbInstrGetstr, false); //get a string variable
|
||||
dbgcmdnew("copystr\1strcpy", cbInstrCopystr, true); //write a string variable to memory
|
||||
dbgcmdnew("looplist", cbInstrLoopList, true); //list loops
|
||||
dbgcmdnew("analyse\1analyze\1an", cbDebugAnalyse, true); //start analysis
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="addrinfo.cpp" />
|
||||
<ClCompile Include="Analysis\AnalysisRunner.cpp" />
|
||||
<ClCompile Include="Analysis\ApiDB.cpp" />
|
||||
<ClCompile Include="Analysis\BeaInterpreter.cpp" />
|
||||
<ClCompile Include="Analysis\FunctionDetector.cpp" />
|
||||
<ClCompile Include="Analysis\ICommand.cpp" />
|
||||
<ClCompile Include="Analysis\IntermodularCallsX64.cpp" />
|
||||
<ClCompile Include="Analysis\IntermodularCallsX86.cpp" />
|
||||
<ClCompile Include="Analysis\RegisterEmulator.cpp" />
|
||||
<ClCompile Include="Analysis\StackEmulator.cpp" />
|
||||
<ClCompile Include="argument.cpp" />
|
||||
<ClCompile Include="assemble.cpp" />
|
||||
<ClCompile Include="breakpoint.cpp" />
|
||||
|
|
@ -45,6 +54,15 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="addrinfo.h" />
|
||||
<ClInclude Include="Analysis\AnalysisRunner.h" />
|
||||
<ClInclude Include="Analysis\ApiDB.h" />
|
||||
<ClInclude Include="Analysis\BeaInterpreter.h" />
|
||||
<ClInclude Include="Analysis\FunctionDetector.h" />
|
||||
<ClInclude Include="Analysis\ICommand.h" />
|
||||
<ClInclude Include="Analysis\IntermodularCalls.h" />
|
||||
<ClInclude Include="Analysis\Meta.h" />
|
||||
<ClInclude Include="Analysis\RegisterEmulator.h" />
|
||||
<ClInclude Include="Analysis\StackEmulator.h" />
|
||||
<ClInclude Include="argument.h" />
|
||||
<ClInclude Include="assemble.h" />
|
||||
<ClInclude Include="BeaEngine\basic_types.h" />
|
||||
|
|
@ -145,7 +163,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;BUILD_DBG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;BUILD_DBG;_CRT_SECURE_NO_WARNINGS;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
<Filter Include="Header Files\lz4">
|
||||
<UniqueIdentifier>{6a8d58f0-1417-4bff-aecd-0f9f5e0641f9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Analysis">
|
||||
<UniqueIdentifier>{70e48ca5-7813-4da6-95c8-3717ace25093}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Analysis">
|
||||
<UniqueIdentifier>{68e04c31-9f66-4c9a-ae1d-54b2f6cf2d1c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_exports.cpp">
|
||||
|
|
@ -129,6 +135,33 @@
|
|||
<ClCompile Include="debugger_commands.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\AnalysisRunner.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\StackEmulator.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\RegisterEmulator.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\IntermodularCallsX64.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\IntermodularCallsX86.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\ICommand.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\ApiDB.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\FunctionDetector.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analysis\BeaInterpreter.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="_exports.h">
|
||||
|
|
@ -275,5 +308,32 @@
|
|||
<ClInclude Include="dynamicmem.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\Meta.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\AnalysisRunner.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\StackEmulator.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\RegisterEmulator.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\IntermodularCalls.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\ICommand.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\ApiDB.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\FunctionDetector.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analysis\BeaInterpreter.h">
|
||||
<Filter>Analysis</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -342,6 +342,11 @@ void Bridge::emitAutoCompleteClearAll()
|
|||
emit autoCompleteClearAll();
|
||||
}
|
||||
|
||||
void Bridge::emitAnalyseCode(int_t Base, int_t Size)
|
||||
{
|
||||
emit analyseCode(Base, Size);
|
||||
}
|
||||
|
||||
void Bridge::emitUpdateSideBar()
|
||||
{
|
||||
emit updateSideBar();
|
||||
|
|
@ -708,6 +713,11 @@ __declspec(dllexport) void* _gui_sendmessage(GUIMSG type, void* param1, void* pa
|
|||
Bridge::getBridge()->emitAutoCompleteClearAll();
|
||||
}
|
||||
break;
|
||||
case GUI_ANALYSE_CODE:
|
||||
{
|
||||
Bridge::getBridge()->emitAnalyseCode((int_t)param1, (int_t)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_ADD_MSG_TO_STATUSBAR:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public:
|
|||
void emitAutoCompleteAddCmd(const QString cmd);
|
||||
void emitAutoCompleteDelCmd(const QString cmd);
|
||||
void emitAutoCompleteClearAll();
|
||||
void emitAnalyseCode(int_t Base, int_t Size);
|
||||
void emitAddMsgToStatusBar(QString msg);
|
||||
void emitUpdateSideBar();
|
||||
void emitRepaintTableView();
|
||||
|
|
@ -143,13 +144,15 @@ signals:
|
|||
void updatePatches();
|
||||
void updateCallStack();
|
||||
void symbolRefreshCurrent();
|
||||
void analyseCode(int_t Base, int_t Size);
|
||||
|
||||
private:
|
||||
QMutex* mBridgeMutex;
|
||||
int_t bridgeResult;
|
||||
bool hasBridgeResult;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue