1
0
Fork 0

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

# Conflicts:
#	src/dbg/threading.h
#	src/dbg/x64_dbg.cpp
#	src/dbg/x64_dbg_dbg.vcxproj.filters
#	src/gui/resource.qrc
This commit is contained in:
mrexodia 2016-07-07 12:16:34 +02:00
commit 504c794667
No known key found for this signature in database
GPG Key ID: D72F9A4FAA0073B4
45 changed files with 2299 additions and 49 deletions

View File

@ -823,6 +823,11 @@ BRIDGE_IMPEXP bool DbgXrefGet(duint addr, XREF_INFO* info)
return true;
}
BRIDGE_IMPEXP bool DbgGetWatchList(ListOf(WATCHINFO) list)
{
return !!_dbg_sendmessage(DBG_GET_WATCH_LIST, list, nullptr);
}
// FIXME all
BRIDGE_IMPEXP bool DbgIsRunLocked()
{
@ -1027,6 +1032,7 @@ BRIDGE_IMPEXP void GuiUpdateAllViews()
GuiUpdateDisassemblyView();
GuiUpdateBreakpointsView();
GuiUpdateDumpView();
GuiUpdateWatchView();
GuiUpdateThreadView();
GuiUpdateSideBar();
GuiUpdatePatches();
@ -1215,6 +1221,12 @@ BRIDGE_IMPEXP void GuiUpdateDumpView()
_gui_sendmessage(GUI_UPDATE_DUMP_VIEW, 0, 0);
}
BRIDGE_IMPEXP void GuiUpdateWatchView()
{
CHECK_GUI_UPDATE_DISABLED
_gui_sendmessage(GUI_UPDATE_WATCH_VIEW, 0, 0);
}
BRIDGE_IMPEXP void GuiUpdateMemoryView()
{
CHECK_GUI_UPDATE_DISABLED

View File

@ -65,6 +65,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
#define MAX_CONDITIONAL_TEXT_SIZE 256
#define MAX_SCRIPT_LINE_SIZE 2048
#define MAX_THREAD_NAME_SIZE 256
#define MAX_WATCH_NAME_SIZE 256
#define MAX_STRING_SIZE 512
#define MAX_ERROR_SIZE 512
#define RIGHTS_STRING_SIZE (sizeof("ERWCG") + 1)
@ -214,6 +215,7 @@ typedef enum
DBG_ARGUMENT_OVERLAPS, // param1=FUNCTION* info, param2=unused
DBG_ARGUMENT_ADD, // param1=FUNCTION* info, param2=unused
DBG_ARGUMENT_DEL, // param1=FUNCTION* info, param2=unused
DBG_GET_WATCH_LIST // param1=ListOf(WATCHINFO), param2=unused
} DBGMSG;
typedef enum
@ -343,6 +345,25 @@ typedef enum
enc_middle //middle of data
} ENCODETYPE;
typedef enum
{
TYPE_UINT, // unsigned integer
TYPE_INT, // signed integer
TYPE_FLOAT,// single precision floating point value
TYPE_ASCII, // ascii string
TYPE_UNICODE, // unicode string
TYPE_INVALID // invalid watch expression or data type
} WATCHVARTYPE;
typedef enum
{
MODE_DISABLED, // watchdog is disabled
MODE_ISTRUE, // alert if expression is not 0
MODE_ISFALSE, // alert if expression is 0
MODE_CHANGED, // alert if expression is changed
MODE_UNCHANGED // alert if expression is not changed
} WATCHDOGMODE;
//Debugger typedefs
typedef MEMORY_SIZE VALUE_SIZE;
typedef struct SYMBOLINFO_ SYMBOLINFO;
@ -389,6 +410,18 @@ typedef struct
BRIDGEBP* bp;
} BPMAP;
typedef struct
{
char WatchName[MAX_WATCH_NAME_SIZE];
char Expression[MAX_CONDITIONAL_EXPR_SIZE];
unsigned int window;
unsigned int id;
WATCHVARTYPE varType;
WATCHDOGMODE watchdogMode;
duint value;
bool watchdogTriggered;
} WATCHINFO;
typedef struct
{
duint start; //OUT
@ -806,6 +839,7 @@ BRIDGE_IMPEXP duint DbgGetEncodeSizeAt(duint addr, duint codesize);
BRIDGE_IMPEXP bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type);
BRIDGE_IMPEXP void DbgDelEncodeTypeRange(duint start, duint end);
BRIDGE_IMPEXP void DbgDelEncodeTypeSegment(duint start);
BRIDGE_IMPEXP bool DbgGetWatchList(ListOf(WATCHINFO) list);
//Gui defines
#define GUI_PLUGIN_MENU 0
@ -901,6 +935,7 @@ typedef enum
GUI_UNREGISTER_SCRIPT_LANG, // param1=int id, param2=unused
GUI_UPDATE_ARGUMENT_VIEW, // param1=unused, param2=unused
GUI_FOCUS_VIEW, // param1=int hWindow, param2=unused
GUI_UPDATE_WATCH_VIEW // param1=unused, param2=unused
} GUIMSG;
//GUI Typedefs
@ -977,6 +1012,7 @@ BRIDGE_IMPEXP void GuiReferenceSetCurrentTaskProgress(int progress, const char*
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col);
BRIDGE_IMPEXP void GuiStackDumpAt(duint addr, duint csp);
BRIDGE_IMPEXP void GuiUpdateDumpView();
BRIDGE_IMPEXP void GuiUpdateWatchView();
BRIDGE_IMPEXP void GuiUpdateThreadView();
BRIDGE_IMPEXP void GuiUpdateMemoryView();
BRIDGE_IMPEXP void GuiAddRecentFile(const char* file);

View File

@ -24,6 +24,7 @@
#include "handles.h"
#include "../bridge/bridgelist.h"
#include "tcpconnections.h"
#include "watch.h"
static DBGFUNCTIONS _dbgfunctions;
@ -292,6 +293,7 @@ void dbgfunctionsinit()
_dbgfunctions.ModSizeFromAddr = ModSizeFromAddr;
_dbgfunctions.ModGetParty = ModGetParty;
_dbgfunctions.ModSetParty = ModSetParty;
_dbgfunctions.WatchIsWatchdogTriggered = WatchIsWatchdogTriggered;
_dbgfunctions.Assemble = assemble;
_dbgfunctions.PatchGet = _patchget;
_dbgfunctions.PatchInRange = _patchinrange;

View File

@ -143,6 +143,7 @@ typedef bool(*ENUMTCPCONNECTIONS)(ListOf(TCPCONNECTIONINFO) connections);
typedef duint(*GETDBGEVENTS)();
typedef int(*MODGETPARTY)(duint base);
typedef void(*MODSETPARTY)(duint base, int party);
typedef bool(*WATCHISWATCHDOGTRIGGERED)(unsigned int id);
typedef struct DBGFUNCTIONS_
{
@ -196,6 +197,7 @@ typedef struct DBGFUNCTIONS_
GETDBGEVENTS GetDbgEvents;
MODGETPARTY ModGetParty;
MODSETPARTY ModSetParty;
WATCHISWATCHDOGTRIGGERED WatchIsWatchdogTriggered;
} DBGFUNCTIONS;
#ifdef BUILD_DBG

View File

@ -32,6 +32,7 @@
#include "xrefs.h"
#include "encodemap.h"
#include "argument.h"
#include "watch.h"
static bool bOnlyCipAutoComments = false;
@ -1211,6 +1212,12 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
BookmarkDelRange((duint)param1, (duint)param2, true);
}
break;
case DBG_GET_WATCH_LIST:
{
BridgeList<WATCHINFO>::CopyData((ListInfo*)param1, WatchGetList());
}
break;
}
return 0;
}

View File

@ -13,6 +13,7 @@
#include "bookmark.h"
#include "function.h"
#include "loop.h"
#include "watch.h"
#include "commandline.h"
#include "database.h"
#include "threading.h"
@ -59,6 +60,7 @@ void DbSave(DbLoadSaveType saveType)
EncodeMapCacheSave(root);
TraceRecord.saveToDb(root);
BpCacheSave(root);
WatchCacheSave(root);
//save notes
char* text = nullptr;
@ -196,6 +198,7 @@ void DbLoad(DbLoadSaveType loadType)
EncodeMapCacheLoad(root);
TraceRecord.loadFromDb(root);
BpCacheLoad(root);
WatchCacheLoad(root);
// Load notes
const char* text = json_string_value(json_object_get(root, "notes"));

View File

@ -11,6 +11,7 @@
#include "command.h"
#include "database.h"
#include "addrinfo.h"
#include "watch.h"
#include "thread.h"
#include "plugin_loader.h"
#include "breakpoint.h"
@ -24,6 +25,7 @@
#include "stackinfo.h"
#include "stringformat.h"
#include "TraceRecord.h"
#include "historycontext.h"
#include "taskthread.h"
struct TraceCondition
@ -35,7 +37,7 @@ struct TraceCondition
explicit TraceCondition(String expression, duint maxCount)
: condition(expression), steps(0), maxSteps(maxCount) {}
bool ContinueTrace()
inline bool ContinueTrace()
{
steps++;
if(steps >= maxSteps)
@ -261,7 +263,6 @@ duint dbggetdbgevents()
return InterlockedExchange(&DbgEvents, 0);
}
static DWORD WINAPI updateCallStackThread(duint ptr)
{
stackupdatecallstack(ptr);
@ -496,6 +497,10 @@ void cbPauseBreakpoint()
auto CIP = GetContextDataEx(hActiveThread, UE_CIP);
DeleteBPX(CIP);
DebugUpdateGuiSetStateAsync(CIP, true);
// Trace record
_dbg_dbgtraceexecute(CIP);
// Watchdog
cbWatchdog(0, nullptr);
//lock
lock(WAITID_RUN);
SetForegroundWindow(GuiGetWindowHandle());
@ -608,6 +613,9 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
// Trace record
_dbg_dbgtraceexecute(CIP);
// Watchdog
cbWatchdog(0, nullptr);
if(*bp.logText && logCondition) //log
{
dprintf("%s\n", stringformatinline(bp.logText).c_str());
@ -695,10 +703,15 @@ void cbRunToUserCodeBreakpoint(void* ExceptionAddress)
RunToUserCodeBreakpoints.clear();
lock(WAITID_RUN);
EXCLUSIVE_RELEASE();
// Watchdog
cbWatchdog(0, nullptr);
// Plugin callback
PLUG_CB_PAUSEDEBUG pauseInfo;
pauseInfo.reserved = nullptr;
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
// Trace record
_dbg_dbgtraceexecute(CIP);
// Update GUI
DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), true);
SetForegroundWindow(GuiGetWindowHandle());
bSkipExceptions = false;
@ -873,6 +886,8 @@ void cbStep()
DebugUpdateGuiSetStateAsync(CIP, true);
// Trace record
_dbg_dbgtraceexecute(CIP);
// Watchdog
cbWatchdog(0, nullptr);
// Plugin interaction
PLUG_CB_STEPPED stepInfo;
stepInfo.reserved = 0;
@ -895,6 +910,8 @@ static void cbRtrFinalStep()
// Trace record
_dbg_dbgtraceexecute(CIP);
DebugUpdateGuiSetStateAsync(CIP, true);
// Watchdog
cbWatchdog(0, nullptr);
//lock
lock(WAITID_RUN);
SetForegroundWindow(GuiGetWindowHandle());
@ -907,6 +924,7 @@ static void cbRtrFinalStep()
void cbRtrStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
unsigned char ch = 0x90;
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
MemRead(cip, &ch, 1);
@ -915,11 +933,14 @@ void cbRtrStep()
if(ch == 0xC3 || ch == 0xC2)
cbRtrFinalStep();
else
{
StepOver((void*)cbRtrStep);
}
}
void cbTOCNDStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
if(traceCondition && traceCondition->ContinueTrace())
{
if(bTraceRecordEnabledDuringTrace)
@ -936,6 +957,7 @@ void cbTOCNDStep()
void cbTICNDStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
if(traceCondition && traceCondition->ContinueTrace())
{
if(bTraceRecordEnabledDuringTrace)
@ -952,6 +974,7 @@ void cbTICNDStep()
void cbTIBTStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
// Trace record
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
if(!traceCondition)
@ -976,6 +999,7 @@ void cbTIBTStep()
void cbTOBTStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
// Trace record
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
if(!traceCondition)
@ -1000,6 +1024,7 @@ void cbTOBTStep()
void cbTIITStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
// Trace record
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
if(!traceCondition)
@ -1024,6 +1049,7 @@ void cbTIITStep()
void cbTOITStep()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
// Trace record
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
if(!traceCondition)
@ -1179,6 +1205,8 @@ static void cbExitProcess(EXIT_PROCESS_DEBUG_INFO* ExitProcess)
plugincbcall(CB_EXITPROCESS, &callbackInfo);
//unload main module
SafeSymUnloadModule64(fdProcessInfo->hProcess, pCreateProcessBase);
//history
HistoryClear();
ModClear(); //clear all modules
}
@ -1204,6 +1232,7 @@ static void cbCreateThread(CREATE_THREAD_DEBUG_INFO* CreateThread)
if(settingboolget("Events", "ThreadStart"))
{
HistoryClear();
//update memory map
MemUpdateMap();
//update GUI
@ -1237,6 +1266,7 @@ static void cbExitThread(EXIT_THREAD_DEBUG_INFO* ExitThread)
callbackInfo.ExitThread = ExitThread;
callbackInfo.dwThreadId = dwThreadId;
plugincbcall(CB_EXITTHREAD, &callbackInfo);
HistoryClear();
ThreadExit(dwThreadId);
dprintf("Thread %X exit\n", dwThreadId);
@ -1254,7 +1284,7 @@ static void cbExitThread(EXIT_THREAD_DEBUG_INFO* ExitThread)
}
}
static void cbSystemBreakpoint(void* ExceptionData)
static void cbSystemBreakpoint(void* ExceptionData) // TODO: System breakpoint event shouldn't be dropped
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
@ -2230,6 +2260,7 @@ static void debugLoopFunction(void* lpParameter, bool attach)
DbClose();
ModClear();
ThreadClear();
WatchClear();
TraceRecord.clear();
GuiSetDebugState(stopped);
GuiUpdateAllViews();

