diff --git a/src/dbg/_dbgfunctions.cpp b/src/dbg/_dbgfunctions.cpp index 9c163bfd..fee2121b 100644 --- a/src/dbg/_dbgfunctions.cpp +++ b/src/dbg/_dbgfunctions.cpp @@ -25,6 +25,7 @@ #include "../bridge/bridgelist.h" #include "tcpconnections.h" #include "watch.h" +#include "animate.h" static DBGFUNCTIONS _dbgfunctions; @@ -341,4 +342,5 @@ void dbgfunctionsinit() _dbgfunctions.EnumTcpConnections = _enumtcpconnections; _dbgfunctions.GetDbgEvents = dbggetdbgevents; _dbgfunctions.MemIsCodePage = MemIsCodePage; + _dbgfunctions.AnimateCommand = _dbg_animatecommand; } diff --git a/src/dbg/_dbgfunctions.h b/src/dbg/_dbgfunctions.h index d086c440..e9f3e296 100644 --- a/src/dbg/_dbgfunctions.h +++ b/src/dbg/_dbgfunctions.h @@ -146,6 +146,7 @@ typedef int (*MODGETPARTY)(duint base); typedef void (*MODSETPARTY)(duint base, int party); typedef bool(*WATCHISWATCHDOGTRIGGERED)(unsigned int id); typedef bool(*MEMISCODEPAGE)(duint addr, bool refresh); +typedef bool(*ANIMATECOMMAND)(const char* command); typedef struct DBGFUNCTIONS_ { @@ -201,6 +202,7 @@ typedef struct DBGFUNCTIONS_ MODSETPARTY ModSetParty; WATCHISWATCHDOGTRIGGERED WatchIsWatchdogTriggered; MEMISCODEPAGE MemIsCodePage; + ANIMATECOMMAND AnimateCommand; } DBGFUNCTIONS; #ifdef BUILD_DBG diff --git a/src/dbg/_exports.cpp b/src/dbg/_exports.cpp index 78ed3a0a..c3159928 100644 --- a/src/dbg/_exports.cpp +++ b/src/dbg/_exports.cpp @@ -33,6 +33,7 @@ #include "encodemap.h" #include "argument.h" #include "watch.h" +#include "animate.h" static bool bOnlyCipAutoComments = false; @@ -883,6 +884,12 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa // Trim the buffer to fit inside MAX_PATH strncpy_s(szSymbolCachePath, cachePath, _TRUNCATE); } + + duint animateInterval; + if(BridgeSettingGetUint("Engine", "AnimateInterval", &animateInterval)) + _dbg_setanimateinterval(animateInterval); + else + _dbg_setanimateinterval(50); // 20 commands per second } break; diff --git a/src/dbg/animate.cpp b/src/dbg/animate.cpp new file mode 100644 index 00000000..967b52c1 --- /dev/null +++ b/src/dbg/animate.cpp @@ -0,0 +1,57 @@ +#include "animate.h" +#include "x64_dbg.h" + +static char animate_command[deflen]; +static unsigned int animate_interval = 50; +HANDLE hAnimateThread = nullptr; + +static DWORD WINAPI animateThread(void* arg1) +{ + while(animate_command[0] != 0) + { + auto beforeTime = GetTickCount(); + if(_dbg_dbgcmdexec(animate_command) != true) + // An error occurs + break; + auto currentTime = GetTickCount(); + if(currentTime < (beforeTime + animate_interval)) + { + Sleep(beforeTime + animate_interval - currentTime); + } + } + // Close the handle itself + HANDLE hAnimateThread2 = hAnimateThread; + hAnimateThread = nullptr; + CloseHandle(hAnimateThread2); + return 0; +} + +bool _dbg_animatecommand(const char* command) +{ + if(command) // Animate command + { + strcpy_s(animate_command, command); + if(hAnimateThread == nullptr) + { + hAnimateThread = CreateThread(NULL, 0, animateThread, nullptr, 0, nullptr); + } + } + else // command = null : stop animating + { + animate_command[0] = 0; + } + return true; +} + +void _dbg_setanimateinterval(unsigned int milliseconds) +{ + if(milliseconds <= 20) + animate_interval = 20; + else + animate_interval = milliseconds; +} + +bool _dbg_isanimating() +{ + return hAnimateThread != nullptr; +} \ No newline at end of file diff --git a/src/dbg/animate.h b/src/dbg/animate.h new file mode 100644 index 00000000..c50f40e0 --- /dev/null +++ b/src/dbg/animate.h @@ -0,0 +1,11 @@ +#ifndef ANIMATE_H +#define ANIMATE_H + +bool _dbg_animatecommand(const char* command); +void _dbg_setanimateinterval(unsigned int milliseconds); +bool _dbg_isanimating(); +inline void _dbg_animatestop() +{ + _dbg_animatecommand(nullptr); +} +#endif //ANIMATE_H \ No newline at end of file diff --git a/src/dbg/database.cpp b/src/dbg/database.cpp index 27d48661..3fbe7446 100644 --- a/src/dbg/database.cpp +++ b/src/dbg/database.cpp @@ -121,7 +121,7 @@ void DbSave(DbLoadSaveType saveType) else //remove database when nothing is in there DeleteFileW(wdbpath.c_str()); - dprintf("%ums\n", GetTickCount() - ticks); + dprintf(QT_TRANSLATE_NOOP("DBG", "%ums\n"), GetTickCount() - ticks); json_decref(root); //free root } @@ -230,7 +230,7 @@ void DbLoad(DbLoadSaveType loadType) json_decref(root); if(loadType != DbLoadSaveType::CommandLine) - dprintf("%ums\n", GetTickCount() - ticks); + dprintf(QT_TRANSLATE_NOOP("DBG", "%ums\n"), GetTickCount() - ticks); } void DbClose() diff --git a/src/dbg/debugger.cpp b/src/dbg/debugger.cpp index 4430e2f8..a3948d34 100644 --- a/src/dbg/debugger.cpp +++ b/src/dbg/debugger.cpp @@ -27,6 +27,7 @@ #include "TraceRecord.h" #include "historycontext.h" #include "taskthread.h" +#include "animate.h" struct TraceCondition { @@ -587,6 +588,7 @@ void cbPauseBreakpoint() auto CIP = GetContextDataEx(hActiveThread, UE_CIP); DeleteBPX(CIP); DebugUpdateGuiSetStateAsync(CIP, true); + _dbg_animatestop(); // Stop animating when paused // Trace record _dbg_dbgtraceexecute(CIP); //lock @@ -625,6 +627,7 @@ static void handleBreakCondition(const BREAKPOINT & bp, const void* ExceptionAdd // Plugin callback PLUG_CB_PAUSEDEBUG pauseInfo = { nullptr }; plugincbcall(CB_PAUSEDEBUG, &pauseInfo); + _dbg_animatestop(); // Stop animating when a breakpoint is hit } } @@ -710,7 +713,7 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr if(*bp.logText && logCondition) //log { - dprintf("%s\n", stringformatinline(bp.logText).c_str()); + dprintf_untranslated("%s\n", stringformatinline(bp.logText).c_str()); } if(*bp.commandText && commandCondition) //command { @@ -1228,6 +1231,7 @@ static void cbExitProcess(EXIT_PROCESS_DEBUG_INFO* ExitProcess) PLUG_CB_EXITPROCESS callbackInfo; callbackInfo.ExitProcess = ExitProcess; plugincbcall(CB_EXITPROCESS, &callbackInfo); + _dbg_animatestop(); // Stop animating //unload main module SafeSymUnloadModule64(fdProcessInfo->hProcess, pCreateProcessBase); //history @@ -1576,12 +1580,14 @@ static void cbException(EXCEPTION_DEBUG_INFO* ExceptionData) else dputs(QT_TRANSLATE_NOOP("DBG", "Detached!")); isDetachedByUser = false; + _dbg_animatestop(); // Stop animating return; } else if(isPausedByUser) { dputs(QT_TRANSLATE_NOOP("DBG", "paused!")); SetNextDbgContinueStatus(DBG_CONTINUE); + _dbg_animatestop(); // Stop animating //update memory map MemUpdateMap(); DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), true); @@ -1810,9 +1816,9 @@ bool cbBreakpointList(const BREAKPOINT* bp) type = "GP"; bool enabled = bp->enabled; if(*bp->name) - dprintf("%d:%s:%p:\"%s\"\n", enabled, type, bp->addr, bp->name); + dprintf_untranslated("%d:%s:%p:\"%s\"\n", enabled, type, bp->addr, bp->name); else - dprintf("%d:%s:%p\n", enabled, type, bp->addr); + dprintf_untranslated("%d:%s:%p\n", enabled, type, bp->addr); return true; } diff --git a/src/dbg/debugger_commands.cpp b/src/dbg/debugger_commands.cpp index 27d2c0ea..aaaa5f4d 100644 --- a/src/dbg/debugger_commands.cpp +++ b/src/dbg/debugger_commands.cpp @@ -25,6 +25,7 @@ #include "function.h" #include "historycontext.h" #include "taskthread.h" +#include "animate.h" static bool bScyllaLoaded = false; duint LoadLibThreadID; @@ -1616,8 +1617,16 @@ CMDRESULT cbDebugPause(int argc, char* argv[]) { if(!dbgisrunning()) { - dputs(QT_TRANSLATE_NOOP("DBG", "Program is not running")); - return STATUS_ERROR; + if(_dbg_isanimating()) + { + _dbg_animatestop(); // pause when animating + return STATUS_CONTINUE; + } + else + { + dputs(QT_TRANSLATE_NOOP("DBG", "Program is not running")); + return STATUS_ERROR; + } } if(SuspendThread(hActiveThread) == -1) { diff --git a/src/dbg/plugin_loader.cpp b/src/dbg/plugin_loader.cpp index b4b368f7..2cddaccc 100644 --- a/src/dbg/plugin_loader.cpp +++ b/src/dbg/plugin_loader.cpp @@ -74,13 +74,13 @@ void pluginload(const char* pluginDir) pluginData.hPlugin = LoadLibraryW(StringUtils::Utf8ToUtf16(szPluginPath).c_str()); //load the plugin library if(!pluginData.hPlugin) { - dprintf("[PLUGIN] Failed to load plugin: %s\n", StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] Failed to load plugin: %s\n"), StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); continue; } pluginData.pluginit = (PLUGINIT)GetProcAddress(pluginData.hPlugin, "pluginit"); if(!pluginData.pluginit) { - dprintf("[PLUGIN] Export \"pluginit\" not found in plugin: %s\n", StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] Export \"pluginit\" not found in plugin: %s\n"), StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); FreeLibrary(pluginData.hPlugin); continue; } @@ -189,18 +189,18 @@ void pluginload(const char* pluginDir) //init plugin if(!pluginData.pluginit(&pluginData.initStruct)) { - dprintf("[PLUGIN] pluginit failed for plugin: %s\n", StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] pluginit failed for plugin: %s\n"), StringUtils::Utf16ToUtf8(foundData.cFileName).c_str()); FreeLibrary(pluginData.hPlugin); continue; } else if(pluginData.initStruct.sdkVersion < PLUG_SDKVERSION) //the plugin SDK is not compatible { - dprintf("[PLUGIN] %s is incompatible with this SDK version\n", pluginData.initStruct.pluginName); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] %s is incompatible with this SDK version\n"), pluginData.initStruct.pluginName); FreeLibrary(pluginData.hPlugin); continue; } else - dprintf("[PLUGIN] %s v%d Loaded!\n", pluginData.initStruct.pluginName, pluginData.initStruct.pluginVersion); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] %s v%d Loaded!\n"), pluginData.initStruct.pluginName, pluginData.initStruct.pluginVersion); SectionLocker menuLock; //exclusive lock @@ -208,7 +208,7 @@ void pluginload(const char* pluginDir) int hNewMenu = GuiMenuAdd(GUI_PLUGIN_MENU, pluginData.initStruct.pluginName); if(hNewMenu == -1) { - dprintf("[PLUGIN] GuiMenuAdd(GUI_PLUGIN_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] GuiMenuAdd(GUI_PLUGIN_MENU) failed for plugin: %s\n"), pluginData.initStruct.pluginName); pluginData.hMenu = -1; } else @@ -225,7 +225,7 @@ void pluginload(const char* pluginDir) hNewMenu = GuiMenuAdd(GUI_DISASM_MENU, pluginData.initStruct.pluginName); if(hNewMenu == -1) { - dprintf("[PLUGIN] GuiMenuAdd(GUI_DISASM_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] GuiMenuAdd(GUI_DISASM_MENU) failed for plugin: %s\n"), pluginData.initStruct.pluginName); pluginData.hMenu = -1; } else @@ -242,7 +242,7 @@ void pluginload(const char* pluginDir) hNewMenu = GuiMenuAdd(GUI_DUMP_MENU, pluginData.initStruct.pluginName); if(hNewMenu == -1) { - dprintf("[PLUGIN] GuiMenuAdd(GUI_DUMP_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] GuiMenuAdd(GUI_DUMP_MENU) failed for plugin: %s\n"), pluginData.initStruct.pluginName); pluginData.hMenu = -1; } else @@ -259,7 +259,7 @@ void pluginload(const char* pluginDir) hNewMenu = GuiMenuAdd(GUI_STACK_MENU, pluginData.initStruct.pluginName); if(hNewMenu == -1) { - dprintf("[PLUGIN] GuiMenuAdd(GUI_STACK_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] GuiMenuAdd(GUI_STACK_MENU) failed for plugin: %s\n"), pluginData.initStruct.pluginName); pluginData.hMenu = -1; } else @@ -451,7 +451,7 @@ bool plugincmdregister(int pluginHandle, const char* command, CBPLUGINCOMMAND cb EXCLUSIVE_ACQUIRE(LockPluginCommandList); pluginCommandList.push_back(plugCmd); EXCLUSIVE_RELEASE(); - dprintf("[PLUGIN] command \"%s\" registered!\n", command); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] command \"%s\" registered!\n"), command); return true; } @@ -475,7 +475,7 @@ bool plugincmdunregister(int pluginHandle, const char* command) EXCLUSIVE_RELEASE(); if(!dbgcmddel(command)) return false; - dprintf("[PLUGIN] command \"%s\" unregistered!\n", command); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] command \"%s\" unregistered!\n"), command); return true; } } @@ -711,7 +711,7 @@ bool pluginexprfuncregister(int pluginHandle, const char* name, int argc, CBPLUG EXCLUSIVE_ACQUIRE(LockPluginExprfunctionList); pluginExprfunctionList.push_back(plugExprfunction); EXCLUSIVE_RELEASE(); - dprintf("[PLUGIN] expression function \"%s\" registered!\n", name); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] expression function \"%s\" registered!\n"), name); return true; } @@ -727,7 +727,7 @@ bool pluginexprfuncunregister(int pluginHandle, const char* name) EXCLUSIVE_RELEASE(); if(!ExpressionFunctions::Unregister(name)) return false; - dprintf("[PLUGIN] expression function \"%s\" unregistered!\n", name); + dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] expression function \"%s\" unregistered!\n"), name); return true; } } diff --git a/src/dbg/x64_dbg.cpp b/src/dbg/x64_dbg.cpp index 54dd014f..ec62f141 100644 --- a/src/dbg/x64_dbg.cpp +++ b/src/dbg/x64_dbg.cpp @@ -437,8 +437,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit() if(!EngineCheckStructAlignment(UE_STRUCT_TITAN_ENGINE_CONTEXT, sizeof(TITAN_ENGINE_CONTEXT_t))) return "Invalid TITAN_ENGINE_CONTEXT_t alignment!"; - if(sizeof(TITAN_ENGINE_CONTEXT_t) != sizeof(REGISTERCONTEXT)) - return "Invalid REGISTERCONTEXT alignment!"; + static_assert(sizeof(TITAN_ENGINE_CONTEXT_t) == sizeof(REGISTERCONTEXT), "Invalid REGISTERCONTEXT alignment!"); dputs(QT_TRANSLATE_NOOP("DBG", "Initializing wait objects...")); waitinitialize(); diff --git a/src/dbg/x64_dbg_dbg.vcxproj b/src/dbg/x64_dbg_dbg.vcxproj index 2bc87632..4d5e3d0c 100644 --- a/src/dbg/x64_dbg_dbg.vcxproj +++ b/src/dbg/x64_dbg_dbg.vcxproj @@ -32,6 +32,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/src/dbg/x64_dbg_dbg.vcxproj.filters b/src/dbg/x64_dbg_dbg.vcxproj.filters index 0c2cd9fe..fc34e8b7 100644 --- a/src/dbg/x64_dbg_dbg.vcxproj.filters +++ b/src/dbg/x64_dbg_dbg.vcxproj.filters @@ -347,6 +347,9 @@ Source Files\Debugger Core + + Source Files\Utilities + @@ -790,5 +793,8 @@ Header Files\Third Party\yara\yara + + Header Files\Utilities + \ No newline at end of file diff --git a/src/gui/Src/Gui/MainWindow.cpp b/src/gui/Src/Gui/MainWindow.cpp index 07534751..fb56837b 100644 --- a/src/gui/Src/Gui/MainWindow.cpp +++ b/src/gui/Src/Gui/MainWindow.cpp @@ -326,6 +326,9 @@ MainWindow::MainWindow(QWidget* parent) makeCommandAction(ui->actionseStepInto, "seStepInto"); makeCommandAction(ui->actionseStepOver, "seStepOver"); makeCommandAction(ui->actionseRun, "seRun"); + connect(ui->actionAnimateInto, SIGNAL(triggered()), this, SLOT(animateIntoSlot())); + connect(ui->actionAnimateOver, SIGNAL(triggered()), this, SLOT(animateOverSlot())); + connect(ui->actionAnimateCommand, SIGNAL(triggered()), this, SLOT(animateCommandSlot())); connect(mCpuWidget->getDisasmWidget(), SIGNAL(updateWindowTitle(QString)), this, SLOT(updateWindowTitleSlot(QString))); connect(mCpuWidget->getDisasmWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget())); @@ -1656,3 +1659,20 @@ void MainWindow::setFavouriteItemShortcut(int type, const QString & name, const } } } + +void MainWindow::animateIntoSlot() +{ + DbgFunctions()->AnimateCommand("StepInto"); +} + +void MainWindow::animateOverSlot() +{ + DbgFunctions()->AnimateCommand("StepOver"); +} + +void MainWindow::animateCommandSlot() +{ + QString command; + if(SimpleInputBox(this, tr("Animate command"), "", command, tr("Example: StepInto"))) + DbgFunctions()->AnimateCommand(command.toUtf8().constData()); +} diff --git a/src/gui/Src/Gui/MainWindow.h b/src/gui/Src/Gui/MainWindow.h index b69eb8d3..5773524f 100644 --- a/src/gui/Src/Gui/MainWindow.h +++ b/src/gui/Src/Gui/MainWindow.h @@ -63,6 +63,9 @@ public slots: void displayAboutWidget(); void execTocnd(); void execTicnd(); + void animateIntoSlot(); + void animateOverSlot(); + void animateCommandSlot(); void openFile(); void restartDebugging(); void displayBreakpointWidget(); diff --git a/src/gui/Src/Gui/MainWindow.ui b/src/gui/Src/Gui/MainWindow.ui index daa0e2a3..fd2d89b3 100644 --- a/src/gui/Src/Gui/MainWindow.ui +++ b/src/gui/Src/Gui/MainWindow.ui @@ -109,16 +109,19 @@ + + + - + @@ -1004,6 +1007,21 @@ Blog + + + Animate into + + + + + Animate over + + + + + Animate command... + + diff --git a/src/x64dbg_translations.pro b/src/x64dbg_translations.pro index 360dc414..3f9b1b2c 100644 --- a/src/x64dbg_translations.pro +++ b/src/x64dbg_translations.pro @@ -188,7 +188,8 @@ SOURCES += \ dbg/analysis/linearanalysis.cpp \ dbg/analysis/LinearPass.cpp \ dbg/analysis/recursiveanalysis.cpp \ - dbg/analysis/xrefsanalysis.cpp + dbg/analysis/xrefsanalysis.cpp \ + dbg/animate.cpp TRANSLATIONS = \ gui/Translations/x64dbg.ts @@ -393,7 +394,8 @@ HEADERS += \ dbg/analysis/linearanalysis.h \ dbg/analysis/LinearPass.h \ dbg/analysis/recursiveanalysis.h \ - dbg/analysis/xrefsanalysis.h + dbg/analysis/xrefsanalysis.h \ + dbg/animate.h FORMS += \ gui/Src/Gui/AppearanceDialog.ui \