8.1 TEB与PEB概述

teb,peb,概述 · 浏览次数 : 24

小编点评

**PEB (进程环境块):** - 存储进程状态信息,包括代码段指针、数据段指针、进程启动参数等。 - 通常在创建进程时分配给每个线程一个PEB。 - PEB结构体中的FS段寄存器通常指向当前进程的PEB结构体。 **TEB (线程环境块):** - 存储线程状态信息,包括堆栈指针、TLS指针、异常处理链表指针等。 - 通常在创建线程时分配给每个进程一个TEB。 - TEB结构体中的FS段寄存器通常指向当前线程的TEB结构体。 **获取进程ID和线程ID的方法:** - 通过访问PEB结构体中的FS段寄存器,可以找到TEB结构体的位置。 - 通过添加0x20到该位置,可以得到PEB的位置。 - 通过添加0x004到PEB的位置,可以得到线程的ID。

正文

在开始使用TEB/PEB获取进程或线程ID之前,我想有必要解释一下这两个名词,PEB指的是进程环境块(Process Environment Block),用于存储进程状态信息和进程所需的各种数据。每个进程都有一个对应的PEB结构体。TEB指的是线程环境块(Thread Environment Block),用于存储线程状态信息和线程所需的各种数据。每个线程同样都有一个对应的TEB结构体。

PEB中包含了进程的代码、数据段指针、进程的环境变量、进程启动参数信息以及加载的dll信息等。PEB结构体中的FS段寄存器通常被设置为0x30,指向当前进程的PEB结构体。其他进程可以通过访问自己的PEB结构体来获取自己的状态和信息。

TEB中包含了线程的堆栈指针、TLS(线程本地存储)指针、异常处理链表指针、用户模式分页表指针等信息。TEB中的FS段寄存器通常被设置为fs:[0],指向当前线程的TEB结构体。其他线程可以通过访问自己的TEB结构体来获取自己的状态和信息。

在创建进程时,操作系统会为每个线程分配一个TEB(线程环境块),并且该环境块中FS段寄存器总是被设置为fs:[0]的位置上,也就是默认指向当前线程的TEB数据。因此,在进行代码分析时,可以通过通配符来找到TEB结构体的具体名称。

接着我们可通过dt -rv ntdll!_TEB命令,查询ntdll!_TEB结构,如下图所示,我们可以看到偏移为+0x018的位置就是TEB结构头指针,在该地址基础上向下偏移0x30就可以得到PEB(进程环境块)的基地址。

其中+0x000的位置指向了NT_TIB结构,+0x018指向NT_TIB结构TEB自身,+0x020+0x000指向的是当前进程的PID,+0x020+0x004则指向父进程的PPID,+0x030指向了PEB结构体,其他字段读者可自行查阅官方文档;

接着再来验证一下,首先偏移地址0x18是TEB结构基地址,也就是指向自身偏移fs:[0x18]的位置,而!teb地址加0x30正是PEB的位置,在teb的基础上加上0x30就可以得到PEB的基地址,拿到PEB基地址就可以干很多事了。

在线程环境块内,fs:[0x18]定位到TEB(线程环境块),加上0x20得到ClientId,此处存储的就是进程与线程ID的结构位置,通过+0x000可得到UniqueProcess也就是进程PID,通过+0x004可得到UniqueThread也就是线程TID,读者可输入如下所示的命令自行验证;

0:000> dd fs:[0x18]                                  # 找到TEB基地址
0053:00000018  0081e000 00000000 0000139c 0000194c
0053:00000028  00000000 0081e02c 0081b000 00000000

0:000> dt _teb 0081e000 
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : (null) 
   +0x020 ClientId         : _CLIENT_ID              # 将TEB+0x20定位到这里(进程与线程信息)
   +0x028 ActiveRpcHandle  : (null) 

0:004> dt _CLIENT_ID 0081e000                        # 查看进程详细结构
ntdll!_CLIENT_ID
   +0x000 UniqueProcess    : 0x00b3f774 Void         # 获取进程PID
   +0x004 UniqueThread     : 0x00b40000 Void         # 获取线程TID

