Title: Just-In-Time Debugging Author: Great Descr: Небольшая статья, в которой я опишу возможности jit-отладки процессов в Windows. 1. Что такое Just-In-Time Debugging? В винде есть возможность установить специальную программу, которая будет "ловить" упавшие процессы (например, по исключению) и которая будет запускаться по кнопочке Debug в назойливом окне "The program has encountered a problem and needs to close". За путь к этой программе отвечает параметр реестра Debugger в ветке HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug. Там же есть и параметр Auto, задающий тип запуска программки. Подробнее об этом можно прочитать, например, в отличной книге М.Руссиновича и Д.Соломона "Внутреннее устройство MS Windows", а мы больше не будем акцентировать этому внимание. Мы созданим свою программку, которая будет выполнять эту функцию. Скажете, сложно? Отнюдь! Для начала пропишем путь к будущей программке, у меня он таков: Debugger = "D:\Progs\dbgdump\Release\dbgdump.exe" -p %ld причем в параметрах передадим ей число - PID (Process ID) упавшего процесса. Винда сама заполнит этот параметр. Приступим к написанию программы. 2. Недры нашей программы Возьмем функции из моей статьи "Анализ стека" и воспользуемся ими здесь для того, чтобы вывести результаты анализа стека рухнувшего процесса. Еще мы выведем информацию о процессе, о потоке и дамп стека. Поехали! Получение инфы о процессе будет очень простым. Мы сделаем снимок всех процессов системы и найдем наш рухнувший по его PID. Это обеспечит следующая функция: Code: // Получение инфы о процессе по ID PROCESSENTRY32* GetProcess(DWORD pid) { HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hSnapShot == INVALID_HANDLE_VALUE) { MessageBox(0, "CreateToolhelp32Snapshot() failed", "Dbgdump", MB_ICONERROR); return 0; } PROCESSENTRY32* pe = new PROCESSENTRY32; ZeroMemory(pe, sizeof(pe)); pe->dwSize = sizeof(*pe); if(!Process32First(hSnapShot, pe)) { MessageBox(0, "Unable to find any processes in the system", "Thread snapshot", MB_ICONERROR); return 0; } bool found=0; int count=0; do { if(pe->th32ProcessID == pid) return pe; } while(Process32Next(hSnapShot, pe)); return 0; } В основной функции WinMain нашей программы мы сделаем следующее: - выделим из командной строки pid - сделаем снимок потоков и найдем первый поток нашего процесса - снимем контекст этого потока - получим информацию о процессе - выведем все это в окошке с прокручиваемым текстовым полем Ниже приведен код функции WinMain, который, очевидно, в пояснениях не нуждается. Code: int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR lpCmdLine,int) { stack = new char[10240]; DWORD dwProcessId; sscanf(lpCmdLine, "-p %d", &dwProcessId); if(!*lpCmdLine || !dwProcessId) return MessageBox(0, "dbgdump usage:\ndbgdump -p [pid]\n\nCoded by Great Icq#893-894 (C) 2006", "Dbgdump", MB_ICONINFORMATION); // Создаем снимок всех потоков системы HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if(hSnapShot == INVALID_HANDLE_VALUE) return MessageBox(0, "CreateToolhelp32Snapshot() failed", "Dbgdump", MB_ICONERROR); THREADENTRY32 te = {sizeof(te)}; if(!Thread32First(hSnapShot, &te)) return MessageBox(0, "Unable to find any threads in the system", "Thread snapshot", MB_ICONERROR); bool found=0; int count=0; do { if(te.th32OwnerProcessID == dwProcessId) { found=1; break; } } while(Thread32Next(hSnapShot, &te)); if(!found) return MessageBox(0, "Unable to find any thread belongs to the debugged process", "Dbgdump", MB_ICONERROR); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwProcessId); if(!hProcess) return MessageBox(0, "Unable to open debuggee process", "Dbgdump", MB_ICONERROR); HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, te.th32ThreadID); if(!hThread) return MessageBox(0, "Unable to open first thread belongs to the debugged process", "Dbgdump", MB_ICONERROR); SuspendThread(hThread); CONTEXT ctx = {CONTEXT_FULL}; GetThreadContext(hThread, &ctx); ResumeThread(hThread); char buf[10240]; PROCESSENTRY32* pe = GetProcess(dwProcessId); DWORD exception=0; wsprintf(buf, "Module '%s' has encountered a problem and needs to close\n\n" "Number of threads: %d\n" "Process ID: %d (0x%08x)\n" "Exception code: 0x%08x\n" //"Event code: 0x%08x\n" "First thread ID: %d (0x%08x)\n" "\n" "First thread context:\n" "EAX = 0x%08x\tEBX = 0x%08x\n" "ECX = 0x%08x\tEDX = 0x%08x\n" "EBP = 0x%08x\tESP = 0x%08x\n" "ESI = 0x%08x\tEDI = 0x%08x\n" "EIP = 0x%08x\tEFL = 0x%08x\n" "\n" , pe->szExeFile, pe->cntThreads, dwProcessId, dwProcessId, exception, //event.dwDebugEventCode, te.th32ThreadID, te.th32ThreadID, ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx, ctx.Ebp, ctx.Esp, ctx.Esi, ctx.Edi, ctx.Eip, ctx.EFlags ); wsprintf(buf+strlen(buf), "Stack unwind for the first thread:\n" "%s\n", StackRemoteUnwind(dwProcessId, te.th32ThreadID, 150) ); wsprintf(buf+strlen(buf), "Stack dump for the first thread:\n"); strcat(buf, Dump((LPVOID)stack, 256, ctx.Esp)); strcat(buf, "\n"); AlternateMessageBox(buf, "Dbgdump", 0, "Lucida console", 14, 750, 600); TerminateProcess(hProcess, 0); delete stack; return 0; } Результат: Полный код можно найти тут: http://gr8.cih.ms/dbgdump.cpp На этом позвольте откланиться, пока
найс. намного удобнее, 4ем крутить окно от4етов мелкософта в поисках регистров (кто пробовал - поймут) ЗЫ: +
Кому надо, я залил бинарник моего творения: http://cribble.by.ru/dbgdump.exe (4k, packed by upack) Юзаем
Да, этот отчёт конечно гораздо более удобечетаемый чем стандартный, но предпочитаю: OllyDbg -> Options -> Just-In-Time Debugging