线程运行在 RING0 (系统地址空间)和 RING3 (用户地址空间)时, FS 段寄存器分别指向不同内存段的。线程运行在 RING0 下, FS 段值是 0x30 ( WindowsXP 下值,在 Windows2000 下值为 0x38 );运行在 RING3 下时, FS 段寄存器值是 0x3b 。 FS 寄存器值的改变是在程序从 Ring3 进入 Ring0 后和从 Ring0 退回到 Ring3 前完成的,也就是说:都是在 Ring0 下给 FS 赋不同值的。
一. 在 RING3 下运行时的 FS
当线程运行在 Ring3 下时, FS 指向的段是 GDT 中的 0x3B 段。该段的长度为 4K ,基地址为当前线程的线程环境块( TEB ),所以该段也被称为“ TEB 段”。因为 Windows 中线程是不停切换的,所以该段的基地址值将随线程切换而改变的。
Windows2000 中进程环境块( PEB )的地址为 0X7FFDF000 ,该进程的第一个线程的 TEB 地址为 0X7FFDE000 ,第二个 TEB 的地址为 0X7FFDD000….. 但是在 WindowsXP SP2 下这些结构的地址都是随机映射的。所以进程的 PEB 的地址只能通过 FS:[0x30] 来获取了。
Windows 中每个线程都有一个 ETHREAD 结构,该结构的 TEB 成员(其实是 KTHREAD 中的成员,而 KTHREAD 又是 ETHREAD 的成员)是用来保存线程的 TEB 地址的,当线程切换时, Windows 就会用该值来更改 GDT 的 0x3B 段描述符的基地址值。
下面就是 WindowsXP SP2 在 RING3 下 FS 段寄存器所指向的数据结构和地址。
_TIB
+0x000 NtTib : _NT_TIB
_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 |
+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 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1 : [24] UChar
+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] Uint2B
+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 HardErrorsAreDisabled : Uint4B
+0xf2c Instrumentation : [16] Ptr32 Void
+0xf6c WinSockData : Ptr32 Void
+0xf70 GdiBatchCount : Uint4B
+0xf74 InDbgPrint : UChar
+0xf75 FreeStackOnTermination : UChar
+0xf76 HasFiberData : UChar
+0xf77 IdealProcessor : UChar
+0xf78 Spare3 : Uint4B
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
+0xf88 Wx86Thread : _Wx86ThreadState
+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
+0xf98 ImpersonationLocale : 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 SafeThunkCall : UChar
+0xfb5 BooleanSpare : [3] Uchar
二. 在 RING0 下运行时的 FS
当线程运行在 Ring0 下时, FS 指向的段是 GDT 中的 0x30 段。该段的长度也为 4K ,基地址为 0xFFDFF000 。该地址指向系统的处理器控制区域( KPCR )。这个区域中保存这处理器相关的一些重要数据值,如 GDT 、 IDT 表的值等等。下面就是 WindowsXP sp2 中的 KPCR 数据结构:
_KPCR
+0x000 NtTib : _NT_TIB
_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 |
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32 Void
+0x038 IDT : Ptr32 _KIDTENTRY
+0x03c GDT : Ptr32 _KGDTENTRY
+0x040 TSS : Ptr32 _KTSS
+0x044 MajorVersion : Uint2B
+0x046 MinorVersion : Uint2B
+0x048 SetMember : Uint4B
+0x04c StallScaleFactor : Uint4B
+0x050 DebugActive : UChar
+0x051 Number : UChar
+0x052 Spare0 : UChar
+0x053 SecondLevelCacheAssociativity : UChar
+0x054 VdmAlert : Uint4B
+0x058 KernelReserved : [14] Uint4B
+0x090 SecondLevelCacheSize : Uint4B
+0x094 HalReserved : [16] Uint4B
+0x0d4 InterruptMode : Uint4B
+0x0d8 Spare1 : UChar
+0x0dc KernelReserved2 : [17] Uint4B
+0x120 PrcbData : _KPRCB
在 WindowsXP 中,许多操作系统的系统变量地址值保存在以 KPCR 开始的数据结构中(可以参看下图)。注意,这是在 WindowsXP 下,而在 WIN2000 下是没有这中情况。有兴趣的读者可以看一下 www.rootkit.com 下的相关文章。