从TEB到PEB再到SEH(一)
什么是TEB?
TEB(Thread Environment Block,线程环境块)
线程环境块中存放着进程中所有线程的各种信息
这里我们了解到了TEB即为线程环境块, 进程中每一条线程都对应着的自己的“TEB”。
TEB的访问方法
ntdll.NtCurrentTeb() 函数用来返回当前线程的TEB结构体指针
从图中我们可以看到NtCurrentTeb() 函数所返回的结构体指针即为 fs:[0x18] 的值,里面的值即为TEB的结构体指针,对比数据窗口即可发现
了解TEB的结构
因为TEB的结构MSDN中没有明确的说明,这里我们利用windbg和符号文件查看它的数据结构:
Windows XP SP3
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
 | 
nt!_TEB   +0x000 NtTib            : _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 | 
这里我们详细的介绍常用的结构体成员及作用:
- +0x000 NtTib            : _NT_TIB
TEB的结构体的第一个成员NtTib即为我们常说的TIB(Thread Information Block,线程信息块)typedef struct _NT_TIB //sizeof 1ch
{
00h struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; //即为指向_EXCEPTION_REGISTRATION_RECORD结构体的链表指针(SEH)
04h PVOID StackBase;//这里为线程堆栈顶部
08h PVOID StackLimit;//这里为线程堆栈底部
0ch PVOID SubSystemTib;
union {
PVOID FiberData;
10h DWORD Version;
};
14h PVOID ArbitraryUserPointer;
18h struct _NT_TIB *Self; //这为_NT_TIB结构体的自引用指针,即为NtCurrentTeb() 函数所读出的TEB结构体指针
}NT_TIB; - +0x020 ClientId         : _CLIENT_ID
这个结构体成员挺有趣的,我们用windbg查询下结构:

UniqueProcess:这个为当前进程的的Pid,可用函数 GetCurrentProcessId() 访问当前结构体成员获取进程标识符:
 
可以看到TEB+0x20即为 UniqueProcess 的成员变量。UniqueThread:
这个为当前进程的的Tid,可用函数 GetCurrentThreadId() 访问当前结构体成员获取线程标识符:
可以看到TEB+0x20即为 UniqueThread 的成员变量。
- +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
这个即为PEB结构体的指针,所以说一般 fs:[0x30] 即为PEB的起始地址。 
什么是PEB?
PEB( Process Envirorment Block ,进程环境块),PEB是存放着进程信息的结构体,线程TEB结构体中,每个TEB+0x30(fs:[0x30])中都指向同一个地址(TEB.ProcessEnvironmentBlock),我们可以用fs:[0x30]来访问PEB的结构体地址

PEB的数据结构
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
 | 
