Win32 SEH异常深度探索_7 对未处理异常的默认处理

Unhandled Exceptions

Earlier in the article, I put off a full description of the UnhandledExceptionFilter API. You normally don't call this API directly (although you can). Most of the time, it's invoked by the filter-expression code for KERNEL32's default exception callback. I showed this earlier in the pseudocode for BaseProcessStart.

如果有用户未处理的异常,会调用UnhandledExceptionFilter, 一般由 KERNEL32 得默认异常回调函数调用。伪代码如下:

 

 

 

Figure 13 shows my pseudocode for UnhandledExceptionFilter. The API starts out a bit strangely (at least in my opinion). If the fault is an EXCEPTION_ACCESS_ VIOLATION, the code calls _BasepCheckForReadOnlyResource. While I haven't provided pseudocode for this function, I can summarize it. If the exception occurred because a resource section (.rsrc) of an EXE or DLL was written to, _BasepCurrentTopLevelFilter changes the faulting page's attributes from its normal read-only state, thereby allowing the write to occur. If this particular scenario occurs, UnhandledExceptionFilter returns EXCEPTION_ CONTINUE_EXECUTION and execution restarts at the faulting instruction.

首先,如果是 EXCEPTION_ACCESS_ VIOLATION ,代码首先调用 _BasepCheckForReadOnlyResource 察看是否因为需要写 EXE DLL 中的资源节 (.rsrc) ,如果是,他将改变该页的只读属性让其可写,然后返回 EXCEPTION_ CONTINUE_EXECUTION 让代码在异常处继续运行。

 

The next task of UnhandledExceptionFilter is to determine if the process is being run under a Win32 debugger. That is, the process was created with the DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS flag. UnhandledExceptionFilter uses the NtQueryInformationProcess Function that I describe in this month's Under the Hood column to tell if the process is being debugged. If so, the API returns EXCEPTION_CONTINUE_SEARCH, which tells some other part of the system to wake up the debugger process and tell it that an exception occurred in the debuggee.

接下来调用 NtQueryInformationProcess 判断进程是否是运行在 Win32 调试器下,也就是通过 DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS 启动,如果是,返回 EXCEPTION_CONTINUE_SEARCH 让系统激活调式器进程并报告异常。

 

Next on UnhandledExceptionFilter's plate is a call to the user-installed unhandled exception filter, if present. Normally, there isn't a user-installed callback, but one can be installed via the SetUnhandledExceptionFilter API. I've also provided pseudocode for this API. The API simply bashes a global variable with the new user callback address, and returns the value of the old callback.

然后他会调用一个用户定义的未处理异常过滤函数 ( 用户通过 SetUnhandledExceptionFilter 设置该函数 )

 

With the preliminaries out of the way, UnhandledExceptionFilter can get down to its primary job: informing you of your ignominious programming blunder with the ever- stylish Application Error dialog. There are two ways that this dialog can be avoided. The first is if the process has called SetErrorMode and specified the SEM_NOGPFAULTERRORBOX flag. The other method is to have the Auto value under the AeDebug registry key set to 1. In this case, UnhandledExceptionFilter skips the Application Error dialog and automatically fires up whatever debugger is specified in the Debugger value of the AeDebug key. If you're familiar with "just in time debugging," this is where the operating system supports it. More on this later.

在大多数情况下 UnhandledExceptionFilter 是做他的主要工作:弹出一个对话框报告有一个程序错误。有两种方法可以避免弹出这个框:

1. 调用 SetErrorMode 并设置 SEM_NOGPFAULTERRORBOX 标志;

2. 设置 AeDebug 注册表值为 1 ,这时 UnhandledExceptionFilter 将自动启动在 AeDebug 中设置的调试器。

 

In most cases, neither of these dialog avoidance conditions are true and UnhandledExceptionFilter calls the NtRaiseHardError function in NTDLL.DLL. It's this function that brings up the Application Error dialog. This dialog waits for you to hit the OK button to terminate the process, or Cancel to debug it. (Maybe it's just me, but hitting Cancel to launch a debugger seems a little backward.)

UnhandledExceptionFilter 是通过调用 NTDLL.DLL 中的 NtRaiseHardError 函数弹出程序错误对话框的,等待用户点击 OK 终止程序,或 Cancel 调式程序。

 

If you hit OK in the Application Error dialog box, UnhandledExceptionFilter returns EXCEPTION_EXECUTE_HANDLER. The code that called UnhandledExceptionFilter usually responds by terminating itself (as you saw in the BaseProcessStart code). This brings up an interesting point. Most people assume that the system terminates a process with an unhandled exception. It's actually more correct to say that the system sets up things so that an unhandled exception causes the process to terminate itself.

如果点击OK, UnhandledExceptionFilter  返回  EXCEPTION_EXECUTE_HANDLER ,后续代码将终止进程。这里关键的一点:不是由于系统发现进程有未处理异常而去终止进程,而是未处理异常引起进程终止自己,也就是,不是系统终止进程,而是进程终止自己。

 

The truly interesting code in UnhandledExceptionFilter executes if you select Cancel in the Application Error dialog, thereby bringing up a debugger on the faulting process. The code first calls CreateEvent to make an event that the debugger will signal after it has attached to the faulting process. This event handle, along with the current process ID, is passed to sprintf, which formats the command line used to start the debugger. Once everything is prepared, UnhandledExceptionFilter calls CreateProcess to start the debugger. If CreateProcess succeeds, the code calls NtWaitForSingleObject on the event created earlier. This call blocks until the debugger process signals the event, indicating that it has attached to the faulting process successfully. There are other little bits and pieces to the UnhandledExceptionFilter code, but I've covered the important highlights here.

如果点击 Cancel UnhandledExceptionFilter 首先创建一个 Event ,然后启动一个调试器进程,把自己的进程 ID 和那个 Event 句柄作为参数传给调试器,然后等待调试器触发 Event 通知自己,然后代码返回 EXCEPTION_CONTINUE_SEARCH

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值