2、异常信息
当一个异常发生时,操作系统向异常处理的线程堆栈中压入3个结构,这三个结构是:EXCEPTION_RECORD,CONTEXT, EXCEPTION_POINTERS。
1、 EXCEPTION_ RECORD结构
EXCEPTION_ RECORD结构包含了有关最近发生异常的详细信息,这些信息独立于CPU。其结构如下:
EXCEPTION_ RECORD STRUCT { +0 DWORD ExceptionCode ;异常代码 +4 DWORD ExceptionFlags ;异常标志 +8 struct EXCEPTION_RECORD ;指向另一个EXCEPTION_ RECORD的指针 +C PVOID ExceptionAddress ;异常发生的地址 +10 DWORD NumberParatemeters ;与异常联系的参数数量(0-15) +14 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS] } EXCEPTION_ RECORD |
其中,ExceptionCode字段定义了产生异常的原因。图二中表示程序引发了一个EXCEPTION_ACCESS_VIOLATION异常,异常代码为0xC0000005,查阅该异常代码后我们知道程序读写了一个没有可读写属性的地址。
3、CONTEXT结构
CONTEXT结构包含了特定处理器的寄存器数据,系统使用CONTEXT结构来执行各种内部操作。该结构可参考WinNt.h的定义,在X86平台下该结构定义为CONTEXT86,后面将直接用CONTEXT代指CONTEXT86。因为由于该结构比较长,出于篇幅考虑只列出来结构的部分成员:
Typedef struct _ CONTEXT86{ …… //通用寄存器 +9C DWORD Edi; +A0 DWORD Esi; +A4 DWORD Ebx; +A8 DWORD Edx; +AC DWORD Ecx; +B0 DWORD Eax; //控制寄存器 +B4 DWORD Ebp; +B8 DWORD Eip; +BC DWORD SegCs; +C0 DWORD EFlags; +C4 DWORD Esp; +C8 DWORD SegSs; …… } CONTEXT86; |
CONTEXT结构非常重要,通过修改CONTEXT结构中的成员,可以使程序能够在异常时执行相应的处理工作,使程序能够继续执行。在Windows Xp系统中,系统调用NTDLL.DLL模块中的KiUserExceptionDIspatcher函数来执行异常处理。该函数最终将程序中注册的异常处理函数的地址装入ECX,然后调用执行。此时堆栈的分布情况如下:
Esp+0x0 -> *EXCEPTION_RECORD |
如果注册的异常处理函数将CONTEXT结构中保存的EIP值修改到一个“安全的地方”,那么执行完异常处理函数后,程序将返回到“安全代码”中去执行。
下面的例子程序将在执行搜索内存的操作之前向异常处理链表中注册一个异常处理函数,用于在发生地址访问错误的时候修正程序的执行路径,修改EIP的值为发生访问违例(执行内存比较)的下一条指令地址。这样程序将能够安全、顺利地执行完搜索内存的操作。
为了弄清楚异常发生时系统的状态我们进行如下跟踪分析:
① 在Ollydbg中打开程序Seh.exe,由于搜索的起始地址为0x200000将会导致一个访问异常。我们OllyDbg的命令窗口中输入bp 0x7C9237BD,在Windows Xp系统将要调用异常处理函数时断下来观察堆栈的状态(Windows 2000 中是 0x77F8E43E)。此时程序的状态如图三所示:

图三、KiUserExceptionDIspatcher函数调用异常处理时的堆栈状态
此时Esp的值为0x12FBF0,该地址指向EXCEPTION_RECORD结构,结构偏移为0x0处保存了异常代码0xC0000005,偏移为0xC处保存了异常发生的地址0x401017,该指令是我们执行模式匹配的指令scasd。Esp+4(0x12FFBC)保存了指向下一个异常处理结构的指针。Esp+8(0x12FCF0)保存了指向CONTEXT结构的指针,该结构偏移为0xB8处保存了异常发生时EIP寄存器的值0x401017,偏移为0x9C处保存了Edi寄存器的值0x200000。CONTEXT保存的各寄存器的状态可参见图四。

图四、异常发生时CONTEXT结构的状态
②按下F7后执行预定义的异常处理函数。该函数将修正CONTEXT中保存的EIP的值为指令add ebx, 01000h在内存中的地址(0x0040101C)。当程序恢复执行时,将从该指令继续执行内存空间的搜索操作。修改后的CONTEXT状态可参见图五。

图五、修正后CONTEXT结构的状态