nt!_PEB   +0x000 InheritedAddressSpace : UChar   +0x001 ReadImageFileExecOptions : UChar   +0x002 BeingDebugged    : UChar   +0x003 SpareBool        : UChar   +0x004 Mutant           : Ptr32 Void   +0x008 ImageBaseAddress : Ptr32 Void   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS   +0x014 SubSystemData    : Ptr32 Void   +0x018 ProcessHeap      : Ptr32 Void   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION   +0x020 FastPebLockRoutine : Ptr32 Void   +0x024 FastPebUnlockRoutine : Ptr32 Void   +0x028 EnvironmentUpdateCount : Uint4B   +0x02c KernelCallbackTable : Ptr32 Void   +0x030 SystemReserved   : [1] Uint4B   +0x034 AtlThunkSListPtr32 : Uint4B   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK   +0x03c TlsExpansionCounter : Uint4B   +0x040 TlsBitmap        : Ptr32 Void   +0x044 TlsBitmapBits    : [2] Uint4B   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void   +0x058 AnsiCodePageData : Ptr32 Void   +0x05c OemCodePageData  : Ptr32 Void   +0x060 UnicodeCaseTableData : Ptr32 Void   +0x064 NumberOfProcessors : Uint4B   +0x068 NtGlobalFlag     : Uint4B   +0x070 CriticalSectionTimeout : _LARGE_INTEGER   +0x078 HeapSegmentReserve : Uint4B   +0x07c HeapSegmentCommit : Uint4B   +0x080 HeapDeCommitTotalFreeThreshold : Uint4B   +0x084 HeapDeCommitFreeBlockThreshold : Uint4B   +0x088 NumberOfHeaps    : Uint4B   +0x08c MaximumNumberOfHeaps : Uint4B   +0x090 ProcessHeaps     : Ptr32 Ptr32 Void   +0x094 GdiSharedHandleTable : Ptr32 Void   +0x098 ProcessStarterHelper : Ptr32 Void   +0x09c GdiDCAttributeList : Uint4B   +0x0a0 LoaderLock       : Ptr32 Void   +0x0a4 OSMajorVersion   : Uint4B   +0x0a8 OSMinorVersion   : Uint4B   +0x0ac OSBuildNumber    : Uint2B   +0x0ae OSCSDVersion     : Uint2B   +0x0b0 OSPlatformId     : Uint4B   +0x0b4 ImageSubsystem   : Uint4B   +0x0b8 ImageSubsystemMajorVersion : Uint4B   +0x0bc ImageSubsystemMinorVersion : Uint4B   +0x0c0 ImageProcessAffinityMask : Uint4B   +0x0c4 GdiHandleBuffer  : [34] Uint4B   +0x14c PostProcessInitRoutine : Ptr32     void    +0x150 TlsExpansionBitmap : Ptr32 Void   +0x154 TlsExpansionBitmapBits : [32] Uint4B   +0x1d4 SessionId        : Uint4B   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER   +0x1e8 pShimData        : Ptr32 Void   +0x1ec AppCompatInfo    : Ptr32 Void   +0x1f0 CSDVersion       : _UNICODE_STRING   +0x1f8 ActivationContextData : Ptr32 Void   +0x1fc ProcessAssemblyStorageMap : Ptr32 Void   +0x200 SystemDefaultActivationContextData : Ptr32 Void   +0x204 SystemAssemblyStorageMap : Ptr32 Void   +0x208 MinimumStackCommit : Uint4B | 
下面我来举例几个常用的结构体成员:
- +0x002 BeingDebugged : UChar
这个结构体成员大家应该都懂,表示当前进程是否处于调试状态,也就是函数 IsDebuggerPresent() 所访问的结构体成员. 
这里我看可以看到先是取出PEB的结构体地址,在取出PEB.BeingDebugged 结构体成员然后返回,因为我们这里有海风月影大牛的SOD插件所以我们不必担心,包括下面的几个结构体成员都一起处理掉的。
- +0x008 ImageBaseAddress : Ptr32 Void
这个结构体成员我们也经常用到,也就是自身的 ImageBase ,和PE结构中的 IMAGE_OPTIONAL_HEADER.ImageBase 。 
可用函 GetModuleHandle (0) 获取自身模块句柄来访问这个结构体成员:
这里判断参数是否为0,也就是取自身的模块句柄 (ImaheBase)这里也同上,先是取出PEB结构体地址,再取出 ImageBaseAddress 。
- +0x00c Ldr : Ptr32 _PEB_LDR_DATA
这个结构体成员就很复杂了,它是指向 _PEB_LDR_DATA 的结构体指针,当DLL加载到进程,可从 PEB.Ldr 中获取该模块的基址和其他信息: 
 12345678910ntdll!_PEB_LDR_DATA+0x000Length//结构体大小+0x004Initialized//进程是否初始化完成+0x008SsHandle+0x00cInLoadOrderModuleList : _LIST_ENTRY+0x014InMemoryOrderModuleList : _LIST_ENTRY+0x01cInInitializationOrderModuleList : _LIST_ENTRY+0x024EntryInProgress+0x028ShutdownInProgress+0x02cShutdownThreadIdInLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList 这三个结构体成员都是指向LIST_ENTRY
的结构体指针,我们查询下这个数据结构:可以看出这是一个双向链表,链表中存放着 _LDR_DATA_TABLE_ENTRY 的结构体信息:
每个进程中的DLL加载进来都有与之对于的_LDR_DATA_TABLE_ENTRY 结构体,这些结构相互链接就形成了双向链表
- +0x018 ProcessHeap      : Ptr32 Void
这个结构体成员就是进程堆的句柄,也就是指向结构体HEAP的指针,我们查询下结构体成员:
 
程序正常运行时,ProcessHeap.Flags的值为2 ,ProcessHeap.
ForceFlags 的值为0,也常用于反调试。
ProcessHeap结构体成员指向的HEAP结构体指针可用函数 GetProcessHeap()获取:
- +0x068 NtGlobalFlag : Uint4B
再调试状态时,PEB.NtGlobalFlag 的值为0x70 ,这个值我也不清楚 只记得几个Flages的值进行 OR(位或) 的结果 
转自https://bbs.pediy.com/thread-223816.htm
从TEB到PEB再到SEH(一)的更多相关文章
- 从TEB到PEB再到SEH(二)
		
什么是SEH? SEH( Structured Exception Handling , 结构化异常处理 ) 结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能.而Visual C ...
 - 旧书重温:0day2【3】 详细解读PEB法 查找kener32地址
		
题外话:上一篇文章中的 PEB法查找kerner32地址的方法 对TEB.PEB .PE结构 知识要求很高,确实在写汇编代码时候小编 感觉自己能力,信手啪啪一顿乱撸,结果一运行,非法访问了,没办法翻阅 ...
 - KPROCESS IDT PEB Ldr 《寒江独钓》内核学习笔记(3)
		