View File

@ -4,6 +4,7 @@
@brief Implements the debugger commands class.
*/
#include "x64_dbg.h"
#include "debugger_commands.h"
#include "jit.h"
#include "console.h"
@ -22,6 +23,7 @@
#include "label.h"
#include "bookmark.h"
#include "function.h"
#include "historycontext.h"
#include "taskthread.h"
static bool bScyllaLoaded = false;
@ -116,6 +118,8 @@ CMDRESULT cbDebugStop(int argc, char* argv[])
// HACK: TODO: Don't kill script on debugger ending a process
//scriptreset(); //reset the currently-loaded script
StopDebug();
//history
HistoryClear();
while(waitislocked(WAITID_STOP)) //custom waiting
{
unlock(WAITID_RUN);
@ -124,6 +128,7 @@ CMDRESULT cbDebugStop(int argc, char* argv[])
return STATUS_CONTINUE;
}
// Run
CMDRESULT cbDebugRun(int argc, char* argv[])
{
// Don't "run" twice if the program is already running
@ -139,8 +144,16 @@ CMDRESULT cbDebugRun(int argc, char* argv[])
return STATUS_CONTINUE;
}
// Run and clear history
CMDRESULT cbDebugRun2(int argc, char* argv[])
{
HistoryClear();
return cbDebugRun(argc, argv);
}
CMDRESULT cbDebugErun(int argc, char* argv[])
{
HistoryClear();
if(!dbgisrunning())
dbgsetskipexceptions(true);
else
@ -715,16 +728,16 @@ CMDRESULT cbDebugSetBPGoto(int argc, char* argv[])
}
char cmd[deflen];
_snprintf(cmd, sizeof(cmd), "SetBreakpointCondition %s, 0", argv[1]);
if(!DbgCmdExecDirect(cmd))
if(!_dbg_dbgcmddirectexec(cmd))
return STATUS_ERROR;
_snprintf(cmd, sizeof(cmd), "SetBreakpointCommand %s, \"CIP=%s\"", argv[1], argv[2]);
if(!DbgCmdExecDirect(cmd))
if(!_dbg_dbgcmddirectexec(cmd))
return STATUS_ERROR;
_snprintf(cmd, sizeof(cmd), "SetBreakpointCommandCondition %s, 1", argv[1]);
if(!DbgCmdExecDirect(cmd))
if(!_dbg_dbgcmddirectexec(cmd))
return STATUS_ERROR;
_snprintf(cmd, sizeof(cmd), "SetBreakpointFastResume %s, 0", argv[1]);
if(!DbgCmdExecDirect(cmd))
if(!_dbg_dbgcmddirectexec(cmd))
return STATUS_ERROR;
return STATUS_CONTINUE;
}
@ -1205,6 +1218,8 @@ CMDRESULT cbDebugBplist(int argc, char* argv[])
CMDRESULT cbDebugStepInto(int argc, char* argv[])
{
StepInto((void*)cbStep);
// History
HistoryAdd();
dbgsetstepping(true);
return cbDebugRun(argc, argv);
}
@ -1218,6 +1233,8 @@ CMDRESULT cbDebugeStepInto(int argc, char* argv[])
CMDRESULT cbDebugStepOver(int argc, char* argv[])
{
StepOver((void*)cbStep);
// History
HistoryAdd();
dbgsetstepping(true);
return cbDebugRun(argc, argv);
}
@ -1235,6 +1252,7 @@ CMDRESULT cbDebugSingleStep(int argc, char* argv[])
if(!valfromstring(argv[1], &stepcount))
stepcount = 1;
SingleStep((DWORD)stepcount, (void*)cbStep);
HistoryClear();
dbgsetstepping(true);
return cbDebugRun(argc, argv);
}
@ -1272,6 +1290,7 @@ CMDRESULT cbDebugDisasm(int argc, char* argv[])
CMDRESULT cbDebugRtr(int argc, char* argv[])
{
HistoryClear();
StepOver((void*)cbRtrStep);
cbDebugRun(argc, argv);
return STATUS_CONTINUE;
@ -1285,6 +1304,7 @@ CMDRESULT cbDebugeRtr(int argc, char* argv[])
CMDRESULT cbDebugRunToParty(int argc, char* argv[])
{
HistoryClear();
EXCLUSIVE_ACQUIRE(LockRunToUserCode);
std::vector<MODINFO> AllModules;
ModGetList(AllModules);
@ -1339,6 +1359,7 @@ static CMDRESULT cbDebugConditionalTrace(void* callBack, bool stepOver, int argc
dprintf("Invalid expression \"%s\"\n", argv[1]);
return STATUS_ERROR;
}
HistoryClear();
if(stepOver)
StepOver(callBack);
else
@ -1754,6 +1775,7 @@ CMDRESULT cbDebugSwitchthread(int argc, char* argv[])
}
//switch thread
hActiveThread = ThreadGetHandle((DWORD)threadid);
HistoryClear();
DebugUpdateGuiAsync(GetContextDataEx(hActiveThread, UE_CIP), true);
dputs("Thread switched!");
return STATUS_CONTINUE;

View File

@ -8,6 +8,7 @@
CMDRESULT cbDebugInit(int argc, char* argv[]);
CMDRESULT cbDebugStop(int argc, char* argv[]);
CMDRESULT cbDebugRun(int argc, char* argv[]);
CMDRESULT cbDebugRun2(int argc, char* argv[]);
CMDRESULT cbDebugErun(int argc, char* argv[]);
CMDRESULT cbDebugSetBPXOptions(int argc, char* argv[]);
CMDRESULT cbDebugSetBPX(int argc, char* argv[]);

View File

@ -114,7 +114,7 @@ duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n)
const char* disasmtext(duint addr)
{
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
MemRead(addr, buffer, sizeof(buffer));
Capstone cp;
static char instruction[64] = "";
if(!cp.Disassemble(addr, buffer))
@ -169,17 +169,17 @@ static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg)
switch(op.size)
{
case 1:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 1);
MemRead(value, (unsigned char*)&arg->memvalue, 1);
break;
case 2:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 2);
MemRead(value, (unsigned char*)&arg->memvalue, 2);
break;
case 4:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 4);
MemRead(value, (unsigned char*)&arg->memvalue, 4);
break;
#ifdef _WIN64
case 8:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 8);
MemRead(value, (unsigned char*)&arg->memvalue, 8);
break;
#endif //_WIN64
}
@ -236,8 +236,10 @@ void disasmget(duint addr, DISASM_INSTR* instr)
return;
}
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
disasmget(buffer, addr, instr);
if(MemRead(addr, buffer, sizeof(buffer)))
disasmget(buffer, addr, instr);
else
memset(instr, 0, sizeof(DISASM_INSTR)); // Buffer overflow
}
void disasmprint(duint addr)
@ -369,4 +371,4 @@ int disasmgetsize(duint addr)
if(!MemRead(addr, data, sizeof(data)))
return 1;
return disasmgetsize(addr, (unsigned char*)data);
}
}

View File

@ -0,0 +1,96 @@
#include "historycontext.h"
#include "disasm_helper.h"
#include "memory.h"
#include "console.h"
#include "watch.h"
#include "_exports.h"
duint HistoryMaxCount = 4096;
std::deque<HistoryContext> history;
//This will capture the current instruction
HistoryContext::HistoryContext()
{
DISASM_INSTR instruction;
if(GetFullContextDataEx(hActiveThread, &registers) && MemIsValidReadPtr(registers.cip))
{
disasmget(registers.cip, &instruction);
if(!(memcmp(instruction.instruction, "nop ", 4) == 0 || memcmp(instruction.instruction, "lea ", 4) == 0))
// do not process the memory operands of these instructions, because these instructions do not write to the memory.
{
if(memcmp(instruction.instruction, "push", 4) == 0 || memcmp(instruction.instruction, "call", 4) == 0)
// push and call instruction : save previous content on the stack
{
ChangedData olddata;
olddata.addr = registers.csp - sizeof(duint);
MemRead(olddata.addr, (unsigned char*)olddata.oldvalue, sizeof(duint));
ChangedLocation.push_back(olddata);
}
// TODO: FPU/SSE instructions, ENTER instruction, and possibly other instructions.
// These instructions can write more than sizeof(duint) bytes.
for(int i = 0; i < instruction.argcount; i++)
{
DISASM_ARG & arg = instruction.arg[i];
if(arg.type == DISASM_ARGTYPE::arg_memory)
{
ChangedData olddata;
olddata.addr = arg.value;
memcpy(olddata.oldvalue, &arg.memvalue, sizeof(arg.memvalue));
ChangedLocation.push_back(olddata);
}
}
}
invalid = false;
}
else
invalid = true;
}
void HistoryContext::restore()
{
if(!invalid)
{
for(auto & i : ChangedLocation)
MemWrite(i.addr, i.oldvalue, sizeof(duint));
SetFullContextDataEx(hActiveThread, &registers);
cbWatchdog(0, nullptr);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
}
else
{
HistoryClear();
dputs("Cannot restore last instruction.");
}
}
HistoryContext::~HistoryContext()
{
}
void HistoryAdd()
{
if(history.size() > HistoryMaxCount)
history.pop_front();
history.emplace_back();
}
void HistoryRestore()
{
if(!history.empty())
{
history.back().restore();
history.pop_back();
}
else
dputs("History record is empty");
}
bool HistoryIsEmpty()
{
return history.empty();
}
void HistoryClear()
{
history.clear();
}

34
src/dbg/historycontext.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef HISTORYCONTEXT_H
#define HISTORYCONTEXT_H
#include "debugger.h"
#include <capstone_wrapper.h>
/**
* @brief The class used to hold history context.
**/
class HistoryContext
{
public:
HistoryContext();
~HistoryContext();
HistoryContext(const HistoryContext & copy);
void restore();
protected:
TITAN_ENGINE_CONTEXT_t registers;
struct ChangedData
{
duint addr;
char oldvalue[32];
};
std::vector<ChangedData> ChangedLocation;
bool invalid;
};
void HistoryAdd();
void HistoryRestore();
void HistoryClear();
bool HistoryIsEmpty();
#endif //HISTORY_CONTEXT_H

View File

@ -41,6 +41,7 @@
#include "exhandlerinfo.h"
#include "symbolinfo.h"
#include "argument.h"
#include "historycontext.h"
static bool bRefinit = false;
static int maxFindResults = 5000;
@ -2746,3 +2747,10 @@ CMDRESULT cbInstrExhandlers(int argc, char* argv[])
dputs("Failed to get UnhandledExceptionFilter (loaded symbols for kernelbase.dll?)");
return STATUS_CONTINUE;
}
CMDRESULT cbInstrInstrUndo(int argc, char* argv[])
{
HistoryRestore();
GuiUpdateAllViews();
return STATUS_CONTINUE;
}

View File

@ -98,5 +98,6 @@ CMDRESULT cbInstrBriefcheck(int argc, char* argv[]);
CMDRESULT cbInstrDisableGuiUpdate(int argc, char* argv[]);
CMDRESULT cbInstrEnableGuiUpdate(int argc, char* argv[]);
CMDRESULT cbInstrExhandlers(int argc, char* argv[]);
CMDRESULT cbInstrInstrUndo(int argc, char* argv[]);
#endif // _INSTRUCTION_H

View File

@ -62,6 +62,7 @@ enum SectionLock
LockEncodeMaps,
LockCallstackCache,
LockRunToUserCode,
LockWatch,
LockExpressionFunctions,
// Number of elements in this enumeration. Must always be the last

553
src/dbg/watch.cpp Normal file
View File

