1
0
Fork 0
x64dbg/x64_dbg_dbg/debugger.cpp

1233 lines
34 KiB
C++

#include "debugger.h"
#include "argument.h"
#include "variable.h"
#include "console.h"
#include "threading.h"
#include "value.h"
#include "instruction.h"
#include "memory.h"
#include "_exports.h"
#include "addrinfo.h"
static PROCESS_INFORMATION g_pi= {0,0,0,0};
PROCESS_INFORMATION* fdProcessInfo=&g_pi;
static char szFileName[deflen]="";
bool bFileIsDll=false;
uint pDebuggedDllBase=0;
BREAKPOINT* bplist=0;
static bool isStepping=false;
static bool isPausedByUser=false;
static bool bScyllaLoaded=false;
//Superglobal variables
char sqlitedb[deflen]="";
//static functions
static void cbStep();
static void cbSystemBreakpoint(void* ExceptionData);
static void cbEntryBreakpoint();
static void cbUserBreakpoint();
void dbgdisablebpx()
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
return;
bool bNext=true;
while(bNext)
{
if(cur->type==BPNORMAL or cur->type==BPSINGLESHOOT)
if(IsBPXEnabled(cur->addr) and DeleteBPX(cur->addr))
cur->enabled=false;
cur=cur->next;
if(!cur)
bNext=false;
}
}
void dbgenablebpx()
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
return;
bool bNext=true;
while(bNext)
{
if(cur->type==BPNORMAL or cur->type==BPSINGLESHOOT)
if(!IsBPXEnabled(cur->addr) and SetBPX(cur->addr, cur->type, (void*)cbUserBreakpoint))
cur->enabled=true;
cur=cur->next;
if(!cur)
bNext=false;
}
}
bool dbgisrunning()
{
if(!waitislocked(WAITID_RUN))
return true;
return false;
}
void DebugUpdateGui(uint disasm_addr)
{
GuiUpdateAllViews();
GuiDisasmAt(disasm_addr, (duint)GetContextData(UE_CIP));
}
static void cbUserBreakpoint()
{
BREAKPOINT* cur=bpfind(bplist, 0, (uint)GetContextData(UE_CIP), 0, BPNORMAL);
if(!cur)
dputs("breakpoint reached not in list!");
else
{
const char* apiname=(const char*)ImporterGetAPINameFromDebugee(fdProcessInfo->hProcess, cur->addr);
char log[deflen]="";
if(apiname)
{
const char* dllname_=(const char*)ImporterGetDLLNameFromDebugee(fdProcessInfo->hProcess, cur->addr);
char dllname[256]="";
strcpy(dllname, dllname_);
_strlwr(dllname);
int len=strlen(dllname);
for(int i=len-1; i!=0; i--)
if(dllname[i]=='.')
{
dllname[i]=0;
break;
}
if(cur->name)
sprintf(log, "breakpoint \"%s\" at %s.%s ("fhex")!", cur->name, dllname, apiname, cur->addr);
else
sprintf(log, "breakpoint at %s.%s ("fhex")!", dllname, apiname, cur->addr);
}
else
{
if(cur->name)
sprintf(log, "breakpoint \"%s\" at "fhex"!", cur->name, cur->addr);
else
sprintf(log, "breakpoint at "fhex"!", cur->addr);
}
dputs(log);
if(cur->type==BPSINGLESHOOT)
bpdel(bplist, 0, cur->addr, BPNORMAL);
}
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static void cbHardwareBreakpoint(void* ExceptionAddress)
{
uint cip=GetContextData(UE_CIP);
BREAKPOINT* cur=bpfind(bplist, 0, (uint)ExceptionAddress, 0, BPHARDWARE);
if(!cur)
dputs("hardware breakpoint reached not in list!");
else
{
//TODO: type
char log[50]="";
if(cur->name)
sprintf(log, "hardware breakpoint \"%s\" "fhex"!", cur->name, cur->addr);
else
sprintf(log, "hardware breakpoint "fhex"!", cur->addr);
dputs(log);
}
DebugUpdateGui(cip);
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static void cbMemoryBreakpoint(void* ExceptionAddress)
{
uint cip=GetContextData(UE_CIP);
uint size;
uint base=memfindbaseaddr(fdProcessInfo->hProcess, (uint)ExceptionAddress, &size);
BREAKPOINT* cur=bpfind(bplist, 0, base, 0, BPMEMORY);
if(!cur)
dputs("memory breakpoint reached not in list!");
else
{
//unsigned char type=cur->oldbytes&0xF;
char log[50]="";
if(cur->name)
sprintf(log, "memory breakpoint \"%s\" on "fhex"!", cur->name, cur->addr);
else
sprintf(log, "memory breakpoint on "fhex"!", cur->addr);
dputs(log);
}
if(!(cur->oldbytes>>4)) //is auto-restoring?
bpdel(bplist, 0, base, BPMEMORY); //delete from breakpoint list
DebugUpdateGui(cip);
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static void cbEntryBreakpoint()
{
pDebuggedDllBase=GetDebuggedDLLBaseAddress();
dputs("entry point reached!");
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static int ecount=0;
static void cbException(void* ExceptionData)
{
EXCEPTION_DEBUG_INFO* edi=(EXCEPTION_DEBUG_INFO*)ExceptionData;
uint addr=(uint)edi->ExceptionRecord.ExceptionAddress;
if(edi->ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)
{
if(isPausedByUser)
{
dputs("paused!");
SetNextDbgContinueStatus(DBG_CONTINUE);
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
return;
}
SetContextData(UE_CIP, (uint)edi->ExceptionRecord.ExceptionAddress);
}
char msg[1024]="";
if(edi->dwFirstChance) //first chance exception
{
sprintf(msg, "first chance exception on "fhex" (%.8X)!", addr, edi->ExceptionRecord.ExceptionCode);
SetNextDbgContinueStatus(DBG_EXCEPTION_NOT_HANDLED);
}
else //lock the exception
{
sprintf(msg, "last chance exception on "fhex" (%.8X)!", addr, edi->ExceptionRecord.ExceptionCode);
SetNextDbgContinueStatus(DBG_CONTINUE);
}
dputs(msg);
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
BOOL
CALLBACK
SymRegisterCallbackProc64(
__in HANDLE hProcess,
__in ULONG ActionCode,
__in_opt ULONG64 CallbackData,
__in_opt ULONG64 UserContext
)
{
UNREFERENCED_PARAMETER(hProcess);
UNREFERENCED_PARAMETER(UserContext);
PIMAGEHLP_CBA_EVENT evt;
// If SYMOPT_DEBUG is set, then the symbol handler will pass
// verbose information on its attempt to load symbols.
// This information be delivered as text strings.
switch (ActionCode)
{
case CBA_EVENT:
evt = (PIMAGEHLP_CBA_EVENT)CallbackData;
printf("%s", (PTSTR)evt->desc);
break;
default:
return FALSE;
}
return TRUE;
}
static void cbLoadDll(LOAD_DLL_DEBUG_INFO* LoadDll)
{
void* base=LoadDll->lpBaseOfDll;
char DLLDebugFileName[deflen]="";
if(!GetMappedFileNameA(fdProcessInfo->hProcess, base, DLLDebugFileName, deflen))
strcpy(DLLDebugFileName, "??? (GetMappedFileName failed)");
else
DevicePathToPath(DLLDebugFileName, DLLDebugFileName, deflen);
dprintf("DLL Loaded: "fhex" %s\n", base, DLLDebugFileName);
SymLoadModuleEx(fdProcessInfo->hProcess, LoadDll->hFile, DLLDebugFileName, 0, (DWORD64)base, 0, 0, 0);
IMAGEHLP_MODULE64 modInfo;
memset(&modInfo, 0, sizeof(modInfo));
modInfo.SizeOfStruct=sizeof(IMAGEHLP_MODULE64);
if(SymGetModuleInfo64(fdProcessInfo->hProcess, (DWORD64)base, &modInfo))
modload(modInfo.BaseOfImage, modInfo.ImageSize, modInfo.ModuleName);
}
static void cbUnloadDll(UNLOAD_DLL_DEBUG_INFO* UnloadDll)
{
void* base=UnloadDll->lpBaseOfDll;
char DLLDebugFileName[deflen]="";
if(!GetMappedFileNameA(fdProcessInfo->hProcess, base, DLLDebugFileName, deflen))
strcpy(DLLDebugFileName, "??? (GetMappedFileName failed)");
else
DevicePathToPath(DLLDebugFileName, DLLDebugFileName, deflen);
dprintf("DLL Unloaded: "fhex" %s\n", base, DLLDebugFileName);
SymUnloadModule64(fdProcessInfo->hProcess, (DWORD64)base);
modunload((uint)base);
}
static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
{
void* base=CreateProcessInfo->lpBaseOfImage;
char DebugFileName[deflen]="";
if(!GetMappedFileNameA(fdProcessInfo->hProcess, base, DebugFileName, deflen))
strcpy(DebugFileName, "??? (GetMappedFileName failed)");
else
DevicePathToPath(DebugFileName, DebugFileName, deflen);
dprintf("Process Started: "fhex" %s\n", base, DebugFileName);
//init program database
int len=strlen(szFileName);
while(szFileName[len]!='\\' && len!=0)
len--;
if(len)
len++;
strcpy(sqlitedb, szFileName+len);
#ifdef _WIN64
strcat(sqlitedb, ".dd64");
#else
strcat(sqlitedb, ".dd32");
#endif // _WIN64
sprintf(dbpath, "%s\\%s", sqlitedb_basedir, sqlitedb);
dprintf("Database file: %s\n", dbpath);
dbinit();
//SymSetOptions(SYMOPT_DEBUG|SYMOPT_LOAD_LINES);
SymInitialize(fdProcessInfo->hProcess, 0, false); //initialize symbols
//SymRegisterCallback64(fdProcessInfo->hProcess, SymRegisterCallbackProc64, 0);
SymLoadModuleEx(fdProcessInfo->hProcess, CreateProcessInfo->hFile, DebugFileName, 0, (DWORD64)base, 0, 0, 0);
IMAGEHLP_MODULE64 modInfo;
memset(&modInfo, 0, sizeof(modInfo));
modInfo.SizeOfStruct=sizeof(IMAGEHLP_MODULE64);
if(SymGetModuleInfo64(fdProcessInfo->hProcess, (DWORD64)base, &modInfo))
modload(modInfo.BaseOfImage, modInfo.ImageSize, modInfo.ModuleName);
}
static void cbSystemBreakpoint(void* ExceptionData)
{
//TODO: handle stuff (TLS, main entry, etc)
SetCustomHandler(UE_CH_SYSTEMBREAKPOINT, 0);
//log message
dputs("system breakpoint reached!");
//update GUI
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//unlock
unlock(WAITID_SYSBREAK);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
/*//my code
//list memorymap(cbListPage)
ReadMemory(va)
setBP(va, type, callback)
//gui
GuiChangeCIP(va, base, size)
//gui
cbClearMap
cbAddPage(MEMORY_BASIC_INFO, modulename)
cbEndMap
//dbg
MemoryMap(cbClear, cbAddPage, cbEndMap)
*/
}
static void cbStep()
{
isStepping=false;
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static void cbRtrFinalStep()
{
DebugUpdateGui(GetContextData(UE_CIP));
GuiSetDebugState(paused);
//lock
lock(WAITID_RUN);
wait(WAITID_RUN);
}
static unsigned char getCIPch()
{
char ch;
dbgdisablebpx();
memread(fdProcessInfo->hProcess, (void*)GetContextData(UE_CIP), &ch, 1, 0);
dbgenablebpx();
return ch;
}
static void cbRtrStep()
{
unsigned int cipch=getCIPch();
if(cipch==0xC3 or cipch==0xC2)
cbRtrFinalStep();
else
StepOver((void*)cbRtrStep);
}
static DWORD WINAPI threadDebugLoop(void* lpParameter)
{
//initialize
INIT_STRUCT* init=(INIT_STRUCT*)lpParameter;
bFileIsDll=IsFileDLL(init->exe, 0);
if(bFileIsDll)
fdProcessInfo=(PROCESS_INFORMATION*)InitDLLDebug(init->exe, false, init->commandline, init->currentfolder, (void*)cbEntryBreakpoint);
else
fdProcessInfo=(PROCESS_INFORMATION*)InitDebugEx(init->exe, init->commandline, init->currentfolder, (void*)cbEntryBreakpoint);
if(!fdProcessInfo)
{
fdProcessInfo=&g_pi;
dputs("error starting process (invalid pe?)!");
unlock(WAITID_SYSBREAK);
return 0;
}
lock(WAITID_STOP);
strcpy(szFileName, init->exe);
efree(init, "threadDebugLoop:init"); //free init struct
varset("$hp", (uint)fdProcessInfo->hProcess, true);
varset("$pid", fdProcessInfo->dwProcessId, true);
ecount=0;
bplist=bpinit();
//NOTE: set custom handlers
SetCustomHandler(UE_CH_CREATEPROCESS, (void*)cbCreateProcess);
SetCustomHandler(UE_CH_SYSTEMBREAKPOINT, (void*)cbSystemBreakpoint);
SetCustomHandler(UE_CH_UNHANDLEDEXCEPTION, (void*)cbException);
SetCustomHandler(UE_CH_LOADDLL, (void*)cbLoadDll);
SetCustomHandler(UE_CH_UNLOADDLL, (void*)cbUnloadDll);
//inform GUI start we started without problems
GuiSetDebugState(initialized);
//run debug loop (returns when process debugging is stopped)
DebugLoop();
DeleteFileA("DLLLoader.exe");
//message the user/do final stuff
SymCleanup(fdProcessInfo->hProcess);
dbclose();
GuiSetDebugState(stopped);
bpfree(bplist);
dputs("debugging stopped!");
varset("$hp", 0, true);
varset("$pid", 0, true);
unlock(WAITID_STOP);
waitclear();
return 0;
}
CMDRESULT cbDebugInit(const char* cmd)
{
if(IsFileBeingDebugged())
{
dputs("already debugging!");
return STATUS_ERROR;
}
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
if(!FileExists(arg1))
{
dputs("file does not exsist!");
return STATUS_ERROR;
}
char arg2[deflen]="";
argget(cmd, arg2, 1, true);
char* commandline=0;
if(strlen(arg2))
commandline=arg2;
char arg3[deflen]="";
argget(cmd, arg3, 2, true);
char currentfolder[deflen]="";
strcpy(currentfolder, arg1);
int len=strlen(currentfolder);
while(currentfolder[len]!='\\' and len!=0)
len--;
currentfolder[len]=0;
if(DirExists(arg3))
strcpy(currentfolder, arg3);
INIT_STRUCT* init=(INIT_STRUCT*)emalloc(sizeof(INIT_STRUCT), "cbDebugInit:init");
memset(init, 0, sizeof(INIT_STRUCT));
init->exe=arg1;
init->commandline=commandline;
if(*currentfolder)
init->currentfolder=currentfolder;
//initialize
waitclear(); //clear waiting flags
lock(WAITID_SYSBREAK);
if(!CreateThread(0, 0, threadDebugLoop, init, 0, 0))
{
dputs("failed creating debug thread!");
return STATUS_ERROR;
}
wait(WAITID_SYSBREAK);
return STATUS_CONTINUE;
}
CMDRESULT cbStopDebug(const char* cmd)
{
StopDebug();
unlock(WAITID_RUN);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugRun(const char* cmd)
{
if(!waitislocked(WAITID_RUN))
{
dputs("program is already running");
return STATUS_ERROR;
}
GuiSetDebugState(running);
unlock(WAITID_RUN);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugSetBPXOptions(const char* cmd)
{
char argtype[deflen]="";
uint type=0;
if(!argget(cmd, argtype, 0, false))
return STATUS_ERROR;
const char* a=0;
if(strstr(argtype, "long"))
{
a="TYPE_LONG_INT3";
type=UE_BREAKPOINT_TYPE_LONG_INT3;
}
else if(strstr(argtype, "ud2"))
{
a="TYPE_UD2";
type=UE_BREAKPOINT_TYPE_UD2;
}
else if(strstr(argtype, "short"))
{
a="TYPE_INT3";
type=UE_BREAKPOINT_TYPE_INT3;
}
else
{
dputs("invalid type specified!");
return STATUS_ERROR;
}
SetBPXOptions(type);
dprintf("default breakpoint type set to: %s\n", a);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugSetBPX(const char* cmd) //bp addr [,name [,type]]
{
char argaddr[deflen]="";
if(!argget(cmd, argaddr, 0, true))
if(!_strnicmp(cmd, "bp", 2))
return cbBadCmd(cmd);
if(!argget(cmd, argaddr, 0, false))
return STATUS_ERROR;
char argname[deflen]="";
argget(cmd, argname, 1, true);
char argtype[deflen]="";
bool has_arg2=argget(cmd, argtype, 2, true);
if(!has_arg2 and (scmp(argname, "ss") or scmp(argname, "long") or scmp(argname, "ud2")))
{
strcpy(argtype, argname);
*argname=0;
}
_strlwr(argtype);
uint addr=0;
if(!valfromstring(argaddr, &addr, 0, 0, false, 0))
{
dprintf("invalid addr: \"%s\"\n", argaddr);
return STATUS_ERROR;
}
if(addr==(uint)(GetPE32Data(szFileName, 0, UE_OEP)+GetPE32Data(szFileName, 0, UE_IMAGEBASE)))
{
dputs("entry breakpoint will be set automatically");
return STATUS_ERROR;
}
uint type=0;
BP_TYPE list_type;
if(strstr(argtype, "ss"))
{
type|=UE_SINGLESHOOT;
list_type=BPSINGLESHOOT;
}
else
{
type|=UE_BREAKPOINT;
list_type=BPNORMAL;
}
if(strstr(argtype, "long"))
type|=UE_BREAKPOINT_TYPE_LONG_INT3;
else if(strstr(argtype, "ud2"))
type|=UE_BREAKPOINT_TYPE_UD2;
else if(strstr(argtype, "short"))
type|=UE_BREAKPOINT_TYPE_INT3;
short oldbytes;
BREAKPOINT* found=bpfind(bplist, 0, addr, 0, BPNORMAL);
if(IsBPXEnabled(addr) or !memread(fdProcessInfo->hProcess, (void*)addr, &oldbytes, sizeof(short), 0) or found or !SetBPX(addr, type, (void*)cbUserBreakpoint))
{
dprintf("error setting breakpoint at "fhex"!\n", addr);
return STATUS_ERROR;
}
if(bpnew(bplist, argname, addr, oldbytes, list_type))
dprintf("breakpoint at "fhex" set!\n", addr);
else
dputs("problem setting breakpoint!");
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugEnableBPX(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, true)) //enable all breakpoints
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
{
dputs("no breakpoints!");
return STATUS_ERROR;
}
bool bNext=true;
CMDRESULT res=STATUS_CONTINUE;
while(bNext)
{
if(!SetBPX(cur->addr, cur->type, (void*)cbUserBreakpoint))
{
dprintf("could not enable %.8X\n", cur->addr);
res=STATUS_ERROR;
}
else
cur->enabled=true;
cur=cur->next;
if(!cur)
bNext=false;
}
dputs("all breakpoints enabled!");
GuiUpdateAllViews();
return res;
}
BREAKPOINT* bp=bpfind(bplist, arg1, 0, 0, BPNORMAL);
if(!bp)
{
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
{
dprintf("invalid addr: \"%s\"\n", arg1);
return STATUS_ERROR;
}
bp=bpfind(bplist, 0, addr, 0, BPNORMAL);
if(!bp)
{
dprintf("no such breakpoint: \"%s\"\n", arg1);
return STATUS_ERROR;
}
}
if(bp->type!=BPNORMAL and bp->type!=BPSINGLESHOOT)
{
dputs("this breakpoint type cannot be enabled");
return STATUS_ERROR;
}
if(bp->enabled)
{
dputs("breakpoint already enabled!");
return STATUS_ERROR;
}
if(!SetBPX(bp->addr, bp->type, (void*)cbUserBreakpoint))
dputs("could not enable breakpoint");
else
bp->enabled=true;
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugDisableBPX(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, true)) //disable all breakpoints
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
{
dputs("no breakpoints!");
return STATUS_ERROR;
}
bool bNext=true;
CMDRESULT res=STATUS_CONTINUE;
while(bNext)
{
if(!DeleteBPX(cur->addr))
{
dprintf("could not disable %.8X\n", cur->addr);
res=STATUS_ERROR;
}
else
cur->enabled=false;
cur=cur->next;
if(!cur)
bNext=false;
}
dputs("all breakpoints disabled!");
GuiUpdateAllViews();
return res;
}
BREAKPOINT* bp=bpfind(bplist, arg1, 0, 0, BPNORMAL);
if(!bp)
{
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
{
dprintf("invalid addr: \"%s\"\n", arg1);
return STATUS_ERROR;
}
bp=bpfind(bplist, 0, addr, 0, BPNORMAL);
if(!bp)
{
dprintf("no such breakpoint: \"%s\"\n", arg1);
return STATUS_ERROR;
}
}
if(bp->type!=BPNORMAL and bp->type!=BPSINGLESHOOT)
{
dputs("this breakpoint type cannot be disabled");
return STATUS_ERROR;
}
if(!bp->enabled)
{
dputs("breakpoint already disabled!");
return STATUS_ERROR;
}
if(!DeleteBPX(bp->addr))
dputs("could not disable breakpoint");
else
bp->enabled=false;
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugToggleBPX(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
BREAKPOINT* bp=bpfind(bplist, arg1, 0, 0, BPNORMAL);
if(!bp)
{
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
{
dprintf("invalid addr: \"%s\"\n", arg1);
return STATUS_ERROR;
}
bp=bpfind(bplist, 0, addr, 0, BPNORMAL);
if(!bp)
{
dprintf("no such breakpoint: \"%s\"\n", arg1);
return STATUS_ERROR;
}
}
if(bp->type!=BPNORMAL and bp->type!=BPSINGLESHOOT)
{
dputs("this breakpoint type cannot be toggled");
return STATUS_ERROR;
}
bool disable=bp->enabled;
if(disable)
{
if(!DeleteBPX(bp->addr))
{
dputs("could not disable breakpoint");
return STATUS_ERROR;
}
else
{
bp->enabled=false;
dputs("breakpoint disabled!");
}
}
else
{
if(!SetBPX(bp->addr, bp->type, (void*)cbUserBreakpoint))
{
dputs("could not disable breakpoint");
return STATUS_ERROR;
}
else
{
bp->enabled=true;
dputs("breakpoint enabled!");
}
}
varset("$res", (uint)disable, false);
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugDeleteBPX(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, true)) //delete all breakpoints
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
{
dputs("no breakpoints!");
return STATUS_ERROR;
}
bool bNext=true;
while(bNext)
{
BREAKPOINT* next=cur->next;
if(cur->type==BPNORMAL or cur->type==BPSINGLESHOOT)
{
DeleteBPX(cur->addr);
bpdel(bplist, 0, cur->addr, BPNORMAL);
}
cur=next;
if(!cur)
bNext=false;
}
//memset(bplist, 0, sizeof(BREAKPOINT));
dputs("all breakpoints deleted!");
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
BREAKPOINT* bp=bpfind(bplist, arg1, 0, 0, BPNORMAL);
if(!bp)
{
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
{
dprintf("invalid addr: \"%s\"\n", arg1);
return STATUS_ERROR;
}
bp=bpfind(bplist, 0, addr, 0, BPNORMAL);
if(!bp)
{
dprintf("no such breakpoint: \"%s\"\n", arg1);
return STATUS_ERROR;
}
}
if(!DeleteBPX(bp->addr))
{
dprintf("delete breakpoint failed: "fhex"\n", bp->addr);
return STATUS_ERROR;
}
bpdel(bplist, 0, bp->addr, BPNORMAL);
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugBplist(const char* cmd)
{
BREAKPOINT* cur=bplist;
if(!cur or !cur->addr)
{
dputs("no breakpoints!");
return STATUS_CONTINUE;
}
bool bNext=true;
while(bNext)
{
const char* type=0;
if(cur->type==BPNORMAL)
type="BP";
if(cur->type==BPSINGLESHOOT)
type="SS";
if(cur->type==BPHARDWARE)
type="HW";
if(cur->type==BPMEMORY)
type="GP";
bool enabled=cur->enabled;
if(cur->name)
dprintf("%d:%s:"fhex":\"%s\"\n", enabled, type, cur->addr, cur->name);
else
dprintf("%d:%s:"fhex"\n", enabled, type, cur->addr);
cur=cur->next;
if(!cur)
bNext=false;
}
return STATUS_CONTINUE;
}
CMDRESULT cbDebugStepInto(const char* cmd)
{
StepInto((void*)cbStep);
isStepping=true;
return cbDebugRun(cmd);
}
CMDRESULT cbDebugStepOver(const char* cmd)
{
StepOver((void*)cbStep);
isStepping=true;
return cbDebugRun(cmd);
}
CMDRESULT cbDebugSingleStep(const char* cmd)
{
char arg1[deflen]="";
uint stepcount=1;
if(argget(cmd, arg1, 0, true))
{
if(!valfromstring(arg1, &stepcount, 0, 0, true, 0))
stepcount=1;
}
SingleStep((DWORD)stepcount, (void*)cbStep);
isStepping=true;
return cbDebugRun(cmd);
}
CMDRESULT cbDebugHide(const char* cmd)
{
if(HideDebugger(fdProcessInfo->hProcess, UE_HIDE_BASIC))
dputs("debugger hidden");
else
dputs("something went wrong");
return STATUS_CONTINUE;
}
CMDRESULT cbDebugDisasm(const char* cmd)
{
char arg1[deflen]="";
uint addr=GetContextData(UE_CIP);
if(argget(cmd, arg1, 0, true))
if(!valfromstring(arg1, &addr, 0, 0, true, 0))
addr=GetContextData(UE_CIP);
DebugUpdateGui(addr);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugMemoryBpx(const char* cmd)
{
char arg1[deflen]=""; //addr
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
uint addr;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
return STATUS_ERROR;
bool restore=false;
char arg2[deflen]=""; //restore
char arg3[deflen]=""; //type
argget(cmd, arg3, 2, true);
if(argget(cmd, arg2, 1, true))
{
if(*arg2=='1')
restore=true;
else if(*arg2=='0')
restore=false;
else
strcpy(arg3, arg2);
}
uint type=UE_MEMORY;
if(*arg3)
{
switch(*arg3)
{
case 'r':
type=UE_MEMORY_READ;
break;
case 'w':
type=UE_MEMORY_WRITE;
break;
case 'x':
type=UE_MEMORY_EXECUTE; //EXECUTE
break;
default:
dputs("invalid type (argument ignored)");
break;
}
}
uint size=0;
uint base=memfindbaseaddr(fdProcessInfo->hProcess, addr, &size);
BREAKPOINT* found=bpfind(bplist, 0, base, 0, BPMEMORY);
if(found or !SetMemoryBPXEx(base, size, type, restore, (void*)cbMemoryBreakpoint))
{
dputs("error setting memory breakpoint!");
return STATUS_ERROR;
}
if(bpnew(bplist, 0, addr, (restore<<4)|type, BPMEMORY))
dprintf("memory breakpoint at "fhex" set!\n", addr);
else
dputs("problem setting breakpoint (report please)!");
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugRtr(const char* cmd)
{
StepOver((void*)cbRtrStep);
cbDebugRun(cmd);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugSetHardwareBreakpoint(const char* cmd)
{
char arg1[deflen]=""; //addr
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
uint addr;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
return STATUS_ERROR;
uint type=UE_HARDWARE_EXECUTE;
char arg2[deflen]=""; //type
if(argget(cmd, arg2, 1, true))
{
switch(*arg2)
{
case 'r':
type=UE_HARDWARE_READWRITE;
break;
case 'w':
type=UE_HARDWARE_WRITE;
break;
case 'x':
break;
default:
dputs("invlalid type, assuming 'x'");
break;
}
}
char arg3[deflen]=""; //size
uint size=UE_HARDWARE_SIZE_1;
if(argget(cmd, arg3, 2, true))
{
if(!valfromstring(arg3, &size, 0, 0, false, 0))
return STATUS_ERROR;
switch(size)
{
case 2:
size=UE_HARDWARE_SIZE_2;
break;
case 4:
size=UE_HARDWARE_SIZE_4;
break;
#ifdef _WIN64
case 8:
size=UE_HARDWARE_SIZE_8;
break;
#endif // _WIN64
default:
dputs("invalid size, using 1");
break;
}
if(addr%size)
{
dprintf("address not aligned to %d\n", size);
return STATUS_ERROR;
}
}
DWORD drx=0;
if(!GetUnusedHardwareBreakPointRegister(&drx))
{
dputs("no free debug register");
return STATUS_ERROR;
}
BREAKPOINT* found=bpfind(bplist, 0, addr, 0, BPHARDWARE);
if(found or !SetHardwareBreakPoint(addr, drx, type, size, (void*)cbHardwareBreakpoint))
{
dputs("error setting hardware breakpoint!");
return STATUS_ERROR;
}
if(bpnew(bplist, 0, addr, (drx<<8)|(type<<4)|size, BPHARDWARE))
dprintf("hardware breakpoint at "fhex" set!\n", addr);
else
dputs("problem setting breakpoint (report please)!");
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbDebugAlloc(const char* cmd)
{
char arg1[deflen]=""; //size
uint size=0x1000;
if(argget(cmd, arg1, 0, true))
if(!valfromstring(arg1, &size, 0, 0, false, 0))
return STATUS_ERROR;
uint mem=(uint)memalloc(fdProcessInfo->hProcess, 0, size, PAGE_EXECUTE_READWRITE);
if(!mem)
dputs("VirtualAllocEx failed");
else
dprintf(fhex"\n", mem);
if(mem)
varset("$lastalloc", mem, true);
varset("$res", mem, false);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugFree(const char* cmd)
{
uint lastalloc;
varget("$lastalloc", &lastalloc, 0, 0);
char arg1[deflen]=""; //addr
uint addr=lastalloc;
if(argget(cmd, arg1, 0, true))
{
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
return STATUS_ERROR;
}
else if(!lastalloc)
dputs("lastalloc is zero, provide a page address");
if(addr==lastalloc)
varset("$lastalloc", 0, true);
bool ok=VirtualFreeEx(fdProcessInfo->hProcess, (void*)addr, 0, MEM_RELEASE);
if(!ok)
dputs("VirtualFreeEx failed");
varset("$res", ok, false);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugMemset(const char* cmd)
{
char arg1[deflen]=""; //addr
char arg2[deflen]=""; //value
char arg3[deflen]=""; //size
uint addr;
uint value;
uint size;
if(!argget(cmd, arg1, 0, false) or !argget(cmd, arg2, 1, false))
return STATUS_ERROR;
if(!valfromstring(arg1, &addr, 0, 0, false, 0) or !valfromstring(arg2, &value, 0, 0, false, 0))
return STATUS_ERROR;
if(argget(cmd, arg3, 2, true))
{
if(!valfromstring(arg3, &size, 0, 0, false, 0))
return STATUS_ERROR;
}
else
{
uint base=memfindbaseaddr(fdProcessInfo->hProcess, addr, &size);
if(!base)
{
dputs("invalid address specified");
return STATUS_ERROR;
}
uint diff=addr-base;
addr=base+diff;
size-=diff;
}
BYTE fi=value&0xFF;
if(!Fill((void*)addr, size&0xFFFFFFFF, &fi))
dputs("memset failed");
else
dprintf("memory "fhex" (size: %.8X) set to %.2X\n", addr, size&0xFFFFFFFF, value&0xFF);
return STATUS_CONTINUE;
}
CMDRESULT cbBenchmark(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
return STATUS_ERROR;
uint ticks=GetTickCount();
char comment[MAX_COMMENT_SIZE]="";
commentset(addr, "benchmark");
for(int i=0; i<100000; i++)
{
commentget(addr, comment);
}
commentdel(addr);
dprintf("%ums\n", GetTickCount()-ticks);
return STATUS_CONTINUE;
}
CMDRESULT cbDebugPause(const char* cmd)
{
if(waitislocked(WAITID_RUN))
{
dputs("program is not running");
return STATUS_ERROR;
}
isPausedByUser=true;
DebugBreakProcess(fdProcessInfo->hProcess);
return STATUS_CONTINUE;
}
CMDRESULT cbMemWrite(const char* cmd)
{
char arg1[deflen]="";
if(!argget(cmd, arg1, 0, false))
return STATUS_ERROR;
uint addr=0;
if(!valfromstring(arg1, &addr, 0, 0, false, 0))
return STATUS_ERROR;
unsigned char* blub=(unsigned char*)emalloc(0x2123, "cbMemWrite:blub");
memread(fdProcessInfo->hProcess, (const void*)addr, blub, 0x2123, 0);
//memwrite(fdProcessInfo->hProcess, (void*)addr, blub, 0x2123, 0);
return STATUS_CONTINUE;
}
DWORD WINAPI scyllaThread(void* lpParam)
{
typedef INT (WINAPI * SCYLLASTARTGUI)(DWORD pid, HINSTANCE mod);
SCYLLASTARTGUI ScyllaStartGui=0;
HINSTANCE hScylla=LoadLibraryA("Scylla.dll");
if(!hScylla)
{
dputs("error loading Scylla.dll!");
bScyllaLoaded=false;
return 0;
}
ScyllaStartGui=(SCYLLASTARTGUI)GetProcAddress(hScylla, "ScyllaStartGui");
if(!ScyllaStartGui)
{
dputs("could not find export 'ScyllaStartGui' inside Scylla.dll");
bScyllaLoaded=false;
return 0;
}
if(bFileIsDll)
ScyllaStartGui(fdProcessInfo->dwProcessId, (HINSTANCE)pDebuggedDllBase);
else
ScyllaStartGui(fdProcessInfo->dwProcessId, 0);
FreeLibrary(hScylla);
bScyllaLoaded=false;
return 0;
}
CMDRESULT cbStartScylla(const char* cmd)
{
if(bScyllaLoaded)
{
dputs("Scylla is already loaded");
return STATUS_ERROR;
}
bScyllaLoaded=true;
CreateThread(0, 0, scyllaThread, 0, 0, 0);
return STATUS_CONTINUE;
}