SEH 机制探索1 --- TEB 结构
在 windows 中的 SEH(Structured Exception Handling)结构化异常处理需要使用 TIB(Thread Information Block)线程信息块的 _EXCEPTION_REGISTRATION_RECORD结构。而 TIB 结构包括在 TEB(Thread Environment Block) 结构下,下面来探索下 TEB 结构。
1. TEB 结构
实际上关于 TIB(Thread Information Block)和 TEB(Thread Environment Block)的定义比较混乱,在 NT 类的系统应该称为 TEB,我没在 SDK 的 include 的文件里找到 TEB 结构的定义,也没有在 VC 的 crt 头文件里找到 TEB 的定义。在 winternl.h 文件里的 __TEB 显然不是我们想要的 TEB 结构。
TEB 和 TIB 都分为 32 位版本和 64 位版本,我们需要借助于 windbg 工具来观察 TEB 结构。
应该要有个认识在 x64 windows 平台,ntdll 模块是 64 位的,而 ntdll32 模块是 32 位的。 |
因此,32 位的TEB 结构符号是:ntdll32!_TEB,64 位的 TEB 结构符号是: ntdll!_TEB
1.1 TEB 整体结构
下面是在我的环境里(x64 windows7 平台)的 windbg 得到的 32 位 TEB 结构:
0:000:x86> dt ntdll32!_TEB +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB +0x034 LastErrorValue : Uint4B +0x038 CountOfOwnedCriticalSections : Uint4B +0x03c CsrClientThread : Ptr32 Void +0x040 Win32ThreadInfo : Ptr32 Void +0x044 User32Reserved : [26] Uint4B +0x0ac UserReserved : [5] Uint4B +0x0c0 WOW32Reserved : Ptr32 Void +0x0c4 CurrentLocale : Uint4B +0x0c8 FpSoftwareStatusRegister : Uint4B +0x0cc SystemReserved1 : [54] Ptr32 Void +0x1a4 ExceptionCode : Int4B +0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK +0x1ac SpareBytes : [36] UChar +0x1d0 TxFsContext : Uint4B +0x1d4 GdiTebBatch : _GDI_TEB_BATCH +0x6b4 RealClientId : _CLIENT_ID +0x6bc GdiCachedProcessHandle : Ptr32 Void +0x6c0 GdiClientPID : Uint4B +0x6c4 GdiClientTID : Uint4B +0x6c8 GdiThreadLocalInfo : Ptr32 Void +0x6cc Win32ClientInfo : [62] Uint4B +0x7c4 glDispatchTable : [233] Ptr32 Void +0xb68 glReserved1 : [29] Uint4B +0xbdc glReserved2 : Ptr32 Void +0xbe0 glSectionInfo : Ptr32 Void +0xbe4 glSection : Ptr32 Void +0xbe8 glTable : Ptr32 Void +0xbec glCurrentRC : Ptr32 Void +0xbf0 glContext : Ptr32 Void +0xbf4 LastStatusValue : Uint4B +0xbf8 StaticUnicodeString : _UNICODE_STRING +0xc00 StaticUnicodeBuffer : [261] Wchar +0xe0c DeallocationStack : Ptr32 Void +0xe10 TlsSlots : [64] Ptr32 Void +0xf10 TlsLinks : _LIST_ENTRY +0xf18 Vdm : Ptr32 Void +0xf1c ReservedForNtRpc : Ptr32 Void +0xf20 DbgSsReserved : [2] Ptr32 Void +0xf28 HardErrorMode : Uint4B +0xf2c Instrumentation : [9] Ptr32 Void +0xf50 ActivityId : _GUID +0xf60 SubProcessTag : Ptr32 Void +0xf64 EtwLocalData : Ptr32 Void +0xf68 EtwTraceData : Ptr32 Void +0xf6c WinSockData : Ptr32 Void +0xf70 GdiBatchCount : Uint4B +0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER +0xf74 IdealProcessorValue : Uint4B +0xf74 ReservedPad0 : UChar +0xf75 ReservedPad1 : UChar +0xf76 ReservedPad2 : UChar +0xf77 IdealProcessor : UChar +0xf78 GuaranteedStackBytes : Uint4B +0xf7c ReservedForPerf : Ptr32 Void +0xf80 ReservedForOle : Ptr32 Void +0xf84 WaitingOnLoaderLock : Uint4B +0xf88 SavedPriorityState : Ptr32 Void +0xf8c SoftPatchPtr1 : Uint4B +0xf90 ThreadPoolData : Ptr32 Void +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void +0xf98 MuiGeneration : Uint4B +0xf9c IsImpersonating : Uint4B +0xfa0 NlsCache : Ptr32 Void +0xfa4 pShimData : Ptr32 Void +0xfa8 HeapVirtualAffinity : Uint4B +0xfac CurrentTransactionHandle : Ptr32 Void +0xfb0 ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME +0xfb4 FlsData : Ptr32 Void +0xfb8 PreferredLanguages : Ptr32 Void +0xfbc UserPrefLanguages : Ptr32 Void +0xfc0 MergedPrefLanguages : Ptr32 Void +0xfc4 MuiImpersonation : Uint4B +0xfc8 CrossTebFlags : Uint2B +0xfc8 SpareCrossTebBits : Pos 0, 16 Bits +0xfca SameTebFlags : Uint2B +0xfca SafeThunkCall : Pos 0, 1 Bit +0xfca InDebugPrint : Pos 1, 1 Bit +0xfca HasFiberData : Pos 2, 1 Bit +0xfca SkipThreadAttach : Pos 3, 1 Bit +0xfca WerInShipAssertCode : Pos 4, 1 Bit +0xfca RanProcessInit : Pos 5, 1 Bit +0xfca ClonedThread : Pos 6, 1 Bit +0xfca SuppressDebugMsg : Pos 7, 1 Bit +0xfca DisableUserStackWalk : Pos 8, 1 Bit +0xfca RtlExceptionAttached : Pos 9, 1 Bit +0xfca InitialThread : Pos 10, 1 Bit +0xfca SpareSameTebBits : Pos 11, 5 Bits +0xfcc TxnScopeEnterCallback : Ptr32 Void +0xfd0 TxnScopeExitCallback : Ptr32 Void +0xfd4 TxnScopeContext : Ptr32 Void +0xfd8 LockCount : Uint4B +0xfdc SpareUlong0 : Uint4B +0xfe0 ResourceRetValue : Ptr32 Void |
一个完整的 TEB 结构是那么的复杂。TEB 结构第 1 个成员就是 TIB 结构(注意是整个结构)
1.2 TIB 结构
我们可以观察 NT_TIB 结构是怎样的,承接上面我们来看 32 位版本的 TIB 结构:
0:000:x86> dt ntdll32!_NT_TIB +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x004 StackBase : Ptr32 Void +0x008 StackLimit : Ptr32 Void +0x00c SubSystemTib : Ptr32 Void +0x010 FiberData : Ptr32 Void +0x010 Version : Uint4B +0x014 ArbitraryUserPointer : Ptr32 Void +0x018 Self : Ptr32 _NT_TIB |
上面就是 32 位版本的 TIB 结构,然而它的第 1 个成员是个指针,指向另一个结构:_EXCEPTION_REGISTRATION_RECORD,这是 SEH 机制中的最重要的一部分。
而在 WinNT.h 文件中对 NT_TIB 结构的定义如下:
typedef struct _NT_TIB { struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; PVOID StackBase; PVOID StackLimit; PVOID SubSystemTib; #if defined(_MSC_EXTENSIONS) union { PVOID FiberData; DWORD Version; }; #else PVOID FiberData; #endif PVOID ArbitraryUserPointer; struct _NT_TIB *Self; } NT_TIB; typedef NT_TIB *PNT_TIB; |
我们重点关注的是这个结构前面有个指向 _EXCEPTION_REGISTRATION_RECORD 结构的指针,这个结构是用来注册我们的 _except_handler() 即:异常处理程序。
1.3 _EXCEPTION_REGISTRATION_RECORD 结构
最后,我们观察 _EXCEPTION_REGISTRATION_RECORD 结构是怎样的:
0:000:x86> dt _EXCEPTION_REGISTRATION_RECORD MSVCR100D!_EXCEPTION_REGISTRATION_RECORD +0x000 Next : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : Ptr32 _EXCEPTION_DISPOSITION |
这个结构不是定义在 ntdll32 模块里的,而是在 VC++ 的运行时库里(MSVCR100D)里,这是调试版本的运行时库里的结构,当然非调试版本的也是这样的。
这个结构里的 Next 成员是指向另一个 _EXCEPTION_REGISTRATION_RECORD 结构,这样就构成一条链,SEH 机制根据这条链可以查找线程中所有的 exception handler,许多文档中这个成员解为 prev 即:前一个,这里并不矛盾。以当前的 EXCETPTION_REGISTRATION_RECORD 结构为参照,当前的是最顶的一层,那么上一个和下一个意思是一样的。
Handler 成员是指向真正处理的 exception handler,这个 exception handler 可以是我们自己定义的异常处理程序,这个异常处理程序的形式是:
typedef __drv_sameIRQL __drv_functionClass(EXCEPTION_ROUTINE) EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE ( __inout struct _EXCEPTION_RECORD *ExceptionRecord, __in PVOID EstablisherFrame, __inout struct _CONTEXT *ContextRecord, __in PVOID DispatcherContext ); typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; |
在 VC 的 CRT 头文件 except.inc 里找到的定义:
; exception registration record structure. __EXCEPTIONREGISTRATIONRECORD struc prev_structure dd ? ExceptionHandler dd ? ExceptionFilter dd ? FilterFrame dd ? PExceptionInfoPtrs dd ? __EXCEPTIONREGISTRATIONRECORD ends |
每个版本的 VC 可能会不一样,上面是在 visual studio 2010 中得到的。这似乎和在 windbg 中所显示的有所不同,不管怎样我们关注的是前面两个用红色标注的成员。
2. FS 寄存器
在 Windows 中 TEB 由 FS:0 指出,FS:0 是被设定为永远指向线程的 TEB 块,由于 TEB 的前面是 _EXCEPTION_REGISTRATION_RECORD 结构的指针,因此 FS:[0] 可以获得这个指针值。
因此,我们可以使用下面代码来人工调用 exception handler:
mov eax, dword ptr fs:[0] ; get exception_registration_record call dword ptr [eax + 4] ; call exception handler |
这里只是演示系统如何是查找并调用 exception handler,代码中不可能使用人工调方法用来调用 exception handler
于是在几乎所有的构建 SEH 链的示例中,都使用类似的这几行代码:
push exception_handler ; set current exception handler push dword ptr fs:[0] ; set prev TEB mov fs:[0], esp ; set current exception_registration_record |
上一页 目录 下一页
版权 mik 所有,转载请注明出处!