@ -0,0 +1,553 @@
#include "watch.h"
#include "console.h"
#include "variable.h"
#include "value.h"
#include "threading.h"
#include "debugger.h"
#include "symbolinfo.h"
#include <Windows.h>
std::map<unsigned int, WatchExpr*> watchexpr;
unsigned int idCounter = 1;
WatchExpr::WatchExpr(const char* name, const char* expression, WATCHVARTYPE type) : expr(expression), varType(type), currValue(0), haveCurrValue(false), watchdogTriggered(false), watchWindow(0)
{
if(!expr.IsValidExpression())
varType = WATCHVARTYPE::TYPE_INVALID;
strcpy_s(this->WatchName, name);
}
duint WatchExpr::getIntValue()
{
duint origVal = currValue;
if(varType == WATCHVARTYPE::TYPE_UINT || varType == WATCHVARTYPE::TYPE_INT || varType == WATCHVARTYPE::TYPE_ASCII || varType == WATCHVARTYPE::TYPE_UNICODE)
{
duint val;
bool ok = expr.Calculate(val, varType == WATCHVARTYPE::TYPE_INT, false);
if(ok)
{
currValue = val;
haveCurrValue = true;
if(getType() != WATCHVARTYPE::TYPE_INVALID)
{
switch(getWatchdogMode())
{
default:
case WATCHDOGMODE::MODE_DISABLED:
break;
case WATCHDOGMODE::MODE_ISTRUE:
if(currValue != 0)
{
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
dprintf("Watchdog %s (expression \"%s\") is triggered at " fhex " ! Original value: " fhex ", New value: " fhex "\n", WatchName, getExpr().c_str(), cip, origVal, currValue);
watchdogTriggered = 1;
}
break;
case WATCHDOGMODE::MODE_ISFALSE:
if(currValue == 0)
{
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
dprintf("Watchdog %s (expression \"%s\") is triggered at " fhex " ! Original value: " fhex ", New value: " fhex "\n", WatchName, getExpr().c_str(), cip, origVal, currValue);
watchdogTriggered = 1;
}
break;
case WATCHDOGMODE::MODE_CHANGED:
if(currValue != origVal || !haveCurrValue)
{
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
dprintf("Watchdog %s (expression \"%s\") is triggered at " fhex " ! Original value: " fhex ", New value: " fhex "\n", WatchName, getExpr().c_str(), cip, origVal, currValue);
watchdogTriggered = 1;
}
break;
case WATCHDOGMODE::MODE_UNCHANGED:
if(currValue == origVal || !haveCurrValue)
{
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
dprintf("Watchdog %s (expression \"%s\") is triggered at " fhex " ! Original value: " fhex ", New value: " fhex "\n", WatchName, getExpr().c_str(), cip, origVal, currValue);
watchdogTriggered = 1;
}
break;
}
}
return val;
}
}
currValue = 0;
haveCurrValue = false;
return 0;
}
bool WatchExpr::modifyExpr(const char* expression, WATCHVARTYPE type)
{
ExpressionParser b(expression);
if(b.IsValidExpression())
{
expr = b;
varType = type;
currValue = 0;
haveCurrValue = false;
return true;
}
else
return false;
}
void WatchExpr::modifyName(const char* newName)
{
strcpy_s(WatchName, newName);
}
// Global functions
// Clear all watch
void WatchClear()
{
if(!watchexpr.empty())
{
for(auto i : watchexpr)
delete i.second;
watchexpr.clear();
}
}
unsigned int WatchAddExprUnlocked(const char* expr, WATCHVARTYPE type)
{
unsigned int newid = InterlockedExchangeAdd(&idCounter, 1);
char DefaultName[MAX_WATCH_NAME_SIZE];
sprintf_s(DefaultName, "Watch %u", newid);
auto temp = watchexpr.emplace(std::make_pair(newid, new WatchExpr(DefaultName, expr, type)));
return temp.second ? newid : 0;
}
unsigned int WatchAddExpr(const char* expr, WATCHVARTYPE type)
{
EXCLUSIVE_ACQUIRE(LockWatch);
unsigned int id = WatchAddExprUnlocked(expr, type);
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
return id;
}
bool WatchModifyExpr(unsigned int id, const char* expr, WATCHVARTYPE type)
{
EXCLUSIVE_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
{
bool success = obj->second->modifyExpr(expr, type);
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
return success;
}
else
return false;
}
void WatchModifyNameUnlocked(unsigned int id, const char* newName)
{
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
{
obj->second->modifyName(newName);
}
}
void WatchModifyName(unsigned int id, const char* newName)
{
EXCLUSIVE_ACQUIRE(LockWatch);
WatchModifyNameUnlocked(id, newName);
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
}
void WatchDelete(unsigned int id)
{
EXCLUSIVE_ACQUIRE(LockWatch);
auto x = watchexpr.find(id);
if(x != watchexpr.end())
{
delete x->second;
watchexpr.erase(x);
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
}
}
void WatchSetWatchdogModeUnlocked(unsigned int id, WATCHDOGMODE mode)
{
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
obj->second->setWatchdogMode(mode);
}
void WatchSetWatchdogMode(unsigned int id, WATCHDOGMODE mode)
{
EXCLUSIVE_ACQUIRE(LockWatch);
WatchSetWatchdogModeUnlocked(id, mode);
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
}
WATCHDOGMODE WatchGetWatchdogEnabled(unsigned int id)
{
SHARED_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
return obj->second->getWatchdogMode();
else
return WATCHDOGMODE::MODE_DISABLED;
}
duint WatchGetUnsignedValue(unsigned int id)
{
EXCLUSIVE_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
return obj->second->getIntValue();
else
return 0;
}
WATCHVARTYPE WatchGetType(unsigned int id)
{
SHARED_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
return obj->second->getType();
else
return WATCHVARTYPE::TYPE_INVALID;
}
unsigned int WatchGetWindow(unsigned int id)
{
SHARED_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
return obj->second->watchWindow;
else
return WATCHVARTYPE::TYPE_INVALID;
}
bool WatchIsWatchdogTriggered(unsigned int id)
{
SHARED_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
return obj->second->watchdogTriggered;
else
return false;
}
void WatchSetWindow(unsigned int id, unsigned int window)
{
EXCLUSIVE_ACQUIRE(LockWatch);
auto obj = watchexpr.find(id);
if(obj != watchexpr.end())
obj->second->watchWindow = window;
EXCLUSIVE_RELEASE();
GuiUpdateWatchView();
}
std::vector<WATCHINFO> WatchGetList()
{
EXCLUSIVE_ACQUIRE(LockWatch);
std::vector<WATCHINFO> watchList;
for(auto & i : watchexpr)
{
WATCHINFO info;
info.value = i.second->getCurrIntValue();
strcpy_s(info.WatchName, i.second->getName());
strcpy_s(info.Expression, i.second->getExpr().c_str());
info.varType = i.second->getType();
info.id = i.first;
info.watchdogMode = i.second->getWatchdogMode();
info.watchdogTriggered = i.second->watchdogTriggered;
info.window = i.second->watchWindow;
watchList.push_back(info);
}
return watchList;
}
// Initialize id counter so that it begin with a unused value
void WatchInitIdCounter()
{
idCounter = 1;
for(auto i : watchexpr)
if(i.first > idCounter)
idCounter = i.first + 1;
}
void WatchCacheSave(JSON root)
{
EXCLUSIVE_ACQUIRE(LockWatch);
JSON watchroot = json_array();
for(auto i : watchexpr)
{
if(i.second->getType() == WATCHVARTYPE::TYPE_INVALID)
continue;
JSON watchitem = json_object();
json_object_set_new(watchitem, "Expression", json_string(i.second->getExpr().c_str()));
json_object_set_new(watchitem, "Name", json_string(i.second->getName()));
switch(i.second->getType())
{
case WATCHVARTYPE::TYPE_INT:
json_object_set_new(watchitem, "DataType", json_string("int"));
break;
case WATCHVARTYPE::TYPE_UINT:
json_object_set_new(watchitem, "DataType", json_string("uint"));
break;
case WATCHVARTYPE::TYPE_FLOAT:
json_object_set_new(watchitem, "DataType", json_string("float"));
break;
case WATCHVARTYPE::TYPE_ASCII:
json_object_set_new(watchitem, "DataType", json_string("ascii"));
break;
case WATCHVARTYPE::TYPE_UNICODE:
json_object_set_new(watchitem, "DataType", json_string("unicode"));
break;
default:
break;
}
switch(i.second->getWatchdogMode())
{
case WATCHDOGMODE::MODE_DISABLED:
json_object_set_new(watchitem, "WatchdogMode", json_string("Disabled"));
break;
case WATCHDOGMODE::MODE_CHANGED:
json_object_set_new(watchitem, "WatchdogMode", json_string("Changed"));
break;
case WATCHDOGMODE::MODE_UNCHANGED:
json_object_set_new(watchitem, "WatchdogMode", json_string("Unchanged"));
break;
case WATCHDOGMODE::MODE_ISTRUE:
json_object_set_new(watchitem, "WatchdogMode", json_string("IsTrue"));
break;
case WATCHDOGMODE::MODE_ISFALSE:
json_object_set_new(watchitem, "WatchdogMode", json_string("IsFalse"));
break;
default:
break;
}
json_array_append_new(watchroot, watchitem);
}
json_object_set_new(root, "Watch", watchroot);
}
void WatchCacheLoad(JSON root)
{
WatchClear();
EXCLUSIVE_ACQUIRE(LockWatch);
JSON watchroot = json_object_get(root, "Watch");
unsigned int i;
JSON val;
if(!watchroot)
return;
json_array_foreach(watchroot, i, val)
{
const char* expr = json_string_value(json_object_get(val, "Expression"));
if(!expr)
continue;
const char* datatype = json_string_value(json_object_get(val, "DataType"));
if(!datatype)
datatype = "uint";
const char* WatchdogMode = json_string_value(json_object_get(val, "WatchdogMode"));
if(!WatchdogMode)
WatchdogMode = "Disabled";
const char* watchname = json_string_value(json_object_get(val, "Name"));
if(!watchname)
watchname = "Watch";
WATCHVARTYPE varType;
WATCHDOGMODE watchdog_mode;
if(strcmp(datatype, "int") == 0)
varType = WATCHVARTYPE::TYPE_INT;
else if(strcmp(datatype, "uint") == 0)
varType = WATCHVARTYPE::TYPE_UINT;
else if(strcmp(datatype, "float") == 0)
varType = WATCHVARTYPE::TYPE_FLOAT;
else if(strcmp(datatype, "ascii") == 0)
varType = WATCHVARTYPE::TYPE_ASCII;
else if(strcmp(datatype, "unicode") == 0)
varType = WATCHVARTYPE::TYPE_UNICODE;
else
continue;
if(strcmp(WatchdogMode, "Disabled") == 0)
watchdog_mode = WATCHDOGMODE::MODE_DISABLED;
else if(strcmp(WatchdogMode, "Changed") == 0)
watchdog_mode = WATCHDOGMODE::MODE_CHANGED;
else if(strcmp(WatchdogMode, "Unchanged") == 0)
watchdog_mode = WATCHDOGMODE::MODE_UNCHANGED;
else if(strcmp(WatchdogMode, "IsTrue") == 0)
watchdog_mode = WATCHDOGMODE::MODE_ISTRUE;
else if(strcmp(WatchdogMode, "IsFalse") == 0)
watchdog_mode = WATCHDOGMODE::MODE_ISFALSE;
else
continue;
unsigned int id = WatchAddExprUnlocked(expr, varType);
WatchModifyNameUnlocked(id, watchname);
WatchSetWatchdogModeUnlocked(id, watchdog_mode);
}
WatchInitIdCounter(); // Initialize id counter so that it begin with a unused value
}
CMDRESULT cbWatchdog(int argc, char* argv[])
{
EXCLUSIVE_ACQUIRE(LockWatch);
bool watchdogTriggered = false;
for(auto j = watchexpr.begin(); j != watchexpr.end(); j++)
{
std::pair<unsigned int, WatchExpr*> i = *j;
i.second->watchdogTriggered = false;
duint intVal = i.second->getIntValue();
watchdogTriggered |= i.second->watchdogTriggered;
}
EXCLUSIVE_RELEASE();
if(watchdogTriggered)
GuiUpdateWatchView();
varset("$result", watchdogTriggered ? 1 : 0, false);
if(watchdogTriggered)
varset("$breakcondition", 1, false);
return STATUS_CONTINUE;
}
CMDRESULT cbAddWatch(int argc, char* argv[])
{
if(argc < 2)
{
dputs("No enough arguments for addwatch\n");
return STATUS_ERROR;
}
WATCHVARTYPE newtype = WATCHVARTYPE::TYPE_UINT;
if(argc > 2)
{
if(_stricmp(argv[2], "uint") == 0)
newtype = WATCHVARTYPE::TYPE_UINT;
else if(_stricmp(argv[2], "int") == 0)
newtype = WATCHVARTYPE::TYPE_INT;
else if(_stricmp(argv[2], "float") == 0)
newtype = WATCHVARTYPE::TYPE_FLOAT;
else if(_stricmp(argv[2], "ascii") == 0)
newtype = WATCHVARTYPE::TYPE_ASCII;
else if(_stricmp(argv[2], "unicode") == 0)
newtype = WATCHVARTYPE::TYPE_UNICODE;
}
unsigned int newid = WatchAddExpr(argv[1], newtype);
varset("$result", newid, false);
return STATUS_CONTINUE;
}
CMDRESULT cbDelWatch(int argc, char* argv[])
{
if(argc < 2)
{
dputs("No enough arguments for delwatch\n");
return STATUS_ERROR;
}
duint id;
bool ok = valfromstring(argv[1], &id);
if(!ok)
{
dputs("Error expression in argument 1.\n");
return STATUS_ERROR;
}
WatchDelete((unsigned int)id);
return STATUS_CONTINUE;
}
CMDRESULT cbSetWatchName(int argc, char* argv[])
{
if(argc < 3)
{
dputs("No enough arguments for SetWatchName");
return STATUS_ERROR;
}
duint id;
bool ok = valfromstring(argv[1], &id);
if(ok)
{
WatchModifyName((unsigned int)id, argv[2]);
return STATUS_CONTINUE;
}
else
{
dputs("Error expression in argument 1.\n");
return STATUS_ERROR;
}
}
CMDRESULT cbSetWatchExpression(int argc, char* argv[])
{
if(argc < 3)
{
dputs("No enough arguments for SetWatchExpression");
return STATUS_ERROR;
}
duint id;
bool ok = valfromstring(argv[1], &id);
if(ok)
{
WATCHVARTYPE varType;
if(argc > 3)
{
if(_stricmp(argv[3], "uint") == 0)
varType = WATCHVARTYPE::TYPE_UINT;
else if(_stricmp(argv[3], "int") == 0)
varType = WATCHVARTYPE::TYPE_INT;
else if(_stricmp(argv[3], "float") == 0)
varType = WATCHVARTYPE::TYPE_FLOAT;
else if(_stricmp(argv[3], "ascii") == 0)
varType = WATCHVARTYPE::TYPE_ASCII;
else if(_stricmp(argv[3], "unicode") == 0)
varType = WATCHVARTYPE::TYPE_UNICODE;
else
varType = WATCHVARTYPE::TYPE_UINT;
}
else
varType = WATCHVARTYPE::TYPE_UINT;
WatchModifyExpr((unsigned int)id, argv[2], varType);
return STATUS_CONTINUE;
}
else
{
dputs("Error expression in argument 1.\n");
return STATUS_ERROR;
}
}
CMDRESULT cbSetWatchdog(int argc, char* argv[])
{
if(argc < 2)
{
dputs("No enough arguments for delwatch\n");
return STATUS_ERROR;
}
duint id;
bool ok = valfromstring(argv[1], &id);
if(!ok)
{
dputs("Error expression in argument 1.\n");
return STATUS_ERROR;
}
WATCHDOGMODE mode;
if(argc > 2)
{
if(_stricmp(argv[2], "disabled") == 0)
mode = WATCHDOGMODE::MODE_DISABLED;
else if(_stricmp(argv[2], "changed") == 0)
mode = WATCHDOGMODE::MODE_CHANGED;
else if(_stricmp(argv[2], "unchanged") == 0)
mode = WATCHDOGMODE::MODE_UNCHANGED;
else if(_stricmp(argv[2], "istrue") == 0)
mode = WATCHDOGMODE::MODE_ISTRUE;
else if(_stricmp(argv[2], "isfalse") == 0)
mode = WATCHDOGMODE::MODE_ISFALSE;
else
{
dputs("Unknown watchdog mode.\n");
return STATUS_ERROR;
}
}
else
mode = (WatchGetWatchdogEnabled((unsigned int)id) == WATCHDOGMODE::MODE_DISABLED) ? WATCHDOGMODE::MODE_CHANGED : WATCHDOGMODE::MODE_DISABLED;
WatchSetWatchdogMode((unsigned int)id, mode);
return STATUS_CONTINUE;
}

