1
0
Fork 0

Merge branch 'patch-1' of https://github.com/torusrxxx/x64dbg into torusrxxx-patch-1

Conflicts:
	src/dbg/_dbgfunctions.cpp
	src/dbg/_dbgfunctions.h
	src/dbg/threading.h
	src/dbg/x64_dbg_dbg.vcxproj.filters
	src/gui/Src/Gui/CPUDisassembly.cpp
	src/gui/Src/Gui/CPUDisassembly.h
This commit is contained in:
mrexodia 2016-05-25 16:39:45 +02:00
commit ffac42d16d
19 changed files with 726 additions and 81 deletions

View File

@ -106,7 +106,7 @@ BRIDGE_IMPEXP void* BridgeAlloc(size_t size)
unsigned char* ptr = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
if(!ptr)
{
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
MessageBoxW(0, L"Could not allocate memory", L"Error", MB_ICONERROR);
ExitProcess(1);
}
memset(ptr, 0, size);

447
src/dbg/TraceRecord.cpp Normal file
View File

@ -0,0 +1,447 @@
#include "TraceRecord.h"
#include "capstone_wrapper.h"
#include "module.h"
#include "memory.h"
#include "threading.h"
#include "console.h"
#include <algorithm>
TraceRecordManager TraceRecord;
TraceRecordManager::TraceRecordManager() : instructionCounter(0)
{
ModuleNames.emplace_back("");
}
TraceRecordManager::~TraceRecordManager()
{
clear();
}
void TraceRecordManager::clear()
{
EXCLUSIVE_ACQUIRE(LockTraceRecord);
for(auto i = TraceRecord.begin(); i != TraceRecord.end(); i++)
efree(i->second.rawPtr, "TraceRecordManager");
TraceRecord.clear();
ModuleNames.clear();
ModuleNames.emplace_back("");
}
bool TraceRecordManager::setTraceRecordType(duint pageAddress, TraceRecordType type)
{
EXCLUSIVE_ACQUIRE(LockTraceRecord);
pageAddress &= ~((duint)4096 - 1);
auto pageInfo = TraceRecord.find(ModHashFromAddr(pageAddress));
if(pageInfo == TraceRecord.end())
{
if(type != TraceRecordType::TraceRecordNone)
{
TraceRecordPage newPage;
char modName[MAX_MODULE_SIZE];
switch(type)
{
case TraceRecordBitExec:
newPage.rawPtr = emalloc(4096 / 8, "TraceRecordManager");
memset(newPage.rawPtr, 0, 4096 / 8);
break;
case TraceRecordByteWithExecTypeAndCounter:
newPage.rawPtr = emalloc(4096, "TraceRecordManager");
memset(newPage.rawPtr, 0, 4096);
break;
case TraceRecordWordWithExecTypeAndCounter:
newPage.rawPtr = emalloc(4096 * 2, "TraceRecordManager");
memset(newPage.rawPtr, 0, 4096 * 2);
break;
default:
return false;
}
newPage.dataType = type;
if(ModNameFromAddr(pageAddress, modName, true))
{
newPage.rva = pageAddress - ModBaseFromAddr(pageAddress);
newPage.moduleIndex = getModuleIndex(std::string(modName));
}
else
newPage.moduleIndex = ~0;
auto inserted = TraceRecord.insert(std::make_pair(ModHashFromAddr(pageAddress), newPage));
if(inserted.second == false) // we failed to insert new page into the map
{
free(newPage.rawPtr);
return false;
}
return true;
}
else
return true;
}
else
{
if(type == TraceRecordType::TraceRecordNone)
{
if(pageInfo != TraceRecord.end())
{
efree(pageInfo->second.rawPtr, "TraceRecordManager");
TraceRecord.erase(pageInfo);
}
return true;
}
else
return pageInfo->second.dataType == type; //Can't covert between data types
}
}
TraceRecordManager::TraceRecordType TraceRecordManager::getTraceRecordType(duint pageAddress)
{
SHARED_ACQUIRE(LockTraceRecord);
pageAddress &= ~((duint)4096 - 1);
auto pageInfo = TraceRecord.find(ModHashFromAddr(pageAddress));
if(pageInfo == TraceRecord.end())
return TraceRecordNone;
else
return pageInfo->second.dataType;
}
void TraceRecordManager::TraceExecute(duint address, duint size)
{
SHARED_ACQUIRE(LockTraceRecord);
if(size == 0)
return;
duint base = address & ~((duint)4096 - 1);
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
if(pageInfoIterator == TraceRecord.end())
return;
TraceRecordPage pageInfo;
pageInfo = pageInfoIterator->second;
duint offset = address - base;
bool isMixed;
if((offset + size) > 4096) // execution crossed page boundary, splitting into 2 sub calls. Noting that byte type may be mislabelled.
{
SHARED_RELEASE();
TraceExecute(address, 4096 - offset);
TraceExecute(base + 4096, size + offset - 4096);
return;
}
isMixed = false;
switch(pageInfo.dataType)
{
case TraceRecordType::TraceRecordBitExec:
for(unsigned char i = 0; i < size; i++)
*((char*)pageInfo.rawPtr + (i + offset) / 8) |= 1 << ((i + offset) % 8);
break;
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
for(unsigned char i = 0; i < size; i++)
{
TraceRecordByteType_2bit currentByteType;
if(isMixed)
currentByteType = TraceRecordByteType_2bit::_InstructionOverlapped;
else if(i == 0)
currentByteType = TraceRecordByteType_2bit::_InstructionHeading;
else if(i == size - 1)
currentByteType = TraceRecordByteType_2bit::_InstructionTailing;
else
currentByteType = TraceRecordByteType_2bit::_InstructionBody;
char* data = (char*)pageInfo.rawPtr + offset + i;
if(*data == 0)
{
*data = (char)currentByteType << 6 | 1;
}
else
{
isMixed |= (*data & 0xC0) >> 6 == currentByteType;
*data = ((char)currentByteType << 6) | ((*data & 0x3F) == 0x3F ? 0x3F : (*data & 0x3F) + 1);
}
}
if(isMixed)
for(unsigned char i = 0; i < size; i++)
*((char*)pageInfo.rawPtr + i + offset) |= 0xC0;
break;
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
for(unsigned char i = 0; i < size; i++)
{
TraceRecordByteType_2bit currentByteType;
if(isMixed)
currentByteType = TraceRecordByteType_2bit::_InstructionOverlapped;
else if(i == 0)
currentByteType = TraceRecordByteType_2bit::_InstructionHeading;
else if(i == size - 1)
currentByteType = TraceRecordByteType_2bit::_InstructionTailing;
else
currentByteType = TraceRecordByteType_2bit::_InstructionBody;
short* data = (short*)pageInfo.rawPtr + offset + i;
if(*data == 0)
{
*data = (char)currentByteType << 14 | 1;
}
else
{
isMixed |= (*data & 0xC0) >> 6 == currentByteType;
*data = ((char)currentByteType << 14) | ((*data & 0x3FFF) == 0x3FFF ? 0x3FFF : (*data & 0x3FFF) + 1);
}
}
if(isMixed)
for(unsigned char i = 0; i < size; i++)
*((short*)pageInfo.rawPtr + i + offset) |= 0xC000;
break;
default:
break;
}
}
unsigned int TraceRecordManager::getHitCount(duint address)
{
SHARED_ACQUIRE(LockTraceRecord);
duint base = address & ~((duint)4096 - 1);
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
if(pageInfoIterator == TraceRecord.end())
return 0;
else
{
TraceRecordPage pageInfo = pageInfoIterator->second;
duint offset = address - base;
switch(pageInfo.dataType)
{
case TraceRecordType::TraceRecordBitExec:
return ((char*)pageInfo.rawPtr)[offset / 8] & (1 << (offset % 8)) ? 1 : 0;
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
return ((char*)pageInfo.rawPtr)[offset] & 0x3F;
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
return ((short*)pageInfo.rawPtr)[offset] & 0x3FFF;
default:
return 0;
}
}
}
TraceRecordManager::TraceRecordByteType TraceRecordManager::getByteType(duint address)
{
SHARED_ACQUIRE(LockTraceRecord);
duint base = address & ~((duint)4096 - 1);
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
if(pageInfoIterator == TraceRecord.end())
return TraceRecordByteType::InstructionHeading;
else
{
TraceRecordPage pageInfo = pageInfoIterator->second;
duint offset = address - base;
switch(pageInfo.dataType)
{
case TraceRecordType::TraceRecordBitExec:
default:
return TraceRecordByteType::InstructionHeading;
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
return (TraceRecordByteType)((((char*)pageInfo.rawPtr)[offset] & 0xC0) >> 6);
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
return (TraceRecordByteType)((((short*)pageInfo.rawPtr)[offset] & 0xC000) >> 14);
}
}
}
void TraceRecordManager::increaseInstructionCounter()
{
InterlockedIncrement(&instructionCounter);
}
void TraceRecordManager::saveToDb(JSON root)
{
EXCLUSIVE_ACQUIRE(LockTraceRecord);
const JSON jsonTraceRecords = json_array();
const char* byteToHex = "0123456789ABCDEF";
for(auto i : TraceRecord)
{
JSON jsonObj = json_object();
duint j;
json_object_set_new(jsonObj, "idx", json_hex(i.first));
if(i.second.moduleIndex != ~0)
{
json_object_set_new(jsonObj, "module", json_string(ModuleNames[i.second.moduleIndex].c_str()));
json_object_set_new(jsonObj, "rva", json_hex(i.second.rva));
}
else
{
json_object_set_new(jsonObj, "module", json_string(""));
json_object_set_new(jsonObj, "rva", json_hex(i.first));
}
json_object_set_new(jsonObj, "type", json_hex((duint)i.second.dataType));
char* ptr = (char*)i.second.rawPtr;
duint size = 0;
char* temp;
switch(i.second.dataType)
{
case TraceRecordType::TraceRecordBitExec:
size = 4096 / 8;
break;
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
size = 4096;
break;
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
size = 4096 * 2;
break;
default:
__debugbreak(); // We have encountered an error condition.
}
temp = (char*)emalloc(size * 2 + 1, "TraceRecordManager::saveToDb");
for(j = 0; j < size; j++)
{
temp[j * 2 + 1] = byteToHex[ptr[j] & 0xF];
temp[j * 2] = byteToHex[(ptr[j] & 0xF0) >> 4];
}
temp[size * 2] = 0;
json_object_set_new(jsonObj, "data", json_string(temp));
efree(temp, "TraceRecordManager::saveToDb");
json_array_append_new(jsonTraceRecords, jsonObj);
}
json_object_set_new(root, "tracerecord", jsonTraceRecords);
}
void TraceRecordManager::loadFromDb(JSON root)
{
clear();
EXCLUSIVE_ACQUIRE(LockTraceRecord);
// get the root object
const JSON tracerecord = json_object_get(root, "tracerecord");
// return if nothing found
if(!tracerecord)
return;
size_t i;
JSON value;
json_array_foreach(tracerecord, i, value)
{
TraceRecordPage currentPage;
size_t size;
currentPage.dataType = (TraceRecordType)json_hex_value(json_object_get(value, "type"));
currentPage.rva = json_hex_value(json_object_get(value, "rva"));
switch(currentPage.dataType)
{
case TraceRecordType::TraceRecordBitExec:
size = 4096 / 8;
break;
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
size = 4096;
break;
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
size = 4096 * 2;
break;
default:
size = 0;
break;
}
if(size != 0)
{
currentPage.rawPtr = emalloc(size, "TraceRecordManager");
const char* p = json_string_value(json_object_get(value, "data"));
char* read_ptr = (char*)currentPage.rawPtr;
const char* c;
for(c = p; c < p + size * 2 && *c != '\0'; c += 2, read_ptr++)
{
if(c[1] >= '0' && c[1] <= '9')
*read_ptr = c[1] - '0';
else if(c[1] >= 'A' && c[0] <= 'F')
*read_ptr = c[1] - 'A' + 10;
else
break;
if(c[0] >= '0' && c[0] <= '9')
*read_ptr |= (c[0] - '0') << 4;
else if(c[0] >= 'A' && c[0] <= 'F')
*read_ptr |= (c[0] - 'A' + 10) << 4;
else
break;
}
if(c != p + size * 2)
{
efree(currentPage.rawPtr, "TraceRecordManager");
}
else
{
const char* moduleName = json_string_value(json_object_get(value, "module"));
duint key;
dprintf("%s\n", moduleName);
if(*moduleName)
{
currentPage.moduleIndex = getModuleIndex(std::string(moduleName));
key = currentPage.rva + ModHashFromName(moduleName);
}
else
{
currentPage.moduleIndex = ~0;
key = currentPage.rva;
}
TraceRecord.insert(std::make_pair(key, currentPage));
}
}
}
}
unsigned int TraceRecordManager::getModuleIndex(std::string moduleName)
{
auto iterator = std::find(ModuleNames.begin(), ModuleNames.end(), moduleName);
if(iterator != ModuleNames.end())
return iterator - ModuleNames.begin(); //TODO: warning
else
{
ModuleNames.push_back(moduleName);
return ModuleNames.size() - 1; //TODO: warning
}
}
void _dbg_dbgtraceexecute(duint CIP)
{
if(TraceRecord.getTraceRecordType(CIP) != TraceRecordManager::TraceRecordType::TraceRecordNone)
{
Capstone disassembler;
unsigned char buffer[16];
duint size;
if(MemRead(CIP, buffer, 16))
{
TraceRecord.increaseInstructionCounter();
disassembler.Disassemble(CIP, buffer);
size = disassembler.Success() ? disassembler.Size() : 1;
TraceRecord.TraceExecute(CIP, size);
}
else
{
duint base = MemFindBaseAddr(CIP, &size);
if(CIP - base + 16 > size) // Corner case where CIP is near the end of the page
{
size = base + size - CIP;
if(MemRead(CIP, buffer, size))
{
TraceRecord.increaseInstructionCounter();
disassembler.Disassemble(CIP, buffer, size); //TODO: warning
size = disassembler.Success() ? disassembler.Size() : 1;
TraceRecord.TraceExecute(CIP, size);
return;
}
}
// if we reaches here, then the executable had executed an invalid address. Don't trace it.
}
}
else
TraceRecord.increaseInstructionCounter();
}
unsigned int _dbg_dbggetTraceRecordHitCount(duint address)
{
return TraceRecord.getHitCount(address);
}
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address)
{
return (TRACERECORDBYTETYPE)TraceRecord.getByteType(address);
}
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type)
{
return TraceRecord.setTraceRecordType(pageAddress, (TraceRecordManager::TraceRecordType)type);
}
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress)
{
return (TRACERECORDTYPE)TraceRecord.getTraceRecordType(pageAddress);
}