继续上一篇(2)未完成的研究,我们接下来学习 KPROCESS这个数据结构. 1. 相关阅读材料 <深入理解计算机系统(原书第2版)> 二. KPROCESS KPROCESS,也叫内核进 ...
 - 【旧文章搬运】获取并修改PEB中的映像路径,命令行和当前目录
		
原文发表于百度空间,2008-7-24 当时对UNICODE_STRING的使用还有点问题,导致最终效果图中字符串被截断了======================================= ...
 - 栈溢出笔记1.9 认识SEH
		
从本节開始,我们就要研究一些略微高级点的话题了,如同在1.2节中看到的,Windows中为抵抗栈溢出做了非常多保护性的检查工作,编译的程序默认开启了这些保护. 假设我们不能绕过这些保护.那么我们的Sh ...
 - windows的SEH异常处理以及顶层异常处理
		
前言 windows的SEH结构化异常处理是基于线程的,传统的SEH结构化异常会基于堆栈形成一条包含异常回调函数地址的链(SEH链).而fs:[0](TEB的第一个字段)指向这条链的链头,当有异常发生 ...
 - 第23章 SEH结构化异常处理(3)_终止处理程序
		
23.3 终止处理程序 23.3.1 程序的结构 (1)框架 __try{ //被保护的代码块 …… } __finally{ //终止处理 } (2)__try/__finally的特点 ①fina ...
 - 结构化异常SEH处理机制详细介绍(二)
		
本文将全面阐述__try,__except,__finally,__leave异常模型机制,它也即是Windows系列操作系统平台上提供的SEH模型.SEH实际包含两个主要功能:结束处理(termin ...
 - OD: Memory Attach Technology - Exception
		
看到第六章了:形形色色的内存攻击技术 异常处理结构体 S.E.H Structure Exception Handler S.E.H 是 Windows 处理异常的重要数据结构.每个 S.E.H 为 ...
 
随机推荐
- t100 常用公用變數
			
g_enterprise 目前的企業代碼,將限制使用者所能閱讀的資料內容g_prog 目前執行的作業編號,用於變換畫面顯示資料與產生系統資訊,不可變更g_code 目前執行的程式代碼(4gl)名稱,不 ...
 - HttpClient参观记:.net core 2.2 对HttpClient到底做了神马
			
.net core 于 10月17日发布了 ASP.NET Core 2.2.0 -preview3,在这个版本中,我看到了一个很让我惊喜的新特性:HTTP Client Performance Im ...
 - Python进阶----进程间数据隔离, join阻塞等待, 进程属性, 僵尸进程和孤儿进程, 守护进程
			
Python进阶----进程间数据隔离, join阻塞等待, 进程属性, 僵尸进程和孤儿进程, 守护进程 一丶获取进程以及父进程的pid 含义: 进程在内存中开启多个,操作系统如何区分这些进程, ...
 - 科普帖:Linux操作系统
			
使用计算机必然会接触操作系统,现代操作系统已经发展的十分成熟,一般用户都可以很轻松的使用计算机.然而,对于要利用计算机进行专业开发和应用的用户来说,需要更加深入地理解操作系统的原理和运行机制,这样才能 ...
 - 2019-07-23 php魔术方法
			
本文对一些php中的魔术方法进行总结,魔术方法顾名思义就是具备神奇功能的方法(function).魔术方法通常在某些特定情况下自动触发,不能用实例化变量名->方法名()来主动触发.不同的魔术方法 ...
 - 拓展 - Webrtc 的回声抵消(aec、aecm)算法简介
			
webrtc 的回声抵消(aec.aecm)算法简介 原文链接:丢失.不好意思 webrtc 的回声抵消(aec.aecm)算法主要包括以下几个重要模块:1.回声时延估计 2.NLMS( ...
 - CentOS 7 - 以root身份登入Gnome
			
新版的7.0很多资料没有,为了安全,linux是禁止root登录到桌面,但为了方便又想用root登录到桌面,在网上找了找,基本上都是这这一篇: http://shaoguangleo.blog.163 ...
 - 一分钟告诉你什么是OPC DA质量代码
			
[关于TOP Server OPC Server试用版可登录慧都网该产品下载页进行下载] OPC DA(OPC实时数据访问规范)定义了包括数据值,更新时间与数据品质信息的相关标准.这个定义相信大家都很 ...
 - TF-IDF词频逆文档频率算法
			
一.简介 1.RF-IDF[term frequency-inverse document frequency]是一种用于检索与探究的常用加权技术. 2.TF-IDF是一种统计方法,用于评估一个词对于 ...
 - golang版本管理工具GO111MODULE
			
在go1.11版本前,想要对go语言包进行管理,只能依赖第三方库实现,比如Vendor,GoVendor,GoDep,Dep,Glide等等. 1. 开启GO111MODULE 用环境变量 GO111 ...
 
			
		