79
src/dbg/watch.h Normal file
View File

@ -0,0 +1,79 @@
#include "_global.h"
#include "command.h"
#include "expressionparser.h"
#include "jansson\jansson.h"
#include "..\bridge\bridgemain.h"
class WatchExpr
{
protected:
char WatchName[MAX_WATCH_NAME_SIZE];
ExpressionParser expr;
WATCHDOGMODE watchdogMode;
bool haveCurrValue;
WATCHVARTYPE varType;
duint currValue; // last result of getIntValue()
public:
bool watchdogTriggered;
unsigned int watchWindow;
WatchExpr(const char* name, const char* expression, WATCHVARTYPE type);
~WatchExpr() {};
duint getIntValue(); // evaluate the expression as integer
bool modifyExpr(const char* expression, WATCHVARTYPE type); // modify the expression and data type
void modifyName(const char* newName);
inline WATCHDOGMODE getWatchdogMode()
{
return watchdogMode;
};
inline char* getName()
{
return WatchName;
};
inline void setWatchdogMode(WATCHDOGMODE mode)
{
watchdogMode = mode;
};
inline WATCHVARTYPE getType()
{
return varType;
};
inline duint getCurrIntValue()
{
return currValue;
};
inline const String & getExpr()
{
return expr.GetExpression();
}
inline const bool HaveCurrentValue()
{
return haveCurrValue;
};
};
extern std::map<unsigned int, WatchExpr*> watchexpr;
void WatchClear();
unsigned int WatchAddExpr(const char* expr, WATCHVARTYPE type);
bool WatchModifyExpr(unsigned int id, const char* expr, WATCHVARTYPE type);
void WatchModifyName(unsigned int id, const char* newName);
void WatchDelete(unsigned int id);
void WatchSetWatchdogMode(unsigned int id, bool isEnabled);
bool WatchIsWatchdogTriggered(unsigned int id);
WATCHDOGMODE WatchGetWatchdogMode(unsigned int id);
duint WatchGetUnsignedValue(unsigned int id);
WATCHVARTYPE WatchGetType(unsigned int id);
std::vector<WATCHINFO> WatchGetList();
void WatchCacheSave(JSON root); // Save watch data to database
void WatchCacheLoad(JSON root); // Load watch data from database
CMDRESULT cbWatchdog(int argc, char* argv[]);
CMDRESULT cbAddWatch(int argc, char* argv[]);
CMDRESULT cbDelWatch(int argc, char* argv[]);
CMDRESULT cbSetWatchName(int argc, char* argv[]);
CMDRESULT cbSetWatchExpression(int argc, char* argv[]);
CMDRESULT cbSetWatchdog(int argc, char* argv[]);

View File

@ -14,6 +14,7 @@
#include "x64_dbg.h"
#include "msgqueue.h"
#include "threading.h"
#include "watch.h"
#include "plugin_loader.h"
#include "_dbgfunctions.h"
#include "debugger_commands.h"
@ -26,6 +27,7 @@
#include "error.h"
#include "exception.h"
#include "expressionfunctions.h"
#include "historycontext.h"
static MESSAGE_STACK* gMsgStack = 0;
static HANDLE hCommandLoopThread = 0;
@ -82,7 +84,7 @@ static void registercommands()
dbgcmdnew("StopDebug\1stop\1dbgstop", cbDebugStop, true); //stop debugger
dbgcmdnew("AttachDebugger\1attach", cbDebugAttach, false); //attach
dbgcmdnew("DetachDebugger\1detach", cbDebugDetach, true); //detach
dbgcmdnew("run\1go\1r\1g", cbDebugRun, true); //unlock WAITID_RUN
dbgcmdnew("run\1go\1r\1g", cbDebugRun2, true); //unlock WAITID_RUN
dbgcmdnew("erun\1egun\1er\1eg", cbDebugErun, true); //run + skip first chance exceptions
dbgcmdnew("pause", cbDebugPause, true); //pause debugger
dbgcmdnew("StepInto\1sti", cbDebugStepInto, true); //StepInto
@ -113,6 +115,7 @@ static void registercommands()
dbgcmdnew("skip", cbDebugSkip, true); //skip one instruction
dbgcmdnew("RunToParty", cbDebugRunToParty, true); //Run to code in a party
dbgcmdnew("RunToUserCode\1rtu", cbDebugRtu, true); //Run to user code
dbgcmdnew("InstrUndo", cbInstrInstrUndo, true); //Instruction undo
//breakpoints
dbgcmdnew("bplist", cbDebugBplist, true); //breakpoint list
@ -163,6 +166,14 @@ static void registercommands()
dbgcmdnew("bpgoto", cbDebugSetBPGoto, true);
//watch
dbgcmdnew("AddWatch", cbAddWatch, true); // add watch
dbgcmdnew("DelWatch", cbDelWatch, true); // delete watch
dbgcmdnew("CheckWatchdog", cbWatchdog, true); // Watchdog
dbgcmdnew("SetWatchdog", cbSetWatchdog, true); // Setup watchdog
dbgcmdnew("SetWatchName", cbSetWatchName, true); // Set watch name
dbgcmdnew("SetWatchExpression", cbSetWatchExpression, true); // Set watch expression
//variables
dbgcmdnew("varnew\1var", cbInstrVar, false); //make a variable arg1:name,[arg2:value]
dbgcmdnew("vardel", cbInstrVarDel, false); //delete a variable, arg1:variable name

View File

@ -1,7 +1,6 @@
#ifndef _X64_DBG_H
#define _X64_DBG_H
#include <windows.h>
#include "_global.h"
#ifdef __cplusplus

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">
@ -52,6 +52,7 @@
<ClCompile Include="expressionparser.cpp" />
<ClCompile Include="filehelper.cpp" />
<ClCompile Include="function.cpp" />
<ClCompile Include="historycontext.cpp" />
<ClCompile Include="jit.cpp" />
<ClCompile Include="linearanalysis.cpp" />
<ClCompile Include="FunctionPass.cpp" />
@ -81,6 +82,7 @@
<ClCompile Include="TraceRecord.cpp" />
<ClCompile Include="value.cpp" />
<ClCompile Include="variable.cpp" />
<ClCompile Include="watch.cpp" />
<ClCompile Include="x64_dbg.cpp" />
<ClCompile Include="xrefs.cpp" />
<ClCompile Include="xrefsanalysis.cpp" />
@ -143,6 +145,7 @@
<ClInclude Include="expressionparser.h" />
<ClInclude Include="filehelper.h" />
<ClInclude Include="function.h" />
<ClInclude Include="historycontext.h" />
<ClInclude Include="jit.h" />
<ClInclude Include="keystone\arm.h" />
<ClInclude Include="keystone\arm64.h" />
@ -180,6 +183,7 @@
<ClInclude Include="taskthread.h" />
<ClInclude Include="tcpconnections.h" />
<ClInclude Include="TraceRecord.h" />
<ClInclude Include="watch.h" />
<ClInclude Include="xrefs.h" />
<ClInclude Include="xrefsanalysis.h" />
<ClInclude Include="yara\yara\stream.h" />
@ -417,4 +421,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">
@ -338,6 +338,12 @@
<ClCompile Include="expressionfunctions.cpp">
<Filter>Source Files\Core</Filter>
</ClCompile>
<ClCompile Include="historycontext.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="watch.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64_dbg.h">
@ -760,6 +766,12 @@
<ClInclude Include="datainst_helper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="historycontext.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="watch.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="taskthread.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
@ -767,4 +779,4 @@
<Filter>Header Files\Core</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

View File

@ -574,6 +574,10 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
}
break;
case GUI_UPDATE_WATCH_VIEW:
emit updateWatch();
break;
}
return nullptr;
}

View File

@ -123,6 +123,7 @@ signals:
void focusDisasm();
void focusDump();
void focusStack();
void updateWatch();
private:
QMutex* mBridgeMutex;

View File

@ -527,6 +527,7 @@ void AppearanceDialog::colorInfoListInit()
colorInfoListAppend(tr("Other:"), "", "");
colorInfoListAppend(tr("Current Thread"), "ThreadCurrentColor", "ThreadCurrentBackgroundColor");
colorInfoListAppend(tr("Watch (When Watchdog is Triggered)"), "WatchTriggeredColor", "WatchTriggeredBackgroundColor");
colorInfoListAppend(tr("Memory Map Breakpoint"), "MemoryMapBreakpointColor", "MemoryMapBreakpointBackgroundColor");
colorInfoListAppend(tr("Memory Map %1").arg(ArchValue(tr("EIP"), tr("RIP"))), "MemoryMapCipColor", "MemoryMapCipBackgroundColor");
colorInfoListAppend(tr("Memory Map Section Text"), "MemoryMapSectionTextColor", "");

View File

@ -0,0 +1,35 @@
#include "BrowseDialog.h"
#include "ui_BrowseDialog.h"
#include <QFileDialog>
BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString & text, const QString & filter, const QString & defaultPath, bool save) :
QDialog(parent),
ui(new Ui::BrowseDialog), mFilter(filter), mSave(save)
{
this->setWindowTitle(title);
ui->setupUi(this);
ui->label->setText(text);
ui->lineEdit->setText(defaultPath);
}
BrowseDialog::~BrowseDialog()
{
delete ui;
}
void BrowseDialog::on_browse_clicked()
{
QString file;
if(mSave)
file = QFileDialog::getSaveFileName(this, ui->label->text(), ui->lineEdit->text(), mFilter);
else
file = QFileDialog::getOpenFileName(this, ui->label->text(), ui->lineEdit->text(), mFilter);
if(file.size() != 0)
ui->lineEdit->setText(file);
}
void BrowseDialog::on_ok_clicked()
{
path = ui->lineEdit->text();
accept();
}

View File

