异常0xc000041d的抛出过程
为了说明这个过程,我们必须写一个示例程序,如下:
#include "stdafx.h" #include <tchar.h> #include <stdio.h> #include <Windows.h> #pragma comment(lib, "user32") WNDPROC oldproc = NULL; LRESULT CALLBACK newproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { throw 0; return oldproc(hwnd, uMsg, wParam, lParam); } int _tmain(int argc, TCHAR *argv[]) { HWND hWnd = CreateWindowEx(0, TEXT("STATIC"), TEXT("Name"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); oldproc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)newproc); UpdateWindow(hWnd); system("pause"); }
将上面的程序在vs建立工程编译运行,得到如下结果
退出,在vs里按下快捷建F11,程序中断后,给函数ZwRaiseException下断点
按F5运行程序,程序中断,观察到程序停在了_NtRaiseException@12
看下调用栈
可以看到此时正在抛出第一个异常,也就是真正的异常 throw 0;
按F5 继续运行程序,程序又中断了,可以看到此时又中断在_NtRaiseException@12,看下栈
这是第二次抛出异常,也就是抛出0xc000041d,我们观察下函数ntdll.dll!_LdrpLogFatalUserCallbackException@8()
在这里里,填充了EXCEPTION_RECORD结构,紧接着调用了_NtRaiseException@12抛出异常。
简单来说,当程序产生了一个异常,首先走的还是正常的异常分发流程,当没有得到处理,又是在Windows系统的用户回调里发生的,会分发给_KiUserCallbackExceptionHandler去处理,_KiUserCallbackExceptionHandler里会调用_LdrpLogFatalUserCallbackException,_LdrpLogFatalUserCallbackException里会重新填充EXCEPTION_RECORD结构抛出异常0xc000041d。
为虫子生,为虫子死,为虫子奋斗一辈子