diff --git a/README.TXT b/README.TXT index e725e4d..f67c50d 100644 --- a/README.TXT +++ b/README.TXT @@ -1,40 +1,40 @@ - - - DBGCB Engine - - by Oleksiuk Dmytro (aka Cr4sh), Esage Lab - - http://d-olex.blogspot.com/ - mailto:dmitry@esagelab.com - -================================= - -Engine for communication with remote kernel debugger (WinDBG, KD) from drivers or user mode application. - -./dbgcb.dll - WinDbg extension, that must be loaded in remote kernel debugger -./common/ - dbgcb client code (can be used in your own applications) -./_Examples/dbgcb_drv.sys - Sample driver -./_Examples/dbgcb_app.exe - Sample user mode application - -Engine working scheme: ./dbgcb_scheme.png -Engine with test driver (dbgcb_drv.sys): ./dbgcb_in_work.png - - - Currently supported functions (see ./common/dbgcb_api.h): - -/** - * Execute debuuger command (IDebugControl::Execute()). - */ -BOOLEAN dbg_exec(PCHAR lpFormat, ...); - -/** - * Evaluate debuuger expression (IDebugControl::Evaluate()). - */ -PVOID dbg_eval(PCHAR lpFormat, ...); - -/** - * Get offset of the some structure field - */ -LONG dbg_field_offset(PCHAR lpFormat, ...); - - + + + DBGCB Engine + + by Oleksiuk Dmytro (aka Cr4sh), Esage Lab + + http://d-olex.blogspot.com/ + mailto:dmitry@esagelab.com + +================================= + +Engine for communication with remote kernel debugger (WinDBG, KD) from drivers or user mode application. + +./dbgcb.dll - WinDbg extension, that must be loaded in remote kernel debugger +./common/ - dbgcb client code (can be used in your own applications) +./_Examples/dbgcb_drv.sys - Sample driver +./_Examples/dbgcb_app.exe - Sample user mode application + +Engine working scheme: ./dbgcb_scheme.png +Engine with test driver (dbgcb_drv.sys): ./dbgcb_in_work.png + + + Currently supported functions (see ./common/dbgcb_api.h): + +/** + * Execute debuuger command (IDebugControl::Execute()). + */ +BOOLEAN dbg_exec(PCHAR lpFormat, ...); + +/** + * Evaluate debuuger expression (IDebugControl::Evaluate()). + */ +PVOID dbg_eval(PCHAR lpFormat, ...); + +/** + * Get offset of the some structure field + */ +LONG dbg_field_offset(PCHAR lpFormat, ...); + + diff --git a/_Examples/dbgcb_app/dbgcb_app.cpp b/_Examples/dbgcb_app/dbgcb_app.cpp index 8caf469..142ccb1 100644 --- a/_Examples/dbgcb_app/dbgcb_app.cpp +++ b/_Examples/dbgcb_app/dbgcb_app.cpp @@ -1,91 +1,91 @@ -#include -#include -#include - -#include "../../common/dbgcb_api.h" -//-------------------------------------------------------------------------------------- -void DbgPrint(char *lpszMsg, ...) -{ - va_list mylist; - va_start(mylist, lpszMsg); - - size_t len = _vscprintf(lpszMsg, mylist) + 0x100; - - char *lpszBuff = (char *)LocalAlloc(LMEM_FIXED, len); - if (lpszBuff == NULL) - { - va_end(mylist); - return; - } - - vsprintf_s(lpszBuff, len, lpszMsg, mylist); - va_end(mylist); - - OutputDebugString(lpszBuff); - - HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStd != INVALID_HANDLE_VALUE) - { - DWORD dwWritten = 0; - WriteFile(hStd, lpszBuff, strlen(lpszBuff), &dwWritten, NULL); - } - - LocalFree(lpszBuff); -} -//-------------------------------------------------------------------------------------- -int -__cdecl -main( - __in ULONG argc, - __in_ecount(argc) PCHAR argv[]) -{ - UNREFERENCED_PARAMETER(argc); - UNREFERENCED_PARAMETER(argv); - - printf("*******************************************************\n\n"); - printf(" KERNEL DEBUGGER COMMUNICATION ENGINE\n"); - printf(" Test application\n\n"); - printf(" Developed by: Oleksiuk Dmytro (aka Cr4sh), Esage Lab\n\n"); - printf(" mailto:dmitry@esagelab.com\n\n"); - printf("*******************************************************\n\n"); - - // Test debugger command execution. - if (dbg_exec(".printf /D \"Hello from " __FUNCTION__ "(), PID=%d\\n\"", GetCurrentProcessId())) - { - DbgPrint("Reloading debug symbols and executing 'kb' in debugger...\n"); - dbg_exec(".reload;kb"); - - // Test symbol querying. - PVOID Addr = dbg_eval("ntdll!KiUserCallbackDispatcher"); - if (Addr) - { - DbgPrint("ntdll!KiUserCallbackDispatcher() is at "IFMT"\n", Addr); - } - else - { - DbgPrint(__FUNCTION__"() ERROR: dbg_eval() fails\n"); - } - - // Test structure field offset querying. - LONG Offset = dbg_field_offset("ntdll!_PEB::KernelCallbackTable"); - if (Offset >= 0) - { - DbgPrint("_PEB::KernelCallbackTable offset is 0x%x\n", Offset); - } - else - { - DbgPrint(__FUNCTION__"() ERROR: dbg_field_offset() fails\n"); - } - } - else - { - DbgPrint(__FUNCTION__"() WARNING: dbgcb extension is not loaded or no connection to remote kernel debugger\n"); - } - - printf("\nPress any key to quit...\n"); - _getch(); - - return 0; -} -//-------------------------------------------------------------------------------------- -// EoF +#include +#include +#include + +#include "../../common/dbgcb_api.h" +//-------------------------------------------------------------------------------------- +void DbgPrint(char *lpszMsg, ...) +{ + va_list mylist; + va_start(mylist, lpszMsg); + + size_t len = _vscprintf(lpszMsg, mylist) + 0x100; + + char *lpszBuff = (char *)LocalAlloc(LMEM_FIXED, len); + if (lpszBuff == NULL) + { + va_end(mylist); + return; + } + + vsprintf_s(lpszBuff, len, lpszMsg, mylist); + va_end(mylist); + + OutputDebugString(lpszBuff); + + HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStd != INVALID_HANDLE_VALUE) + { + DWORD dwWritten = 0; + WriteFile(hStd, lpszBuff, strlen(lpszBuff), &dwWritten, NULL); + } + + LocalFree(lpszBuff); +} +//-------------------------------------------------------------------------------------- +int +__cdecl +main( + __in ULONG argc, + __in_ecount(argc) PCHAR argv[]) +{ + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + printf("*******************************************************\n\n"); + printf(" KERNEL DEBUGGER COMMUNICATION ENGINE\n"); + printf(" Test application\n\n"); + printf(" Developed by: Oleksiuk Dmytro (aka Cr4sh), Esage Lab\n\n"); + printf(" mailto:dmitry@esagelab.com\n\n"); + printf("*******************************************************\n\n"); + + // Test debugger command execution. + if (dbg_exec(".printf /D \"Hello from " __FUNCTION__ "(), PID=%d\\n\"", GetCurrentProcessId())) + { + DbgPrint("Reloading debug symbols and executing 'kb' in debugger...\n"); + dbg_exec(".reload;kb"); + + // Test symbol querying. + PVOID Addr = dbg_eval("ntdll!KiUserCallbackDispatcher"); + if (Addr) + { + DbgPrint("ntdll!KiUserCallbackDispatcher() is at "IFMT"\n", Addr); + } + else + { + DbgPrint(__FUNCTION__"() ERROR: dbg_eval() fails\n"); + } + + // Test structure field offset querying. + LONG Offset = dbg_field_offset("ntdll!_PEB::KernelCallbackTable"); + if (Offset >= 0) + { + DbgPrint("_PEB::KernelCallbackTable offset is 0x%x\n", Offset); + } + else + { + DbgPrint(__FUNCTION__"() ERROR: dbg_field_offset() fails\n"); + } + } + else + { + DbgPrint(__FUNCTION__"() WARNING: dbgcb extension is not loaded or no connection to remote kernel debugger\n"); + } + + printf("\nPress any key to quit...\n"); + _getch(); + + return 0; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/_Examples/dbgcb_app/dbgcb_stub.cpp b/_Examples/dbgcb_app/dbgcb_stub.cpp index 9de03cd..ebcc7de 100644 --- a/_Examples/dbgcb_app/dbgcb_stub.cpp +++ b/_Examples/dbgcb_app/dbgcb_stub.cpp @@ -1,2 +1,2 @@ - -#include "../../common/dbgcb_client.cpp" + +#include "../../common/dbgcb_client.cpp" diff --git a/_Examples/dbgcb_app/makefile b/_Examples/dbgcb_app/makefile index 5818975..9c985f5 100644 --- a/_Examples/dbgcb_app/makefile +++ b/_Examples/dbgcb_app/makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/_Examples/dbgcb_app/sources b/_Examples/dbgcb_app/sources index 1c069b1..4dec9a7 100644 --- a/_Examples/dbgcb_app/sources +++ b/_Examples/dbgcb_app/sources @@ -1,22 +1,22 @@ - -!if "$(_BUILDARCH)"=="AMD64" -TARGETNAME = ..\..\..\dbgcb_app_x64 -!else -TARGETNAME = ..\..\..\dbgcb_app -!endif - -TARGETTYPE = PROGRAM - -TARGETLIBS = \ - $(SDK_LIB_PATH)\kernel32.lib \ - $(SDK_LIB_PATH)\user32.lib - -UMTYPE = console - -USE_MSVCRT = 1 - -SOURCES = \ - dbgcb_stub.cpp \ - dbgcb_app.cpp - -_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_WINXP) + +!if "$(_BUILDARCH)"=="AMD64" +TARGETNAME = ..\..\..\dbgcb_app_x64 +!else +TARGETNAME = ..\..\..\dbgcb_app +!endif + +TARGETTYPE = PROGRAM + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\user32.lib + +UMTYPE = console + +USE_MSVCRT = 1 + +SOURCES = \ + dbgcb_stub.cpp \ + dbgcb_app.cpp + +_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_WINXP) diff --git a/_Examples/dbgcb_drv.bat b/_Examples/dbgcb_drv.bat index b75a2d6..68dce79 100644 --- a/_Examples/dbgcb_drv.bat +++ b/_Examples/dbgcb_drv.bat @@ -1,24 +1,24 @@ -@echo off - -set SRCPATH=dbgcb_drv.sys -set DSTPATH=%SystemRoot%\system32\drivers\dbgcb_drv.sys - -:: copy driver to the system directory -copy %SRCPATH% %DSTPATH% /Y - -:: create service -sc create dbgcb_drv binPath= %DSTPATH% type= kernel start= demand - -:: start service -sc start dbgcb_drv - -:: stop service -sc stop dbgcb_drv - -:: delete service -sc delete dbgcb_drv - -:: delete file -del %DSTPATH% - -pause +@echo off + +set SRCPATH=dbgcb_drv.sys +set DSTPATH=%SystemRoot%\system32\drivers\dbgcb_drv.sys + +:: copy driver to the system directory +copy %SRCPATH% %DSTPATH% /Y + +:: create service +sc create dbgcb_drv binPath= %DSTPATH% type= kernel start= demand + +:: start service +sc start dbgcb_drv + +:: stop service +sc stop dbgcb_drv + +:: delete service +sc delete dbgcb_drv + +:: delete file +del %DSTPATH% + +pause diff --git a/_Examples/dbgcb_drv/dbgcb_drv.cpp b/_Examples/dbgcb_drv/dbgcb_drv.cpp index 1449b07..4a70881 100644 --- a/_Examples/dbgcb_drv/dbgcb_drv.cpp +++ b/_Examples/dbgcb_drv/dbgcb_drv.cpp @@ -1,71 +1,71 @@ -#include -#include -#include - -#include "../../common/dbgcb_api.h" - -extern "C" -{ -NTSTATUS NTAPI -DriverEntry( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath -); -} -//-------------------------------------------------------------------------------------- -VOID NTAPI DriverUnload(PDRIVER_OBJECT DriverObject) -{ - DbgPrint(__FUNCTION__"()\n"); -} -//-------------------------------------------------------------------------------------- -NTSTATUS NTAPI DriverEntry( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath) -{ - DriverObject->DriverUnload = DriverUnload; - - DbgPrint(__FUNCTION__"()\n"); - - // Test debugger command execution. - if (dbg_exec(".printf /D \"Hello from " __FUNCTION__ "()\\n\"")) - { - // another DML example - dbg_exec( - ".printf /D \"Show _DRIVER_OBJECT information.\\n\"", - DriverObject - ); - - DbgPrint("Breaking into the kernel debugger (check the DML link above)...\n"); - DbgBreakPoint(); - - // Test symbol querying. - PVOID Addr = dbg_eval("nt!KiDispatchException"); - if (Addr) - { - DbgPrint("nt!KiDispatchException() is at "IFMT"\n", Addr); - } - else - { - DbgPrint(__FUNCTION__"() ERROR: dbg_eval() fails\n"); - } - - // Test structure field offset querying. - LONG Offset = dbg_field_offset("nt!_EPROCESS::ImageFileName"); - if (Offset >= 0) - { - DbgPrint("_EPROCESS::ImageFileName offset is 0x%x\n", Offset); - } - else - { - DbgPrint(__FUNCTION__"() ERROR: dbg_field_offset() fails\n"); - } - } - else - { - DbgPrint(__FUNCTION__"() WARNING: dbgcb extension is not loaded\n"); - } - - return STATUS_SUCCESS; -} -//-------------------------------------------------------------------------------------- -// EoF +#include +#include +#include + +#include "../../common/dbgcb_api.h" + +extern "C" +{ +NTSTATUS NTAPI +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath +); +} +//-------------------------------------------------------------------------------------- +VOID NTAPI DriverUnload(PDRIVER_OBJECT DriverObject) +{ + DbgPrint(__FUNCTION__"()\n"); +} +//-------------------------------------------------------------------------------------- +NTSTATUS NTAPI DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + DriverObject->DriverUnload = DriverUnload; + + DbgPrint(__FUNCTION__"()\n"); + + // Test debugger command execution. + if (dbg_exec(".printf /D \"Hello from " __FUNCTION__ "()\\n\"")) + { + // another DML example + dbg_exec( + ".printf /D \"Show _DRIVER_OBJECT information.\\n\"", + DriverObject + ); + + DbgPrint("Breaking into the kernel debugger (check the DML link above)...\n"); + DbgBreakPoint(); + + // Test symbol querying. + PVOID Addr = dbg_eval("nt!KiDispatchException"); + if (Addr) + { + DbgPrint("nt!KiDispatchException() is at "IFMT"\n", Addr); + } + else + { + DbgPrint(__FUNCTION__"() ERROR: dbg_eval() fails\n"); + } + + // Test structure field offset querying. + LONG Offset = dbg_field_offset("nt!_EPROCESS::ImageFileName"); + if (Offset >= 0) + { + DbgPrint("_EPROCESS::ImageFileName offset is 0x%x\n", Offset); + } + else + { + DbgPrint(__FUNCTION__"() ERROR: dbg_field_offset() fails\n"); + } + } + else + { + DbgPrint(__FUNCTION__"() WARNING: dbgcb extension is not loaded\n"); + } + + return STATUS_SUCCESS; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/_Examples/dbgcb_drv/dbgcb_stub.cpp b/_Examples/dbgcb_drv/dbgcb_stub.cpp index 7cfd3c6..7ca4c64 100644 --- a/_Examples/dbgcb_drv/dbgcb_stub.cpp +++ b/_Examples/dbgcb_drv/dbgcb_stub.cpp @@ -1,3 +1,3 @@ - -#define DBGCB_DRIVER -#include "../../common/dbgcb_client.cpp" + +#define DBGCB_DRIVER +#include "../../common/dbgcb_client.cpp" diff --git a/_Examples/dbgcb_drv/makefile b/_Examples/dbgcb_drv/makefile index 5818975..9c985f5 100644 --- a/_Examples/dbgcb_drv/makefile +++ b/_Examples/dbgcb_drv/makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/_Examples/dbgcb_drv/sources b/_Examples/dbgcb_drv/sources index 2aa62c3..f84f87d 100644 --- a/_Examples/dbgcb_drv/sources +++ b/_Examples/dbgcb_drv/sources @@ -1,13 +1,13 @@ - -!if "$(_BUILDARCH)"=="AMD64" -TARGETNAME = ..\..\..\dbgcb_drv_x64 -!else -TARGETNAME = ..\..\..\dbgcb_drv -!endif - -TARGETTYPE = DRIVER - -SOURCES = \ - dbgcb_stub.cpp \ - dbgcb_drv.cpp - + +!if "$(_BUILDARCH)"=="AMD64" +TARGETNAME = ..\..\..\dbgcb_drv_x64 +!else +TARGETNAME = ..\..\..\dbgcb_drv +!endif + +TARGETTYPE = DRIVER + +SOURCES = \ + dbgcb_stub.cpp \ + dbgcb_drv.cpp + diff --git a/_Examples/dbgcb_drv_x64.bat b/_Examples/dbgcb_drv_x64.bat index 556c6b2..d7826c4 100644 --- a/_Examples/dbgcb_drv_x64.bat +++ b/_Examples/dbgcb_drv_x64.bat @@ -1,24 +1,24 @@ -@echo off - -set SRCPATH=dbgcb_drv_x64.sys -set DSTPATH=%SystemRoot%\system32\drivers\dbgcb_drv.sys - -:: copy driver to the system directory -copy %SRCPATH% %DSTPATH% /Y - -:: create service -sc create dbgcb_drv binPath= %DSTPATH% type= kernel start= demand - -:: start service -sc start dbgcb_drv - -:: stop service -sc stop dbgcb_drv - -:: delete service -sc delete dbgcb_drv - -:: delete file -del %DSTPATH% - -pause +@echo off + +set SRCPATH=dbgcb_drv_x64.sys +set DSTPATH=%SystemRoot%\system32\drivers\dbgcb_drv.sys + +:: copy driver to the system directory +copy %SRCPATH% %DSTPATH% /Y + +:: create service +sc create dbgcb_drv binPath= %DSTPATH% type= kernel start= demand + +:: start service +sc start dbgcb_drv + +:: stop service +sc stop dbgcb_drv + +:: delete service +sc delete dbgcb_drv + +:: delete file +del %DSTPATH% + +pause diff --git a/_Examples/dirs b/_Examples/dirs index b9363dd..823b224 100644 --- a/_Examples/dirs +++ b/_Examples/dirs @@ -1,3 +1,3 @@ -DIRS = \ - dbgcb_drv \ - dbgcb_app +DIRS = \ + dbgcb_drv \ + dbgcb_app diff --git a/build_ext.bat b/build_ext.bat index e017733..e97899c 100644 --- a/build_ext.bat +++ b/build_ext.bat @@ -1,10 +1,10 @@ -@echo off - -:: Path to the SDK from Microsoft Debugging Tools for Windows -set DBGSDK_PATH=D:\dbg\sdk - -set DBGSDK_INC_PATH=$(DBGSDK_PATH)\inc -set DBGSDK_LIB_PATH=$(DBGSDK_PATH)\lib -set DBGLIB_LIB_PATH=$(DBGSDK_PATH)\lib - -build +@echo off + +:: Path to the SDK from Microsoft Debugging Tools for Windows +set DBGSDK_PATH=D:\dbg\sdk + +set DBGSDK_INC_PATH=$(DBGSDK_PATH)\inc +set DBGSDK_LIB_PATH=$(DBGSDK_PATH)\lib +set DBGLIB_LIB_PATH=$(DBGSDK_PATH)\lib + +build diff --git a/common/dbgcb_api.h b/common/dbgcb_api.h index 3a21c53..4751c62 100644 --- a/common/dbgcb_api.h +++ b/common/dbgcb_api.h @@ -1,55 +1,55 @@ - -#ifndef _DBGCB_H_ -#define _DBGCB_H_ - -/** - * Magic constants for Kernel Debugger Communication Engine commands. - */ -#define DBGCB_GET_SYMBOL 'DBGS' -#define DBGCB_EXECUTE 'DBGE' -#define DBGCB_FIELD_OFFSET 'DBGF' - - -/** - * Format strings for 32/64-bit pointers. - */ - -#define IFMT32 "0x%.8x" -#define IFMT64 "0x%.16I64x" - -#define IFMT32_W L"0x%.8x" -#define IFMT64_W L"0x%.16I64x" - -#ifdef _X86_ - -#define IFMT IFMT32 -#define IFMT_W IFMT32_W - -#elif _AMD64_ - -#define IFMT IFMT64 -#define IFMT_W IFMT64_W - -#endif - - -/** - * Kernel Debugger Communication Engine functions. - */ - -/** - * Execute debuuger command (IDebugControl::Execute()). - */ -BOOLEAN dbg_exec(PCHAR lpFormat, ...); - -/** - * Evaluate debuuger expression (IDebugControl::Evaluate()). - */ -PVOID dbg_eval(PCHAR lpFormat, ...); - -/** - * Get offset of the some structure field - */ -LONG dbg_field_offset(PCHAR lpFormat, ...); - -#endif // _DBGCB_H_ + +#ifndef _DBGCB_H_ +#define _DBGCB_H_ + +/** + * Magic constants for Kernel Debugger Communication Engine commands. + */ +#define DBGCB_GET_SYMBOL 'DBGS' +#define DBGCB_EXECUTE 'DBGE' +#define DBGCB_FIELD_OFFSET 'DBGF' + + +/** + * Format strings for 32/64-bit pointers. + */ + +#define IFMT32 "0x%.8x" +#define IFMT64 "0x%.16I64x" + +#define IFMT32_W L"0x%.8x" +#define IFMT64_W L"0x%.16I64x" + +#ifdef _X86_ + +#define IFMT IFMT32 +#define IFMT_W IFMT32_W + +#elif _AMD64_ + +#define IFMT IFMT64 +#define IFMT_W IFMT64_W + +#endif + + +/** + * Kernel Debugger Communication Engine functions. + */ + +/** + * Execute debuuger command (IDebugControl::Execute()). + */ +BOOLEAN dbg_exec(PCHAR lpFormat, ...); + +/** + * Evaluate debuuger expression (IDebugControl::Evaluate()). + */ +PVOID dbg_eval(PCHAR lpFormat, ...); + +/** + * Get offset of the some structure field + */ +LONG dbg_field_offset(PCHAR lpFormat, ...); + +#endif // _DBGCB_H_ diff --git a/common/dbgcb_client.cpp b/common/dbgcb_client.cpp index f4d5d4a..efb60c6 100644 --- a/common/dbgcb_client.cpp +++ b/common/dbgcb_client.cpp @@ -1,133 +1,133 @@ - -/******************************************************* - - KERNEL DEBUGGER COMMUNICATION ENGINE - - Developed by: Oleksiuk Dmytro (aka Cr4sh), Esage Lab - - mailto:dmitry@esagelab.com - - http://esagelab.com/ - http://d-olex.blogspot.com/ - - *******************************************************/ - -#include -#include - -#ifdef DBGCB_DRIVER - -// Compile for kernel driver. -#include - -#else - -// Compile for user-mode application. -#include - -#endif - -#include "dbgcb_api.h" - -#define DBGCB_MAX_STRING_LENGTH 0x100 - -#ifdef DBGCB_DRIVER - -extern "C" PBOOLEAN KdDebuggerNotPresent; -extern "C" PBOOLEAN KdDebuggerEnabled; - -#define dbg_malloc(_len_) ExAllocatePool(NonPagedPool, (_len_)) -#define dbg_free(_addr_) ExFreePool((_addr_)) - -#else - -#define dbg_malloc(_len_) VirtualAlloc(NULL, (_len_), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE) -#define dbg_free(_addr_) VirtualFree((_addr_), 0, MEM_RELEASE) - -#endif - -PVOID dbg_command(PCHAR lpParams, ULONG Command) -{ - PVOID ret = NULL; - - typedef PVOID (__fastcall * func_dbg_command)( - PCHAR lpParams, - ULONG Command - ); - -#ifdef DBGCB_DRIVER - - // Check for active kernel debugger. - if (*KdDebuggerNotPresent == FALSE && - *KdDebuggerEnabled == TRUE) - -#else - - __try - -#endif - - { - func_dbg_command f_dbg_command = (func_dbg_command)dbg_malloc(sizeof(ULONG)); - if (f_dbg_command) - { - // xor rax, rax \ int 3 \ ret - *(PULONG)f_dbg_command = '\x33\xC0\xCC\xC3'; - - ret = f_dbg_command(lpParams, Command); - - dbg_free(f_dbg_command); - } - } - -#ifndef DBGCB_DRIVER - - __except (EXCEPTION_EXECUTE_HANDLER) - { - // dbgcb extension is not loaded, or no connection to - // remote kernel debugger - } - -#endif - - return ret; -} - -#define DBGCB_FORMAT_ARGS() \ - \ - char Buffer[DBGCB_MAX_STRING_LENGTH]; \ - va_list mylist; \ - \ - va_start(mylist, lpFormat); \ - vsprintf(Buffer, lpFormat, mylist); \ - va_end(mylist); - -/** - * Execute debuuger command (IDebugControl::Execute()). - */ -BOOLEAN dbg_exec(PCHAR lpFormat, ...) -{ - DBGCB_FORMAT_ARGS(); - - return (BOOLEAN)dbg_command(Buffer, DBGCB_EXECUTE); -} - -/** - * Evaluate debuuger expression (IDebugControl::Evaluate()). - */ -PVOID dbg_eval(PCHAR lpFormat, ...) -{ - DBGCB_FORMAT_ARGS(); - - return dbg_command(Buffer, DBGCB_GET_SYMBOL); -} - -/** - * Get offset of the some structure field - */ -LONG dbg_field_offset(PCHAR lpFormat, ...) -{ - DBGCB_FORMAT_ARGS(); - - return (LONG)dbg_command(Buffer, DBGCB_FIELD_OFFSET); -} + +/******************************************************* + + KERNEL DEBUGGER COMMUNICATION ENGINE + + Developed by: Oleksiuk Dmytro (aka Cr4sh), Esage Lab + + mailto:dmitry@esagelab.com + + http://esagelab.com/ + http://d-olex.blogspot.com/ + + *******************************************************/ + +#include +#include + +#ifdef DBGCB_DRIVER + +// Compile for kernel driver. +#include + +#else + +// Compile for user-mode application. +#include + +#endif + +#include "dbgcb_api.h" + +#define DBGCB_MAX_STRING_LENGTH 0x100 + +#ifdef DBGCB_DRIVER + +extern "C" PBOOLEAN KdDebuggerNotPresent; +extern "C" PBOOLEAN KdDebuggerEnabled; + +#define dbg_malloc(_len_) ExAllocatePool(NonPagedPool, (_len_)) +#define dbg_free(_addr_) ExFreePool((_addr_)) + +#else + +#define dbg_malloc(_len_) VirtualAlloc(NULL, (_len_), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE) +#define dbg_free(_addr_) VirtualFree((_addr_), 0, MEM_RELEASE) + +#endif + +PVOID dbg_command(PCHAR lpParams, ULONG Command) +{ + PVOID ret = NULL; + + typedef PVOID (__fastcall * func_dbg_command)( + PCHAR lpParams, + ULONG Command + ); + +#ifdef DBGCB_DRIVER + + // Check for active kernel debugger. + if (*KdDebuggerNotPresent == FALSE && + *KdDebuggerEnabled == TRUE) + +#else + + __try + +#endif + + { + func_dbg_command f_dbg_command = (func_dbg_command)dbg_malloc(sizeof(ULONG)); + if (f_dbg_command) + { + // xor rax, rax \ int 3 \ ret + *(PULONG)f_dbg_command = '\x33\xC0\xCC\xC3'; + + ret = f_dbg_command(lpParams, Command); + + dbg_free(f_dbg_command); + } + } + +#ifndef DBGCB_DRIVER + + __except (EXCEPTION_EXECUTE_HANDLER) + { + // dbgcb extension is not loaded, or no connection to + // remote kernel debugger + } + +#endif + + return ret; +} + +#define DBGCB_FORMAT_ARGS() \ + \ + char Buffer[DBGCB_MAX_STRING_LENGTH]; \ + va_list mylist; \ + \ + va_start(mylist, lpFormat); \ + vsprintf(Buffer, lpFormat, mylist); \ + va_end(mylist); + +/** + * Execute debuuger command (IDebugControl::Execute()). + */ +BOOLEAN dbg_exec(PCHAR lpFormat, ...) +{ + DBGCB_FORMAT_ARGS(); + + return (BOOLEAN)dbg_command(Buffer, DBGCB_EXECUTE); +} + +/** + * Evaluate debuuger expression (IDebugControl::Evaluate()). + */ +PVOID dbg_eval(PCHAR lpFormat, ...) +{ + DBGCB_FORMAT_ARGS(); + + return dbg_command(Buffer, DBGCB_GET_SYMBOL); +} + +/** + * Get offset of the some structure field + */ +LONG dbg_field_offset(PCHAR lpFormat, ...) +{ + DBGCB_FORMAT_ARGS(); + + return (LONG)dbg_command(Buffer, DBGCB_FIELD_OFFSET); +} diff --git a/dbgcb/dbgcb.cpp b/dbgcb/dbgcb.cpp index 1590a24..0712077 100644 --- a/dbgcb/dbgcb.cpp +++ b/dbgcb/dbgcb.cpp @@ -1,650 +1,650 @@ -#include "stdafx.h" - -EXT_API_VERSION g_ExtApiVersion = { 1, 1, EXT_API_VERSION_NUMBER, 0 }; - -WINDBG_EXTENSION_APIS ExtensionApis = { 0 }; - -IDebugClient *g_Client = NULL; -PDEBUG_CONTROL g_Control = NULL; -IDebugSymbols3 *g_Symbols = NULL; -IDebugSystemObjects *g_SystemObjects = NULL; -IDebugRegisters *g_Registers = NULL; -IDebugDataSpaces *g_DataSpaces = NULL; - -ULONG g_EipIndex = DEBUG_ANY_ID; -ULONG g_EaxIndex = DEBUG_ANY_ID, g_EcxIndex = DEBUG_ANY_ID, g_EdxIndex = DEBUG_ANY_ID; - -LONG g_RefCount = 0; - -BOOL g_bIs64 = FALSE; -ULONG g_RegPtrType = 0; - -#define SIGN_EXTEND(_x_) (ULONG64)(LONG)(_x_) -//-------------------------------------------------------------------------------------- - -/** - * Wrappers for working with registry values as 32/64-bit pointers. - */ - -ULONG64 RegPtrGet(PDEBUG_VALUE Register) -{ - if (g_bIs64) - { - return Register->I64; - } - - return SIGN_EXTEND(Register->I32); -} - -VOID RegPtrSet(PDEBUG_VALUE Register, ULONG64 Value) -{ - if (g_bIs64) - { - Register->Type = DEBUG_VALUE_INT64; - Register->I64 = Value; - } - else - { - Register->Type = DEBUG_VALUE_INT32; - Register->I32 = (ULONG)Value; - } -} -//-------------------------------------------------------------------------------------- -void __cdecl ExtOut(PCSTR Format, ...) -{ - va_list Args; - va_start(Args, Format); - - g_Control->ControlledOutputVaList( - DEBUG_OUTCTL_AMBIENT_DML, - DEBUG_OUTPUT_NORMAL, - Format, Args - ); - - va_end(Args); -} - -void ExtCleanup(void) -{ - /** - * clean up any resources - */ - - ExtOut(__FUNCTION__"()\n"); - - if (g_DataSpaces) - { - g_DataSpaces->Release(); - } - - if (g_Registers) - { - g_Registers->Release(); - } - - if (g_Control) - { - g_Control->Release(); - } - - if (g_Symbols) - { - g_Symbols->Release(); - } - - if (g_SystemObjects) - { - g_SystemObjects->Release(); - } - - if (g_Client) - { - g_Client->Release(); - } -} - -void __cdecl ExtErr(PCSTR Format, ...) -{ - va_list Args; - va_start(Args, Format); - - g_Control->ControlledOutputVaList( - DEBUG_OUTCTL_AMBIENT_DML, - DEBUG_OUTPUT_ERROR, - Format, Args - ); - - va_end(Args); -} - -void ExtExec(PCSTR Command) -{ - g_Control->Execute( - DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, - Command, DEBUG_EXECUTE_DEFAULT - ); -} -//---------------------------------------------------------------------------- -class EventCallbacks : public DebugBaseEventCallbacks -{ -public: - - // IUnknown. - STDMETHOD_(ULONG, AddRef)( - THIS - ); - - STDMETHOD_(ULONG, Release)( - THIS - ); - - // IDebugEventCallbacks. - STDMETHOD(GetInterestMask)( - THIS_ - OUT PULONG Mask - ); - - STDMETHOD(Exception)( - THIS_ - IN PEXCEPTION_RECORD64 Exception, - IN ULONG FirstChance - ); - - STDMETHOD(ChangeEngineState)( - THIS_ - IN ULONG Flags, - IN ULONG64 Argument - ); -}; - -BOOL g_ResumeState = FALSE; - -STDMETHODIMP_(ULONG) -EventCallbacks::AddRef(THIS) -{ - ExtOut(__FUNCTION__"()\n"); - - InterlockedIncrement(&g_RefCount); - - return 1; -} - -STDMETHODIMP_(ULONG) -EventCallbacks::Release(THIS) -{ - ExtOut(__FUNCTION__"()\n"); - - return 0; -} - -STDMETHODIMP -EventCallbacks::GetInterestMask( - THIS_ - OUT PULONG Mask) -{ - *Mask = DEBUG_EVENT_EXCEPTION | DEBUG_EVENT_CHANGE_ENGINE_STATE; - return S_OK; -} - -STDMETHODIMP -EventCallbacks::ChangeEngineState( - THIS_ - IN ULONG Flags, - IN ULONG64 Argument) -{ - if (Flags == DEBUG_CES_EXECUTION_STATUS && - Argument == DEBUG_STATUS_BREAK) - { - if (g_ResumeState) - { - // Resume execution due to handled int 3 exception. - ExtExec("g"); - } - - g_ResumeState = FALSE; - } - - return S_OK; -} - -STDMETHODIMP -EventCallbacks::Exception( - THIS_ - IN PEXCEPTION_RECORD64 Exception, - IN ULONG FirstChance) -{ - g_ResumeState = FALSE; - - if (Exception->ExceptionCode == STATUS_BREAKPOINT) - { - if (FirstChance) - { - DEBUG_VALUE Reg, Ecx, Edx; - - // Query EIP, EAX and ECX value. - if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && - g_Registers->GetValue(g_EdxIndex, &Edx) == S_OK && - g_Registers->GetValue(g_EcxIndex, &Ecx) == S_OK) - { - char szParam[MAX_PATH]; - ULONG ReadedBytes = 0; - - // Read current instruction opcode value. - ZeroMemory(szParam, sizeof(szParam)); - HRESULT Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Reg), &szParam, 1, &ReadedBytes); - if (Hr != S_OK) - { - ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); - return DEBUG_STATUS_NO_CHANGE; - } - - // Check for int 3 at EIP. - if (szParam[0] != '\xCC') - { - return DEBUG_STATUS_NO_CHANGE; - } - - // Check for the magic engine constnat in EDX. - if (Edx.I32 != DBGCB_GET_SYMBOL && - Edx.I32 != DBGCB_EXECUTE && - Edx.I32 != DBGCB_FIELD_OFFSET) - { - return DEBUG_STATUS_NO_CHANGE; - } - - g_ResumeState = TRUE; - - // Read ASCII string with command arguments. - ZeroMemory(szParam, sizeof(szParam)); - Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Ecx), &szParam, sizeof(szParam), &ReadedBytes); - if (Hr != S_OK) - { - ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); - return DEBUG_STATUS_NO_CHANGE; - } - - switch (Edx.I32) - { - case DBGCB_GET_SYMBOL: - { - ExtOut("" __FUNCTION__"(): DBGCB_GET_SYMBOL \"%s\"\n", szParam); - - RegPtrSet(&Reg, 0); - g_Registers->SetValue(g_EaxIndex, &Reg); - - Hr = g_Control->Evaluate(szParam, g_RegPtrType, &Reg, NULL); - if (Hr == S_OK) - { - // Return symbol address in EAX. - g_Registers->SetValue(g_EaxIndex, &Reg); - } - else - { - ExtErr(__FUNCTION__"() WARNING: IDebugControl::Evaluate() fails: %lx\n", Hr); - } - - break; - } - - case DBGCB_EXECUTE: - { - ExtOut("" __FUNCTION__ "(): DBGCB_EXECUTE\n"); - - // execute debugger command - Hr = g_Control->Execute( - DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, - szParam, - DEBUG_EXECUTE_DEFAULT - ); - if (Hr == S_OK) - { - // Return TRUE in EAX - RegPtrSet(&Reg, 1); - g_Registers->SetValue(g_EaxIndex, &Reg); - } - else - { - ExtErr(__FUNCTION__"() WARNING: IDebugControl::Execute() fails: %lx\n", Hr); - } - - break; - } - - case DBGCB_FIELD_OFFSET: - { - RegPtrSet(&Reg, (ULONG64)-1); - - char *lpszModule = szParam, *lpszStruct = NULL, *lpszField = NULL; - - ExtOut("" __FUNCTION__"(): DBGCB_FIELD_OFFSET \"%s\"\n", szParam); - - // parse structure and field description string - if (lpszStruct = strstr(lpszModule, "!")) - { - *lpszStruct = '\x00'; - lpszStruct += 1; - - if (lpszField = strstr(lpszStruct, "::")) - { - *lpszField = '\x00'; - lpszField += 2; - } - } - - if (lpszStruct && lpszField) - { - // enumerate fields - for (ULONG i = 0; ;i++) - { - ULONG64 Module = 0; - ULONG TypeId = 0; - - // get ID of this symbol - Hr = g_Symbols->GetSymbolTypeId(lpszStruct, &TypeId, &Module); - if (Hr == S_OK) - { - char szFieldName[MAX_PATH]; - - // query name of the filed - HRESULT Hr = g_Symbols->GetFieldName(Module, TypeId, i, szFieldName, MAX_PATH, NULL); - if (Hr == S_OK) - { - ULONG Offset = 0, FieldTypeId = 0; - - // query filed type and offset - Hr = g_Symbols->GetFieldTypeAndOffset(Module, TypeId, szFieldName, &FieldTypeId, &Offset); - if (Hr == S_OK) - { - if (!strcmp(szFieldName, lpszField)) - { - // Return symbol offset in EAX - RegPtrSet(&Reg, (ULONG64)Offset); - break; - } - } - else - { - ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldTypeAndOffset() fails: %lx\n", Hr); - } - } - else if (Hr == E_INVALIDARG) - { - // All Fields done - break; - } - else - { - ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldName() fails: %lx\n", Hr); - } - } - else - { - ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetSymbolTypeId() fails: %lx\n", Hr); - } - } - } - else - { - ExtErr(__FUNCTION__"() WARNING: Bad name format (must be !::)\n"); - } - - g_Registers->SetValue(g_EaxIndex, &Reg); - - break; - } - - default: - - return DEBUG_STATUS_NO_CHANGE; - } - - // Skip current int 3 instruction and continue execution - if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && Reg.Type == DEBUG_VALUE_INT32) - { - if (g_bIs64) - { - Reg.I64 += 1; - } - else - { - Reg.I32 += 1; - } - - g_Registers->SetValue(g_EipIndex, &Reg); - } - - return DEBUG_STATUS_GO_HANDLED; - } - } - } - - return DEBUG_STATUS_NO_CHANGE; -} - -EventCallbacks g_EventCb; -//-------------------------------------------------------------------------------------- -VOID WDBGAPI WinDbgExtensionDllInit( - PWINDBG_EXTENSION_APIS lpExtensionApis, - USHORT usMajorVersion, USHORT usMinorVersion) -{ - if (g_RefCount > 0) - { - // extension is allready initialized - return; - } - - HRESULT Hr = DebugCreate(__uuidof(IDebugClient), (void **)&g_Client); - if (Hr != S_OK) - { - MessageBoxA(0, "DebugCreate() fails", __FUNCTION__, MB_ICONERROR); - return; - } - - Hr = g_Client->QueryInterface(__uuidof(IDebugControl), (void **)&g_Control); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::QueryInterface(IDebugControl) fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - ULONG TargetMachine = 0; - Hr = g_Control->GetActualProcessorType(&TargetMachine); - if (Hr == S_OK) - { - switch (TargetMachine) - { - case IMAGE_FILE_MACHINE_I386: - - g_bIs64 = FALSE; - g_RegPtrType = DEBUG_VALUE_INT32; - break; - - - case IMAGE_FILE_MACHINE_AMD64: - - g_bIs64 = TRUE; - g_RegPtrType = DEBUG_VALUE_INT64; - break; - - default: - - MessageBoxA( - 0, - "Target architecture is not supported", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - - break; - } - } - else - { - MessageBoxA( - 0, - "DebugControl::GetActualProcessorType() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - Hr = g_Client->QueryInterface(__uuidof(IDebugSymbols3), (void **)&g_Symbols); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::QueryInterface(IDebugSymbols3) fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - Hr = g_Client->QueryInterface(__uuidof(IDebugSystemObjects), (void **)&g_SystemObjects); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::QueryInterface(IDebugSystemObjects) fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - Hr = g_Client->QueryInterface(__uuidof(IDebugRegisters), (void **)&g_Registers); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::QueryInterface(IDebugRegisters) fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - Hr = g_Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&g_DataSpaces); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::QueryInterface(IDebugDataSpaces) fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - char *lpszEip = "eip", *lpszEax = "eax", *lpszEcx = "ecx"; - if (g_bIs64) - { - // use 64-bit registers for parameter and return value - lpszEip = "rip"; - lpszEax = "rax"; - lpszEcx = "rcx"; - } - - // Find the register index for eip/rip - Hr = g_Registers->GetIndexByName(lpszEip, &g_EipIndex); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugRegisters::GetIndexByName() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - // Find the register index for eax/rax - Hr = g_Registers->GetIndexByName(lpszEax, &g_EaxIndex); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugRegisters::GetIndexByName() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - // Find the register index for ecx/rcx - Hr = g_Registers->GetIndexByName(lpszEcx, &g_EcxIndex); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugRegisters::GetIndexByName() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - // Find the register index for edx - Hr = g_Registers->GetIndexByName("edx", &g_EdxIndex); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugRegisters::GetIndexByName() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - // Register our event callbacks. - Hr = g_Client->SetEventCallbacks(&g_EventCb); - if (Hr != S_OK) - { - MessageBoxA( - 0, - "DebugClient::SetEventCallbacks() fails", - __FUNCTION__, MB_ICONERROR - ); - - ExitProcess(0); - } - - ExtOut("" __FUNCTION__"(): Initialized (x64: %s)\n", g_bIs64 ? "Yes" : "No"); -} -//-------------------------------------------------------------------------------------- -LPEXT_API_VERSION WDBGAPI ExtensionApiVersion(void) -{ - return &g_ExtApiVersion; -} -//-------------------------------------------------------------------------------------- -BOOL APIENTRY DllMain( - HANDLE hModule, - DWORD dwReason, - DWORD dwReserved) -{ - switch (dwReason) - { - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_ATTACH: - - break; - - case DLL_PROCESS_DETACH: - - ExtCleanup(); - break; - } - - return TRUE; -} -//-------------------------------------------------------------------------------------- -// EoF +#include "stdafx.h" + +EXT_API_VERSION g_ExtApiVersion = { 1, 1, EXT_API_VERSION_NUMBER, 0 }; + +WINDBG_EXTENSION_APIS ExtensionApis = { 0 }; + +IDebugClient *g_Client = NULL; +PDEBUG_CONTROL g_Control = NULL; +IDebugSymbols3 *g_Symbols = NULL; +IDebugSystemObjects *g_SystemObjects = NULL; +IDebugRegisters *g_Registers = NULL; +IDebugDataSpaces *g_DataSpaces = NULL; + +ULONG g_EipIndex = DEBUG_ANY_ID; +ULONG g_EaxIndex = DEBUG_ANY_ID, g_EcxIndex = DEBUG_ANY_ID, g_EdxIndex = DEBUG_ANY_ID; + +LONG g_RefCount = 0; + +BOOL g_bIs64 = FALSE; +ULONG g_RegPtrType = 0; + +#define SIGN_EXTEND(_x_) (ULONG64)(LONG)(_x_) +//-------------------------------------------------------------------------------------- + +/** + * Wrappers for working with registry values as 32/64-bit pointers. + */ + +ULONG64 RegPtrGet(PDEBUG_VALUE Register) +{ + if (g_bIs64) + { + return Register->I64; + } + + return SIGN_EXTEND(Register->I32); +} + +VOID RegPtrSet(PDEBUG_VALUE Register, ULONG64 Value) +{ + if (g_bIs64) + { + Register->Type = DEBUG_VALUE_INT64; + Register->I64 = Value; + } + else + { + Register->Type = DEBUG_VALUE_INT32; + Register->I32 = (ULONG)Value; + } +} +//-------------------------------------------------------------------------------------- +void __cdecl ExtOut(PCSTR Format, ...) +{ + va_list Args; + va_start(Args, Format); + + g_Control->ControlledOutputVaList( + DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_NORMAL, + Format, Args + ); + + va_end(Args); +} + +void ExtCleanup(void) +{ + /** + * clean up any resources + */ + + ExtOut(__FUNCTION__"()\n"); + + if (g_DataSpaces) + { + g_DataSpaces->Release(); + } + + if (g_Registers) + { + g_Registers->Release(); + } + + if (g_Control) + { + g_Control->Release(); + } + + if (g_Symbols) + { + g_Symbols->Release(); + } + + if (g_SystemObjects) + { + g_SystemObjects->Release(); + } + + if (g_Client) + { + g_Client->Release(); + } +} + +void __cdecl ExtErr(PCSTR Format, ...) +{ + va_list Args; + va_start(Args, Format); + + g_Control->ControlledOutputVaList( + DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_ERROR, + Format, Args + ); + + va_end(Args); +} + +void ExtExec(PCSTR Command) +{ + g_Control->Execute( + DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, + Command, DEBUG_EXECUTE_DEFAULT + ); +} +//---------------------------------------------------------------------------- +class EventCallbacks : public DebugBaseEventCallbacks +{ +public: + + // IUnknown. + STDMETHOD_(ULONG, AddRef)( + THIS + ); + + STDMETHOD_(ULONG, Release)( + THIS + ); + + // IDebugEventCallbacks. + STDMETHOD(GetInterestMask)( + THIS_ + OUT PULONG Mask + ); + + STDMETHOD(Exception)( + THIS_ + IN PEXCEPTION_RECORD64 Exception, + IN ULONG FirstChance + ); + + STDMETHOD(ChangeEngineState)( + THIS_ + IN ULONG Flags, + IN ULONG64 Argument + ); +}; + +BOOL g_ResumeState = FALSE; + +STDMETHODIMP_(ULONG) +EventCallbacks::AddRef(THIS) +{ + ExtOut(__FUNCTION__"()\n"); + + InterlockedIncrement(&g_RefCount); + + return 1; +} + +STDMETHODIMP_(ULONG) +EventCallbacks::Release(THIS) +{ + ExtOut(__FUNCTION__"()\n"); + + return 0; +} + +STDMETHODIMP +EventCallbacks::GetInterestMask( + THIS_ + OUT PULONG Mask) +{ + *Mask = DEBUG_EVENT_EXCEPTION | DEBUG_EVENT_CHANGE_ENGINE_STATE; + return S_OK; +} + +STDMETHODIMP +EventCallbacks::ChangeEngineState( + THIS_ + IN ULONG Flags, + IN ULONG64 Argument) +{ + if (Flags == DEBUG_CES_EXECUTION_STATUS && + Argument == DEBUG_STATUS_BREAK) + { + if (g_ResumeState) + { + // Resume execution due to handled int 3 exception. + ExtExec("g"); + } + + g_ResumeState = FALSE; + } + + return S_OK; +} + +STDMETHODIMP +EventCallbacks::Exception( + THIS_ + IN PEXCEPTION_RECORD64 Exception, + IN ULONG FirstChance) +{ + g_ResumeState = FALSE; + + if (Exception->ExceptionCode == STATUS_BREAKPOINT) + { + if (FirstChance) + { + DEBUG_VALUE Reg, Ecx, Edx; + + // Query EIP, EAX and ECX value. + if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && + g_Registers->GetValue(g_EdxIndex, &Edx) == S_OK && + g_Registers->GetValue(g_EcxIndex, &Ecx) == S_OK) + { + char szParam[MAX_PATH]; + ULONG ReadedBytes = 0; + + // Read current instruction opcode value. + ZeroMemory(szParam, sizeof(szParam)); + HRESULT Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Reg), &szParam, 1, &ReadedBytes); + if (Hr != S_OK) + { + ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); + return DEBUG_STATUS_NO_CHANGE; + } + + // Check for int 3 at EIP. + if (szParam[0] != '\xCC') + { + return DEBUG_STATUS_NO_CHANGE; + } + + // Check for the magic engine constnat in EDX. + if (Edx.I32 != DBGCB_GET_SYMBOL && + Edx.I32 != DBGCB_EXECUTE && + Edx.I32 != DBGCB_FIELD_OFFSET) + { + return DEBUG_STATUS_NO_CHANGE; + } + + g_ResumeState = TRUE; + + // Read ASCII string with command arguments. + ZeroMemory(szParam, sizeof(szParam)); + Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Ecx), &szParam, sizeof(szParam), &ReadedBytes); + if (Hr != S_OK) + { + ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr); + return DEBUG_STATUS_NO_CHANGE; + } + + switch (Edx.I32) + { + case DBGCB_GET_SYMBOL: + { + ExtOut("" __FUNCTION__"(): DBGCB_GET_SYMBOL \"%s\"\n", szParam); + + RegPtrSet(&Reg, 0); + g_Registers->SetValue(g_EaxIndex, &Reg); + + Hr = g_Control->Evaluate(szParam, g_RegPtrType, &Reg, NULL); + if (Hr == S_OK) + { + // Return symbol address in EAX. + g_Registers->SetValue(g_EaxIndex, &Reg); + } + else + { + ExtErr(__FUNCTION__"() WARNING: IDebugControl::Evaluate() fails: %lx\n", Hr); + } + + break; + } + + case DBGCB_EXECUTE: + { + ExtOut("" __FUNCTION__ "(): DBGCB_EXECUTE\n"); + + // execute debugger command + Hr = g_Control->Execute( + DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, + szParam, + DEBUG_EXECUTE_DEFAULT + ); + if (Hr == S_OK) + { + // Return TRUE in EAX + RegPtrSet(&Reg, 1); + g_Registers->SetValue(g_EaxIndex, &Reg); + } + else + { + ExtErr(__FUNCTION__"() WARNING: IDebugControl::Execute() fails: %lx\n", Hr); + } + + break; + } + + case DBGCB_FIELD_OFFSET: + { + RegPtrSet(&Reg, (ULONG64)-1); + + char *lpszModule = szParam, *lpszStruct = NULL, *lpszField = NULL; + + ExtOut("" __FUNCTION__"(): DBGCB_FIELD_OFFSET \"%s\"\n", szParam); + + // parse structure and field description string + if (lpszStruct = strstr(lpszModule, "!")) + { + *lpszStruct = '\x00'; + lpszStruct += 1; + + if (lpszField = strstr(lpszStruct, "::")) + { + *lpszField = '\x00'; + lpszField += 2; + } + } + + if (lpszStruct && lpszField) + { + // enumerate fields + for (ULONG i = 0; ;i++) + { + ULONG64 Module = 0; + ULONG TypeId = 0; + + // get ID of this symbol + Hr = g_Symbols->GetSymbolTypeId(lpszStruct, &TypeId, &Module); + if (Hr == S_OK) + { + char szFieldName[MAX_PATH]; + + // query name of the filed + HRESULT Hr = g_Symbols->GetFieldName(Module, TypeId, i, szFieldName, MAX_PATH, NULL); + if (Hr == S_OK) + { + ULONG Offset = 0, FieldTypeId = 0; + + // query filed type and offset + Hr = g_Symbols->GetFieldTypeAndOffset(Module, TypeId, szFieldName, &FieldTypeId, &Offset); + if (Hr == S_OK) + { + if (!strcmp(szFieldName, lpszField)) + { + // Return symbol offset in EAX + RegPtrSet(&Reg, (ULONG64)Offset); + break; + } + } + else + { + ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldTypeAndOffset() fails: %lx\n", Hr); + } + } + else if (Hr == E_INVALIDARG) + { + // All Fields done + break; + } + else + { + ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldName() fails: %lx\n", Hr); + } + } + else + { + ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetSymbolTypeId() fails: %lx\n", Hr); + } + } + } + else + { + ExtErr(__FUNCTION__"() WARNING: Bad name format (must be !::)\n"); + } + + g_Registers->SetValue(g_EaxIndex, &Reg); + + break; + } + + default: + + return DEBUG_STATUS_NO_CHANGE; + } + + // Skip current int 3 instruction and continue execution + if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && Reg.Type == DEBUG_VALUE_INT32) + { + if (g_bIs64) + { + Reg.I64 += 1; + } + else + { + Reg.I32 += 1; + } + + g_Registers->SetValue(g_EipIndex, &Reg); + } + + return DEBUG_STATUS_GO_HANDLED; + } + } + } + + return DEBUG_STATUS_NO_CHANGE; +} + +EventCallbacks g_EventCb; +//-------------------------------------------------------------------------------------- +VOID WDBGAPI WinDbgExtensionDllInit( + PWINDBG_EXTENSION_APIS lpExtensionApis, + USHORT usMajorVersion, USHORT usMinorVersion) +{ + if (g_RefCount > 0) + { + // extension is allready initialized + return; + } + + HRESULT Hr = DebugCreate(__uuidof(IDebugClient), (void **)&g_Client); + if (Hr != S_OK) + { + MessageBoxA(0, "DebugCreate() fails", __FUNCTION__, MB_ICONERROR); + return; + } + + Hr = g_Client->QueryInterface(__uuidof(IDebugControl), (void **)&g_Control); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::QueryInterface(IDebugControl) fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + ULONG TargetMachine = 0; + Hr = g_Control->GetActualProcessorType(&TargetMachine); + if (Hr == S_OK) + { + switch (TargetMachine) + { + case IMAGE_FILE_MACHINE_I386: + + g_bIs64 = FALSE; + g_RegPtrType = DEBUG_VALUE_INT32; + break; + + + case IMAGE_FILE_MACHINE_AMD64: + + g_bIs64 = TRUE; + g_RegPtrType = DEBUG_VALUE_INT64; + break; + + default: + + MessageBoxA( + 0, + "Target architecture is not supported", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + + break; + } + } + else + { + MessageBoxA( + 0, + "DebugControl::GetActualProcessorType() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + Hr = g_Client->QueryInterface(__uuidof(IDebugSymbols3), (void **)&g_Symbols); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::QueryInterface(IDebugSymbols3) fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + Hr = g_Client->QueryInterface(__uuidof(IDebugSystemObjects), (void **)&g_SystemObjects); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::QueryInterface(IDebugSystemObjects) fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + Hr = g_Client->QueryInterface(__uuidof(IDebugRegisters), (void **)&g_Registers); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::QueryInterface(IDebugRegisters) fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + Hr = g_Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&g_DataSpaces); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::QueryInterface(IDebugDataSpaces) fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + char *lpszEip = "eip", *lpszEax = "eax", *lpszEcx = "ecx"; + if (g_bIs64) + { + // use 64-bit registers for parameter and return value + lpszEip = "rip"; + lpszEax = "rax"; + lpszEcx = "rcx"; + } + + // Find the register index for eip/rip + Hr = g_Registers->GetIndexByName(lpszEip, &g_EipIndex); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugRegisters::GetIndexByName() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + // Find the register index for eax/rax + Hr = g_Registers->GetIndexByName(lpszEax, &g_EaxIndex); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugRegisters::GetIndexByName() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + // Find the register index for ecx/rcx + Hr = g_Registers->GetIndexByName(lpszEcx, &g_EcxIndex); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugRegisters::GetIndexByName() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + // Find the register index for edx + Hr = g_Registers->GetIndexByName("edx", &g_EdxIndex); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugRegisters::GetIndexByName() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + // Register our event callbacks. + Hr = g_Client->SetEventCallbacks(&g_EventCb); + if (Hr != S_OK) + { + MessageBoxA( + 0, + "DebugClient::SetEventCallbacks() fails", + __FUNCTION__, MB_ICONERROR + ); + + ExitProcess(0); + } + + ExtOut("" __FUNCTION__"(): Initialized (x64: %s)\n", g_bIs64 ? "Yes" : "No"); +} +//-------------------------------------------------------------------------------------- +LPEXT_API_VERSION WDBGAPI ExtensionApiVersion(void) +{ + return &g_ExtApiVersion; +} +//-------------------------------------------------------------------------------------- +BOOL APIENTRY DllMain( + HANDLE hModule, + DWORD dwReason, + DWORD dwReserved) +{ + switch (dwReason) + { + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_ATTACH: + + break; + + case DLL_PROCESS_DETACH: + + ExtCleanup(); + break; + } + + return TRUE; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/dbgcb/dbgcb.def b/dbgcb/dbgcb.def index 89940de..3e2578f 100644 --- a/dbgcb/dbgcb.def +++ b/dbgcb/dbgcb.def @@ -1,3 +1,3 @@ -EXPORTS -WinDbgExtensionDllInit -ExtensionApiVersion +EXPORTS +WinDbgExtensionDllInit +ExtensionApiVersion diff --git a/dbgcb/dbgcb.rc b/dbgcb/dbgcb.rc index 2a719f4..f5d7917 100644 --- a/dbgcb/dbgcb.rc +++ b/dbgcb/dbgcb.rc @@ -1,11 +1,11 @@ -#include -#include - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT2_UNKNOWN -#define VER_FILEDESCRIPTION_STR "Custom Debugger Callbacks Dispatcher Extension" - -#define VER_INTERNALNAME_STR "dbgcb.dll" -#define VER_ORIGINALFILENAME_STR "dbgcb.dll" - -#include "common.ver" +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Custom Debugger Callbacks Dispatcher Extension" + +#define VER_INTERNALNAME_STR "dbgcb.dll" +#define VER_ORIGINALFILENAME_STR "dbgcb.dll" + +#include "common.ver" diff --git a/dbgcb/dbgcb_x64.def b/dbgcb/dbgcb_x64.def index 89940de..3e2578f 100644 --- a/dbgcb/dbgcb_x64.def +++ b/dbgcb/dbgcb_x64.def @@ -1,3 +1,3 @@ -EXPORTS -WinDbgExtensionDllInit -ExtensionApiVersion +EXPORTS +WinDbgExtensionDllInit +ExtensionApiVersion diff --git a/dbgcb/makefile b/dbgcb/makefile index 7dcbe92..78b7165 100644 --- a/dbgcb/makefile +++ b/dbgcb/makefile @@ -1,6 +1,6 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the components of Windows -# -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of Windows +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/dbgcb/sources b/dbgcb/sources index ec0e13a..85557c3 100644 --- a/dbgcb/sources +++ b/dbgcb/sources @@ -1,33 +1,33 @@ -TARGETTYPE = DYNLINK -_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_WINXP) - -!if "$(_BUILDARCH)"=="AMD64" -TARGETNAME = ..\..\..\dbgcb_x64 -!else -TARGETNAME = ..\..\..\dbgcb -!endif - -DLLENTRY = _DllMainCRTStartup - -!if "$(DBGSDK_INC_PATH)" != "" -INCLUDES = $(DBGSDK_INC_PATH);$(INCLUDES) -!endif -!if "$(DBGSDK_LIB_PATH)" == "" -DBGSDK_LIB_PATH = $(SDK_LIB_PATH) -!else -DBGSDK_LIB_PATH = $(DBGSDK_LIB_PATH)\$(TARGET_DIRECTORY) -!endif - -TARGETLIBS = \ - $(SDK_LIB_PATH)\kernel32.lib \ - $(SDK_LIB_PATH)\user32.lib \ - $(DBGSDK_LIB_PATH)\dbgeng.lib - -USE_MSVCRT = 1 - -UMTYPE = windows - -SOURCES = \ - dbgcb.cpp \ - dbgcb.rc - +TARGETTYPE = DYNLINK +_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_WINXP) + +!if "$(_BUILDARCH)"=="AMD64" +TARGETNAME = ..\..\..\dbgcb_x64 +!else +TARGETNAME = ..\..\..\dbgcb +!endif + +DLLENTRY = _DllMainCRTStartup + +!if "$(DBGSDK_INC_PATH)" != "" +INCLUDES = $(DBGSDK_INC_PATH);$(INCLUDES) +!endif +!if "$(DBGSDK_LIB_PATH)" == "" +DBGSDK_LIB_PATH = $(SDK_LIB_PATH) +!else +DBGSDK_LIB_PATH = $(DBGSDK_LIB_PATH)\$(TARGET_DIRECTORY) +!endif + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(DBGSDK_LIB_PATH)\dbgeng.lib + +USE_MSVCRT = 1 + +UMTYPE = windows + +SOURCES = \ + dbgcb.cpp \ + dbgcb.rc + diff --git a/dbgcb/stdafx.h b/dbgcb/stdafx.h index 632dfbb..d2ae897 100644 --- a/dbgcb/stdafx.h +++ b/dbgcb/stdafx.h @@ -1,21 +1,21 @@ -#pragma once - -#include "targetver.h" - -#include -#include -#include - -#include -#include - -// DbgHelp API headers -#define KDEXT_64BIT -#include -#include - -#pragma warning(disable:4201) // nonstandard extension used : nameless struct -#pragma warning(disable:4995) -#include - -#include "../common/dbgcb_api.h" +#pragma once + +#include "targetver.h" + +#include +#include +#include + +#include +#include + +// DbgHelp API headers +#define KDEXT_64BIT +#include +#include + +#pragma warning(disable:4201) // nonstandard extension used : nameless struct +#pragma warning(disable:4995) +#include + +#include "../common/dbgcb_api.h" diff --git a/dbgcb/targetver.h b/dbgcb/targetver.h index 6fe8eb7..a38195a 100644 --- a/dbgcb/targetver.h +++ b/dbgcb/targetver.h @@ -1,13 +1,13 @@ -#pragma once - -// The following macros define the minimum required platform. The minimum required platform -// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run -// your application. The macros work by enabling all features available on platform versions up to and -// including the version specified. - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. -#endif - +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/dirs b/dirs index a6fc2bd..7499a4e 100644 --- a/dirs +++ b/dirs @@ -1,3 +1,3 @@ -DIRS = \ - _Examples \ - dbgcb +DIRS = \ + _Examples \ + dbgcb