@ -0,0 +1,30 @@
#ifndef BROWSEDIALOG_H
#define BROWSEDIALOG_H
#include <QDialog>
namespace Ui
{
class BrowseDialog;
}
class BrowseDialog : public QDialog
{
Q_OBJECT
public:
explicit BrowseDialog(QWidget* parent, const QString & title, const QString & text, const QString & filter, const QString & defaultPath, bool save);
~BrowseDialog();
QString path;
public slots:
void on_browse_clicked();
void on_ok_clicked();
private:
Ui::BrowseDialog* ui;
QString mFilter;
bool mSave;
};
#endif // BROWSEDIALOG_H

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BrowseDialog</class>
<widget class="QDialog" name="BrowseDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>487</width>
<height>97</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Please input the file path.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="browse">
<property name="text">
<string>&amp;Browse...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="ok">
<property name="text">
<string>&amp;OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancel">
<property name="text">
<string>&amp;Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>cancel</sender>
<signal>clicked()</signal>
<receiver>BrowseDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>439</x>
<y>75</y>
</hint>
<hint type="destinationlabel">
<x>243</x>
<y>48</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -18,8 +18,13 @@ CPUMultiDump::CPUMultiDump(CPUDisassembly* disas, int nbCpuDumpTabs, QWidget* pa
this->addTabEx(cpuDump, QIcon(":/icons/images/dump.png"), tr("Dump ") + QString::number(i + 1), QString("Dump ") + QString::number(i + 1));
}
mCurrentCPUDump = (CPUDump*)currentWidget();
mCurrentCPUDump = dynamic_cast<CPUDump*>(currentWidget());
mWatch = new WatchView(this);
//mMaxCPUDumpTabs++;
this->addTabEx(mWatch, QIcon(":/icons/images/geolocation-goto.png"), tr("Watch ") + QString::number(1), QString("Watch 1"));
mWatch->loadColumnFromConfig("Watch1");
connect(this, SIGNAL(currentChanged(int)), this, SLOT(updateCurrentTabSlot(int)));
connect(tabBar(), SIGNAL(OnDoubleClickTabIndex(int)), this, SLOT(openChangeTabTitleDialogSlot(int)));
@ -45,6 +50,8 @@ void CPUMultiDump::getTabNames(QList<QString> & names)
names.clear();
for(int i = 0; i < count(); i++)
{
if(!getNativeName(i).startsWith("Dump "))
continue;
// If empty name, then widget is detached
if(this->tabBar()->tabText(i).length() == 0)
{
@ -76,7 +83,9 @@ int CPUMultiDump::getMaxCPUTabs()
void CPUMultiDump::updateCurrentTabSlot(int tabIndex)
{
mCurrentCPUDump = (CPUDump*)widget(tabIndex);
CPUDump* t = dynamic_cast<CPUDump*>(widget(tabIndex));
if(t)
mCurrentCPUDump = t;
}
void CPUMultiDump::printDumpAtSlot(dsint parVa)
@ -86,6 +95,8 @@ void CPUMultiDump::printDumpAtSlot(dsint parVa)
CPUDump* cpuDump = NULL;
for(int i = 0; i < count(); i++)
{
if(!getNativeName(i).startsWith("Dump "))
continue;
cpuDump = (CPUDump*)widget(i);
cpuDump->historyClear();
cpuDump->addVaToHistory(parVa);
@ -105,10 +116,21 @@ void CPUMultiDump::printDumpAtSlot(dsint parVa)
void CPUMultiDump::printDumpAtNSlot(duint parVa, int index)
{
setCurrentIndex(index);
mCurrentCPUDump = (CPUDump*) widget(index);
mCurrentCPUDump->printDumpAt(parVa);
mCurrentCPUDump->addVaToHistory(parVa);
CPUDump* current = dynamic_cast<CPUDump*>(widget(index));
if(current)
{
current->printDumpAt(parVa);
current->addVaToHistory(parVa);
}
else if(index > 0 && unsigned int(index) < mMaxCPUDumpTabs)
{
current = dynamic_cast<CPUDump*>(widget(index + 1));
if(current)
{
current->printDumpAt(parVa);
current->addVaToHistory(parVa);
}
}
}
void CPUMultiDump::selectionGetSlot(SELECTIONDATA* selectionData)

View File

@ -4,6 +4,7 @@
#include <QWidget>
#include "CPUDump.h"
#include "TabWidget.h"
#include "WatchView.h"
class CPUDump;
@ -35,6 +36,7 @@ private:
bool mInitAllDumpTabs;
uint mMaxCPUDumpTabs;
WatchView* mWatch;
};
#endif // CPUMULTIDUMP_H

View File

@ -0,0 +1,381 @@
#include "FavouriteTools.h"
#include "ui_FavouriteTools.h"
#include "Bridge.h"
#include "BrowseDialog.h"
#include "MainWindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include "MiscUtil.h"
FavouriteTools::FavouriteTools(QWidget* parent) :
QDialog(parent),
ui(new Ui::FavouriteTools)
{
ui->setupUi(this);
//set window flags
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setModal(true);
setupTools("Tool", ui->listTools);
setupTools("Script", ui->listScript);
QStringList tblHeaderCommand;
tblHeaderCommand << tr("Command") << tr("Shortcut");
QTableWidget* list = ui->listCommand;
list->setColumnCount(2);
list->verticalHeader()->setVisible(false);
list->setHorizontalHeaderLabels(tblHeaderCommand);
list->setEditTriggers(QAbstractItemView::NoEditTriggers);
list->setSelectionBehavior(QAbstractItemView::SelectRows);
list->setSelectionMode(QAbstractItemView::SingleSelection);
list->setShowGrid(false);
list->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
list->verticalHeader()->setDefaultSectionSize(15);
char buffer[MAX_SETTING_SIZE];
int i;
std::vector<QString> allCommand;
std::vector<QString> allToolShortcut;
for(i = 1; BridgeSettingGet("Favourite", QString("Command%1").arg(i).toUtf8().constData(), buffer); i++)
{
QString command = QString::fromUtf8(buffer);
QString commandShortcut("");
if(BridgeSettingGet("Favourite", QString("CommandShortcut%1").arg(i).toUtf8().constData(), buffer))
commandShortcut = QString::fromUtf8(buffer);
allCommand.push_back(command);
allToolShortcut.push_back(commandShortcut);
}
i--;
if(!allCommand.empty())
{
list->setRowCount(i);
for(int j = 0; j < i; j++)
{
list->setItem(j, 0, new QTableWidgetItem(allCommand.at(j)));
list->setItem(j, 1, new QTableWidgetItem(allToolShortcut.at(j)));
}
}
originalToolsCount = ui->listTools->rowCount();
originalScriptCount = ui->listScript->rowCount();
originalCommandCount = ui->listCommand->rowCount();
ui->listTools->selectRow(0);
ui->listScript->selectRow(0);
ui->listCommand->selectRow(0);
connect(ui->listTools, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged()));
connect(ui->listScript, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged()));
connect(ui->listCommand, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged()));
}
void FavouriteTools::setupTools(QString name, QTableWidget* list)
{
QStringList tblHeaderTools;
tblHeaderTools << tr("Path") << tr("Shortcut") << tr("Description");
list->setColumnCount(3);
list->verticalHeader()->setVisible(false);
list->setHorizontalHeaderLabels(tblHeaderTools);
list->setEditTriggers(QAbstractItemView::NoEditTriggers);
list->setSelectionBehavior(QAbstractItemView::SelectRows);
list->setSelectionMode(QAbstractItemView::SingleSelection);
list->setShowGrid(false);
list->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
list->verticalHeader()->setDefaultSectionSize(15);
char buffer[MAX_SETTING_SIZE];
int i;
std::vector<QString> allToolPath;
std::vector<QString> allToolShortcut;
std::vector<QString> allToolDescription;
for(i = 1; BridgeSettingGet("Favourite", (name + QString::number(i)).toUtf8().constData(), buffer); i++)
{
QString toolPath = QString::fromUtf8(buffer);
QString toolShortcut("");
QString toolDescription("");
if(BridgeSettingGet("Favourite", (name + "Shortcut" + QString::number(i)).toUtf8().constData(), buffer))
toolShortcut = QString::fromUtf8(buffer);
if(BridgeSettingGet("Favourite", (name + "Description" + QString::number(i)).toUtf8().constData(), buffer))
toolDescription = QString::fromUtf8(buffer);
allToolPath.push_back(toolPath);
allToolShortcut.push_back(toolShortcut);
allToolDescription.push_back(toolDescription);
}
i--;
if(!allToolPath.empty())
{
list->setRowCount(i);
for(int j = 0; j < i; j++)
{
list->setItem(j, 0, new QTableWidgetItem(allToolPath.at(j)));
list->setItem(j, 1, new QTableWidgetItem(allToolShortcut.at(j)));
list->setItem(j, 2, new QTableWidgetItem(allToolDescription.at(j)));
}
}
}
// Events
void FavouriteTools::on_btnAddFavouriteTool_clicked()
{
QString filename;
char buffer[MAX_SETTING_SIZE];
memset(buffer, 0, sizeof(buffer));
BridgeSettingGet("Favourite", "LastToolPath", buffer);
BrowseDialog browse(this, QString("Browse tool"), QString("Enter the path of the tool."), QString("Executable Files (*.exe);;All Files (*.*)"), QString::fromUtf8(buffer), false);
if(browse.exec() != QDialog::Accepted)
return;
filename = browse.path;
BridgeSettingSet("Favourite", "LastToolPath", filename.toUtf8().constData());
int rows = ui->listTools->rowCount();
ui->listTools->setRowCount(rows + 1);
ui->listTools->setItem(rows, 0, new QTableWidgetItem(filename));
ui->listTools->setItem(rows, 1, new QTableWidgetItem(QString()));
ui->listTools->setItem(rows, 2, new QTableWidgetItem(filename));
if(rows == 0)
ui->listTools->selectRow(0);
}
void FavouriteTools::upbutton(QTableWidget* table)
{
int currentRow = table->currentRow();
if(currentRow == 0)
return;
for(int i = 0; i < table->columnCount(); i++)
{
QString prevContent(table->item(currentRow, i)->text());
table->item(currentRow, i)->setText(table->item(currentRow - 1, i)->text());
table->item(currentRow - 1, i)->setText(prevContent);
}
table->selectRow(currentRow - 1);
}
void FavouriteTools::downbutton(QTableWidget* table)
{
int currentRow = table->currentRow();
if(currentRow == table->rowCount() - 1)
return;
for(int i = 0; i < table->columnCount(); i++)
{
QString prevContent(table->item(currentRow, i)->text());
table->item(currentRow, i)->setText(table->item(currentRow + 1, i)->text());
table->item(currentRow + 1, i)->setText(prevContent);
}
table->selectRow(currentRow + 1);
}
void FavouriteTools::on_btnRemoveFavouriteTool_clicked()
{
QTableWidget* table = ui->listTools;
table->removeRow(table->currentRow());
}
void FavouriteTools::on_btnDescriptionFavouriteTool_clicked()
{
QTableWidget* table = ui->listTools;
QString description = table->item(table->currentRow(), 2)->text();
if(SimpleInputBox(this, tr("Enter the description"), description, description))
table->item(table->currentRow(), 2)->setText(description);
}
void FavouriteTools::on_btnUpFavouriteTool_clicked()
{
upbutton(ui->listTools);
}
void FavouriteTools::on_btnDownFavouriteTool_clicked()
{
downbutton(ui->listTools);
}
void FavouriteTools::on_btnAddFavouriteScript_clicked()
{
QString filename;
char buffer[MAX_SETTING_SIZE];
memset(buffer, 0, sizeof(buffer));
BridgeSettingGet("Favourite", "LastScriptPath", buffer);
filename = QFileDialog::getOpenFileName(this, tr("Select script"), QString::fromUtf8(buffer), tr("Script files (*.txt *.scr);;All files (*.*)"));
if(filename.size() == 0)
return;
BridgeSettingSet("Favourite", "LastScriptPath", filename.toUtf8().constData());
int rows = ui->listScript->rowCount();
ui->listScript->setRowCount(rows + 1);
ui->listScript->setItem(rows, 0, new QTableWidgetItem(filename));
ui->listScript->setItem(rows, 1, new QTableWidgetItem(QString("NOT_SET")));
ui->listScript->setItem(rows, 2, new QTableWidgetItem(filename));
if(rows == 0)
ui->listScript->selectRow(0);
}
void FavouriteTools::on_btnRemoveFavouriteScript_clicked()
{
QTableWidget* table = ui->listScript;
table->removeRow(table->currentRow());
}
void FavouriteTools::on_btnDescriptionFavouriteScript_clicked()
{
QTableWidget* table = ui->listScript;
QString description = table->item(table->currentRow(), 2)->text();
if(SimpleInputBox(this, tr("Enter the description"), description, description))
table->item(table->currentRow(), 2)->setText(description);
}
void FavouriteTools::on_btnUpFavouriteScript_clicked()
{
upbutton(ui->listScript);
}
void FavouriteTools::on_btnDownFavouriteScript_clicked()
{
downbutton(ui->listScript);
}
void FavouriteTools::on_btnAddFavouriteCommand_clicked()
{
QString cmd;
if(SimpleInputBox(this, tr("Enter the command that you want to create a shortcut for :"), "", cmd))
{
int rows = ui->listCommand->rowCount();
ui->listCommand->setRowCount(rows + 1);
ui->listCommand->setItem(rows, 0, new QTableWidgetItem(cmd));
ui->listCommand->setItem(rows, 1, new QTableWidgetItem(QString("NOT_SET")));
if(rows == 0)
ui->listCommand->selectRow(0);
}
}
void FavouriteTools::on_btnRemoveFavouriteCommand_clicked()
{
QTableWidget* table = ui->listCommand;
table->removeRow(table->currentRow());
}
void FavouriteTools::on_btnUpFavouriteCommand_clicked()
{
upbutton(ui->listCommand);
}
void FavouriteTools::on_btnDownFavouriteCommand_clicked()
{
downbutton(ui->listCommand);
}
void FavouriteTools::onListSelectionChanged()
{
QTableWidget* table = qobject_cast<QTableWidget*>(sender());
if(table == nullptr)
throw std::exception("No active table!");
QModelIndexList indexes = table->selectionModel()->selectedRows();
if(indexes.count() < 1)
return;
ui->shortcutEdit->setErrorState(false);
currentShortcut = QKeySequence(table->item(table->currentRow(), 1)->text());
ui->shortcutEdit->setText(currentShortcut.toString(QKeySequence::NativeText));
}
void FavouriteTools::on_shortcutEdit_askForSave()
{
QTableWidget* table;
switch(ui->tabWidget->currentIndex())
{
case 0:
table = ui->listTools;
break;
case 1:
table = ui->listScript;
break;
case 2:
table = ui->listCommand;
break;
default:
throw std::exception("No active table!");
}
const QKeySequence newKey = ui->shortcutEdit->getKeysequence();
if(newKey != currentShortcut)
{
bool good = true;
if(!newKey.isEmpty())
{
for(auto i = Config()->Shortcuts.cbegin(); i != Config()->Shortcuts.cend(); ++i)
{
if(i.value().Hotkey == newKey) //newkey is trying to override a global shortcut
{
good = false;
break;
}
}
}
if(good)
{
QString keyText = "";
if(!newKey.isEmpty())
keyText = newKey.toString(QKeySequence::NativeText);
table->item(table->currentRow(), 1)->setText(keyText);
ui->shortcutEdit->setErrorState(false);
}
else
{
ui->shortcutEdit->setErrorState(true);
}
}
}
void FavouriteTools::on_btnOK_clicked()
{
for(int i = 1; i <= ui->listTools->rowCount(); i++)
{
BridgeSettingSet("Favourite", QString("Tool%1").arg(i).toUtf8().constData(), ui->listTools->item(i - 1, 0)->text().toUtf8().constData());
BridgeSettingSet("Favourite", QString("ToolShortcut%1").arg(i).toUtf8().constData(), ui->listTools->item(i - 1, 1)->text().toUtf8().constData());
BridgeSettingSet("Favourite", QString("ToolDescription%1").arg(i).toUtf8().constData(), ui->listTools->item(i - 1, 2)->text().toUtf8().constData());
}
if(ui->listTools->rowCount() == 0)
{
BridgeSettingSet("Favourite", "Tool1", "");
BridgeSettingSet("Favourite", "ToolShortcut1", "");
BridgeSettingSet("Favourite", "ToolDescription1", "");
}
else
for(int i = ui->listTools->rowCount() + 1; i <= originalToolsCount; i++)
{
BridgeSettingSet("Favourite", QString("Tool%1").arg(i).toUtf8().constData(), "");
BridgeSettingSet("Favourite", QString("ToolShortcut%1").arg(i).toUtf8().constData(), "");
BridgeSettingSet("Favourite", QString("ToolDescription%1").arg(i).toUtf8().constData(), "");
}
for(int i = 1; i <= ui->listScript->rowCount(); i++)
{
BridgeSettingSet("Favourite", QString("Script%1").arg(i).toUtf8().constData(), ui->listScript->item(i - 1, 0)->text().toUtf8().constData());
BridgeSettingSet("Favourite", QString("ScriptShortcut%1").arg(i).toUtf8().constData(), ui->listScript->item(i - 1, 1)->text().toUtf8().constData());
BridgeSettingSet("Favourite", QString("ScriptDescription%1").arg(i).toUtf8().constData(), ui->listScript->item(i - 1, 2)->text().toUtf8().constData());
}
if(ui->listScript->rowCount() == 0)
{
BridgeSettingSet("Favourite", "Script1", "");
BridgeSettingSet("Favourite", "ScriptShortcut1", "");
BridgeSettingSet("Favourite", "ScriptDescription1", "");
}
else
for(int i = ui->listScript->rowCount() + 1; i <= originalScriptCount; i++)
{
BridgeSettingSet("Favourite", QString("Script%1").arg(i).toUtf8().constData(), "");
BridgeSettingSet("Favourite", QString("ScriptShortcut%1").arg(i).toUtf8().constData(), "");
BridgeSettingSet("Favourite", QString("ScriptDescription%1").arg(i).toUtf8().constData(), "");
}
for(int i = 1; i <= ui->listCommand->rowCount(); i++)
{
BridgeSettingSet("Favourite", QString("Command%1").arg(i).toUtf8().constData(), ui->listCommand->item(i - 1, 0)->text().toUtf8().constData());
BridgeSettingSet("Favourite", QString("CommandShortcut%1").arg(i).toUtf8().constData(), ui->listCommand->item(i - 1, 1)->text().toUtf8().constData());
}
if(ui->listCommand->rowCount() == 0)
{
BridgeSettingSet("Favourite", "Command1", "");
BridgeSettingSet("Favourite", "CommandShortcut1", "");
}
else
for(int i = ui->listCommand->rowCount() + 1; i <= originalCommandCount; i++)
{
BridgeSettingSet("Favourite", QString("Command%1").arg(i).toUtf8().constData(), "");
BridgeSettingSet("Favourite", QString("CommandShortcut%1").arg(i).toUtf8().constData(), "");
}
this->done(QDialog::Accepted);
}
FavouriteTools::~FavouriteTools()
{
delete ui;
}

