#include #include #include #include #define _DBDBG32_ #include "dbwin32.h" ProcessList::ProcessList() : GrowableList(sizeof(ProcessInfo)) { } ProcessList::~ProcessList() { } BOOL ProcessList::IsEqual(void *pv1, void *pv2) { return(!memcmp(pv1, pv2, sizeof(DWORD))); } ThreadList::ThreadList() : GrowableList(sizeof(ThreadInfo)) { } ThreadList::~ThreadList() { } BOOL ThreadList::IsEqual(void *pv1, void *pv2) { return(!memcmp(pv1, pv2, sizeof(ThreadInfo))); } DllList::DllList() : GrowableList(sizeof(DllInfo)) { } DllList::~DllList() { } BOOL DllList::IsEqual(void *pv1, void *pv2) { return(!memcmp(pv1, pv2, (sizeof(DWORD) + sizeof(LPVOID)))); } void __cdecl AttachThread(void *pv) { AttachInfo *pai = (AttachInfo *)pv; if (DebugActiveProcess(pai->dwProcess)) DebugThread(pai->hwndFrame, pai->dwProcess); else { MessageBeep(MB_ICONEXCLAMATION); MessageBox(pai->hwndFrame, "Unable to attach to process.", "DbWin32", MB_ICONEXCLAMATION | MB_OK); } delete pai; } void __cdecl ExecThread(void *pv) { ExecInfo *pei = (ExecInfo *)pv; STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.wShowWindow = SW_SHOWDEFAULT; pi.hProcess = NULL; if (CreateProcess(NULL, pei->lpszCommandLine, NULL, NULL, TRUE, DEBUG_PROCESS | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); DebugThread(pei->hwndFrame, pi.dwProcessId); } else { MessageBeep(MB_ICONEXCLAMATION); MessageBox(pei->hwndFrame, "Unable to execute process.", "DbWin32", MB_ICONEXCLAMATION | MB_OK); } free((void *)(pei->lpszCommandLine)); delete pei; } void __cdecl SystemThread(void *pv) { BOOL fFailed = TRUE; DWORD dwRet; HANDLE hevtBuffer = NULL, hevtData = NULL; HANDLE hfileShared = NULL; HWND hwndFrame = (HWND)pv; LPVOID lpvBuffer = NULL; LPSTR lpszText = NULL; DEBUG_EVENT DebugEvent; hevtBuffer = CreateEvent(NULL, FALSE, FALSE, "DBWIN_BUFFER_READY"); if (hevtBuffer) hevtData = CreateEvent(NULL, FALSE, FALSE, "DBWIN_DATA_READY"); if (hevtBuffer && hevtData) hfileShared = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, "DBWIN_BUFFER"); if (hevtBuffer && hevtData && hfileShared) lpvBuffer = MapViewOfFile(hfileShared, FILE_MAP_READ, 0, 0, 512); if (hevtBuffer && hevtData && hfileShared && lpvBuffer) { fFailed = FALSE; lpszText = (LPSTR)lpvBuffer + sizeof(DWORD); DebugEvent.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; DebugEvent.dwProcessId = DebugEvent.dwThreadId = 0; SetEvent(hevtBuffer); } else { MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwndFrame, "Unable to open System Window.", "DbWin32", MB_ICONEXCLAMATION | MB_OK); } while (!fFailed) { dwRet = WaitForSingleObject(hevtData, INFINITE); if (dwRet != WAIT_OBJECT_0) { SendText(hwndFrame, &DebugEvent, 0, "-------- DbWin32 ERROR! --------\r\n", DBO_OUTPUTDEBUGSTRING); SendText(hwndFrame, &DebugEvent, 0, "-------- Shutting down System Window --------\r\n", DBO_OUTPUTDEBUGSTRING); fFailed = TRUE; } else { SendText(hwndFrame, &DebugEvent, 0, lpszText, DBO_OUTPUTDEBUGSTRING); SetEvent(hevtBuffer); } } if (hfileShared) CloseHandle(hfileShared); if (hevtData) CloseHandle(hevtData); if (hevtBuffer) CloseHandle(hevtBuffer); } void __cdecl DebugThread(HWND hwndFrame, DWORD dwProcess) { char DisplayBuffer[BUF_SIZE]; WORD wEvent; DWORD dwContinue; SIZE_T dwRead; ProcessList pl; ProcessInfo pi; ThreadList tl; ThreadInfo ti; DllList dl; DllInfo di; int iItem; BOOL fDone = FALSE; DEBUG_EVENT DebugEvent; EXCEPTION_DEBUG_INFO *pException = &DebugEvent.u.Exception; CREATE_THREAD_DEBUG_INFO *pCreateThread = &DebugEvent.u.CreateThread; CREATE_PROCESS_DEBUG_INFO *pCreateProcessInfo = &DebugEvent.u.CreateProcessInfo; EXIT_THREAD_DEBUG_INFO *pExitThread = &DebugEvent.u.ExitThread; EXIT_PROCESS_DEBUG_INFO *pExitProcess = &DebugEvent.u.ExitProcess; LOAD_DLL_DEBUG_INFO *pLoadDll = &DebugEvent.u.LoadDll; UNLOAD_DLL_DEBUG_INFO *pUnloadDll = &DebugEvent.u.UnloadDll; OUTPUT_DEBUG_STRING_INFO *pDebugString = &DebugEvent.u.DebugString; RIP_INFO *pRipInfo = &DebugEvent.u.RipInfo; while (!fDone && WaitForDebugEvent(&DebugEvent, INFINITE)) { *DisplayBuffer = '\0'; dwContinue = DBG_CONTINUE; switch (DebugEvent.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: ProcessExceptionEvent(pException, DisplayBuffer); if (pException->ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT) { dwContinue = DBG_EXCEPTION_NOT_HANDLED; } wEvent = DBO_EXCEPTIONS; break; case CREATE_THREAD_DEBUG_EVENT: ti.dwProcess = DebugEvent.dwProcessId; ti.dwThread = DebugEvent.dwThreadId; tl.InsertItem(&ti); wsprintf(DisplayBuffer, "Create Thread: PID 0x%X - TID 0x%X\r\n", ti.dwProcess, ti.dwThread); wEvent = DBO_THREADCREATE; break; case CREATE_PROCESS_DEBUG_EVENT: ti.dwProcess = pi.dwProcess = DebugEvent.dwProcessId; ti.dwThread = DebugEvent.dwThreadId; tl.InsertItem(&ti); pi.hProcess = pCreateProcessInfo->hProcess; GetModuleName(pCreateProcessInfo->hFile, pi.hProcess, (DWORD_PTR)pCreateProcessInfo->lpBaseOfImage, pi.rgchModule); pl.InsertItem(&pi); wsprintf(DisplayBuffer, "Create Process: PID 0x%X - %s\r\n", pi.dwProcess, pi.rgchModule); wEvent = DBO_PROCESSCREATE; break; case EXIT_THREAD_DEBUG_EVENT: ti.dwProcess = DebugEvent.dwProcessId; ti.dwThread = DebugEvent.dwThreadId; tl.RemoveItem(&ti); wsprintf(DisplayBuffer, "Exit Thread: PID 0x%X - TID 0x%X - dwReturnCode %d\r\n", ti.dwProcess, ti.dwThread, pExitThread->dwExitCode); wEvent = DBO_THREADEXIT; break; case EXIT_PROCESS_DEBUG_EVENT: pi.dwProcess = DebugEvent.dwProcessId; if (pl.FindItem(&pi, &iItem)) { pl.RemoveItem(iItem); } wsprintf(DisplayBuffer, "Exit Process: PID 0x%X - %s - dwReturnCode %d\r\n", pi.dwProcess, pi.rgchModule, pExitProcess->dwExitCode); if (pi.dwProcess == dwProcess) { fDone = TRUE; } wEvent = DBO_PROCESSEXIT; break; case LOAD_DLL_DEBUG_EVENT: di.dwProcess = pi.dwProcess = DebugEvent.dwProcessId; if (pl.FindItem(&pi)) { di.lpBaseOfDll = pLoadDll->lpBaseOfDll; GetModuleName(pLoadDll->hFile, pi.hProcess, (DWORD_PTR)di.lpBaseOfDll, di.rgchModule); dl.InsertItem(&di); wsprintf(DisplayBuffer, "DLL Load: %s\r\n", di.rgchModule); wEvent = DBO_DLLLOAD; } break; case UNLOAD_DLL_DEBUG_EVENT: di.dwProcess = DebugEvent.dwProcessId; di.lpBaseOfDll = pUnloadDll->lpBaseOfDll; if (dl.FindItem(&di, &iItem)) { dl.RemoveItem(iItem); } wsprintf(DisplayBuffer, "Dll Unload: %s\r\n", di.rgchModule); wEvent = DBO_DLLUNLOAD; break; case OUTPUT_DEBUG_STRING_EVENT: pi.dwProcess = DebugEvent.dwProcessId; if (!pl.FindItem(&pi) || (!ReadProcessMemory(pi.hProcess, pDebugString->lpDebugStringData, DisplayBuffer, pDebugString->nDebugStringLength, &dwRead))) { dwRead = 0; } DisplayBuffer[dwRead] = '\0'; wEvent = DBO_OUTPUTDEBUGSTRING; break; case RIP_EVENT: wsprintf(DisplayBuffer, "RIP: dwError %d - dwType %d\r\n", pRipInfo->dwError, pRipInfo->dwType); wEvent = DBO_RIP; break; // No events should reach here. default: wsprintf(DisplayBuffer, "Unknown Event: 0x%X\r\n", DebugEvent.dwDebugEventCode); wEvent = DBO_ALL; break; } if (*DisplayBuffer) SendText(hwndFrame, &DebugEvent, dwProcess, DisplayBuffer, wEvent); if (DebugEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) PostMessage(hwndFrame, WM_ENDTHREAD, (WPARAM)ti.dwThread, ti.dwProcess); if (DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { if (fDone) { for (iItem = tl.Count(); iItem > 0; iItem--) { tl.GetItem(iItem - 1, &ti); PostMessage(hwndFrame, WM_ENDTHREAD, (WPARAM)ti.dwThread, ti.dwProcess); } for (iItem = pl.Count(); iItem > 0; iItem--) { pl.GetItem(iItem - 1, &pi); PostMessage(hwndFrame, WM_ENDTHREAD, 0, pi.dwProcess); } } PostMessage(hwndFrame, WM_ENDTHREAD, 0, DebugEvent.dwProcessId); } ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinue); } } void SendText(HWND hwndFrame, DEBUG_EVENT *pDebugEvent, DWORD dwParentProcess, LPCSTR lpszText, WORD wEvent) { char rgchText[BUF_SIZE], *pch = rgchText; StringInfo *psi; psi = new StringInfo; // Niceify the text if (pDebugEvent->dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { psi->cLines = 0; while (*lpszText != '\0') { if ((*lpszText == 0x0d) || (*lpszText == 0x0a)) { *pch++ = 0x0d; *pch++ = 0x0a; while ((*lpszText == 0x0d) || (*lpszText == 0x0a)) lpszText++; psi->cLines++; } else { *pch++ = *lpszText++; } } *pch = '\0'; psi->lpszText = _strdup(rgchText); } else { psi->cLines = 1; psi->lpszText = _strdup(lpszText); } psi->dwProcess = pDebugEvent->dwProcessId; psi->dwThread = pDebugEvent->dwThreadId; psi->dwParentProcess = dwParentProcess; PostMessage(hwndFrame, WM_SENDTEXT, wEvent, (LPARAM)psi); } void ProcessExceptionEvent(EXCEPTION_DEBUG_INFO *pException, LPSTR lpszBuf) { if (pException->dwFirstChance) strcpy(lpszBuf, "First"); else strcpy(lpszBuf, "Second"); strcat(lpszBuf, " chance exception: "); switch (pException->ExceptionRecord.ExceptionCode) { //--standard exceptions case EXCEPTION_ACCESS_VIOLATION: strcat(lpszBuf, "Access Violation"); break; case EXCEPTION_DATATYPE_MISALIGNMENT: strcat(lpszBuf, "Datatype Misalignment"); break; case EXCEPTION_BREAKPOINT: strcat(lpszBuf, "Breakpoint"); break; case EXCEPTION_SINGLE_STEP: strcat(lpszBuf, "Single Step"); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: strcat(lpszBuf, "Array Bound Exceeded"); break; case EXCEPTION_FLT_DENORMAL_OPERAND: strcat(lpszBuf, "FP-Denormal Operand"); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: strcat(lpszBuf, "FP-Divide By Zero"); break; case EXCEPTION_FLT_INEXACT_RESULT: strcat(lpszBuf, "FP-Inexact Result"); break; case EXCEPTION_FLT_INVALID_OPERATION: strcat(lpszBuf, "FP-Invalid Operation"); break; case EXCEPTION_FLT_OVERFLOW: strcat(lpszBuf, "FP-Overflow"); break; case EXCEPTION_FLT_STACK_CHECK: strcat(lpszBuf, "FP-Stack Check"); break; case EXCEPTION_FLT_UNDERFLOW: strcat(lpszBuf, "FP-Underflow"); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: strcat(lpszBuf, "INT-Divide By Zero"); break; case EXCEPTION_INT_OVERFLOW: strcat(lpszBuf, "INT-Overflow"); break; case EXCEPTION_PRIV_INSTRUCTION: strcat(lpszBuf, "Privileged Instruction"); break; case EXCEPTION_IN_PAGE_ERROR: strcat(lpszBuf, "In Page Error"); break; //-- Debug exceptions case DBG_TERMINATE_THREAD: strcat(lpszBuf, "DBG-Terminate Thread"); break; case DBG_TERMINATE_PROCESS: strcat(lpszBuf, "DBG-Terminate Process"); break; case DBG_CONTROL_C: strcat(lpszBuf, "DBG-Control+C"); break; case DBG_CONTROL_BREAK: strcat(lpszBuf, "DBG-Control+Break"); break; //-- RPC exceptions (some) case RPC_S_UNKNOWN_IF: strcat(lpszBuf, "RPC-Unknown Interface"); break; case RPC_S_SERVER_UNAVAILABLE: strcat(lpszBuf, "RPC-Server Unavailable"); break; //-- VDM exceptions (minimal information) case EXCEPTION_VDM_EVENT: // see dbwin32.h for definition strcat(lpszBuf, "VDM"); break; default: char rgchTmp[25]; wsprintf(rgchTmp, "Unknown-[0x%X]", pException->ExceptionRecord.ExceptionCode); strcat(lpszBuf, rgchTmp); break; } strcat(lpszBuf, "\r\n"); } #define IMAGE_SECOND_HEADER_OFFSET (15 * sizeof(ULONG)) #define IMAGE_EXPORT_TABLE_RVA_OFFSET (30 * sizeof(DWORD)) #define IMAGE_NAME_RVA_OFFSET offsetof(IMAGE_EXPORT_DIRECTORY, Name) void GetModuleName(HANDLE hFile, HANDLE hProcess, DWORD_PTR BaseOfImage, LPSTR lpszBuf) { DWORD dwRead = 0; WORD DosSignature; DWORD NtSignature, PeHeader, ExportTableRVA, NameRVA; strcpy(lpszBuf, ""); if (!hFile) return; if (GetFileType(hFile) != FILE_TYPE_DISK) return; SetFilePointer(hFile, 0L, NULL, FILE_BEGIN); if (!ReadFile(hFile, &DosSignature, sizeof(DosSignature), &dwRead, NULL)) return; if (DosSignature != IMAGE_DOS_SIGNATURE) return; SetFilePointer(hFile, IMAGE_SECOND_HEADER_OFFSET, NULL, FILE_BEGIN); if (!ReadFile(hFile, &PeHeader, sizeof(PeHeader), &dwRead, NULL)) return; SetFilePointer(hFile, PeHeader, NULL, FILE_BEGIN); if (!ReadFile(hFile, &NtSignature, sizeof(NtSignature), &dwRead, NULL)) return; if (NtSignature != IMAGE_NT_SIGNATURE) return; SetFilePointer(hFile, PeHeader + IMAGE_EXPORT_TABLE_RVA_OFFSET, NULL, FILE_BEGIN); if (!ReadFile(hFile, &ExportTableRVA, sizeof(ExportTableRVA), &dwRead, NULL)) return; if (!ExportTableRVA) return; ReadProcessMemory(hProcess, (LPVOID)(BaseOfImage + ExportTableRVA + IMAGE_NAME_RVA_OFFSET), &NameRVA, sizeof(NameRVA), NULL); ReadProcessMemory(hProcess, (LPVOID)(BaseOfImage + NameRVA), lpszBuf, MODULE_SIZE, NULL); }