在Windows 8.1 Preview x64上,OllyDbg如果试图启动一个程序进行调试,会出现一个死在ntdll.RtlUserThreadStart的单步异常:
这个问题其实是由内核在创建进程时引发的,内核如何做的我没仔细看,就在创建进程后,内核把LdrInitializeThunk中执行ZwContinue的CONTEXT结构体的EFlags设置加上了TF(单步)标志,使得ZwContinue设置CONTEXT跑去执行RtlUserThreadStart的一条指令后就中断了,而又没有异常处理去Skip这个异常,就出现了无法调试的问题。
修复这个问题很简单,设置OD停在系统断点,然后把ZwContinue的CONTEXT中的EFlags改成202而不是默认的302即可,如下图:
这样F9后就能停在入口点了。还是希望8.1的RTM能修复这个问题。
还有大家需要注意下目前x64上32位程序在切内核时跟x86的异同。
x86:
x64的32位程序:
把下面这份代码编译成Dll放到OD的插件目录让OD载入可以修复这个问题。
#include <Windows.h> typedef BOOL (WINAPI* fnWaitForDebugEvent)(LPDEBUG_EVENT,DWORD); typedef HWND (WINAPI *fnCreateWindowExA)(DWORD,LPCSTR,LPCSTR,DWORD,INT,INT,INT,INT,HWND,HMENU,HINSTANCE,LPVOID); PVOID pfnWaitForDebugEvent; PVOID pfnCreateWindowExA; HWND WINAPI _CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,INT x,INT y,INT nWidth,INT nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam) { register HWND hWnd = ((fnCreateWindowExA)pfnCreateWindowExA)(dwExStyle,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); if (IsWindow(hWnd)) { ChangeWindowMessageFilterEx(hWnd,WM_DROPFILES,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(hWnd,WM_COPYDATA,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(hWnd,WM_USER,MSGFLT_ALLOW,NULL); } return hWnd; } BOOL WINAPI _WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds) { register BOOL bResult = ((fnWaitForDebugEvent)pfnWaitForDebugEvent)(lpDebugEvent,dwMilliseconds); if (lpDebugEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { if (lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP && lpDebugEvent->u.Exception.dwFirstChance == 0 && lpDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress == (PVOID)((DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),"RtlUserThreadStart") + 4)) { ContinueDebugEvent(lpDebugEvent->dwProcessId,lpDebugEvent->dwThreadId,DBG_CONTINUE); bResult = FALSE; } } return bResult; } BOOL WINAPI DllMain(HINSTANCE hDllInst,DWORD dwReason,LPVOID pvReserved) { if (dwReason == DLL_PROCESS_ATTACH) { typedef NTSTATUS (NTAPI* fnLdrAddRefDll)(ULONG,PVOID); ((fnLdrAddRefDll)GetProcAddress(GetModuleHandle("ntdll.dll"),"LdrAddRefDll"))(0,hDllInst); DisableThreadLibraryCalls(hDllInst); BOOL bWow64 = FALSE; IsWow64Process((HANDLE)-1,&bWow64); register DWORD dwWaitForDebugEvent = (UINT_PTR)GetModuleHandle(NULL) + 0x3961E; register DWORD dwCreateWindowExA = (UINT_PTR)GetModuleHandle(NULL) + 0xAF39E; DWORD dwOldProtect; VirtualProtect((PVOID)dwWaitForDebugEvent,4,PAGE_EXECUTE_READWRITE,&dwOldProtect); pfnWaitForDebugEvent = (PVOID)(*(PDWORD)dwWaitForDebugEvent + dwWaitForDebugEvent + sizeof(DWORD)); if (bWow64) *(PDWORD)dwWaitForDebugEvent = (DWORD)&_WaitForDebugEvent - dwWaitForDebugEvent - sizeof(DWORD); VirtualProtect((PVOID)dwWaitForDebugEvent,4,dwOldProtect,&dwOldProtect); pfnCreateWindowExA = (PVOID)(*(PDWORD)(*(PDWORD)dwCreateWindowExA)); VirtualProtect((PVOID)(*(PDWORD)dwCreateWindowExA),4,PAGE_READWRITE,&dwOldProtect); *(PDWORD)(*(PDWORD)dwCreateWindowExA) = (DWORD)&_CreateWindowExA; VirtualProtect((PVOID)(*(PDWORD)dwCreateWindowExA),4,dwOldProtect,&dwOldProtect); ChangeWindowMessageFilterEx(*(HWND*)0x4D3B7C,WM_DROPFILES,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(*(HWND*)0x4D3B7C,WM_COPYDATA,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(*(HWND*)0x4D3B80,WM_DROPFILES,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(*(HWND*)0x4D3B80,WM_COPYDATA,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(*(HWND*)0x4CD6A0,WM_DROPFILES,MSGFLT_ALLOW,NULL); ChangeWindowMessageFilterEx(*(HWND*)0x4CD6A0,WM_COPYDATA,MSGFLT_ALLOW,NULL); } return TRUE; }