View File

@ -0,0 +1,50 @@
#ifndef FAVOURITETOOLS_H
#define FAVOURITETOOLS_H
#include <QDialog>
#include <QTableWidget>
namespace Ui
{
class FavouriteTools;
}
class FavouriteTools : public QDialog
{
Q_OBJECT
public:
explicit FavouriteTools(QWidget* parent = 0);
~FavouriteTools();
public slots:
void on_btnAddFavouriteTool_clicked();
void on_btnRemoveFavouriteTool_clicked();
void on_btnDescriptionFavouriteTool_clicked();
void on_btnUpFavouriteTool_clicked();
void on_btnDownFavouriteTool_clicked();
void on_btnAddFavouriteScript_clicked();
void on_btnRemoveFavouriteScript_clicked();
void on_btnDescriptionFavouriteScript_clicked();
void on_btnUpFavouriteScript_clicked();
void on_btnDownFavouriteScript_clicked();
void on_btnAddFavouriteCommand_clicked();
void on_btnRemoveFavouriteCommand_clicked();
void on_btnUpFavouriteCommand_clicked();
void on_btnDownFavouriteCommand_clicked();
void onListSelectionChanged();
void on_shortcutEdit_askForSave();
void on_btnOK_clicked();
private:
Ui::FavouriteTools* ui;
QKeySequence currentShortcut;
int originalToolsCount;
int originalScriptCount;
int originalCommandCount;
void upbutton(QTableWidget* table);
void downbutton(QTableWidget* table);
void setupTools(QString name, QTableWidget* list);
};
#endif // FAVOURITETOOLS_H

View File

