TEB(Thread Environment Block)是线程环境块。而PEB(Process Environment Block)是进程环境块。我们知道在一个进程中有多个线程。因此每一个线程都对应一个线程环境块,而一个进程也对应有一个进程环境块。
TEB在在操作系统中是用一个结构体标识的,以下是我调试Windows10查看的TEB:
这个结构体非常大,我只截取了部分信息。我们只关注两个成员,一个是在偏移0x60处的ProcessEnvironmentBlock成员,一个就是第一个成员NtTib。
ProcessEnvionmentBlock这个成员是指向PEB的。属于同一个进程的线程这个值是一样的,因此比较重要。在x86模式下FS寄存器是指向当前线程的TEB结构体的。而在x64模式下不再使用FS寄存器而是改用GS寄存器,一会我们通过实验来验证这个问题。下面我们用一个程序来试验一下:
#include<windows.h>
#include<stdio.h>
//x86模式
int main() {
HANDLE a;
a = GetProcessHeap();
printf("%p\n", a);
HANDLE ret1;
_asm
{ push eax
mov eax, fs: [00000030h]
mov eax, [eax + 00000018h]
mov ret1, eax
pop eax
}
printf("%p", ret1);
return 0;
}
这是在x86模式下运行的一段程序。输出是这样的:
GetProcessHeap是一个API函数,如果函数成功,则返回值是调用进程的堆的句柄。首先会获取TEB的地址,接着找到TEB偏移18h的位置找到ProcessHeap这个成员的值返回。
由于我调试的是64位的win10,因此我们做下x64的实验,在x64模式下我们跟进GetProcessHeap函数的实现:
我们知道在x64下gs指向的是TEB,在TEB偏移60的位置取得ProcessEnvionmentBlock,也就是PEB的地址。
我们看看win10 x64下的PEB结构体:
这个结构体也很大,我们只截取部分,看到偏移30的位置是ProcessHeap。这个成员就是进程堆的句柄。返回这个成员的值也就是ProcessHeap函数的返回值。通过x86以及x64模式下TEB,PEB的探究,我们大致了解了这两个结构体。也清晰了两个模式下指向他们的寄存器分别是fs,以及gs。