SEH 机制探索1 --- TEB 结构

SEH 机制探索1 --- TEB 结构


在 windows 中的 SEHStructured Exception Handling)结构化异常处理需要使用 TIBThread Information Block)线程信息块的 _EXCEPTION_REGISTRATION_RECORD结构。而 TIB 结构包括在 TEBThread Environment Block) 结构下,下面来探索下 TEB 结构。


1. TEB 结构

实际上关于 TIBThread Information Block)和 TEBThread 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 所有,转载请注明出处!

### 回答1: libgcc_s_seh-1.dll 是一个由 GNU Compiler Collection (GCC) 生成的 C 语言运行时库。它提供了 C 语言程序所需的基本运行时函数,如内存分配、字符串处理等。该文件在程序运行时需要被加载。 ### 回答2: libgcc_s_seh-1.dll是Windows操作系统中的一个系统文件,是GCC(GNU编译器集合)编译器链中使用的共享库文件之一。GCC编译器集合是一种常用的编译器集合,它可以用于开发C、C++以及其它语言的编译器,包括Fortran、Java、Objective-C等等。在Windows操作系统中,如果在安装某些应用程序时缺少libgcc_s_seh-1.dll文件,就会导致应用程序无法运行。 libgcc_s_seh-1.dll文件的作用是提供一些运行时库函数,为GCC所编译出的程序提供支持。这个dll文件是GCC编译器链中的一个共享库,是用来管理C++异常机制的库,在Windows情况下,这个库是很重要的。 在Windows操作系统中,如果某些软件需要使用libgcc_s_seh-1.dll文件,那么你需要通过下载该文件,并将其放置在正确的目录中才能使该软件正常工作。要注意的是,应该从可信的来源下载libgcc_s_seh-1.dll文件,因为恶意软件可能会伪装成libgcc_s_seh-1.dll文件,也可能会通过该文件中的漏洞攻击你的计算机。 总的来说,libgcc_s_seh-1.dll在Windows操作系统中扮演着重要的角色,提供了对GCC编译的程序的支持,如果出现缺失或错误,就需要采取适当的措施来解决问题,以保证计算机可以正常工作。 ### 回答3: libgcc_s_seh-1.dll是一个非常重要的DLL文件,它是GCC运行时库中的一个核心文件。GCC是GNU编译器套件的缩写,是一套自由软件编译器集合,用于编译C、C++、Objective-C等各种编程语言。而运行时库则是GCC编译后生成的可执行文件所需要的动态链接库,libgcc_s_seh-1.dll就是其中一个。 libgcc_s_seh-1.dll主要提供了一些函数和接口,用于实现程序运行时的支持,例如异常处理、禁用字节对齐操作等等。如果缺少了这个DLL文件,程序就无法正常运行,很可能会报错提示找不到这个文件。因此,libgcc_s_seh-1.dll可以说是GCC编译的可执行文件的必备文件。 一般情况下,我们并不需要手动安装或更新libgcc_s_seh-1.dll,因为它会随着GCC编译器的安装而自动安装到系统目录下。但是,如果在使用某个程序时出现了缺少libgcc_s_seh-1.dll的错误提示,我们可以尝试以下几种解决办法: 1. 重新安装程序:有时候,程序安装不完整或文件损坏也会导致libgcc_s_seh-1.dll缺失的错误。在这种情况下,可以尝试重新安装软件,让系统自动把文件安装好。 2. 手动下载:如果重新安装软件并没有起到作用,我们可以尝试手动下载libgcc_s_seh-1.dll文件,并将其放入程序安装目录下或者Windows系统目录下。可以从互联网上一些DLL文件下载网站下载相关文件。 3. 更新GCC编译器:如果你是开发者或有一定的编程经验,当你发现程序需要的libgcc_s_seh-1.dll已经非常旧了,可能无法满足新开发的需求,那么可以考虑更新GCC编译器来更新该文件。 总之,libgcc_s_seh-1.dll是GCC编译器运行时库中一个非常重要的文件,它能够提供程序运行时的支持。如果程序提示该文件错误,可以尝试重新安装程序、手动下载、更新GCC编译器等方法解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值