慎用RtlCaptureContext
RtlCaptureContext可以用来获取调用者的线程环境结构CONTEXT,但有个很重要的前提,就是调用者必须是bp-based frame的函数,所谓的bp-based frame,就是指函数开头有push ebp/mov ebp, esp指令,如果调用者不是bp-based frame的,则RtlCaptureContext有可能产生0xC0000005异常而使程序退出,这取决于调用者的ebp值,看看RtlCaptureContext的实现就知道了:
@RtlCaptureContext: push ebx mov ebx, dword ptr [esp+8] mov dword ptr [ebx+B0], eax mov dword ptr [ebx+AC], ecx mov dword ptr [ebx+A8], edx mov eax, dword ptr [esp] mov dword ptr [ebx+A4], eax mov dword ptr [ebx+A0], esi mov dword ptr [ebx+9C], edi jmp short @L00000001 mov edi, edi push ebx mov ebx, dword ptr [esp+8] mov dword ptr [ebx+B0], 0 mov dword ptr [ebx+AC], 0 mov dword ptr [ebx+A8], 0 mov dword ptr [ebx+A4], 0 mov dword ptr [ebx+A0], 0 mov dword ptr [ebx+9C], 0 @L00000001: mov word ptr [ebx+BC], cs mov word ptr [ebx+98], ds mov word ptr [ebx+94], es mov word ptr [ebx+90], fs mov word ptr [ebx+8C], gs mov word ptr [ebx+C8], ss pushfd pop dword ptr [ebx+C0] ; 注意下面这条指令,直接访问了调用者的ebp, ; 如果调用者不是bp-based frame的,则ebp ; 有可能指向无效的内存 mov eax, dword ptr [ebp+4] mov dword ptr [ebx+B8], eax mov eax, dword ptr [ebp] mov dword ptr [ebx+B4], eax lea eax, dword ptr [ebp+8] mov dword ptr [ebx+C4], eax pop ebx retn 4
VC++编译出来的程序,Debug版一般都是bp-based frame的,而Release版因为会优化代码,就不一定是bp-based frame,比如Release版经常会把函数编译成类似如下:
; 函数开头没有push ebp/mov ebp, esp sub esp, xxx ; 省略... call RtlCaptureContext
这种情况很明显了,因为ebp的值不确定,所以call RtlCaptureContext极有可能崩溃。
MSDN里没看到有关于bp-based frame的说明,这是我测试google-breakpad时发现的,以后要注意了。
(google-breakpad是Google的一个跨平台开源库,用来生成崩溃转储的,目前Chrome,Firefox等在使用此库)

不错。