Windows中FS段寄存器 V2
2015-07-21 10:41
696 查看
原文链接:
http://blog.csdn.net/misterliwei/article/details/4391580
Windows 中 FS
段寄存器
V2
[注意:本文是以前文章《Windows中FS段寄存器》的修订版。]
代码运行在
RING0 (系统地址空间)和 RING3(用户地址空间)时,FS
段寄存器分别指向 GDT(
全局描述符表)中不同段:在
RING3 下,
FS 段值是 0x3B
(这是WindowsXP下值;在
Windows2000 下值为
0x38。差别就是在XP
下 RPL=3
);运行在RING0下时,
FS 段寄存器值是
0x30。下面以XP
为例说说。
一. RING3 下的 FS
当代码运行在 Ring3 下时, FS 值为指向的段是 GDT 中的 0x38 段( RPL 为 3 )。该段的长度为 4K ,基地址为 当前线程 的线程环境块( TEB ),所以该段也被称为“ TEB 段”。
WINXPSP1 及以前的 Windows2000 等系统中,进程环境块( PEB )的地址固定为 0X7FFDF000 ,该进程的第一个线程的 TEB 地址为 0X7FFDE000 ,第二个 TEB 的地址为 0X7FFDD000….. 但是自从 WindowsXP SP2 开始 PEB 和 TEB 的地址都是随机映射的 ( 详见博文:MiCreatePebOrTeb函数注释
) 。
下图是 WindowsXP SP3下的TEB
结构 (
大小为 0XFB8):
nt!_TEB
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
+0x004 StackBase : Ptr32
+0x008 StackLimit : Ptr32
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32
+0x018 Self : Ptr32 < ——
+0x01c EnvironmentPointer : Ptr32
+0x020 ClientId : _CLIENT_ID
+0x000 UniqueProcess : Ptr32
+0x004 UniqueThread : Ptr32
+0x028 ActiveRpcHandle : Ptr32
+0x02c ThreadLocalStoragePointer : Ptr32
+0x030 ProcessEnvironmentBlock : Ptr32
< ——
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32
+0x040 Win32ThreadInfo : Ptr32
……
FS:[0x18] 就是TEB所在的地址,FS:[0x30]就是PEB所在的地址。由于每个线程的TEB不尽相同,所以GDT中0x30描述符的基地址会随着线程的切换而改变。我们来看看在什么地方变换的。看XP SP2下的SwapContext的代码(该段代码在博文pjf获得SwapContext地址方法的解析:http://blog.csdn.net/misterliwei/article/details/3575267中曾被引用,来说明如何获取SwapContext地址):
…………
8086dd6c 8b4b40 mov ecx,dword ptr [ebx+40h]
8086dd6f 894104
4000
mov dword ptr [ecx+4],eax
8086dd72 8b6628 mov esp,dword ptr [esi+28h]
8086dd75 8b4620 mov eax,dword ptr [esi+20h]//这两条指令将新线程的TEB 保存在KPRC
8086dd78 894318 mov dword ptr [ebx+18h],eax//的0X18 中
8086dd7b fb sti
8086dd7c 8b4744 mov eax,dword ptr [edi+44h]
8086dd7f 3b4644 cmp eax,dword ptr [esi+44h]
8086dd82 c6475000 mov byte ptr [edi+50h],0
8086dd86 7440 je nt!SwapContext+0xe8 (8086ddc8)
8086dd88 8b7e44 mov edi,dword ptr [esi+44h]
8086dd8b 8b4b48 mov ecx,dword ptr [ebx+48h]
8086dd8e 314834 xor dword ptr [eax+34h],ecx
8086dd91 314f34 xor dword ptr [edi+34h],ecx
8086dd94 66f74720ffff test word ptr [edi+20h],0FFFFh
8086dd9a 7571 jne nt!SwapContext+0x12d (8086de0d)
8086dd9c 33c0 xor eax,eax
8086dd9e 0f00d0 lldt ax
8086dda1 8d8b40050000 lea ecx,[ebx+540h]
8086dda7 e850afffff call nt!KeReleaseQueuedSpinLockFromDpcLevel (80868cfc)
8086ddac 33c0 xor eax,eax
8086ddae 8ee8 mov gs,ax
8086ddb0 8b4718 mov eax,dword ptr [edi+18h]
8086ddb3 8b6b40 mov ebp,dword ptr [ebx+40h]
8086ddb6 8b4f30 mov ecx,dword ptr [edi+30h]
8086ddb9 89451c mov dword ptr [ebp+1Ch],eax
8086ddbc 0f22d8 mov cr3,eax
8086ddbf 66894d66 mov word ptr [ebp+66h],cx
8086ddc3 eb0e jmp nt!SwapContext+0xf3 (8086ddd3)
8086ddc5 8d4900 lea ecx,[ecx]
8086ddc8 8d8b40050000 lea ecx,[ebx+540h]
8086ddce e829afffff call nt!KeReleaseQueuedSpinLockFromDpcLevel (80868cfc)
8086ddd3 8b4318 mov eax,dword ptr [ebx+18h]//这几句就是将新线程的TEB 的地址
8086ddd6 8b4b3c mov ecx,dword ptr [ebx+3Ch]//更新到GDT 的0X38 描述符的基地址
8086ddd9 6689413a mov word ptr [ecx+3Ah],ax //
中去 。
8086dddd c1e810 shr eax,10h //
8086dde0 88413c mov byte ptr [ecx+3Ch],al //
8086dde3 88613f mov byte ptr [ecx+3Fh],ah //
8086dde6 ff464c inc dword ptr [esi+4Ch]
.........
二. RING0 下的 FS
当线程运行在 Ring0
下时, FS
指向的段是GDT中的
0x30 段。该段的长度也为 4K,基地址为0xFFDFF000
(我的 P4
单核 XPSP3 下除了
0FFDFF000外还会有其它值,不是是何原因?)。该地址指向系统的处理器控制区域(KPCR
)。这个区域中保存这处理器相关的一些重要数据值,如GDT
、 IDT
表的值等等(关于通过 KPCR获得系统一些重要变量可看博文Windows XP 内核变量)。下面就是WindowsXP
sp3中的 KPCR
数据结构:
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
+0x004 StackBase : Ptr32
+0x008 StackLimit : Ptr32
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32
+0x018 Self : Ptr32
< ----
+0x01c SelfPcr : Ptr32
< -----
+0x020 Prcb : Ptr32
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32
+0x038 IDT : Ptr32
+0x03c GDT : Ptr32
+0x040 TSS : Ptr32
+0x044 MajorVersion : Uint2B
……………
看两个地址 0x18
和 0x1C 。在
TEB 中 0x18
指向自己,即 TEB 。而KPCR中指向自己的确是
0x1C ;
0x18 却是指向当前线程的TEB
,所以0x18字段名叫做
Self-used 比较确切(
WIN2K源码如此定义)。总之,不管是在RING3
还是 RING0
, FS:[0x18]总是指向当前线程的
TEB 。
三. RING0 与 RING3
之间的变换
RING0 和 RING3 之间的变换通常是发生在系统调用与返回时,关于系统调用,可参看博文
WINDOWS系统调用 和 SYSENTER系统服务调用过程 。
FS 在 RING0 和 RING3 中是不同的值,在 KiFastCallEntry / KiSystemService 中 FS 值由 0x3B 变成 0x30 ;在 KiSystemCallExit / KiSystemCallExitBranch / KiSystemCallExit2 中再将 RING3 的 FS 恢复。
下面来看看 KiSystemService 的开头部分代码 (KiFastCallEntry 也是一样 ) :
nt!KiSystemService:
808696a1 6a00 push 0
808696a3 55 push ebp
808696a4 53 push ebx
808696a5 56 push esi
808696a6 57 push edi
808696a7 0fa0 push fs ;旧的RING3 下的FS 保存入栈
808696a9 bb30000000 mov ebx,30h
808696ae 668ee3 mov fs,bx ;FS=0X30 FS 值变成了0X30.
808696b1 64ff3500000000 push dword ptr fs:[0]
808696b8 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
808696c3 648b3524010000 mov esi,dword ptr fs:[124h] ;ESI=_ETHEAD
808696ca ffb640010000 push dword ptr [esi+140h] ;PreviousMode
808696d0 83ec48 sub esp,
b188
48h ;
808696d3 8b5c246c mov ebx,dword ptr [esp+6Ch] ;
…………
再看看下面的 KiSystemCallExit部分代码:
…………
80869945 8d6550 lea esp,[ebp+50h]
80869948 0fa1 pop fs //恢复 FS 值
8086994a 8d6554 lea esp,[ebp+54h]
8086994d 5f pop edi
8086994e 5e pop esi
8086994f 5b pop ebx
80869950 5d pop ebp
80869951 66817c24088000 cmp word ptr [esp+8],80h
…………
http://blog.csdn.net/misterliwei/article/details/4391580
Windows 中 FS
段寄存器
V2
[注意:本文是以前文章《Windows中FS段寄存器》的修订版。]
代码运行在
RING0 (系统地址空间)和 RING3(用户地址空间)时,FS
段寄存器分别指向 GDT(
全局描述符表)中不同段:在
RING3 下,
FS 段值是 0x3B
(这是WindowsXP下值;在
Windows2000 下值为
0x38。差别就是在XP
下 RPL=3
);运行在RING0下时,
FS 段寄存器值是
0x30。下面以XP
为例说说。
一. RING3 下的 FS
当代码运行在 Ring3 下时, FS 值为指向的段是 GDT 中的 0x38 段( RPL 为 3 )。该段的长度为 4K ,基地址为 当前线程 的线程环境块( TEB ),所以该段也被称为“ TEB 段”。
WINXPSP1 及以前的 Windows2000 等系统中,进程环境块( PEB )的地址固定为 0X7FFDF000 ,该进程的第一个线程的 TEB 地址为 0X7FFDE000 ,第二个 TEB 的地址为 0X7FFDD000….. 但是自从 WindowsXP SP2 开始 PEB 和 TEB 的地址都是随机映射的 ( 详见博文:MiCreatePebOrTeb函数注释
) 。
下图是 WindowsXP SP3下的TEB
结构 (
大小为 0XFB8):
nt!_TEB
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
+0x004 StackBase : Ptr32
+0x008 StackLimit : Ptr32
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32
+0x018 Self : Ptr32 < ——
+0x01c EnvironmentPointer : Ptr32
+0x020 ClientId : _CLIENT_ID
+0x000 UniqueProcess : Ptr32
+0x004 UniqueThread : Ptr32
+0x028 ActiveRpcHandle : Ptr32
+0x02c ThreadLocalStoragePointer : Ptr32
+0x030 ProcessEnvironmentBlock : Ptr32
< ——
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32
+0x040 Win32ThreadInfo : Ptr32
……
FS:[0x18] 就是TEB所在的地址,FS:[0x30]就是PEB所在的地址。由于每个线程的TEB不尽相同,所以GDT中0x30描述符的基地址会随着线程的切换而改变。我们来看看在什么地方变换的。看XP SP2下的SwapContext的代码(该段代码在博文pjf获得SwapContext地址方法的解析:http://blog.csdn.net/misterliwei/article/details/3575267中曾被引用,来说明如何获取SwapContext地址):
…………
8086dd6c 8b4b40 mov ecx,dword ptr [ebx+40h]
8086dd6f 894104
4000
mov dword ptr [ecx+4],eax
8086dd72 8b6628 mov esp,dword ptr [esi+28h]
8086dd75 8b4620 mov eax,dword ptr [esi+20h]//这两条指令将新线程的TEB 保存在KPRC
8086dd78 894318 mov dword ptr [ebx+18h],eax//的0X18 中
8086dd7b fb sti
8086dd7c 8b4744 mov eax,dword ptr [edi+44h]
8086dd7f 3b4644 cmp eax,dword ptr [esi+44h]
8086dd82 c6475000 mov byte ptr [edi+50h],0
8086dd86 7440 je nt!SwapContext+0xe8 (8086ddc8)
8086dd88 8b7e44 mov edi,dword ptr [esi+44h]
8086dd8b 8b4b48 mov ecx,dword ptr [ebx+48h]
8086dd8e 314834 xor dword ptr [eax+34h],ecx
8086dd91 314f34 xor dword ptr [edi+34h],ecx
8086dd94 66f74720ffff test word ptr [edi+20h],0FFFFh
8086dd9a 7571 jne nt!SwapContext+0x12d (8086de0d)
8086dd9c 33c0 xor eax,eax
8086dd9e 0f00d0 lldt ax
8086dda1 8d8b40050000 lea ecx,[ebx+540h]
8086dda7 e850afffff call nt!KeReleaseQueuedSpinLockFromDpcLevel (80868cfc)
8086ddac 33c0 xor eax,eax
8086ddae 8ee8 mov gs,ax
8086ddb0 8b4718 mov eax,dword ptr [edi+18h]
8086ddb3 8b6b40 mov ebp,dword ptr [ebx+40h]
8086ddb6 8b4f30 mov ecx,dword ptr [edi+30h]
8086ddb9 89451c mov dword ptr [ebp+1Ch],eax
8086ddbc 0f22d8 mov cr3,eax
8086ddbf 66894d66 mov word ptr [ebp+66h],cx
8086ddc3 eb0e jmp nt!SwapContext+0xf3 (8086ddd3)
8086ddc5 8d4900 lea ecx,[ecx]
8086ddc8 8d8b40050000 lea ecx,[ebx+540h]
8086ddce e829afffff call nt!KeReleaseQueuedSpinLockFromDpcLevel (80868cfc)
8086ddd3 8b4318 mov eax,dword ptr [ebx+18h]//这几句就是将新线程的TEB 的地址
8086ddd6 8b4b3c mov ecx,dword ptr [ebx+3Ch]//更新到GDT 的0X38 描述符的基地址
8086ddd9 6689413a mov word ptr [ecx+3Ah],ax //
中去 。
8086dddd c1e810 shr eax,10h //
8086dde0 88413c mov byte ptr [ecx+3Ch],al //
8086dde3 88613f mov byte ptr [ecx+3Fh],ah //
8086dde6 ff464c inc dword ptr [esi+4Ch]
.........
二. RING0 下的 FS
当线程运行在 Ring0
下时, FS
指向的段是GDT中的
0x30 段。该段的长度也为 4K,基地址为0xFFDFF000
(我的 P4
单核 XPSP3 下除了
0FFDFF000外还会有其它值,不是是何原因?)。该地址指向系统的处理器控制区域(KPCR
)。这个区域中保存这处理器相关的一些重要数据值,如GDT
、 IDT
表的值等等(关于通过 KPCR获得系统一些重要变量可看博文Windows XP 内核变量)。下面就是WindowsXP
sp3中的 KPCR
数据结构:
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
+0x004 StackBase : Ptr32
+0x008 StackLimit : Ptr32
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32
+0x018 Self : Ptr32
< ----
+0x01c SelfPcr : Ptr32
< -----
+0x020 Prcb : Ptr32
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32
+0x038 IDT : Ptr32
+0x03c GDT : Ptr32
+0x040 TSS : Ptr32
+0x044 MajorVersion : Uint2B
……………
看两个地址 0x18
和 0x1C 。在
TEB 中 0x18
指向自己,即 TEB 。而KPCR中指向自己的确是
0x1C ;
0x18 却是指向当前线程的TEB
,所以0x18字段名叫做
Self-used 比较确切(
WIN2K源码如此定义)。总之,不管是在RING3
还是 RING0
, FS:[0x18]总是指向当前线程的
TEB 。
三. RING0 与 RING3
之间的变换
RING0 和 RING3 之间的变换通常是发生在系统调用与返回时,关于系统调用,可参看博文
WINDOWS系统调用 和 SYSENTER系统服务调用过程 。
FS 在 RING0 和 RING3 中是不同的值,在 KiFastCallEntry / KiSystemService 中 FS 值由 0x3B 变成 0x30 ;在 KiSystemCallExit / KiSystemCallExitBranch / KiSystemCallExit2 中再将 RING3 的 FS 恢复。
下面来看看 KiSystemService 的开头部分代码 (KiFastCallEntry 也是一样 ) :
nt!KiSystemService:
808696a1 6a00 push 0
808696a3 55 push ebp
808696a4 53 push ebx
808696a5 56 push esi
808696a6 57 push edi
808696a7 0fa0 push fs ;旧的RING3 下的FS 保存入栈
808696a9 bb30000000 mov ebx,30h
808696ae 668ee3 mov fs,bx ;FS=0X30 FS 值变成了0X30.
808696b1 64ff3500000000 push dword ptr fs:[0]
808696b8 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
808696c3 648b3524010000 mov esi,dword ptr fs:[124h] ;ESI=_ETHEAD
808696ca ffb640010000 push dword ptr [esi+140h] ;PreviousMode
808696d0 83ec48 sub esp,
b188
48h ;
808696d3 8b5c246c mov ebx,dword ptr [esp+6Ch] ;
…………
再看看下面的 KiSystemCallExit部分代码:
…………
80869945 8d6550 lea esp,[ebp+50h]
80869948 0fa1 pop fs //恢复 FS 值
8086994a 8d6554 lea esp,[ebp+54h]
8086994d 5f pop edi
8086994e 5e pop esi
8086994f 5b pop ebx
80869950 5d pop ebp
80869951 66817c24088000 cmp word ptr [esp+8],80h
…………
相关文章推荐
- C++ 操作符重载
- 反复执行addChild()有问题吗?
- gedit中文文本乱码
- hdu1043 bfs 康拓展开
- [离散化]求区域的个数
- 0.HelloWorld
- 九九乘法表
- java中==和equals
- 响应式布局
- Linux(Ubuntu12.04)安装nginx
- 存储过程参数输入输出
- 颜色代码表#FFFFFF #FF0000 #00FF00 #FF00FF (2015-07-21 10:39)转载
- Win10开发必备工具:Visual Studio 2015正式版下载
- Android 通过反射让SQlite建表如此简单
- 2015GitWebRTC编译实录8
- Android应用程序中应用图标和名字的设置
- 高血压补钾降压该咋吃
- jQuery Ajax学习与运用
- Java小数四舍五入与保留位(二)
- linux的百度网盘客户端