93
src/dbg/TraceRecord.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef TRACERECORD_H
#define TRACERECORD_H
#include "_global.h"
#include "_dbgfunctions.h"
class TraceRecordManager
{
public:
enum TraceRecordByteType
{
InstructionBody = 0,
InstructionHeading = 1,
InstructionTailing = 2,
InstructionOverlapped = 3, // The byte was executed with differing instruction base addresses
DataByte, // This and the following is not implemented yet.
DataWord,
DataDWord,
DataQWord,
DataFloat,
DataDouble,
DataLongDouble,
DataXMM,
DataYMM,
DataMMX,
DataMixed, //the byte is accessed in multiple ways
InstructionDataMixed //the byte is both executed and written
};
/***************************************************************
* Trace record data layout
* TraceRecordNonoe: disable trace record
* TraceRecordBitExec: single-bit, executed.
* TraceRecordByteWithExecTypeAndCounter: 8-bit, YYXXXXXX YY:=TraceRecordByteType_2bit, XXXXXX:=Hit count(6bit)
* TraceRecordWordWithExecTypeAndCounter: 16-bit, YYXXXXXX XXXXXXXX YY:=TraceRecordByteType_2bit, XX:=Hit count(14bit)
* Other: reserved for future expanding
**************************************************************/
enum TraceRecordType
{
TraceRecordNone,
TraceRecordBitExec,
TraceRecordByteWithExecTypeAndCounter,
TraceRecordWordWithExecTypeAndCounter
};
TraceRecordManager();
~TraceRecordManager();
void clear();
bool setTraceRecordType(duint pageAddress, TraceRecordType type);
TraceRecordType getTraceRecordType(duint pageAddress);
void TraceExecute(duint address, duint size);
//void TraceAccess(duint address, unsigned char size, TraceRecordByteType accessType);
unsigned int getHitCount(duint address);
TraceRecordByteType getByteType(duint address);
void increaseInstructionCounter();
void saveToDb(JSON root);
void loadFromDb(JSON root);
private:
enum TraceRecordByteType_2bit
{
_InstructionBody = 0,
_InstructionHeading = 1,
_InstructionTailing = 2,
_InstructionOverlapped = 3
};
struct TraceRecordPage
{
void* rawPtr;
duint rva;
TraceRecordType dataType;
unsigned int moduleIndex;
};
//Key := page base, value := trace record raw data
std::map<duint, TraceRecordPage> TraceRecord;
std::vector<std::string> ModuleNames;
unsigned int getModuleIndex(std::string moduleName);
unsigned int instructionCounter;
};
extern TraceRecordManager TraceRecord;
void _dbg_dbgtraceexecute(duint CIP);
//exported to bridge
unsigned int _dbg_dbggetTraceRecordHitCount(duint address);
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address);
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type);
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress);
#endif // TRACERECORD_H

