HRESULT CALLBACK lbl(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; INIT_API(); #if VERBOSE >= 2 dprintf("[sync] !lbl called\n"); #endif if (!Args || !*Args) { dprintf("[sync] !lbl <comment to add>\n"); return E_FAIL; } hRes=TunnelSend("[sync]{\"type\":\"lbl\",\"msg\":\"%s\",\"base\":%llu,\"offset\":%llu}\n", Args, g_Base, g_Offset); 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; }
HRESULT CALLBACK syncoff(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; UNREFERENCED_PARAMETER(Args); INIT_API(); #if VERBOSE >= 2 dprintf("[sync] !syncoff command called\n"); #endif if(!g_Synchronized) return hRes; ReleasePollTimer(); hRes=TunnelClose(); dprintf("[sync] sync is now disabled\n"); return hRes; }
HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) { IDebugClient4 *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); IDebugClient4 *Client = DebugClient; INIT_API(); DebugControl->Release(); } //DebugClient->Release(); return Hr; }
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; }
HRESULT CALLBACK sync(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; PCSTR Host; PSTR pszId=NULL; INIT_API(); // Reset global state g_Base = NULL; g_Offset = NULL; #if VERBOSE >= 2 dprintf("[sync] sync function called\n"); #endif if(g_Synchronized) { dprintf("[sync] sync update\n"); UpdateState(); goto exit; } if (!Args || !*Args) { dprintf("[sync] No argument found, using default host (%s:%s)\n", g_DefaultHost, g_DefaultPort); Host=g_DefaultHost; }else{ Host=Args; } if(FAILED(hRes=TunnelCreate(Host, g_DefaultPort))) { dprintf("[sync] sync failed\n"); goto exit; } dprintf("[sync] probing sync\n"); if(FAILED(hRes=Identity(&pszId))) { dprintf("[sync] get identity failed\n"); goto exit; } hRes=TunnelSend("[notice]{\"type\":\"new_dbg\",\"msg\":\"dbg connect - %s\"}\n", pszId); if(SUCCEEDED(hRes)) { dprintf("[sync] sync is now enabled with host %s\n", Host); UpdateState(); CreatePollTimer(); } else { dprintf("[sync] sync aborted\n"); } exit: if(!(pszId==NULL)) free(pszId); return hRes; }
HRESULT CALLBACK modcheck(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes; DWORD cbBinary; int NbBytesRecvd = 0; LPSTR pszResString= NULL; CHAR *msg = NULL; CHAR *type; CHAR cmd[64] = {0}; BOOL bUsePdb = TRUE; INIT_API(); if(!g_Synchronized) { dprintf("[sync] please enable sync\n"); return E_FAIL; } if (!(*g_NameBuffer)) { dprintf("[sync] no module\n"); return E_FAIL; } // check args // md5 is accepted only with local debuggee if (!Args || !*Args) { bUsePdb=TRUE; } else if(strcmp("md5", Args)==0) { bUsePdb=FALSE; if (!(IsLocalDebuggee())) { dprintf("[sync] can't use md5 check with non local debuggee\n"); return E_FAIL; } } else dprintf("[sync] unknown argument, defaulting to pdb match\n"); // The debugger does not know if an IDB client // is actually connected to the dispatcher. // First disable tunnel polling for commands (happy race...) ReleasePollTimer(); // default behavior is to used !IToldYouSo command. if (bUsePdb) { type = "pdb"; _snprintf_s(cmd, 64, _TRUNCATE , "!itoldyouso %x", g_Base); // g_CommandBuffer first four bytes should contains // return value for command exec hRes=LocalCmd(Client, cmd); if (FAILED(hRes) || FAILED(*g_CommandBuffer)) { dprintf("[sync] failed to evaluate !ItoldYouSo command\n"); goto Exit; } cbBinary = (DWORD) strlen(g_CommandBuffer+4); if (cbBinary == 0) { dprintf(" ItoldYouSo return empty result\n"); goto Exit; } dprintf("%s\n", g_CommandBuffer+4); hRes=ToBase64((const byte *)g_CommandBuffer+4, cbBinary, &pszResString); if (FAILED(hRes)) { dprintf("[sync] modcheck ToBase64 failed\n"); goto Exit; } } else { type="md5"; hRes=modmd5(&pszResString); if (FAILED(hRes)) { dprintf("[sync] modcheck modmd5 failed\n"); goto Exit; } dprintf(" MD5: %s\n", pszResString); } hRes = TunnelSend("[sync]{\"type\":\"modcheck\",\"%s\":\"%s\"}\n", type, pszResString); if (FAILED(hRes)) { dprintf("[sync] modcheck send failed\n"); goto Exit; } // Let time for the IDB client to reply if it exists Sleep(150); // Poll tunnel hRes=TunnelPoll(&NbBytesRecvd, &msg); if (FAILED(hRes)) { dprintf("[sync] modcheck poll failed\n"); goto Exit; } else { if ((NbBytesRecvd>0) & (msg != NULL)) dprintf("%s\n", msg); else dprintf(" -> no reply, make sure an idb is enabled first\n"); } Exit: // Re-enable tunnel polling CreatePollTimer(); if (pszResString) free(pszResString); if (msg) free(msg); return hRes; }
HRESULT CALLBACK bpcmds(PDEBUG_CLIENT4 Client, PCSTR Args) { HRESULT hRes=S_OK; char *msg, *decoded, *query; LPSTR pszString; int NbBytesRecvd; size_t cbBinary; INIT_API(); #if VERBOSE >= 2 dprintf("[sync] !bpcmds called\n"); #endif if(!g_Synchronized) { dprintf("[sync] please enable sync\n"); return E_FAIL; } if (!Args || !*Args){ msg = "query"; } else { msg = (char *)Args; } if ((strncmp("load", msg, 4)==0) || (strncmp("query", msg, 5)==0)) { dprintf("[sync] query idb for bpcmds\n"); hRes=TunnelSend("[sync]{\"type\":\"bps_get\"}\n"); } else if(strncmp("save", msg, 4)==0) { dprintf("[sync] dumping bpcmds to idb\n"); hRes=LocalCmd(Client, ".bpcmds"); // g_CommandBuffer first four bytes should contains // return value for command exec if (FAILED(hRes) || FAILED(*g_CommandBuffer)) { dprintf("[sync] failed to evaluate .bpcmds command\n"); return E_FAIL; } cbBinary = strlen(g_CommandBuffer+4); dprintf("%s\n", g_CommandBuffer); hRes = ToBase64((const byte *)g_CommandBuffer+4, (unsigned int)cbBinary, &pszString); if (SUCCEEDED(hRes)) { hRes = TunnelSend("[sync]{\"type\":\"bps_set\",\"msg\":\"%s\"}\n", pszString); free(pszString); } } else { dprintf("[sync] usage !bpcmds <||query|save|load|\n"); return E_FAIL; } // Check if we failed to query the idb client if (FAILED(hRes)){ dprintf("[sync] !bpcmds failed\n"); return hRes; } // Get result from idb client hRes=TunnelReceive(&NbBytesRecvd, &query); if (!(SUCCEEDED(hRes) & (NbBytesRecvd>0) & (query != NULL))) { dprintf("[sync] !bpcmds failed\n"); return hRes; } // Handle result if(strncmp("load", msg, 4)==0) { hRes = FromBase64(query, (BYTE **)(&decoded)); if (SUCCEEDED(hRes)) { hRes = ExecCmdList(decoded); free(decoded); } } else if(strncmp("query", msg, 4)==0) { hRes = FromBase64(query, (BYTE **)(&decoded)); if (SUCCEEDED(hRes)) { dprintf("[sync] idb's saved bpcmds:\n %s\n", decoded); free(decoded); } } else { dprintf("%s\n", query); } free(query); return hRes; }
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; }
/* Sample extension to read and dump a struct on target This reads the struct _EXCEPTION_RECORD which is defined as: typedef struct _EXCEPTION_RECORD { NTSTATUS ExceptionCode; ULONG ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; ULONG NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD; */ HRESULT CALLBACK structsample(PDEBUG_CLIENT4 Client, PCSTR args) { ULONG64 Address; INIT_API(); Address = GetExpression(args); DWORD Buffer[4], cb; // Read and display first 4 dwords at Address if (ReadMemory(Address, &Buffer, sizeof(Buffer), &cb) && cb == sizeof(Buffer)) { dprintf("%p: %08lx %08lx %08lx %08lx\n\n", Address, Buffer[0], Buffer[1], Buffer[2], Buffer[3]); } // // Method 1 to dump a struct // dprintf("Method 1:\n"); // Inititalze type read from the Address if (InitTypeRead(Address, _EXCEPTION_RECORD) != 0) { dprintf("Error in reading _EXCEPTION_RECORD at %p", // Use %p to print pointer values Address); } else { // read and dump the fields dprintf("_EXCEPTION_RECORD @ %p\n", Address); dprintf("\tExceptionCode : %lx\n", (ULONG) ReadField(ExceptionCode)); dprintf("\tExceptionAddress : %p\n", ReadField(ExceptionAddress)); dprintf("\tExceptionInformation[1] : %I64lx\n", ReadField(ExceptionInformation[1])); // And so on... } // // Method 2 to read a struct // ULONG64 ExceptionInformation_1, ExceptionAddress, ExceptionCode; dprintf("\n\nMethod 2:\n"); // Read and dump the fields by specifying type and address individually if (GetFieldValue(Address, "_EXCEPTION_RECORD", "ExceptionCode", ExceptionCode)) { dprintf("Error in reading _EXCEPTION_RECORD at %p\n", Address); } else { // Pointers are read as ULONG64 values GetFieldValue(Address, "_EXCEPTION_RECORD", "ExceptionAddress", ExceptionAddress); GetFieldValue(Address, "_EXCEPTION_RECORD", "ExceptionInformation[1]", ExceptionInformation_1); // And so on.. dprintf("_EXCEPTION_RECORD @ %p\n", Address); dprintf("\tExceptionCode : %lx\n", ExceptionCode); dprintf("\tExceptionAddress : %p\n", ExceptionAddress); dprintf("\tExceptionInformation[1] : %I64lx\n", ExceptionInformation_1); } ULONG64 Module; ULONG i, TypeId; CHAR Name[MAX_PATH]; // // To get/list field names // g_ExtSymbols->GetSymbolTypeId("_EXCEPTION_RECORD", &TypeId, &Module); dprintf("Fields of _EXCEPTION_RECORD\n"); for (i=0; ;i++) { HRESULT Hr; ULONG Offset=0; Hr = g_ExtSymbols->GetFieldName(Module, TypeId, i, Name, MAX_PATH, NULL); if (Hr == S_OK) { g_ExtSymbols->GetFieldOffset(Module, TypeId, Name, &Offset); dprintf("%lx (+%03lx) %s\n", i, Offset, Name); } else if (Hr == E_INVALIDARG) { // All Fields done break; } else { dprintf("GetFieldName Failed %lx\n", Hr); break; } } // // Get name for an enumerate // // typedef enum { // Enum1, // Enum2, // Enum3, // } TEST_ENUM; // ULONG ValueOfEnum = 0; g_ExtSymbols->GetSymbolTypeId("TEST_ENUM", &TypeId, &Module); g_ExtSymbols->GetConstantName(Module, TypeId, ValueOfEnum, Name, MAX_PATH, NULL); dprintf("Testenum %I64lx == %s\n", ExceptionCode, Name); // This prints out, Testenum 0 == Enum1 // // Read an array // // typedef struct FOO_TYPE { // ULONG Bar; // ULONG Bar2; // } FOO_TYPE; // // FOO_TYPE sampleArray[20]; ULONG Bar, Bar2; CHAR TypeName[100]; for (i=0; i<20; i++) { sprintf_s(TypeName, sizeof(TypeName), "sampleArray[%lx]", i); if (GetFieldValue(0, TypeName, "Bar", Bar)) break; GetFieldValue(0, TypeName, "Bar2", Bar2); dprintf("%16s - Bar %2ld Bar2 %ld\n", TypeName, Bar, Bar2); } EXIT_API(); return S_OK; }
/* Extension to look at locals through IDebugSymbolGroup interface Usage: !symgrptest [args] To demontrate local/args lookup, this will go through the stack and set scope with the instruction of the stack frame and enumerate all the locals/arguments for the frame function */ HRESULT CALLBACK symgrptest(PDEBUG_CLIENT4 Client, PCSTR args) { HRESULT hRes; IDebugSymbolGroup *pDbgSymGroup; ULONG ulCount, nFrames; DEBUG_STACK_FRAME Stack[50]; ULONG SymGroupType; INIT_API(); if (!_stricmp(args, "args")) { // Disply only the arguments SymGroupType = DEBUG_SCOPE_GROUP_ARGUMENTS; } else { // Display all the locals SymGroupType = DEBUG_SCOPE_GROUP_LOCALS; } // // Get the current stack // if ((hRes = g_ExtControl->GetStackTrace(0, 0, 0, &Stack[0], 50, &nFrames)) != S_OK) { dprintf("Stacktrace failed - %lx\n", hRes); nFrames = 0; } // Create a local symbol group client if ((hRes = g_ExtSymbols-> GetScopeSymbolGroup(SymGroupType, NULL, &pDbgSymGroup)) == E_NOTIMPL) { EXIT_API(); return S_OK; } while (nFrames) { // // Enumerate locals for this frame // --nFrames; // Set scope at this frame g_ExtSymbols->SetScope(0, &Stack[nFrames], NULL, 0); // refresh the symbol group with current scope if ((hRes = g_ExtSymbols-> GetScopeSymbolGroup(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup)) == E_NOTIMPL) { break; } hRes = pDbgSymGroup->GetNumberSymbols ( &ulCount); dprintf("\n\n>Scope Frame %lx: %lx Symbols\n",nFrames,ulCount); PDEBUG_SYMBOL_PARAMETERS pSymParams = new DEBUG_SYMBOL_PARAMETERS[ ulCount ] ; if (ulCount) { // Get all symbols for the frame hRes = pDbgSymGroup->GetSymbolParameters (0, ulCount , pSymParams); } if ( S_OK == hRes ) { for ( ULONG i = 0 ; i < ulCount ; i++ ) { TCHAR szName[ MAX_PATH ], *pName; ULONG ulSize; DEBUG_VALUE Value; // Lookup symbol name and print pName = &szName[1]; hRes = pDbgSymGroup->GetSymbolName ( i, pName, MAX_PATH - 1, &ulSize ) ; if (SUCCEEDED(hRes)) { // Prefix ! so this is evaluated as symbol szName[0] = '!'; hRes = g_ExtControl->Evaluate(szName, DEBUG_VALUE_INVALID, &Value, NULL); if (SUCCEEDED(hRes)) { dprintf("%lx: %32s = 0x%p\n", i, pName, Value.I64); } } } } delete []pSymParams; } pDbgSymGroup->Release(); EXIT_API(); return S_OK; }
HRESULT CALLBACK pe(PDEBUG_CLIENT4 Client, PCSTR args) { INIT_API(); ULONG_PTR ulAddress = 0; ULONG_PTR ulBase = 0; ULONG_PTR ulImageSize = 0; HRESULT result = S_OK; ULONG ulSetionCount = 0; BOOL bAllPrint = TRUE; BOOL bPrintDosHeard = FALSE; BOOL bPrintNtHeard = FALSE; BOOL bSection = FALSE; BOOL bImport = FALSE; BOOL bExport = FALSE; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = { 0 }; if ( args == NULL) { result = S_FALSE; goto ex; }do { const char * split = " "; char * p = NULL, *params = NULL, *next = NULL; params = new char[strlen(args) + 1]; if (params == NULL) { result = S_FALSE; goto ex; } _try { memset(params, 0, strlen(args) + 1); strcpy_s(params, strlen(args) + 1, args); p = strtok_s(params, split, &next); while (p != NULL) { if (_stricmp(p, "-section") == 0) { bAllPrint = FALSE; bSection = TRUE; } else if (_stricmp(p, "-dos") == 0) { bAllPrint = FALSE; bPrintDosHeard = TRUE; } else if (_stricmp(p, "-nt") == 0) { bAllPrint = FALSE; bPrintNtHeard = TRUE; } else if (_stricmp(p, "-import") == 0) { bAllPrint = FALSE; bImport = TRUE; } else if (_stricmp(p, "-export") == 0) { bAllPrint = FALSE; bExport = TRUE; } else if (p) { char *endptr = NULL; ulAddress = str2ull(p, &endptr, 16); ulBase = ulAddress; } p = strtok_s(NULL, split, &next); } }_finally { if (params) { delete[]params; params = NULL; } } } while (FALSE); if (ulAddress == 0) { result = S_FALSE; goto ex; } if (result = PE_PrintDosHeard(&ulAddress, bAllPrint | bPrintDosHeard) != S_OK) { goto ex; } if (result = PE_PrintNtHeard(&ulAddress, bAllPrint | bPrintNtHeard, &ulSetionCount, DataDirectory, &ulImageSize) != S_OK) { goto ex; } if (result = PE_PrintSection(&ulAddress, ulSetionCount, bAllPrint | bSection) != S_OK) { goto ex; } PBYTE pImage = new BYTE[ulImageSize]; if (pImage == NULL) { result = S_FALSE; goto ex; } _try { ULONG ulReadSize = 0; memset(pImage, 0, ulImageSize); result = g_ExtDataSpaces->ReadVirtual(ulBase, pImage, ulImageSize, &ulReadSize); if (result != S_OK) { dprintf("读取虚拟地址 %x 错误 \n", ulBase); goto ex; } if (ulReadSize != ulImageSize) { dprintf("读取数据长度错误。 \n"); result = S_FALSE; goto ex; } if (result = PE_PrintImport(pImage, DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT], bAllPrint | bImport) != S_OK) { goto ex; } if (result = PE_PrintExport(pImage, DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT], ulBase, bAllPrint | bExport) != S_OK) { goto ex; } }_finally { if (pImage) { delete[]pImage; pImage = NULL; } } ex: EXIT_API(); return result; }