📄 jiurl玩玩win2k进程线程篇 teb.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0066)http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/PsTeb.htm -->
<HTML><HEAD><TITLE>JIURL玩玩Win2k进程线程篇 TEB</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<STYLE type=text/css>.title {
FONT-FAMILY: "黑体", Arial, sans-serif; FONT-SIZE: 21px; FONT-WEIGHT: bold; LINE-HEIGHT: 48px; TEXT-DECORATION: none
}
.author {
FONT-FAMILY: "宋体"; FONT-SIZE: 12px; LINE-HEIGHT: 16px
}
.content {
FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=29 width="96%">
<TBODY>
<TR>
<TD class=title height=41 width="100%">
<P align=center><FONT face=宋体>JIURL玩玩Win2k进程线程篇 </FONT><FONT
face=宋体>TEB</FONT></P></TD></TR></CENTER>
<TR>
<TD class=author height=9 width="100%">
<P align=center><FONT face=宋体>作者: <A
href="mailto:jiurl@mail.china.com">JIURL</A> </FONT></P></TD></TR>
<TR>
<TD class=author height=6 width="100%">
<P align=center><FONT
face=宋体>
主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A>
</FONT></P></TD></TR>
<TR>
<TD class=author height=2 width="100%">
<P align=center><FONT face=宋体> 日期: 2003-7-30</FONT>
</P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=1 width="96%">
<TBODY>
<TR>
<TD height=1 width="100%">
<HR color=#396da5 SIZE=3>
</TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE border=0 cellPadding=0 cellSpacing=0 class=content height=4097
width="96%">
<TBODY>
<TR>
<TD height=1929 vAlign=top width="131%">
<P> TEB,Thread Environment Block,线程环境块。位于用户地址空间。在比 PEB
所在地址低的地方,比如 0x7FFDF000,0x7FFDE000。每个线程都有自己的一个 TEB。由于 TEB
在用户地址空间,所以本进程中运行在用户模式下的代码就可以访问 TEB 结构。Win2k Build 2195 中一个线程的 ETHREAD 结构偏移
+020 处的 *Teb 指向这个线程的 TEB 结构。在 undocumented.ntinternals.net
(需要注意的是这是个非官方的站点)我们可以找到 TEB 及其相关结构的定义。从 kd
中也可以找到一些相关结构的定义。我们首先列出结构的定义,然后对一些内容进行说明。<BR><BR>// 来自
undocumented.ntinternals.net<BR>typedef struct _TEB {<BR>NT_TIB
Tib;<BR>PVOID EnvironmentPointer;<BR>CLIENT_ID Cid;<BR>PVOID
ActiveRpcInfo;<BR>PVOID ThreadLocalStoragePointer;<BR>PPEB Peb;<BR>ULONG
LastErrorValue;<BR>ULONG CountOfOwnedCriticalSections;<BR>PVOID
CsrClientThread;<BR>PVOID Win32ThreadInfo;<BR>ULONG
Win32ClientInfo[0x1F];<BR>PVOID WOW32Reserved;<BR>ULONG
CurrentLocale;<BR>ULONG FpSoftwareStatusRegister;<BR>PVOID
SystemReserved1[0x36];<BR>PVOID Spare1;<BR>ULONG ExceptionCode;<BR>ULONG
SpareBytes1[0x28];<BR>PVOID SystemReserved2[0xA];<BR>ULONG
GdiRgn;<BR>ULONG GdiPen;<BR>ULONG GdiBrush;<BR>CLIENT_ID
RealClientId;<BR>PVOID GdiCachedProcessHandle;<BR>ULONG
GdiClientPID;<BR>ULONG GdiClientTID;<BR>PVOID
GdiThreadLocaleInfo;<BR>PVOID UserReserved[5];<BR>PVOID
GlDispatchTable[0x118];<BR>ULONG GlReserved1[0x1A];<BR>PVOID
GlReserved2;<BR>PVOID GlSectionInfo;<BR>PVOID GlSection;<BR>PVOID
GlTable;<BR>PVOID GlCurrentRC;<BR>PVOID GlContext;<BR>NTSTATUS
LastStatusValue;<BR>UNICODE_STRING StaticUnicodeString;<BR>WCHAR
StaticUnicodeBuffer[0x105];<BR>PVOID DeallocationStack;<BR>PVOID
TlsSlots[0x40];<BR>LIST_ENTRY TlsLinks;<BR>PVOID Vdm;<BR>PVOID
ReservedForNtRpc;<BR>PVOID DbgSsReserved[0x2];<BR>ULONG
HardErrorDisabled;<BR>PVOID Instrumentation[0x10];<BR>PVOID
WinSockData;<BR>ULONG GdiBatchCount;<BR>ULONG Spare2;<BR>ULONG
Spare3;<BR>ULONG Spare4;<BR>PVOID ReservedForOle;<BR>ULONG
WaitingOnLoaderLock;<BR>PVOID StackCommit;<BR>PVOID
StackCommitMax;<BR>PVOID StackReserved;<BR>} TEB, *PTEB;<BR><BR>// 来自
kd<BR>struct _NT_TIB (sizeof=28)<BR>+00 struct
_EXCEPTION_REGISTRATION_RECORD *ExceptionList<BR>+04 void
*StackBase<BR>+08 void *StackLimit<BR>+0c void *SubSystemTib<BR>+10 void
*FiberData<BR>+10 uint32 Version<BR>+14 void *ArbitraryUserPointer<BR>+18
struct _NT_TIB *Self<BR><BR>struct _CLIENT_ID (sizeof=8)<BR>+0 void
*UniqueProcess<BR>+4 void *UniqueThread<BR><BR>struct
_EXCEPTION_REGISTRATION_RECORD (sizeof=8)<BR>+0 struct
_EXCEPTION_REGISTRATION_RECORD *Next<BR>+4 function *Handler<BR><BR>struct
_UNICODE_STRING (sizeof=8)<BR>+0 uint16 Length<BR>+2 uint16
MaximumLength<BR>+4 uint16 *Buffer<BR><BR><B>异常处理链</B><BR><BR>struct
_TEB<BR>struct _NT_TIB (sizeof=28)<BR>+00 struct
_EXCEPTION_REGISTRATION_RECORD
*ExceptionList<BR><BR>指向结构化异常处理(SEH)链的指针。<BR><BR><B>线程用户模式下的堆栈</B><BR><BR>struct
_TEB<BR>struct _NT_TIB (sizeof=28)<BR>+04 void *StackBase<BR>+08 void
*StackLimit<BR><BR>一个线程,有两个自己的堆栈(Stack)。一个是内核模式下的堆栈,一个是用户模式下的堆栈。当线程在内核模式,也就是
ring0 下,执行代码的时候,使用的是内核模式堆栈。当线程在用户模式下,也就是 ring3
下,执行代码的时候,使用的是用户模式堆栈。某些只在内核模式运行的线程没有用户模式堆栈,比如 System
进程(PID为8的进程)的一些线程。<BR><BR>一个线程的用户模式堆栈,位于用户地址空间。线程 TEB 偏移 +04 处的 StackBase
是该线程用户模式堆栈的最高地址,也就是开始地址,堆栈是向下增长的。线程 TEB 偏移 +08 处的 StackLimit
是该线程用户模式堆栈的最低地址(有效部分)。<BR><BR>线程的内核模式堆栈的信息在线程 ETHREAD 结构中。<BR><BR><B>FS
段</B><BR><BR>在系统的许多函数的汇编代码中我们进程可以看到使用 fs 段。对于 x86 来说,分段机制是默认,并且必须使用的。Win2k
使用了平坦(Flat)模型,把段设为整个4G地址空间,隐藏了分段机制。不过 fs
段是一个例外。对于运行在用户模式下,也就是运行在ring3下的程序,fs 段是当前线程的 TEB
所在地址空间。对于运行在内核模式下,也就是运行在ring0下的程序,fs 段是从地址 FFDFF000 开始,大小为 0x2000
的那部分地址空间。<BR><BR>下面我们使用 SoftICE 分别观察在 ring3 执行代码的 FS段 和在 ring0 执行代码的
FS段。<BR><BR>ring3<BR><BR>在ring3执行某一时刻的段寄存器和全局描述符表<BR><BR>:r
-d<BR>CS:EIP=001B:00401919 SS:ESP=0023:0012FE20<BR>EAX=00000001
EBX=7FFDF000 ECX=0012FFB0 EDX=00040000<BR>ESI=0012FE20 EDI=0012FF80
EBP=0012FF80 EFL=00000246<BR>DS=0023 ES=0023 FS=0038 GS=0000<BR><BR>注意 CS
为 1B ,说明 CPL 为 ring3。注意 FS 段选择符。<BR><BR>:gdt<BR>Sel. Type Base Limit DPL
Attributes<BR>GDTbase=80036000 Limit=03FF<BR>0008 Code32 00000000 FFFFFFFF
0 P RE<BR>0010 Data32 00000000 FFFFFFFF 0 P RW<BR>001B Code32 00000000
FFFFFFFF 3 P RE<BR>0023 Data32 00000000 FFFFFFFF 3 P RW<BR>0028 TSS32
801F4000 000020AB 0 P B<BR>0030 Data32 FFDFF000 00001FFF 0 P RW<BR>003B
Data32 7FFDE000 00000FFF 3 P RW<BR>// FS 对应的段描述符,Base=7FFDE000 DPL=3<BR>//
当前的线程的 TEB 就在 7FFDE000 开始处的 4KB 地址空间中。<BR>0043 Data16 00000400 0000FFFF 3
P RW<BR>0048 Reserved 00000000 00000000 0 NP<BR>0050 TSS32 80470040
00000068 0 P<BR>...<BR><BR><BR>ring0 <BR><BR>刚才的ring3程序进行系统调用,产生了 int
2e 中断。当转到中断2e的中断处理程序时,CPU
以及转换了堆栈段,代码段。中断2e的中断处理程序会把原来的fs段选择符压栈,将fs段选择符赋值为30。<BR><BR>这时的段寄存器和全局描述符表<BR><BR><BR>//
注意 CS 和 SS ,CPL 已经是 ring0 了。注意 FS 值为30。<BR>:r -d<BR>CS:EIP=0008:804615DD
SS:ESP=0010:EF0B5DB4<BR>EAX=00000038 EBX=00000030 ECX=80002000
EDX=0012FD9C<BR>ESI=00000000 EDI=0012FF80 EBP=0012FDF8
EFL=00000002<BR>DS=0023 ES=0023 FS=0030 GS=0000<BR><BR>:gdt<BR>Sel. Type
Base Limit DPL Attributes<BR>GDTbase=80036000 Limit=03FF<BR>0008 Code32
00000000 FFFFFFFF 0 P RE<BR>0010 Data32 00000000 FFFFFFFF 0 P RW<BR>001B
Code32 00000000 FFFFFFFF 3 P RE<BR>0023 Data32 00000000 FFFFFFFF 3 P
RW<BR>0028 TSS32 801F4000 000020AB 0 P B<BR>0030 Data32 FFDFF000 00001FFF
0 P RW<BR>// FS 对应的段描述符,Base=FFDFF000 DPL=0<BR>003B Data32 7FFDE000
00000FFF 3 P RW<BR>...<BR><BR>用户模式下的 FS 段是当前线程的 TEB。<BR>内核模式下的 FS 段,是
FFDFF000 开始的8KB(通常只有4KB映射了物理内存)地址空间。它的内容是和当前线程有关的一些信息。其中<BR>偏移+00
处的4个字节是内核模式下 EXCEPTION_REGISTRATION_RECORD *ExceptionList 。<BR>偏移+04
处的4个字节,偏移+08 处的4个字节,是和线程内核堆栈有关的信息。<BR>偏移+124 处的4个字节,是指向当前线程的 ETHREAD
结构的指针。<BR>注意 FFDFF000
开始的这段地址空间中是当前线程的有关信息,对于不同的线程,这段地址空间中的内容也是不一样。<BR><BR>为了方便观察某个进程地址空间中内容,我写了一个叫
<A
href="http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/JiurlProcessMemSee.zip">JiurlProcessMemSee</A>
的程序,可以获得指定进程地址空间中的内容。
<P>欢迎交流,欢迎交朋友,<BR>欢迎访问 <A
href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> <A
href="http://jiurl.cosoft.org.cn/forum">http://jiurl.cosoft.org.cn/forum</A>
<P>
<P><A
href="http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/JiurlProcessMemSee.zip">下载
JiurlProcessMemSee
可执行文件及源程序</A><BR></P></TD></TR></TBODY></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -