/* 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; }
// 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 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 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; }
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; }
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; }