TEB结构
TEB(Thread Environment Block,线程环境块)在Windows9X系列中称为TIB(Thread Information Block,线程信息块),它记录着线程的重要信息。每一个线程对应一个TEB结构,在Windows2000 DDK中定义为:
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
union {
PVOID FiberData;
DWORD Version;
};
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
} NT_TIB;
与异常处理相关的项是指向_EXCEPTION_REGISTRATION_RECORD 结构的指针*ExceptionList,正好位于TEB的偏移0处。Windows在创建线程时,操作系统均会为每个线程分配TEB,而且都将FS段选择器指向当前线程的TEB数据,即TEB总是由[FS:0]指向的。
下面所说的_EXCEPTION_REGISTRATION_RECORD 结构就是前面的异常处理的基本过程中链起来的异常处理线程基础。
EXCEPTION_REGISTRATION结构
我能找到正式定义 EXCEPTION_REGISTRATION 结构的唯一地方是 EXSUP.INC 文件,该文件来自 Visual C++ 运行库的源:
_EXCEPTION_REGISTRATION struc
prev dd ? ;指向前一个EXCEPTION_REGISTRATION结构的指针
handler dd ? ;当前异常处理回调函数的地址
_EXCEPTION_REGISTRATION ends
你还将看到该结构在 WINNT.H 文件中定义的 NT_TIB 结构中被引用为 _EXCEPTION_REGISTRATION_RECORD。唉,除此之外,没有什么地方能找到 _EXCEPTION_REGISTRATION_RECORD 的定义,所以我只能使用 EXSUP.INC 文件中定义的汇编语言结构。
其中,prev是指向前一个EXCEPTION_REGISTRATION(简称ERR)的指针,形成一个链状结构;handler指向异常处理代码,当系统遇到一个它不知道如何处理的异常时,它就查找异常处理链表。每个线程都有它自己的异常处理链表。
00401000 > 8D4424 F8 lea eax,dword ptr ss:[esp-0x8] ;分配8个字节来存放ERR结构,并把地址存放到eax中
00401004 64:8705 0000000>xchg dword ptr fs:[0],eax ;eax和fs:[0]交换位置,现在的eax指向一开始fs:[0]的ERR结构;fs:[0]指向现在构造的ERR结构
0040100B BB 2E104000 mov ebx,Seh.0040102E
00401010 53 push ebx ;handler
00401011 50 push eax ;prev
00401012 BE 00000000 mov esi,0x0
00401017 8B06 mov eax,dword ptr ds:[esi] ;当这里读取异常的时候,将交给系统异常处理,处理完毕后,调回到handler执行
00401019 6A 00 push 0x0
0040101B 68 00304000 push Seh.00403000 ; ASCII "OK"
00401020 68 10304000 push Seh.00403010 ; ASCII "SEH Fail"
00401025 6A 00 push 0x0
00401027 E8 1C000000 call <jmp.&USER32.MessageBoxA>
0040102C EB 13 jmp short Seh.00401041
0040102E 6A 00 push 0x0
00401030 68 00304000 push Seh.00403000 ; ASCII "OK"
00401035 68 03304000 push Seh.00403003 ; ASCII "SEH Succeed "
0040103A 6A 00 push 0x0
0040103C E8 07000000 call <jmp.&USER32.MessageBoxA>
00401041 6A 00 push 0x0
00401043 E8 06000000 call <jmp.&KERNEL32.ExitProcess>
00401048 - FF25 08204000 jmp dword ptr ds:[<&USER32.MessageBoxA>] ; user32.MessageBoxA
0040104E - FF25 00204000 jmp dword ptr ds:[<&KERNEL32.ExitProcess>; kernel32.ExitProcess
当堆栈刚出现这个的时候,就要注意handler的地址,因为程序即将跳到handler的地址执行。分析的时候需提前下断。