View File

@ -19,6 +19,7 @@
#include "breakpoint.h"
#include "threading.h"
#include "stringformat.h"
#include "TraceRecord.h"
#include "mnemonichelp.h"
static DBGFUNCTIONS _dbgfunctions;
@ -293,4 +294,8 @@ void dbgfunctionsinit()
_dbgfunctions.GetBridgeBp = _getbridgebp;
_dbgfunctions.StringFormatInline = _stringformatinline;
_dbgfunctions.GetMnemonicBrief = _getmnemonicbrief;
_dbgfunctions.GetTraceRecordHitCount = _dbg_dbggetTraceRecordHitCount;
_dbgfunctions.GetTraceRecordByteType = _dbg_dbggetTraceRecordByteType;
_dbgfunctions.SetTraceRecordType = _dbg_dbgsetTraceRecordType;
_dbgfunctions.GetTraceRecordType = _dbg_dbggetTraceRecordType;
}

View File

@ -45,6 +45,35 @@ typedef struct
char szExeFile[MAX_PATH];
} DBGPROCESSINFO;
enum TRACERECORDBYTETYPE
{
InstructionBody = 0,
InstructionHeading = 1,
InstructionTailing = 2,
InstructionOverlapped = 3, // The byte was executed with differing instruction base addresses
DataByte, // This and the following is not implemented yet.
DataWord,
DataDWord,
DataQWord,
DataFloat,
DataDouble,
DataLongDouble,
DataXMM,
DataYMM,
DataMMX,
DataMixed, //the byte is accessed in multiple ways
InstructionDataMixed //the byte is both executed and written
};
enum TRACERECORDTYPE
{
TraceRecordNone,
TraceRecordBitExec,
TraceRecordByteWithExecTypeAndCounter,
TraceRecordWordWithExecTypeAndCounter
};
typedef bool (*ASSEMBLEATEX)(duint addr, const char* instruction, char* error, bool fillnop);
typedef bool (*SECTIONFROMADDR)(duint addr, char* section);
typedef bool (*MODNAMEFROMADDR)(duint addr, char* modname, bool extension);
@ -85,6 +114,10 @@ typedef bool (*PATCHGETEX)(duint addr, DBGPATCHINFO* info);
typedef bool(*GETBRIDGEBP)(BPXTYPE type, duint addr, BRIDGEBP* bp);
typedef bool(*STRINGFORMATINLINE)(const char* format, size_t resultSize, char* result);
typedef void(*GETMNEMONICBRIEF)(const char* mnem, size_t resultSize, char* result);
typedef unsigned int (*GETTRACERECORDHITCOUNT)(duint address);
typedef TRACERECORDBYTETYPE(*GETTRACERECORDBYTETYPE)(duint address);
typedef bool (*SETTRACERECORDTYPE)(duint pageAddress, TRACERECORDTYPE type);
typedef TRACERECORDTYPE(*GETTRACERECORDTYPE)(duint pageAddress);
typedef struct DBGFUNCTIONS_
{
@ -128,6 +161,10 @@ typedef struct DBGFUNCTIONS_
GETBRIDGEBP GetBridgeBp;
STRINGFORMATINLINE StringFormatInline;
GETMNEMONICBRIEF GetMnemonicBrief;
GETTRACERECORDHITCOUNT GetTraceRecordHitCount;
GETTRACERECORDBYTETYPE GetTraceRecordByteType;
SETTRACERECORDTYPE SetTraceRecordType;
GETTRACERECORDTYPE GetTraceRecordType;
} DBGFUNCTIONS;
#ifdef BUILD_DBG