@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FavouriteTools</class>
<widget class="QDialog" name="FavouriteTools">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Favourites</string>
</property>
<property name="windowIcon">
<iconset resource="../../resource.qrc">
<normaloff>:/icons/images/star.png</normaloff>:/icons/images/star.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabFavouriteTool">
<attribute name="title">
<string>Tools</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QTableWidget" name="listTools"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="btnAddFavouriteTool">
<property name="text">
<string>&amp;Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveFavouriteTool">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDescriptionFavouriteTool">
<property name="text">
<string>De&amp;scription...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpFavouriteTool">
<property name="text">
<string>&amp;Up</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDownFavouriteTool">
<property name="text">
<string>&amp;Down</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabFavouriteScript">
<attribute name="title">
<string>Script</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTableWidget" name="listScript"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="btnAddFavouriteScript">
<property name="text">
<string>&amp;Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveFavouriteScript">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDescriptionFavouriteScript">
<property name="text">
<string>De&amp;scription...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpFavouriteScript">
<property name="text">
<string>&amp;Up</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDownFavouriteScript">
<property name="text">
<string>&amp;Down</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabFavouriteCommand">
<attribute name="title">
<string>Command</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QTableWidget" name="listCommand"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QPushButton" name="btnAddFavouriteCommand">
<property name="text">
<string>&amp;Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveFavouriteCommand">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpFavouriteCommand">
<property name="text">
<string>&amp;Up</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDownFavouriteCommand">
<property name="text">
<string>&amp;Down</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Shortcut</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="ShortcutEdit" name="shortcutEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnOK">
<property name="text">
<string>&amp;OK</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>&amp;Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ShortcutEdit</class>
<extends>QLineEdit</extends>
<header>ShortcutEdit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../resource.qrc"/>
</resources>
<connections>
<connection>
<sender>btnCancel</sender>
<signal>clicked()</signal>
<receiver>FavouriteTools</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>352</x>
<y>378</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>199</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -71,7 +71,7 @@ void LineEditDialog::on_textEdit_textChanged(const QString & arg1)
int ct = arg1.size() - (int) this->fixed_size;
if(ct > 0)
symbolct = "+";
ui->label->setText(QString("<font color='red'>") + QString("CT: ") + symbolct + QString::number(ct) + QString("</font>"));
ui->label->setText(tr("<font color='red'>CT: %1%2</font>").arg(symbolct).arg(ct));
}
else
{

View File

@ -14,6 +14,7 @@
#include "LineEditDialog.h"
#include "StringUtil.h"
#include "MiscUtil.h"
#include "FavouriteTools.h"
QString MainWindow::windowTitle = "";
@ -241,6 +242,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(ui->actionTRTOBT, SIGNAL(triggered()), this, SLOT(execTRTOBT()));
connect(ui->actionTRTIIT, SIGNAL(triggered()), this, SLOT(execTRTIIT()));
connect(ui->actionTRTOIT, SIGNAL(triggered()), this, SLOT(execTRTOIT()));
connect(ui->actionInstrUndo, SIGNAL(triggered()), this, SLOT(execInstrUndo()));
connect(ui->actionSkipNextInstruction, SIGNAL(triggered()), this, SLOT(execSkip()));
connect(ui->actionScript, SIGNAL(triggered()), this, SLOT(displayScriptWidget()));
connect(ui->actionRunSelection, SIGNAL(triggered()), this, SLOT(runSelection()));
@ -271,6 +273,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(ui->actionSEHChain, SIGNAL(triggered()), this, SLOT(displaySEHChain()));
connect(ui->actionDonate, SIGNAL(triggered()), this, SLOT(donate()));
connect(ui->actionReportBug, SIGNAL(triggered()), this, SLOT(reportBug()));
connect(ui->actionCrashDump, SIGNAL(triggered()), this, SLOT(crashDump()));
connect(ui->actionAttach, SIGNAL(triggered()), this, SLOT(displayAttach()));
connect(ui->actionDetach, SIGNAL(triggered()), this, SLOT(detach()));
connect(ui->actionChangeCommandLine, SIGNAL(triggered()), this, SLOT(changeCommandLine()));
@ -292,16 +295,18 @@ MainWindow::MainWindow(QWidget* parent)
connect(mTabWidget, SIGNAL(tabMovedTabWidget(int, int)), this, SLOT(tabMovedSlot(int, int)));
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcuts()));
// Setup favourite tools menu
updateFavouriteTools();
// Set default setttings (when not set)
SettingsDialog defaultSettings;
lastException = 0;
defaultSettings.SaveSettings();
// Don't need to set shortcuts because the code above will signal refreshShortcuts()
// Create updatechecker
mUpdateChecker = new UpdateChecker(this);
refreshShortcuts();
// Setup close thread and dialog
bCanClose = false;
mCloseThread = new MainWindowCloseThread(this);
@ -466,13 +471,17 @@ void MainWindow::refreshShortcuts()
setGlobalShortcut(ui->actionTocnd, ConfigShortcut("DebugTraceOverConditional"));
setGlobalShortcut(ui->actionTRBit, ConfigShortcut("DebugEnableTraceRecordBit"));
setGlobalShortcut(ui->actionTRNone, ConfigShortcut("DebugTraceRecordNone"));
setGlobalShortcut(ui->actionInstrUndo, ConfigShortcut("DebugInstrUndo"));
setGlobalShortcut(ui->actionScylla, ConfigShortcut("PluginsScylla"));
setGlobalShortcut(actionManageFavourites, ConfigShortcut("FavouritesManage"));
setGlobalShortcut(ui->actionSettings, ConfigShortcut("OptionsPreferences"));
setGlobalShortcut(ui->actionAppearance, ConfigShortcut("OptionsAppearance"));
setGlobalShortcut(ui->actionShortcuts, ConfigShortcut("OptionsShortcuts"));
setGlobalShortcut(ui->actionTopmost, ConfigShortcut("OptionsTopmost"));
setGlobalShortcut(ui->actionReloadStylesheet, ConfigShortcut("OptionsReloadStylesheet"));
setGlobalShortcut(ui->actionAbout, ConfigShortcut("HelpAbout"));
setGlobalShortcut(ui->actionDonate, ConfigShortcut("HelpDonate"));
@ -480,6 +489,7 @@ void MainWindow::refreshShortcuts()
setGlobalShortcut(ui->actionCalculator, ConfigShortcut("HelpCalculator"));
setGlobalShortcut(ui->actionReportBug, ConfigShortcut("HelpReportBug"));
setGlobalShortcut(ui->actionManual, ConfigShortcut("HelpManual"));
setGlobalShortcut(ui->actionCrashDump, ConfigShortcut("HelpCrashDump"));
setGlobalShortcut(ui->actionStrings, ConfigShortcut("ActionFindStrings"));
setGlobalShortcut(ui->actionCalls, ConfigShortcut("ActionFindIntermodularCalls"));
@ -652,6 +662,11 @@ void MainWindow::execTRTOIT()
DbgCmdExec("toit");
}
void MainWindow::execInstrUndo()
{
DbgCmdExec("InstrUndo");
}
void MainWindow::execTicnd()
{
if(!DbgIsDebugging())
@ -1158,10 +1173,7 @@ void MainWindow::patchWindow()
{
if(!DbgIsDebugging())
{
QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("Patches cannot be shown when not debugging..."));
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
SimpleErrorBox(this, tr("Error!"), tr("Patches cannot be shown when not debugging..."));
return;
}
GuiUpdatePatches();
@ -1242,6 +1254,24 @@ void MainWindow::reportBug()
QDesktopServices::openUrl(QUrl("http://report.x64dbg.com"));
}
void MainWindow::crashDump()
{
QMessageBox msg(QMessageBox::Critical, tr("Generate crash dump"), tr("This action will crash the debugger and generate a crash dump. You will LOSE ALL YOUR DATA. Do you really want to continue?"));
msg.setWindowIcon(QIcon(":/icons/images/fatal-error.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msg.setDefaultButton(QMessageBox::Cancel);
if(msg.exec() != QMessageBox::Ok)
return;
// Fatal error
__debugbreak();
// Congratulations! We survived a fatal error!
SimpleWarningBox(this, "Have fun debugging the debugger!", "Debugger detected!");
}
void MainWindow::displayAttach()
{
AttachDialog attach(this);
@ -1283,18 +1313,12 @@ void MainWindow::changeCommandLine()
return; //pressed cancel
if(!DbgFunctions()->SetCmdline((char*)mLineEdit.editText.toUtf8().constData()))
{
QMessageBox msg(QMessageBox::Warning, tr("Error!"), tr("Could not set command line!"));
msg.setWindowIcon(QIcon(":/icons/images/compile-warning.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
}
SimpleErrorBox(this, tr("Error!"), tr("Could not set command line!"));
else
{
DbgFunctions()->MemUpdateMap();
GuiUpdateMemoryView();
GuiAddStatusBarMessage(QString("New command line: " + mLineEdit.editText + "\n").toUtf8().constData());
GuiAddStatusBarMessage((tr("New command line: ") + mLineEdit.editText + "\n").toUtf8().constData());
}
}
@ -1404,3 +1428,108 @@ void MainWindow::displayHandlesWidget()
{
showQWidgetTab(mHandlesView);
}
void MainWindow::manageFavourites()
{
FavouriteTools favToolsDialog(this);
favToolsDialog.exec();
updateFavouriteTools();
}
void MainWindow::updateFavouriteTools()
{
char buffer[MAX_SETTING_SIZE];
bool isanythingexists = false;
ui->menuFavourites->clear();
for(unsigned int i = 1; BridgeSettingGet("Favourite", QString("Tool%1").arg(i).toUtf8().constData(), buffer); i++)
{
QString exePath = QString::fromUtf8(buffer);
QAction* newAction = new QAction(this);
newAction->setData(QVariant(QString("Tool,%1").arg(exePath)));
if(BridgeSettingGet("Favourite", QString("ToolShortcut%1").arg(i).toUtf8().constData(), buffer))
if(*buffer && strcmp(buffer, "NOT_SET") != 0)
setGlobalShortcut(newAction, QKeySequence(QString::fromUtf8(buffer)));
if(BridgeSettingGet("Favourite", QString("ToolDescription%1").arg(i).toUtf8().constData(), buffer))
newAction->setText(QString::fromUtf8(buffer));
else
newAction->setText(exePath);
connect(newAction, SIGNAL(triggered()), this, SLOT(clickFavouriteTool()));
ui->menuFavourites->addAction(newAction);
isanythingexists = true;
}
if(isanythingexists)
{
isanythingexists = false;
ui->menuFavourites->addSeparator();
}
for(unsigned int i = 1; BridgeSettingGet("Favourite", QString("Script%1").arg(i).toUtf8().constData(), buffer); i++)
{
QString scriptPath = QString::fromUtf8(buffer);
QAction* newAction = new QAction(this);
newAction->setData(QVariant(QString("Script,%1").arg(scriptPath)));
if(BridgeSettingGet("Favourite", QString("ScriptShortcut%1").arg(i).toUtf8().constData(), buffer))
if(*buffer && strcmp(buffer, "NOT_SET") != 0)
setGlobalShortcut(newAction, QKeySequence(QString::fromUtf8(buffer)));
if(BridgeSettingGet("Favourite", QString("ScriptDescription%1").arg(i).toUtf8().constData(), buffer))
newAction->setText(QString::fromUtf8(buffer));
else
newAction->setText(scriptPath);
connect(newAction, SIGNAL(triggered()), this, SLOT(clickFavouriteTool()));
ui->menuFavourites->addAction(newAction);
isanythingexists = true;
}
if(isanythingexists)
{
isanythingexists = false;
ui->menuFavourites->addSeparator();
}
for(unsigned int i = 1; BridgeSettingGet("Favourite", QString("Command%1").arg(i).toUtf8().constData(), buffer); i++)
{
QAction* newAction = new QAction(QString::fromUtf8(buffer), this);
newAction->setData(QVariant(QString("Command")));
if(BridgeSettingGet("Favourite", QString("CommandShortcut%1").arg(i).toUtf8().constData(), buffer))
if(*buffer && strcmp(buffer, "NOT_SET") != 0)
setGlobalShortcut(newAction, QKeySequence(QString::fromUtf8(buffer)));
connect(newAction, SIGNAL(triggered()), this, SLOT(clickFavouriteTool()));
ui->menuFavourites->addAction(newAction);
isanythingexists = true;
}
if(isanythingexists)
ui->menuFavourites->addSeparator();
actionManageFavourites = new QAction(QIcon(":/icons/images/star.png"), tr("Manage Favourite Tools"), this);
ui->menuFavourites->addAction(actionManageFavourites);
setGlobalShortcut(actionManageFavourites, ConfigShortcut("FavouritesManage"));
connect(ui->menuFavourites->actions().last(), SIGNAL(triggered()), this, SLOT(manageFavourites()));
}
void MainWindow::clickFavouriteTool()
{
QAction* action = qobject_cast<QAction*>(sender());
if(action == nullptr)
throw std::exception("Bad favourite tool shortcut action");
QString data = action->data().toString();
if(data.startsWith("Tool,"))
{
QString toolPath = data.mid(5);
duint PID = DbgValFromString("$pid");
toolPath.replace(QString("%PID%"), QString::number(PID), Qt::CaseInsensitive);
PROCESS_INFORMATION procinfo;
STARTUPINFO startupinfo;
memset(&procinfo, 0, sizeof(PROCESS_INFORMATION));
memset(&startupinfo, 0, sizeof(startupinfo));
startupinfo.cb = sizeof(startupinfo);
CreateProcessW(nullptr, (LPWSTR)toolPath.toStdWString().c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupinfo, &procinfo);
CloseHandle(procinfo.hThread);
CloseHandle(procinfo.hProcess);
}
else if(data.startsWith("Script,"))
{
QString scriptPath = data.mid(7);
DbgScriptUnload();
DbgScriptLoad(scriptPath.toUtf8().constData());
}
else if(data.compare("Command") == 0)
{
DbgCmdExec(action->text().toUtf8().constData());
}
}

View File

@ -84,6 +84,7 @@ public slots:
void execTRTOBT();
void execTRTIIT();
void execTRTOIT();
void execInstrUndo();
void displayCpuWidget();
void displaySymbolWidget();
void displaySourceViewWidget();
@ -116,6 +117,7 @@ public slots:
void displayBookmarks();
void displayFunctions();
void checkUpdates();
void crashDump();
void displayCallstack();
void displaySEHChain();
void setGlobalShortcut(QAction* action, const QKeySequence & key);
@ -140,6 +142,9 @@ public slots:
void dbgStateChangedSlot(DBGSTATE state);
void displayNotesWidget();
void displayHandlesWidget();
void manageFavourites();
void updateFavouriteTools();
void clickFavouriteTool();
private:
Ui::MainWindow* ui;
@ -175,6 +180,8 @@ private:
int mMaxMRU;
unsigned int lastException;
QAction* actionManageFavourites;
void loadMRUList(int maxItems);
void saveMRUList();
void addMRUEntry(QString entry);

View File

@ -114,6 +114,7 @@
<addaction name="actionSkipNextInstruction"/>
<addaction name="separator"/>
<addaction name="menuTrace_record"/>
<addaction name="actionInstrUndo"/>
<addaction name="separator"/>
<addaction name="actionCommand"/>
<addaction name="separator"/>
@ -131,6 +132,8 @@
<addaction name="actionManual"/>
<addaction name="actionFaq"/>
<addaction name="actionAbout"/>
<addaction name="separator"/>
<addaction name="actionCrashDump"/>
</widget>
<widget class="QMenu" name="menuPlugins">
<property name="title">
@ -148,10 +151,16 @@
<addaction name="actionTopmost"/>
<addaction name="actionReloadStylesheet"/>
</widget>
<widget class="QMenu" name="menuFavourites">
<property name="title">
<string>Favourites</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
<addaction name="menuDebug"/>
<addaction name="menuPlugins"/>
<addaction name="menuFavourites"/>
<addaction name="menuOptions"/>
<addaction name="menuHelp"/>
</widget>
@ -898,6 +907,25 @@
<string>Run until e&amp;xpression</string>
</property>
</action>
<action name="actionInstrUndo">
<property name="text">
<string>Undo last instruction</string>
</property>
</action>
<action name="actionCrashDump">
<property name="icon">
<iconset resource="../../resource.qrc">
<normaloff>:/icons/images/fatal-error.png</normaloff>:/icons/images/fatal-error.png</iconset>
</property>
<property name="text">
<string>Generate crash dump</string>
</property>
</action>
<action name="actionManageFavourite">
<property name="text">
<string>&amp;Manage Favourite Tools...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -0,0 +1,242 @@
#include "Bridge.h"
#include "WatchView.h"
#include "CPUMultiDump.h"
#include "MiscUtil.h"
WatchView::WatchView(CPUMultiDump* parent) : StdTable(parent)
{
int charWidth = getCharWidth();
addColumnAt(8 + charWidth * 12, tr("Name"), false);
addColumnAt(8 + charWidth * 20, tr("Expression"), false);
addColumnAt(8 + charWidth * sizeof(duint) * 2, tr("Value"), false);
addColumnAt(8 + charWidth * 8, tr("Type"), false);
addColumnAt(150, tr("Watchdog Mode"), false);
addColumnAt(30, tr("ID"), false);
connect(Bridge::getBridge(), SIGNAL(updateWatch()), this, SLOT(updateWatch()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
updateColors();
setupContextMenu();
setDrawDebugOnly(true);
}
void WatchView::updateWatch()
{
if(!DbgIsDebugging())
{
setRowCount(0);
return;
}
BridgeList<WATCHINFO> WatchList;
DbgGetWatchList(&WatchList);
setRowCount(WatchList.Count());
for(int i = 0; i < WatchList.Count(); i++)
{
setCellContent(i, 0, QString::fromUtf8(WatchList[i].WatchName));
setCellContent(i, 1, QString::fromUtf8(WatchList[i].Expression));
switch(WatchList[i].varType)
{
case WATCHVARTYPE::TYPE_UINT:
setCellContent(i, 3, "UINT");
setCellContent(i, 2, ToPtrString(WatchList[i].value));
break;
case WATCHVARTYPE::TYPE_INT:
setCellContent(i, 3, "INT");
setCellContent(i, 2, QString::number((dsint)WatchList[i].value));
break;
case WATCHVARTYPE::TYPE_FLOAT:
setCellContent(i, 3, "FLOAT");
setCellContent(i, 2, QString::number(*(float*)&WatchList[i].value));
break;
case WATCHVARTYPE::TYPE_ASCII:
setCellContent(i, 3, "ASCII");
{
char buffer[128];
// zero the buffer
memset(buffer, 0, sizeof(buffer));
if(DbgMemRead(WatchList[i].value, (unsigned char*)buffer, sizeof(buffer) - 1))
{
// convert the ASCII string to QString
QString text = QString::fromLocal8Bit(buffer);
if(strlen(buffer) == sizeof(buffer) - 1)
text.append("...");
// remove CRLF
text.replace(QChar('\x13'), "\\r");
text.replace(QChar('\x10'), "\\n");
setCellContent(i, 2, text);
}
else
setCellContent(i, 2, tr("%1 is not readable.").arg(ToPtrString(WatchList[i].value)));
}
break;
case WATCHVARTYPE::TYPE_UNICODE:
setCellContent(i, 3, "UNICODE");
{
unsigned short buffer[128];
// zero the buffer
memset(buffer, 0, sizeof(buffer));
if(DbgMemRead(WatchList[i].value, (unsigned char*)buffer, sizeof(buffer) - sizeof(unsigned short)))
{
QString text = QString::fromUtf16(buffer);
size_t size = text.size();
// Check if the last character is an incomplete UTF-16 surrogate.
if(text.at(text.size() - 1).isHighSurrogate())
text.chop(text.size() - 1); // Delete the incomplete surrogate.
// Check if something is truncated.
if(size == sizeof(buffer) / sizeof(unsigned short) - 1)
text.append("...");
// remove CRLF
text.replace(QChar('\x13'), "\\r");
text.replace(QChar('\x10'), "\\n");
setCellContent(i, 2, text);
}
else
setCellContent(i, 2, tr("%1 is not readable.").arg(ToPtrString(WatchList[i].value)));
}
break;
case WATCHVARTYPE::TYPE_INVALID:
default:
setCellContent(i, 3, "INVALID");
setCellContent(i, 2, "");
break;
}
switch(WatchList[i].watchdogMode)
{
case WATCHDOGMODE::MODE_DISABLED:
default:
setCellContent(i, 4, tr("Disabled"));
break;
case WATCHDOGMODE::MODE_CHANGED:
setCellContent(i, 4, tr("Changed"));
break;
case WATCHDOGMODE::MODE_ISTRUE:
setCellContent(i, 4, tr("Is true"));
break;
case WATCHDOGMODE::MODE_ISFALSE:
setCellContent(i, 4, tr("Is false"));
break;
case WATCHDOGMODE::MODE_UNCHANGED:
setCellContent(i, 4, tr("Not changed"));
break;
}
setCellContent(i, 5, QString::number(WatchList[i].id));
}
reloadData();
}
void WatchView::updateColors()
{
mWatchTriggeredColor = QPen(ConfigColor("WatchTriggeredColor"));
mWatchTriggeredBackgroundColor = QBrush(ConfigColor("WatchTriggeredBackgroundColor"));
StdTable::updateColors();
}
void WatchView::setupContextMenu()
{
mMenu = new MenuBuilder(this, [](QMenu*)
{
return DbgIsDebugging();
});
mMenu->addAction(makeAction(tr("&Add..."), SLOT(addWatchSlot())));
mMenu->addAction(makeAction(tr("&Delete"), SLOT(delWatchSlot())));
mMenu->addAction(makeAction(tr("Rename"), SLOT(renameWatchSlot())));
mMenu->addAction(makeAction(tr("&Edit..."), SLOT(editWatchSlot())));
QMenu* watchdogMenu = new QMenu(tr("Watchdog"), this);
watchdogMenu->addAction(makeAction(QIcon(":/icons/images/close-all-tabs.png"), tr("Disabled"), SLOT(watchdogDisableSlot())));
watchdogMenu->addSeparator();
watchdogMenu->addAction(makeAction(tr("Changed"), SLOT(watchdogChangedSlot())));
watchdogMenu->addAction(makeAction(tr("Not changed"), SLOT(watchdogUnchangedSlot())));
watchdogMenu->addAction(makeAction(tr("Is true"), SLOT(watchdogIsTrueSlot())));
watchdogMenu->addAction(makeAction(tr("Is false"), SLOT(watchdogIsFalseSlot())));
mMenu->addMenu(watchdogMenu);
}
QString WatchView::getSelectedId()
{
return getCellContent(getInitialSelection(), 5);
}
QString WatchView::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h)
{
QString ret = StdTable::paintContent(painter, rowBase, rowOffset, col, x, y, w, h);
const dsint row = rowBase + rowOffset;
if(row != getInitialSelection() && DbgFunctions()->WatchIsWatchdogTriggered(getCellContent(row, 5).toUInt()))
{
painter->fillRect(QRect(x, y, w, h), mWatchTriggeredBackgroundColor);
painter->setPen(mWatchTriggeredColor); //white text
painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, ret);
return "";
}
else
return ret;
}
//SLOTS
void WatchView::contextMenuSlot(const QPoint & pos)
{
QMenu wMenu(this);
mMenu->build(&wMenu);
wMenu.exec(mapToGlobal(pos));
}
void WatchView::addWatchSlot()
{
QString name;
if(SimpleInputBox(this, tr("Enter the expression to watch"), "", name))
DbgCmdExecDirect(QString("AddWatch ").append(name).toUtf8().constData());
updateWatch();
}
void WatchView::delWatchSlot()
{
DbgCmdExecDirect(QString("DelWatch ").append(getSelectedId()).toUtf8().constData());
updateWatch();
}
void WatchView::renameWatchSlot()
{
QString name;
if(SimpleInputBox(this, tr("Enter the name of the watch variable"), getCellContent(getInitialSelection(), 0), name))
DbgCmdExecDirect(QString("SetWatchName ").append(getSelectedId() + "," + name).toUtf8().constData());
updateWatch();
}
void WatchView::editWatchSlot()
{
QString expr;
if(SimpleInputBox(this, tr("Enter the expression to watch"), "", expr))
DbgCmdExecDirect(QString("SetWatchExpression ").append(getSelectedId()).append(",").append(expr).toUtf8().constData());
updateWatch();
}
void WatchView::watchdogDisableSlot()
{
DbgCmdExecDirect(QString("SetWatchdog %1, \"disabled\"").arg(getSelectedId()).toUtf8().constData());
updateWatch();
}
void WatchView::watchdogChangedSlot()
{
DbgCmdExecDirect(QString("SetWatchdog %1, \"changed\"").arg(getSelectedId()).toUtf8().constData());
updateWatch();
}
void WatchView::watchdogUnchangedSlot()
{
DbgCmdExecDirect(QString("SetWatchdog %1, \"unchanged\"").arg(getSelectedId()).toUtf8().constData());
updateWatch();
}
void WatchView::watchdogIsTrueSlot()
{
DbgCmdExecDirect(QString("SetWatchdog %1, \"istrue\"").arg(getSelectedId()).toUtf8().constData());
updateWatch();
}
void WatchView::watchdogIsFalseSlot()
{
DbgCmdExecDirect(QString("SetWatchdog %1, \"isfalse\"").arg(getSelectedId()).toUtf8().constData());
updateWatch();
}

View File

@ -0,0 +1,40 @@
#ifndef WATCHVIEW_H
#define WATCHVIEW_H
#include "StdTable.h"
#include "MenuBuilder.h"
class CPUMultiDump;
class WatchView : public StdTable
{
Q_OBJECT
public:
WatchView(CPUMultiDump* parent);
QString paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h);
void updateColors();
public slots:
void contextMenuSlot(const QPoint & event);
void updateWatch();
void addWatchSlot();
void delWatchSlot();
void renameWatchSlot();
void editWatchSlot();
void watchdogDisableSlot();
void watchdogChangedSlot();
void watchdogUnchangedSlot();
void watchdogIsTrueSlot();
void watchdogIsFalseSlot();
protected:
void setupContextMenu();
QString getSelectedId();
MenuBuilder* mMenu;
QPen mWatchTriggeredColor;
QBrush mWatchTriggeredBackgroundColor;
};
#endif // WATCHVIEW_H

View File

@ -161,6 +161,8 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
defaultColors.insert("ThreadCurrentColor", QColor("#FFFFFF"));
defaultColors.insert("ThreadCurrentBackgroundColor", QColor("#000000"));
defaultColors.insert("WatchTriggeredColor", QColor("#FF0000"));
defaultColors.insert("WatchTriggeredBackgroundColor", QColor("#FFF8F0"));
defaultColors.insert("MemoryMapBreakpointColor", QColor("#000000"));
defaultColors.insert("MemoryMapBreakpointBackgroundColor", QColor("#FF0000"));
defaultColors.insert("MemoryMapCipColor", QColor("#FFFFFF"));
@ -199,6 +201,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "CPUStack", 3);
for(int i = 1; i <= 5; i++)
AbstractTableView::setupColumnConfigDefaultValue(guiUint, QString("CPUDump%1").arg(i), 4);
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Watch1", 6);
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "SoftwareBreakpoint", 10);
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "HardwareBreakpoint", 10);
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "MemoryBreakpoint", 10);
@ -296,13 +299,17 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
defaultShortcuts.insert("DebugTraceOverConditional", Shortcut(tr("Debug -> Trace Over Conditional"), ""));
defaultShortcuts.insert("DebugEnableTraceRecordBit", Shortcut(tr("Debug -> Trace Record -> Bit"), ""));
defaultShortcuts.insert("DebugTraceRecordNone", Shortcut(tr("Debug -> Trace Record -> None"), ""));
defaultShortcuts.insert("DebugInstrUndo", Shortcut(tr("Debug -> Undo instruction"), "Alt+U"));
defaultShortcuts.insert("PluginsScylla", Shortcut(tr("Plugins -> Scylla"), "Ctrl+I", true));
defaultShortcuts.insert("FavouritesManage", Shortcut(tr("Favourites -> Manage Favourite Tools"), "", true));
defaultShortcuts.insert("OptionsPreferences", Shortcut(tr("Options -> Preferences"), "", true));
defaultShortcuts.insert("OptionsAppearance", Shortcut(tr("Options -> Appearance"), "", true));
defaultShortcuts.insert("OptionsShortcuts", Shortcut(tr("Options -> Shortcuts"), "", true));
defaultShortcuts.insert("OptionsTopmost", Shortcut(tr("Options -> Topmost"), "Ctrl+F5", true));
defaultShortcuts.insert("OptionsReloadStylesheet", Shortcut(tr("Options -> Reload style.css") , "", true));
defaultShortcuts.insert("HelpAbout", Shortcut(tr("Help -> About"), "", true));
defaultShortcuts.insert("HelpDonate", Shortcut(tr("Help -> Donate"), "", true));
@ -310,6 +317,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
defaultShortcuts.insert("HelpCalculator", Shortcut(tr("Help -> Calculator"), "?"));
defaultShortcuts.insert("HelpReportBug", Shortcut(tr("Help -> Report Bug"), "", true));
defaultShortcuts.insert("HelpManual", Shortcut(tr("Help -> Manual"), "F1", true));
defaultShortcuts.insert("HelpCrashDump", Shortcut(tr("Help -> Generate Crash Dump"), "", true));
defaultShortcuts.insert("ActionFindStrings", Shortcut(tr("Actions -> Find Strings"), "", true));
defaultShortcuts.insert("ActionFindIntermodularCalls", Shortcut(tr("Actions -> Find Intermodular Calls"), "", true));

