/* This gets called (by DebugExtensionNotify whentarget is halted and is accessible */ HRESULT NotifyOnTargetAccessible(PDEBUG_CONTROL Control) { dprintf("Extension dll detected a break"); if (Connected) { dprintf(" connected to "); switch (TargetMachine) { case IMAGE_FILE_MACHINE_I386: dprintf("X86"); break; case IMAGE_FILE_MACHINE_IA64: dprintf("IA64"); break; default: dprintf("Other"); break; } } dprintf("\n"); // // show the top frame and execute dv to dump the locals here and return // Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, ".frame", // Command to be executed DEBUG_EXECUTE_DEFAULT ); Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, "dv", // Command to be executed DEBUG_EXECUTE_DEFAULT ); return S_OK; }
HRESULT ExecCmdList(PCSTR cmd) { HRESULT hRes=S_OK; ULONG Status; char *ptr, *orig, *end; ptr = orig = (char *)cmd; end = ptr+strlen(cmd); while(cmd < end) { ptr = (char *) strchr(cmd, 0xA); if( ptr != NULL) *ptr = 0; else break; // msdn: Executes the specified debugger commands. hRes=g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, cmd, DEBUG_EXECUTE_ECHO|DEBUG_EXECUTE_NO_REPEAT); // msdn: Describes the nature of the current target. hRes=g_ExtControl->GetExecutionStatus(&Status); if (FAILED(hRes)) break; // Drop commands if the target is not paused if (!(Status==DEBUG_STATUS_BREAK)) break; cmd= ptr+1; } return hRes; }
HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient *DebugClient = NULL; HRESULT Hr= S_OK; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; // Connect to client if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } // Get the windbg-style extension APIS PDEBUG_CONTROL DebugControl; if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { ExtensionApis.nSize = sizeof (ExtensionApis); Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis); DebugControl->Release(); } // done DebugClient->Release(); return Hr; }
void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) { UNREFERENCED_PARAMETER(Argument); // // The first time we actually connect to a target // /* *New debugger extensions get new debugger interfaces by calling *DebugCreate(__uuidof (IDebugClient), &DebugClient)) *DebugClient->QueryInterface(_uuidof(Interface_you_want) */ if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) { IDebugClient *DebugClient; HRESULT Hr; PDEBUG_CONTROL DebugControl; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) == S_OK) { // // Get the architecture type. // if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { //jc:QueryInterface must fill in DebugControl if ((Hr = DebugControl->GetActualProcessorType( &TargetMachine)) == S_OK) { Connected = TRUE; } DebugControl->Release(); } DebugClient->Release(); } } if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) { Connected = FALSE; TargetMachine = 0; } return; }
// Under certain conditions, breakpoint event should be dismissed // msdn: bp 0x1000 "r rax; g" // Problem: matching conditionnal commands: // bp Address ".if (Condition) {OptionalCommands} .else {gc}" HRESULT EventFilterCb(BOOL *pbIgnoreEvent) { HRESULT hRes=S_OK; ULONG Type, ProcessId, ThreadId, BreakpointId, ExtraInformationUsed, CommandSize; PDEBUG_BREAKPOINT Breakpoint; CHAR *LastCommand; // msdn: Returns information about the last event that occurred in a target. hRes = g_ExtControl->GetLastEventInformation(&Type, &ProcessId, &ThreadId, &BreakpointId, sizeof(ULONG), &ExtraInformationUsed, NULL, NULL, NULL); if (FAILED(hRes)) goto Exit; if ((Type != DEBUG_EVENT_BREAKPOINT) || (ExtraInformationUsed != 4)) goto Exit; hRes = g_ExtControl->GetBreakpointById(BreakpointId, &Breakpoint); if (FAILED(hRes)) goto Exit; // msdn: Returns the command string that is executed when a breakpoint is triggered. hRes = Breakpoint->GetCommand(g_CommandBuffer, MAX_CMD, &CommandSize); if (SUCCEEDED(hRes)) { if (CommandSize > 1) { // Find last command, delimiter is ';' LastCommand = strrchr(g_CommandBuffer, 0x3b); if (LastCommand == NULL) LastCommand = g_CommandBuffer; else LastCommand++; while (*LastCommand == 0x20) LastCommand++; // 'Go' command (g, gH, gN), epicly loosy matching if (*LastCommand == 0x67) *pbIgnoreEvent = true; } } Exit: return hRes; }
// Poll socket for incoming commands HRESULT PollCmd() { HRESULT hRes=S_OK; int NbBytesRecvd = 0; int ch = 0xA; char *msg, *next, *orig = NULL; hRes=TunnelPoll(&NbBytesRecvd, &msg); if (SUCCEEDED(hRes) & (NbBytesRecvd>0) & (msg != NULL)) { next = orig = msg; while((msg-orig) < NbBytesRecvd) { next = strchr(msg, ch); if( next != NULL) *next = 0; hRes=g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, msg, DEBUG_EXECUTE_ECHO); if (FAILED(hRes)) dprintf("[sync] failed to execute received command\n", msg); // No more command if( next == NULL) break; msg = next+1; } free(orig); } return hRes; }
void ExtExec(PCSTR Command) { g_Control->Execute( DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, Command, DEBUG_EXECUTE_DEFAULT ); }
HRESULT CALLBACK jmpraw(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes; ULONG64 Offset =0; ULONG RemainderIndex; DEBUG_VALUE DebugValue = {}; INIT_API(); if (!Args || !*Args) { dprintf("[sync] !jumpraw <expression>\n"); return E_FAIL; } /* msdn: Evaluate method evaluates an expression, returning the result. */ hRes=g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] jumpraw: failed to evaluate expression\n"); return E_FAIL; } Offset = (ULONG64)DebugValue.I64; hRes=TunnelSend("[sync]{\"type\":\"loc\",\"offset\":%llu}\n", Offset); return hRes; }
void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) { static BOOL Connected; UNREFERENCED_PARAMETER(Argument); // The first time we actually connect to a target if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) { IDebugClient *DebugClient = NULL; HRESULT Hr; PDEBUG_CONTROL DebugControl = NULL; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) == S_OK) { // // Get the architecture type. // if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { ULONG TargetMachine; if ((Hr = DebugControl->GetActualProcessorType( &TargetMachine)) == S_OK) { Connected = TRUE; } //NotifyOnTargetAccessible(DebugControl); DebugControl->Release(); } DebugClient->Release(); } } // The target is gone if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) Connected = FALSE; return; }
// Error output. void __cdecl ExtErr(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args); va_end(Args); }
// Warning output. void __cdecl ExtWarn(PCSTR Format, ...) { va_list Args; va_start(Args, Format); g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args); va_end(Args); }
HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { HRESULT hRes=S_OK; IDebugClient *DebugClient; PDEBUG_CONTROL DebugControl; *Version = DEBUG_EXTENSION_VERSION(EXT_MAJOR_VER, EXT_MINOR_VER); *Flags = 0; if (FAILED(hRes=DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient))) return hRes; if (SUCCEEDED(hRes=DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl))) { // Get the windbg-style extension APIS ExtensionApis.nSize = sizeof (ExtensionApis); hRes = DebugControl->GetWindbgExtensionApis64(&ExtensionApis); DebugControl->Release(); dprintf("[sync] DebugExtensionInitialize, ExtensionApis loaded\n"); } DebugClient->Release(); g_ExtClient = NULL; g_Synchronized = FALSE; g_hPollCompleteEvent = CreateEvent(NULL, true, false, NULL); if (g_hPollCompleteEvent == NULL) { dprintf("[sync] Command polling feature init failed\n"); return E_FAIL; } InitializeCriticalSection(&g_CritSectPollRelease); if(SUCCEEDED(LoadConfigurationFile())) dprintf("[sync] Configuration file loaded\n -> set HOST to %s:%s\n", g_DefaultHost, g_DefaultPort); return hRes; }
HRESULT CALLBACK testext(PDEBUG_CLIENT4 Client, PCSTR args) { PDEBUG_OUTPUT_CALLBACKS prev; PDEBUG_CONTROL Control; char cmd[256]; sprintf(cmd, "!E:\\talk\\demo\\Debug\\dbgexts.plusplus %s", args); Client->GetOutputCallbacks(&prev); Client->SetOutputCallbacks(&g_OutputCb); Client->QueryInterface(__uuidof(IDebugControl), (void **)&Control); Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, cmd, // Command to be executed DEBUG_EXECUTE_DEFAULT ); Control->Release(); Client->SetOutputCallbacks(prev); return S_OK; }
//jc: this in the init routine. Runs on load. HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient *DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; Hr = S_OK; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { // // Get the windbg-style extension APIS // ExtensionApis.nSize = sizeof (ExtensionApis); Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis); DebugControl->Release(); } dprintf("[Byakugan] Successfully loaded!\n"); DebugClient->Release(); return (Hr); }
HRESULT CALLBACK bc(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; ULONG DwRGB = 0; ULONG RemainderIndex; DEBUG_VALUE DebugValue = {}; char * msg; char * rgb_msg[64] = {0}; INIT_API(); #if VERBOSE >= 2 dprintf("[sync] !bc called\n"); #endif if (!Args || !*Args) { msg = "oneshot"; } else if (strcmp("on", Args) == 0) { msg = (char *)Args; } else if (strcmp("off", Args) == 0) { msg = (char *)Args; } else if (strncmp("set ", Args, 4) == 0) { *((char *)Args+3) = 0; hRes=g_ExtControl->Evaluate((char *) (Args+4), DEBUG_VALUE_INT32, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] failed to evaluate RGB code\n"); return E_FAIL; } DwRGB = (ULONG)DebugValue.I32; _snprintf_s((char *) rgb_msg, 64, _TRUNCATE , "%s\", \"rgb\":%lu, \"reserved\":\"", Args, DwRGB); msg = (char *)rgb_msg; } else { dprintf("[sync] usage !bc <|||on|off|set 0xBBGGRR> >\n"); return E_FAIL; } hRes=TunnelSend("[sync]{\"type\":\"bc\",\"msg\":\"%s\",\"base\":%llu,\"offset\":%llu}\n", msg, g_Base, g_Offset); return hRes; }
//-------------------------------------------------------------------------------------- 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); }
extern "C" HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient *DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; Hr = S_OK; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { ExtensionApis.nSize = sizeof(ExtensionApis); Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis); DebugControl->Release(); } DebugClient->Release(); return Hr; }
HRESULT CALLBACK cmd(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; ULONG Flags; PDEBUG_OUTPUT_CALLBACKS Callbacks; INIT_API(); #if VERBOSE >= 2 dprintf("[sync] !cmd command called\n"); #endif if (!Args || !*Args) { dprintf("[sync] !cmd <command to execute and dump>\n"); return E_FAIL; } if (FAILED(hRes=g_ExtClient->GetOutputCallbacks(&Callbacks))) { dprintf("[sync] GetOutputCallbacks failed\n"); goto exit; } if (FAILED(hRes=g_ExtClient->SetOutputCallbacks(&g_OutputCb))) { dprintf("[sync] SetOutputCallbacks failed\n"); goto exit; } // msdn: Execute method executes the specified debugger commands. Flags = DEBUG_EXECUTE_ECHO; if (g_OutputCbLocal) Flags = DEBUG_EXECUTE_NOT_LOGGED; hRes=g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, Args, Flags); g_ExtClient->FlushCallbacks(); g_ExtClient->SetOutputCallbacks(Callbacks); #if VERBOSE >= 2 dprintf("[sync] OutputCallbacks removed\n"); #endif exit: return hRes; }
HRESULT CALLBACK modunmap(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes; ULONG64 ModBase=0; ULONG RemainderIndex; DEBUG_VALUE DebugValue = {}; INIT_API(); if (!Args || !*Args) { dprintf("[sync] !modunmap <mod base>\n"); return E_FAIL; } /* msdn: Evaluate method evaluates an expression, returning the result. */ hRes=g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] modunmap: failed to evaluate module base\n"); return E_FAIL; } ModBase = (ULONG64)DebugValue.I64; /* msdn: The RemoveSyntheticModule method removes a synthetic module from the module list the debugger maintains for the current process. */ hRes=g_ExtSymbols3->RemoveSyntheticModule(ModBase); if(FAILED(hRes)) { dprintf("[sync] modunmap: RemoveSyntheticModule failed\n"); return E_FAIL; } return hRes; }
BOOL IsLocalDebuggee() { HRESULT hRes=S_OK; BOOL bLocal = FALSE; ULONG Class; ULONG Qualifier; hRes = g_ExtControl->GetDebuggeeType(&Class, &Qualifier); if (FAILED(hRes)) return hRes; if ((Class == DEBUG_CLASS_USER_WINDOWS) & (Qualifier == DEBUG_USER_WINDOWS_PROCESS)) bLocal = TRUE; else if ((Class == DEBUG_CLASS_KERNEL) & (Qualifier == DEBUG_KERNEL_LOCAL)) bLocal = TRUE; return bLocal; }
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(); } }
HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient *DebugClient; PDEBUG_CONTROL DebugControl; HRESULT Hr; *Version = DEBUG_EXTENSION_VERSION(1, 0); *Flags = 0; if (g_Initialized) { return S_OK; } g_Initialized = true; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) != S_OK) { return Hr; } if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) != S_OK) { return Hr; } ExtensionApis.nSize = sizeof (ExtensionApis); if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) { return Hr; } // Fixes the "Unable to read dynamic function table entries" error messages by disabling the WinDbg security // feature that prevents the loading of unknown out of proc tack walkers. DebugControl->Execute(DEBUG_OUTCTL_IGNORE, ".settings set EngineInitialization.VerifyFunctionTableCallbacks=false", DEBUG_EXECUTE_NOT_LOGGED | DEBUG_EXECUTE_NO_REPEAT); ExtQuery(DebugClient); if (IsMiniDumpFileNODAC()) { ExtOut ( "----------------------------------------------------------------------------\n" "The user dump currently examined is a minidump. Consequently, only a subset\n" "of sos.dll functionality will be available. If needed, attaching to the live\n" "process or debugging a full dump will allow access to sos.dll's full feature\n" "set.\n" "To create a full user dump use the command: .dump /ma <filename>\n" "----------------------------------------------------------------------------\n"); } ExtRelease(); OnUnloadTask::Register(CleanupEventCallbacks); g_pCallbacksClient = DebugClient; EventCallbacks* pCallbacksObj = new EventCallbacks(DebugClient); IDebugEventCallbacks* pCallbacks = NULL; pCallbacksObj->QueryInterface(__uuidof(IDebugEventCallbacks), (void**)&pCallbacks); pCallbacksObj->Release(); if(FAILED(Hr = g_pCallbacksClient->SetEventCallbacks(pCallbacks))) { ExtOut ("SOS: Failed to register callback events\n"); pCallbacks->Release(); return Hr; } pCallbacks->Release(); #ifndef _ARM_ // Make sure we do not tear down the debugger when a security function fails // Since we link statically against CRT this will only affect the SOS module. _set_invalid_parameter_handler(_SOS_invalid_parameter); #endif DebugControl->Release(); return S_OK; }
HRESULT CALLBACK modmap(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes; ULONG64 ModBase=0; ULONG ModSize; ULONG RemainderIndex; DEBUG_VALUE DebugValue = {}; INIT_API(); if (!Args || !*Args) { dprintf("[sync] !modmap <mod base> <mod size> <mod name>\n"); return E_FAIL; } /* msdn: Evaluate method evaluates an expression, returning the result. */ hRes=g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] modmap: failed to evaluate module base\n"); return E_FAIL; } ModBase = (ULONG64)DebugValue.I64; Args += RemainderIndex; hRes=g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT32, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] modmap: failed to evaluate module size\n"); return E_FAIL; } ModSize = (ULONG64)DebugValue.I32; Args += RemainderIndex; StrTrim((LPSTR)Args, " "); if (!*Args) { dprintf("[sync] modmap: failed to evaluate module name\n"); return E_FAIL; } /* msdn: The AddSyntheticModule method adds a synthetic module to the module list the debugger maintains for the current process. */ hRes=g_ExtSymbols3->AddSyntheticModule(ModBase, ModSize, Args, Args, DEBUG_ADDSYNTHMOD_DEFAULT); if(FAILED(hRes)) { dprintf("[sync] modmap: AddSyntheticModule failed\n"); return E_FAIL; } /* msdn: The AddSyntheticSymbol method adds a synthetic symbol to a module in the current process. */ hRes=g_ExtSymbols3->AddSyntheticSymbol(ModBase, ModSize, Args, DEBUG_ADDSYNTHSYM_DEFAULT, NULL); if(FAILED(hRes)) { dprintf("[sync] modmap: AddSyntheticSymbol failed\n"); hRes=g_ExtSymbols3->RemoveSyntheticModule(ModBase); return E_FAIL; } return hRes; }
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("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_GET_SYMBOL \"%s\"</col>\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("<col fg=\"srccmnt\">" __FUNCTION__ "(): DBGCB_EXECUTE</col>\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("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_FIELD_OFFSET \"%s\"</col>\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 <module>!<struct_name>::<field_name>)\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; }
void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 /*Argument*/) { // // The first time we actually connect to a target, get the page size // if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) { IDebugClient *DebugClient; PDEBUG_DATA_SPACES DebugDataSpaces; PDEBUG_CONTROL DebugControl; HRESULT Hr; ULONG64 Page; if ((Hr = DebugCreate(__uuidof(IDebugClient), (void **)&DebugClient)) == S_OK) { // // Get the page size and PAE enable flag // if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&DebugDataSpaces)) == S_OK) { if ((Hr = DebugDataSpaces->ReadDebuggerData( DEBUG_DATA_MmPageSize, &Page, sizeof(Page), NULL)) == S_OK) { PageSize = (ULONG)(ULONG_PTR)Page; } DebugDataSpaces->Release(); } // // Get the architecture type. // if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl)) == S_OK) { if ((Hr = DebugControl->GetActualProcessorType( &TargetMachine)) == S_OK) { Connected = TRUE; } ULONG Qualifier; if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &Qualifier)) == S_OK) { } DebugControl->Release(); } DebugClient->Release(); } } if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) { Connected = FALSE; PageSize = 0; TargetMachine = 0; } return; }
//-------------------------------------------------------------------------------------- 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("<col fg=\"srckw\">" __FUNCTION__"(): Initialized (x64: %s)</col>\n", g_bIs64 ? "Yes" : "No"); }
HRESULT CALLBACK jmpto(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes; ULONG64 Base, Offset =0; ULONG NameSize=0; ULONG RemainderIndex; DEBUG_VALUE DebugValue = {}; INIT_API(); if (!Args || !*Args) { dprintf("[sync] !jumpto <expression>\n"); return E_FAIL; } /* msdn: Evaluate method evaluates an expression, returning the result. */ hRes=g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &DebugValue, &RemainderIndex); if(FAILED(hRes)) { dprintf("[sync] jumpto: failed to evaluate expression\n"); return E_FAIL; } Offset = (ULONG64)DebugValue.I64; /* msdn: GetModuleByOffset method searches through the target's modules for one whose memory allocation includes the specified location. */ hRes=g_ExtSymbols->GetModuleByOffset(Offset, 0, NULL, &Base); if(FAILED(hRes)) { dprintf("[sync] jumpto: failed to get module base for address 0x%x\n", Base); return E_FAIL; } /* Update module name stored in g_NameBuffer msdn: GetModuleNameString method returns the name of the specified module. */ hRes=g_ExtSymbols2->GetModuleNameString(DEBUG_MODNAME_LOADED_IMAGE, DEBUG_ANY_ID, Base, g_NameBuffer, MAX_NAME, &NameSize); if(!(SUCCEEDED(hRes) & (NameSize>0) & (((char) *g_NameBuffer)!=0))) { dprintf("[sync] jumpto: failed to get module name for target address\n"); return E_FAIL; } // Check if we are in a new module if(g_Base != Base) { // Update base address of current active module g_Base = Base; hRes=TunnelSend("[notice]{\"type\":\"module\",\"path\":\"%s\"}\n", g_NameBuffer); if(FAILED(hRes)) return hRes; } hRes=TunnelSend("[sync]{\"type\":\"loc\",\"base\":%llu,\"offset\":%llu}\n", Base, Offset); return hRes; }