Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Авторские статьи (https://forum.antichat.xyz/forumdisplay.php?f=31)
-   -   Just-In-Time Debugging (https://forum.antichat.xyz/showthread.php?t=30598)

_Great_ 05.01.2007 01:16

Just-In-Time Debugging
 
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. Это обеспечит следующая функция:
Код:

// Получение инфы о процессе по 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, который, очевидно, в пояснениях не нуждается.

Код:

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/data/jit.png

Полный код можно найти тут: http://gr8.cih.ms/dbgdump.cpp

На этом позвольте откланиться, пока :)

ProTeuS 05.01.2007 01:31

найс. намного удобнее, 4ем крутить окно от4етов мелкософта в поисках регистров (кто пробовал - поймут)

ЗЫ: +

_Great_ 05.01.2007 01:39

Кому надо, я залил бинарник моего творения: http://cribble.by.ru/dbgdump.exe (4k, packed by upack)

Юзаем :)

hidden 06.01.2007 01:22

Да, этот отчёт конечно гораздо более удобечетаемый чем стандартный, но предпочитаю:
OllyDbg -> Options -> Just-In-Time Debugging


Время: 12:23