View File

@ -23,7 +23,7 @@ QByteArray & ByteReverse(QByteArray & array)
return array;
}
QString SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue)
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output)
{
LineEditDialog mEdit(parent);
mEdit.setWindowIcon(parent->windowIcon());
@ -31,9 +31,12 @@ QString SimpleInputBox(QWidget* parent, const QString & title, QString defaultVa
mEdit.setWindowTitle(title);
mEdit.setCheckBox(false);
if(mEdit.exec() == QDialog::Accepted)
return mEdit.editText;
{
output = mEdit.editText;
return true;
}
else
return "";
return false;
}
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text)

View File

@ -5,7 +5,7 @@
void SetApplicationIcon(WId winId);
QByteArray & ByteReverse(QByteArray & array);
QString SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue = "");
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output);
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text);
void SimpleWarningBox(QWidget* parent, const QString & title, const QString & text);

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/gui/images/star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

View File

@ -217,6 +217,8 @@
<file>images/thread-setpriority_alt.png</file>
<file>images/thread-switch.png</file>
<file>images/unicode.png</file>
<file>images/fatal-error.png</file>
<file>images/star.png</file>
<file>images/16bit.png</file>
<file>images/16bit-short.png</file>
<file>images/32bit.png</file>

View File

@ -156,7 +156,10 @@ SOURCES += \
Src/Gui/CodepageSelectionDialog.cpp \
Src/Gui/ColumnReorderDialog.cpp \
Src/Utils/EncodeMap.cpp \
Src/Utils/CodeFolding.cpp
Src/Utils/CodeFolding.cpp \
Src/Gui/WatchView.cpp \
Src/Gui/FavouriteTools.cpp \
Src/Gui/BrowseDialog.cpp
HEADERS += \
@ -254,7 +257,10 @@ HEADERS += \
Src/Utils/CachedFontMetrics.h \
Src/Gui/ColumnReorderDialog.h \
Src/Utils/EncodeMap.h \
Src/Utils/CodeFolding.h
Src/Utils/CodeFolding.h \
Src/Gui/WatchView.h \
Src/Gui/FavouriteTools.h \
Src/Gui/BrowseDialog.h
FORMS += \
@ -287,7 +293,9 @@ FORMS += \
Src/Gui/EditFloatRegister.ui \
Src/Gui/XrefBrowseDialog.ui \
Src/Gui/CodepageSelectionDialog.ui \
Src/Gui/ColumnReorderDialog.ui
Src/Gui/ColumnReorderDialog.ui \
Src/Gui/FavouriteTools.ui \
Src/Gui/BrowseDialog.ui
TRANSLATIONS = \
Translations/x64dbg.ts