有了上述分析结果那么读者可以很容易的获取到当前自身进程的PID以及TID信息,其完整代码片段如下所示,当读者向GetSelfID()传入1则表示读取PID,否则则读取TID信息;

#include <stdio.h>
#include <Windows.h>

// 传入1获取PID传入0获取TID
DWORD GetSelfID(DWORD isPid)
{
    DWORD ref = 0;

    if (isPid == 1)
    {
        __asm
        {
            mov eax, fs:[0x18]    // 获取到PEB基地址
            add eax, 0x20         // 加上20得到 _CLIENT_ID
            add eax, 0x0          // 加上偏移0得到 UniqueProcess
            mov eax, [eax]        // 取出内存地址中的值
            mov ref, eax
        }
    }
    else
    {
        __asm
        {
            mov eax, fs:[0x18]   // 获取到PEB基地址
            add eax, 0x20        // 加上20得到 _CLIENT_ID
            add eax, 0x04        // 加上偏移04得到 UniqueThread
            mov eax, [eax]       // 取出内存地址中的值
            mov ref, eax
        }
    }
    return ref;
}

int main(int argc, char* argv[])
{
    printf("进程 Pid = %d \n", GetSelfID(1));
    printf("线程 Tid = %d \n", GetSelfID(0));

    system("pause");
    return 0;
}

读者可运行上述代码,并自行打开任务管理器验证是否可以正确获取到,此处执行效果图如下所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/f60a0f6f.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与8.1 TEB与PEB概述相似的内容:

8.1 TEB与PEB概述

在开始使用`TEB/PEB`获取进程或线程ID之前,我想有必要解释一下这两个名词,PEB指的是进程环境块`(Process Environment Block)`,用于存储进程状态信息和进程所需的各种数据。每个进程都有一个对应的`PEB`结构体。TEB指的是线程环境块`(Thread Environment Block)`,用于存储线程状态信息和线程所需的各种数据。每个线程同样都有一个对应的`TE

8.1 C++ STL 变易拷贝算法

C++ STL中的变易算法(Modifying Algorithms)是指那些能够修改容器内容的算法,主要用于修改容器中的数据,例如插入、删除、替换等操作。这些算法同样定义在头文件 algorithm中,它们允许在容器之间进行元素的复制、拷贝、移动等操作,从而可以方便地对容器进行修改和重组。

算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP

网络最大流算法 EK, Dinic, ISAP 详解

.NET周刊【8月第1期 2023-08-06】

## 国内文章 ### NativeBuferring,一种零分配的数据类型(上篇) https://www.cnblogs.com/artech/p/17586781.html 之前一个项目涉及到针对海量(千万级)实时变化数据的计算,由于对性能要求非常高,我们不得不将参与计算的数据存放到内存中,并

[转帖]老外惊呼: 世界变化快! PostgreSQL 14 on ARM 8.1 加上LSE patch性能飙升到140万tps

https://www.modb.pro/db/91515 PostgreSQL , arm , lse , 14 背景 老外惊呼: 世界变化快! ARM 8.1 defines a set of LSE instructions, which, in particular, provide the

Raid0创建

实验步骤 步骤1: 确认硬盘 确认你的硬盘设备名。 [root@servera ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 20G 0 disk ├─sda1 8:1 0 300M 0 part /boot ├─sda2 8

[转帖]Django系列3-Django常用命令

文章目录 一. Django常用命令概述二. Django常用命令实例2.1 help命令2.2 version2.3 check2.4 startproject2.5 startapp2.6 runserver2.7 shell2.8 migrations2.8.1 makemigrations2

虚拟机磁盘扩容(parted、lvm)

1、虚拟化平台虚拟机添加硬盘 系统查看添加的硬盘 [root@yumserver ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 50G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:

ElasticSearch必知必会-进阶篇

京东物流:康睿 姚再毅 李振 刘斌 王北永 说明:以下全部均基于elasticsearch8.1 版本 一.跨集群检索 - ccr 官网文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/modules-cross-cl

初步动态规划讲解:数字三角形

题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的样例中,从 7 → 3 → 8 → 7 → 5 7 \to 3 \to 8 \