View File

@ -35,7 +35,7 @@ void* emalloc(size_t size, const char* reason)
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
if(!a)
{
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
MessageBoxW(0, L"Could not allocate memory", L"Error", MB_ICONERROR);
ExitProcess(1);
}
memset(a, 0, size);
@ -61,7 +61,7 @@ void* erealloc(void* ptr, size_t size, const char* reason)
// Free the memory if the pointer was set (as per documentation).
if(ptr)
efree(ptr);
efree(ptr, reason);
return emalloc(size, reason);
}
@ -345,4 +345,4 @@ void WaitForThreadTermination(HANDLE hThread)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
}

View File

@ -17,6 +17,7 @@
#include "database.h"
#include "threading.h"
#include "filehelper.h"
#include "TraceRecord.h"
/**
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
@ -49,6 +50,7 @@ void DbSave(DbLoadSaveType saveType)
BookmarkCacheSave(root);
FunctionCacheSave(root);
LoopCacheSave(root);
TraceRecord.saveToDb(root);
BpCacheSave(root);
//save notes
@ -158,6 +160,7 @@ void DbLoad(DbLoadSaveType loadType)
BookmarkCacheLoad(root);
FunctionCacheLoad(root);
LoopCacheLoad(root);
TraceRecord.loadFromDb(root);
BpCacheLoad(root);
// Load notes
@ -251,4 +254,4 @@ void DbSetPath(const char* Directory, const char* ModulePath)
dprintf("Database file: %s\n", dbpath);
}
}
}

View File

@ -23,6 +23,7 @@
#include "commandline.h"
#include "stackinfo.h"
#include "stringformat.h"
#include "TraceRecord.h"
static PROCESS_INFORMATION g_pi = {0, 0, 0, 0};
static char szBaseFileName[MAX_PATH] = "";
@ -395,51 +396,6 @@ static bool getConditionValue(const char* expression)
return true;
}
static void BreakpointProlog(BREAKPOINT & bp, bool breakCondition, bool logCondition, bool commandCondition)
{
// update GUI
if(breakCondition)
{
GuiSetDebugState(paused);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
}
// plugin interaction
lock(WAITID_RUN);
if(breakCondition)
{
PLUG_CB_PAUSEDEBUG pauseInfo;
pauseInfo.reserved = nullptr;
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
}
PLUG_CB_BREAKPOINT bpInfo;
BRIDGEBP bridgebp;
bpInfo.breakpoint = &bridgebp;
memset(&bpInfo, 0, sizeof(bpInfo));
BpToBridge(&bp, &bridgebp);
plugincbcall(CB_BREAKPOINT, &bpInfo);
if(*bp.logText && logCondition) //log
{
dprintf("%s\n", stringformatinline(bp.logText).c_str());
}
if(*bp.commandText && commandCondition) //command
{
//TODO: commands like run/step etc will fuck up your shit
DbgCmdExec(bp.commandText);
}
if(breakCondition) //break the debugger
{
SetForegroundWindow(GuiGetWindowHandle());
bSkipExceptions = false;
}
else //resume immediately
unlock(WAITID_RUN);
//wait until the user resumes
wait(WAITID_RUN);
}
static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr)
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
@ -503,6 +459,7 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
else
commandCondition = breakCondition; //if no condition is set, execute the command when the debugger would break
lock(WAITID_RUN);
if(breakCondition)
{
if(bp.singleshoot)
@ -521,9 +478,46 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
default:
break;
}
GuiSetDebugState(paused);
DebugUpdateGui(CIP, true);
}
BreakpointProlog(bp, breakCondition, logCondition, commandCondition);
// plugin interaction
if(breakCondition)
{
PLUG_CB_PAUSEDEBUG pauseInfo;
pauseInfo.reserved = nullptr;
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
}
PLUG_CB_BREAKPOINT bpInfo;
BRIDGEBP bridgebp;
bpInfo.breakpoint = &bridgebp;
memset(&bpInfo, 0, sizeof(bpInfo));
BpToBridge(&bp, &bridgebp);
plugincbcall(CB_BREAKPOINT, &bpInfo);
// Trace record
_dbg_dbgtraceexecute(CIP);
if(*bp.logText && logCondition) //log
{
dprintf("%s\n", stringformatinline(bp.logText).c_str());
}
if(*bp.commandText && commandCondition) //command
{
//TODO: commands like run/step etc will fuck up your shit
DbgCmdExec(bp.commandText);
}
if(breakCondition) //break the debugger
{
SetForegroundWindow(GuiGetWindowHandle());
bSkipExceptions = false;
}
else //resume immediately
unlock(WAITID_RUN);
//wait until the user resumes
wait(WAITID_RUN);
}
void cbUserBreakpoint()
@ -706,7 +700,11 @@ void cbStep()
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
isStepping = false;
GuiSetDebugState(paused);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
DebugUpdateGui(CIP, true);
// Trace record
_dbg_dbgtraceexecute(CIP);
// Plugin interaction
PLUG_CB_STEPPED stepInfo;
stepInfo.reserved = 0;
//lock
@ -724,7 +722,10 @@ static void cbRtrFinalStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
GuiSetDebugState(paused);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
DebugUpdateGui(CIP, true);
// Trace record
_dbg_dbgtraceexecute(CIP);
//lock
lock(WAITID_RUN);
SetForegroundWindow(GuiGetWindowHandle());
@ -883,7 +884,7 @@ static void cbExitProcess(EXIT_PROCESS_DEBUG_INFO* ExitProcess)
plugincbcall(CB_EXITPROCESS, &callbackInfo);
//unload main module
SafeSymUnloadModule64(fdProcessInfo->hProcess, pCreateProcessBase);
ModUnload(pCreateProcessBase);
ModClear(); //clear all modules
}
static void cbCreateThread(CREATE_THREAD_DEBUG_INFO* CreateThread)
@ -1530,9 +1531,7 @@ bool dbglistprocesses(std::vector<PROCESSENTRY32>* list)
{
if(pe32.th32ProcessID == GetCurrentProcessId())
continue;
if(!_stricmp(pe32.szExeFile, "System"))
continue;
if(!_stricmp(pe32.szExeFile, "[System Process]"))
if(pe32.th32ProcessID == 0 || pe32.th32ProcessID == 4) // System process and Idle process have special PID.
continue;
Handle hProcess = TitanOpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pe32.th32ProcessID);
if(!hProcess)
@ -1928,6 +1927,7 @@ static void debugLoopFunction(void* lpParameter, bool attach)
DbClose();
ModClear();
ThreadClear();
TraceRecord.clear();
GuiSetDebugState(stopped);
GuiUpdateAllViews();
dputs("Debugging stopped!");

View File

@ -31,7 +31,7 @@ bool waitislocked(WAIT_ID id)
void waitinitialize()
{
for(int i = 0; i < WAITID_LAST; i++)
waitArray[i] = CreateEventA(NULL, TRUE, TRUE, NULL);
waitArray[i] = CreateEventW(NULL, TRUE, TRUE, NULL);
}
void waitdeinitialize()
@ -126,4 +126,4 @@ void SectionLockerGlobal::Deinitialize()
}
m_Initialized = false;
}
}

View File

@ -55,6 +55,7 @@ enum SectionLock
LockPluginMenuList,
LockSehCache,
LockMnemonicHelp,
LockTraceRecord,
// Number of elements in this enumeration. Must always be the last
// index.
@ -153,4 +154,4 @@ private:
using Internal = SectionLockerGlobal;
};
#endif // _THREADING_H
#endif // _THREADING_H

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@ -70,6 +70,7 @@
<ClCompile Include="symbolinfo.cpp" />
<ClCompile Include="thread.cpp" />
<ClCompile Include="threading.cpp" />
<ClCompile Include="TraceRecord.cpp" />
<ClCompile Include="value.cpp" />
<ClCompile Include="variable.cpp" />
<ClCompile Include="x64_dbg.cpp" />
@ -148,6 +149,7 @@
<ClInclude Include="patternfind.h" />
<ClInclude Include="plugin_loader.h" />
<ClInclude Include="reference.h" />
<ClInclude Include="TraceRecord.h" />
<ClInclude Include="yara\yara\stream.h" />
<ClInclude Include="_scriptapi.h" />
<ClInclude Include="simplescript.h" />
@ -381,4 +383,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
@ -296,6 +296,9 @@
<ClCompile Include="exhandlerinfo.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="TraceRecord.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="mnemonichelp.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
@ -658,5 +661,8 @@
<ClInclude Include="mnemonichelp.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="TraceRecord.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

View File

@ -78,6 +78,7 @@ void Disassembly::updateColors()
mLabelColor = ConfigColor("DisassemblyLabelColor");
mLabelBackgroundColor = ConfigColor("DisassemblyLabelBackgroundColor");
mSelectedAddressBackgroundColor = ConfigColor("DisassemblySelectedAddressBackgroundColor");
mTracedAddressBackgroundColor = ConfigColor("DisassemblyTracedBackgroundColor");
mSelectedAddressColor = ConfigColor("DisassemblySelectedAddressColor");
mAddressBackgroundColor = ConfigColor("DisassemblyAddressBackgroundColor");
mAddressColor = ConfigColor("DisassemblyAddressColor");
@ -133,6 +134,8 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
{
Q_UNUSED(rowBase);
const DBGFUNCTIONS* dbgFuncs = DbgFunctions();
bool isTraced;
if(mHighlightingMode)
{
QPen pen(mInstructionHighlightColor);
@ -144,17 +147,20 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
}
dsint wRVA = mInstBuffer.at(rowOffset).rva;
bool wIsSelected = isSelected(&mInstBuffer, rowOffset);
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
isTraced = dbgFuncs->GetTraceRecordHitCount(cur_addr) != 0;
// Highlight if selected
if(wIsSelected)
painter->fillRect(QRect(x, y, w, h), QBrush(mSelectionColor));
else if(isTraced)
painter->fillRect(QRect(x, y, w, h), QBrush(mTracedAddressBackgroundColor));
switch(col)
{
case 0: // Draw address (+ label)
{
char label[MAX_LABEL_SIZE] = "";
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
QString addrText = getAddrText(cur_addr, label);
BPXTYPE bpxtype = DbgGetBpxTypeAt(cur_addr);
bool isbookmark = DbgGetBookmarkAt(cur_addr);
@ -202,12 +208,12 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
{
if(*label) //label
{
if(bpxtype == bp_none) //label only
if(bpxtype == bp_none) //label only : fill label background
{
painter->setPen(mLabelColor); //red -> address + label text
painter->fillRect(QRect(x, y, w, h), QBrush(mLabelBackgroundColor)); //fill label background
}
else //label+breakpoint
else //label + breakpoint
{
if(bpxtype & bp_normal) //label + normal breakpoint
{
@ -284,7 +290,7 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
painter->setPen(mLabelColor); //red -> address + label text
painter->fillRect(QRect(x, y, w, h), QBrush(mBookmarkBackgroundColor)); //fill label background
}
else //label+breakpoint+bookmark
else //label + breakpoint + bookmark
{
QColor color = mBookmarkBackgroundColor;
if(!color.alpha()) //we don't want transparent text
@ -337,7 +343,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
case 1: //draw bytes (TODO: some spaces between bytes)
{
//draw functions
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
Function_t funcType;
FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr);
FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + mInstBuffer.at(rowOffset).length - 1);
@ -395,7 +400,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
case 2: //draw disassembly (with colours needed)
{
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
int loopsize = 0;
int depth = 0;
@ -442,7 +446,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
case 3: //draw comments
{
int argsize = 0;
duint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
ARGTYPE argType = DbgGetArgTypeAt(cur_addr);
if(argType != ARG_NONE)

View File

@ -161,6 +161,7 @@ protected:
QColor mLabelBackgroundColor;
QColor mSelectedAddressBackgroundColor;
QColor mTracedAddressBackgroundColor;
QColor mSelectedAddressColor;
QColor mAddressBackgroundColor;
QColor mAddressColor;

View File

@ -438,6 +438,7 @@ void AppearanceDialog::colorInfoListInit()
colorInfoListAppend("Conditional Jump Lines (jump)", "DisassemblyConditionalJumpLineTrueColor", "");
colorInfoListAppend("Conditional Jump Lines (no jump)", "DisassemblyConditionalJumpLineFalseColor", "");
colorInfoListAppend("Unconditional Jump Lines", "DisassemblyUnconditionalJumpLineColor", "");
colorInfoListAppend(tr("Traced line"), "DisassemblyTracedBackgroundColor", "");
colorInfoListAppend("Function Lines", "DisassemblyFunctionColor", "");
colorInfoListAppend("Loop Lines", "DisassemblyLoopColor", "");

View File

@ -237,7 +237,7 @@ void CPUDisassembly::setupRightClickContextMenu()
QAction* setHwBreakpointAction = makeAction(tr("Set Hardware on Execution"), SLOT(toggleHwBpActionSlot()));
QAction* removeHwBreakpointAction = makeAction(tr("Remove Hardware"), SLOT(toggleHwBpActionSlot()));
QMenu* replaceSlotMenu = makeMenu("Set Hardware on Execution");
QMenu* replaceSlotMenu = makeMenu(tr("Set Hardware on Execution"));
QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 0 (Free)"), SLOT(setHwBpOnSlot0ActionSlot()));
QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 1 (Free)"), SLOT(setHwBpOnSlot1ActionSlot()));
QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 2 (Free)"), SLOT(setHwBpOnSlot2ActionSlot()));
@ -373,6 +373,24 @@ void CPUDisassembly::setupRightClickContextMenu()
});
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/label.png"), tr("Label")), labelMenu);
QAction* traceRecordDisable = makeAction(tr("Disable"), SLOT(ActionTraceRecordDisableSlot()));
QAction* traceRecordEnableBit = makeAction(tr("Bit"), SLOT(ActionTraceRecordBitSlot()));
QAction* traceRecordEnableByte = makeAction(tr("Byte"), SLOT(ActionTraceRecordByteSlot()));
QAction* traceRecordEnableWord = makeAction(tr("Word"), SLOT(ActionTraceRecordWordSlot()));
//TODO: I can't get mMenuBuilder work without an icon. Please add an icon for trace record. --torusrxxx
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/breakpoint.png"), tr("Trace record")), [ = ](QMenu * menu)
{
if(DbgFunctions()->GetTraceRecordType(rvaToVa(getInitialSelection())) == TRACERECORDTYPE::TraceRecordNone)
{
menu->addAction(traceRecordEnableBit);
menu->addAction(traceRecordEnableByte);
menu->addAction(traceRecordEnableWord);
}
else
menu->addAction(traceRecordDisable);
return true;
});
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/comment.png"), tr("Comment"), SLOT(setCommentSlot()), "ActionSetComment"));
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/bookmark.png"), tr("Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark"));
QAction* toggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), tr("Function"), SLOT(toggleFunctionSlot()), "ActionToggleFunction");
@ -438,7 +456,6 @@ void CPUDisassembly::setupRightClickContextMenu()
mSearchModuleMenu->addAction(mFindStringsModule);
mSearchModuleMenu->addAction(mFindCallsModule);
// Search in All Modules menu
mFindCommandAll = makeAction(tr("C&ommand"), SLOT(findCommandSlot()));
mFindConstantAll = makeAction(tr("&Constant"), SLOT(findConstantSlot()));
@ -1373,6 +1390,36 @@ void CPUDisassembly::editSoftBpActionSlot()
Breakpoints::editBP(bp_normal, ToHexString(rvaToVa(getInitialSelection())), this);
}
void CPUDisassembly::ActionTraceRecordBitSlot()
{
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordBitExec)))
GuiAddLogMessage("Failed to set trace record.\n");
}
void CPUDisassembly::ActionTraceRecordByteSlot()
{
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordByteWithExecTypeAndCounter)))
GuiAddLogMessage("Failed to set trace record.\n");
}
void CPUDisassembly::ActionTraceRecordWordSlot()
{
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordWordWithExecTypeAndCounter)))
GuiAddLogMessage("Failed to set trace record.\n");
}
void CPUDisassembly::ActionTraceRecordDisableSlot()
{
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordNone)))
GuiAddLogMessage("Failed to set trace record.\n");
}
void CPUDisassembly::mnemonicBriefSlot()
{
mShowMnemonicBrief = !mShowMnemonicBrief;
reloadData();
}
void CPUDisassembly::mnemonicHelpSlot()
{
BASIC_INSTRUCTION_INFO disasm;
@ -1385,9 +1432,3 @@ void CPUDisassembly::mnemonicHelpSlot()
DbgCmdExecDirect(QString("mnemonichelp %1").arg(disasm.instruction).toUtf8().constData());
emit displayLogWidget();
}
void CPUDisassembly::mnemonicBriefSlot()
{
mShowMnemonicBrief = !mShowMnemonicBrief;
reloadData();
}

View File

@ -89,6 +89,10 @@ public slots:
void editSoftBpActionSlot();
void mnemonicHelpSlot();
void mnemonicBriefSlot();
void ActionTraceRecordBitSlot();
void ActionTraceRecordByteSlot();
void ActionTraceRecordWordSlot();
void ActionTraceRecordDisableSlot();
protected:
void paintEvent(QPaintEvent* event);

View File

@ -63,8 +63,8 @@ MainWindow::MainWindow(QWidget* parent)
setWindowTitle(QString(mWindowMainTitle));
// Load application icon
HICON hIcon = LoadIcon(GetModuleHandleA(0), MAKEINTRESOURCE(100));
SendMessageA((HWND)MainWindow::winId(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
HICON hIcon = LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(100));
SendMessageW((HWND)MainWindow::winId(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
DestroyIcon(hIcon);
// Load recent files

View File

@ -28,6 +28,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
defaultColors.insert("DisassemblyLabelBackgroundColor", Qt::transparent);
defaultColors.insert("DisassemblyBackgroundColor", QColor("#FFF8F0"));
defaultColors.insert("DisassemblySelectionColor", QColor("#C0C0C0"));
defaultColors.insert("DisassemblyTracedBackgroundColor", QColor("#C0FFC0"));
defaultColors.insert("DisassemblyAddressColor", QColor("#808080"));
defaultColors.insert("DisassemblyAddressBackgroundColor", Qt::transparent);
defaultColors.insert("DisassemblySelectedAddressColor", QColor("#000000"));