1
0
Fork 0
x64dbg/x64_dbg_dbg/x64_dbg.cpp

335 lines
13 KiB
C++

#include "_global.h"
#include "argument.h"
#include "command.h"
#include "variable.h"
#include "instruction.h"
#include "debugger.h"
#include "data.h"
#include "simplescript.h"
#include "console.h"
#include "math.h"
#include "x64_dbg.h"
#include "msgqueue.h"
#include "addrinfo.h"
#include "threading.h"
#include "plugin_loader.h"
#include "assemble.h"
#include "_dbgfunctions.h"
#include "debugger_commands.h"
static MESSAGE_STACK* gMsgStack = 0;
static COMMAND* command_list = 0;
static HANDLE hCommandLoopThread = 0;
static char alloctrace[MAX_PATH] = "";
//Original code by Aurel from http://www.codeguru.com/cpp/w-p/win32/article.php/c1427/A-Simple-Win32-CommandLine-Parser.htm
static void commandlinefree(int argc, char** argv)
{
for(int i = 0; i < argc; i++)
efree(argv[i]);
efree(argv);
}
static char** commandlineparse(int* argc)
{
if(!argc)
return NULL;
LPWSTR wcCommandLine = GetCommandLineW();
LPWSTR* argw = CommandLineToArgvW(wcCommandLine, argc);
char** argv = (char**)emalloc(sizeof(void*) * (*argc + 1));
for(int i = 0; i < *argc; i++)
{
int bufSize = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, argw[i], -1, NULL, 0, NULL, NULL);
argv[i] = (char*)emalloc(bufSize + 1);
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, argw[i], bufSize, argv[i], bufSize * sizeof(char), NULL, NULL);
}
LocalFree(argw);
return argv;
}
static CMDRESULT cbStrLen(int argc, char* argv[])
{
if(argc < 2)
{
dputs("not enough arguments!");
return STATUS_ERROR;
}
dprintf("\"%s\"[%d]\n", argv[1], strlen(argv[1]));
return STATUS_CONTINUE;
}
static CMDRESULT cbCls(int argc, char* argv[])
{
GuiLogClear();
return STATUS_CONTINUE;
}
static CMDRESULT cbPrintf(int argc, char* argv[])
{
if(argc < 2)
dprintf("\n");
else
dprintf("%s", argv[1]);
return STATUS_CONTINUE;
}
static void registercommands()
{
COMMAND* cmd = command_list = cmdinit();
//debug control
dbgcmdnew("InitDebug\1init\1initdbg", cbDebugInit, false); //init debugger arg1:exefile,[arg2:commandline]
dbgcmdnew("StopDebug\1stop\1dbgstop", cbStopDebug, 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("erun\1egun\1er\1eg", cbDebugErun, true); //run + skip first chance exceptions
dbgcmdnew("pause", cbDebugPause, true); //pause debugger
dbgcmdnew("StepInto\1sti", cbDebugStepInto, true); //StepInto
dbgcmdnew("eStepInto\1esti", cbDebugeStepInto, true); //StepInto + skip first chance exceptions
dbgcmdnew("StepOver\1step\1sto\1st", cbDebugStepOver, true); //StepOver
dbgcmdnew("eStepOver\1estep\1esto\1est", cbDebugeStepOver, true); //StepOver + skip first chance exceptions
dbgcmdnew("SingleStep\1sstep\1sst", cbDebugSingleStep, true); //SingleStep arg1:count
dbgcmdnew("eSingleStep\1esstep\1esst", cbDebugeSingleStep, true); //SingleStep arg1:count + skip first chance exceptions
dbgcmdnew("StepOut\1rtr", cbDebugRtr, true); //rtr
dbgcmdnew("eStepOut\1ertr", cbDebugeRtr, true); //rtr + skip first chance exceptions
dbgcmdnew("DebugContinue\1con", cbDebugContinue, true); //set continue status
dbgcmdnew("LibrarianSetBreakPoint\1bpdll", cbDebugBpDll, true); //set dll breakpoint
dbgcmdnew("LibrarianRemoveBreakPoint\1bcdll", cbDebugBcDll, true); //remove dll breakpoint
dbgcmdnew("switchthread\1threadswitch", cbDebugSwitchthread, true); //switch thread
dbgcmdnew("suspendthread\1threadsuspend", cbDebugSuspendthread, true); //suspend thread
dbgcmdnew("resumethread\1threadresume", cbDebugResumethread, true); //resume thread
dbgcmdnew("killthread\1threadkill", cbDebugKillthread, true); //kill thread
dbgcmdnew("setthreadpriority\1setprioritythread\1threadsetpriority", cbDebugSetPriority, true); //set thread priority
dbgcmdnew("symdownload\1downloadsym", cbDebugDownloadSymbol, true); //download symbols
dbgcmdnew("setjit\1jitset", cbDebugSetJIT, false); //set JIT
dbgcmdnew("getjit\1jitget", cbDebugGetJIT, false); //get JIT
//breakpoints
dbgcmdnew("bplist", cbDebugBplist, true); //breakpoint list
dbgcmdnew("SetBPXOptions\1bptype", cbDebugSetBPXOptions, false); //breakpoint type
dbgcmdnew("SetBPX\1bp\1bpx", cbDebugSetBPX, true); //breakpoint
dbgcmdnew("DeleteBPX\1bpc\1bc", cbDebugDeleteBPX, true); //breakpoint delete
dbgcmdnew("EnableBPX\1bpe\1be", cbDebugEnableBPX, true); //breakpoint enable
dbgcmdnew("DisableBPX\1bpd\1bd", cbDebugDisableBPX, true); //breakpoint disable
dbgcmdnew("SetHardwareBreakpoint\1bph\1bphws", cbDebugSetHardwareBreakpoint, true); //hardware breakpoint
dbgcmdnew("DeleteHardwareBreakpoint\1bphc\1bphwc", cbDebugDeleteHardwareBreakpoint, true); //delete hardware breakpoint
dbgcmdnew("EnableHardwareBreakpoint\1bphe\1bphwe", cbDebugEnableHardwareBreakpoint, true); //enable hardware breakpoint
dbgcmdnew("DisableHardwareBreakpoint\1bphd\1bphwd", cbDebugDisableHardwareBreakpoint, true); //disable hardware breakpoint
dbgcmdnew("SetMemoryBPX\1membp\1bpm", cbDebugSetMemoryBpx, true); //SetMemoryBPX
dbgcmdnew("DeleteMemoryBPX\1membpc\1bpmc", cbDebugDeleteMemoryBreakpoint, true); //delete memory breakpoint
dbgcmdnew("EnableMemoryBreakpoint\1membpe\1bpme", cbDebugEnableMemoryBreakpoint, true); //enable memory breakpoint
dbgcmdnew("DisableMemoryBreakpoint\1membpd\1bpmd", cbDebugDisableMemoryBreakpoint, true); //enable memory breakpoint
//variables
dbgcmdnew("varnew\1var", cbInstrVar, false); //make a variable arg1:name,[arg2:value]
dbgcmdnew("vardel", cbInstrVarDel, false); //delete a variable, arg1:variable name
dbgcmdnew("varlist", cbInstrVarList, false); //list variables[arg1:type filter]
dbgcmdnew("mov\1set", cbInstrMov, false); //mov a variable, arg1:dest,arg2:src
//misc
dbgcmdnew("strlen\1charcount\1ccount", cbStrLen, false); //get strlen, arg1:string
dbgcmdnew("cls\1lc\1lclr", cbCls, false); //clear the log
dbgcmdnew("chd", cbInstrChd, false); //Change directory
dbgcmdnew("disasm\1dis\1d", cbDebugDisasm, true); //doDisasm
dbgcmdnew("HideDebugger\1dbh\1hide", cbDebugHide, true); //HideDebugger
dbgcmdnew("dump", cbDebugDump, true); //dump at address
dbgcmdnew("sdump", cbDebugStackDump, true); //dump at stack address
dbgcmdnew("refinit", cbInstrRefinit, false);
dbgcmdnew("refadd", cbInstrRefadd, false);
dbgcmdnew("asm", cbAssemble, true); //assemble instruction
dbgcmdnew("sleep", cbInstrSleep, false); //Sleep
//user database
dbgcmdnew("cmt\1cmtset\1commentset", cbInstrCmt, true); //set/edit comment
dbgcmdnew("cmtc\1cmtdel\1commentdel", cbInstrCmtdel, true); //delete comment
dbgcmdnew("lbl\1lblset\1labelset", cbInstrLbl, true); //set/edit label
dbgcmdnew("lblc\1lbldel\1labeldel", cbInstrLbldel, true); //delete label
dbgcmdnew("bookmark\1bookmarkset", cbInstrBookmarkSet, true); //set bookmark
dbgcmdnew("bookmarkc\1bookmarkdel", cbInstrBookmarkDel, true); //delete bookmark
dbgcmdnew("savedb\1dbsave", cbSavedb, true); //save program database
dbgcmdnew("loaddb\1dbload", cbLoaddb, true); //load program database
dbgcmdnew("functionadd\1func", cbFunctionAdd, true); //function
dbgcmdnew("functiondel\1funcc", cbFunctionDel, true); //function
dbgcmdnew("commentlist", cbInstrCommentList, true); //list comments
dbgcmdnew("labellist", cbInstrLabelList, true); //list labels
dbgcmdnew("bookmarklist", cbInstrBookmarkList, true); //list bookmarks
dbgcmdnew("functionlist", cbInstrFunctionList, true); //list functions
//memory operations
dbgcmdnew("alloc", cbDebugAlloc, true); //allocate memory
dbgcmdnew("free", cbDebugFree, true); //free memory
dbgcmdnew("Fill\1memset", cbDebugMemset, true); //memset
//plugins
dbgcmdnew("StartScylla\1scylla\1imprec", cbDebugStartScylla, false); //start scylla
//general purpose
dbgcmdnew("cmp", cbInstrCmp, false); //compare
dbgcmdnew("gpa", cbInstrGpa, true);
dbgcmdnew("add", cbInstrAdd, false);
dbgcmdnew("and", cbInstrAnd, false);
dbgcmdnew("dec", cbInstrDec, false);
dbgcmdnew("div", cbInstrDiv, false);
dbgcmdnew("inc", cbInstrInc, false);
dbgcmdnew("mul", cbInstrMul, false);
dbgcmdnew("neg", cbInstrNeg, false);
dbgcmdnew("not", cbInstrNot, false);
dbgcmdnew("or", cbInstrOr, false);
dbgcmdnew("rol", cbInstrRol, false);
dbgcmdnew("ror", cbInstrRor, false);
dbgcmdnew("shl", cbInstrShl, false);
dbgcmdnew("shr", cbInstrShr, false);
dbgcmdnew("sub", cbInstrSub, false);
dbgcmdnew("test", cbInstrTest, false);
dbgcmdnew("xor", cbInstrXor, false);
//script
dbgcmdnew("scriptload", cbScriptLoad, false);
dbgcmdnew("msg", cbScriptMsg, false);
dbgcmdnew("msgyn", cbScriptMsgyn, false);
//data
dbgcmdnew("reffind\1findref\1ref", cbInstrRefFind, true);
dbgcmdnew("refstr\1strref", cbInstrRefStr, true);
dbgcmdnew("find", cbInstrFind, true); //find a pattern
dbgcmdnew("findall", cbInstrFindAll, true); //find all patterns
dbgcmdnew("modcallfind", cbInstrModCallFind, true); //find intermodular calls
//undocumented
dbgcmdnew("bench", cbDebugBenchmark, true); //benchmark test (readmem etc)
dbgcmdnew("dprintf", cbPrintf, false); //printf
dbgcmdnew("setstr\1strset", cbInstrSetstr, false); //set a string variable
dbgcmdnew("getstr\1strget", cbInstrGetstr, false); //get a string variable
dbgcmdnew("copystr\1strcpy", cbInstrCopystr, true); //write a string variable to memory
dbgcmdnew("looplist", cbInstrLoopList, true); //list loops
}
static bool cbCommandProvider(char* cmd, int maxlen)
{
MESSAGE msg;
msgwait(gMsgStack, &msg);
char* newcmd = (char*)msg.param1;
if(strlen(newcmd) >= deflen)
newcmd[deflen - 1] = 0;
strcpy(cmd, newcmd);
efree(newcmd, "cbCommandProvider:newcmd"); //free allocated command
return true;
}
extern "C" DLL_EXPORT bool _dbg_dbgcmdexec(const char* cmd)
{
int len = (int)strlen(cmd);
char* newcmd = (char*)emalloc((len + 1) * sizeof(char), "_dbg_dbgcmdexec:newcmd");
strcpy(newcmd, cmd);
return msgsend(gMsgStack, 0, (uint)newcmd, 0);
}
static DWORD WINAPI DbgCommandLoopThread(void* a)
{
cmdloop(command_list, cbBadCmd, cbCommandProvider, cmdfindmain, false);
return 0;
}
static void* emalloc_json(size_t size)
{
return emalloc(size, "json:ptr");
}
static void efree_json(void* ptr)
{
efree(ptr, "json:ptr");
}
extern "C" DLL_EXPORT const char* _dbg_dbginit()
{
dbginit();
dbgfunctionsinit();
json_set_alloc_funcs(emalloc_json, efree_json);
char dir[deflen] = "";
if(!GetModuleFileNameA(hInst, dir, deflen))
return "GetModuleFileNameA failed!";
int len = (int)strlen(dir);
while(dir[len] != '\\')
len--;
dir[len] = 0;
strcpy(alloctrace, dir);
PathAppendA(alloctrace, "\\alloctrace.txt");
DeleteFileA(alloctrace);
setalloctrace(alloctrace);
strcpy(dbbasepath, dir); //debug directory
PathAppendA(dbbasepath, "db");
CreateDirectoryA(dbbasepath, 0); //create database directory
strcpy(szSymbolCachePath, dir);
PathAppendA(szSymbolCachePath, "symbols");
SetCurrentDirectoryA(dir);
gMsgStack = msgallocstack();
if(!gMsgStack)
return "Could not allocate message stack!";
varinit();
registercommands();
hCommandLoopThread = CreateThread(0, 0, DbgCommandLoopThread, 0, 0, 0);
char plugindir[deflen] = "";
strcpy(plugindir, dir);
PathAppendA(plugindir, "plugins");
pluginload(plugindir);
//handle command line
int argc = 0;
char** argv = commandlineparse(&argc);
if(argc == 2) //we have an argument
{
std::string str = "init \"";
str += argv[1];
str += "\"";
DbgCmdExec(str.c_str());
}
else if(argc == 5) //4 arguments (JIT)
{
if(_strcmpi(argv[1], "-a") == 0 && !_stricmp(argv[3], "-e"))
{
std::string str = "attach .";
str += argv[2];
str += ", .";
str += argv[4];
DbgCmdExec(str.c_str());
}
}
commandlinefree(argc, argv);
return 0;
}
extern "C" DLL_EXPORT void _dbg_dbgexitsignal()
{
cbStopDebug(0, 0);
scriptabort();
wait(WAITID_STOP); //after this, debugging stopped
pluginunload();
TerminateThread(hCommandLoopThread, 0);
CloseHandle(hCommandLoopThread);
cmdfree(command_list);
varfree();
msgfreestack(gMsgStack);
if(memleaks())
{
char msg[256] = "";
sprintf(msg, "%d memory leak(s) found!\n\nPlease send 'alloctrace.txt' to the authors of x64_dbg.", memleaks());
MessageBoxA(0, msg, "error", MB_ICONERROR | MB_SYSTEMMODAL);
}
else
DeleteFileA(alloctrace);
CriticalSectionDeleteLocks();
}
extern "C" DLL_EXPORT bool _dbg_dbgcmddirectexec(const char* cmd)
{
if(cmddirectexec(command_list, cmd) == STATUS_ERROR)
return false;
return true;
}
COMMAND* dbggetcommandlist()
{
return command_list;
}