首页
社区
课程
招聘
[原创]从TEB到PEB再到SEH(一)
2018-1-6 23:04 16467

[原创]从TEB到PEB再到SEH(一)

2018-1-6 23:04
16467

下面我们开始初步了解和认识TEB,如有错误还请各位指正!

什么是TEB

TEB(Thread Environment Block,线程环境块)

线程环境块中存放着进程中所有线程的各种信息

这里我们了解到了TEB即为线程环境块, 进程中每一条线程都对应着的自己的“TEB”。


TEB的访问方法:

ntdll.NtCurrentTeb() 函数用来返回当前线程的TEB结构体指针


从图中我们可以看到NtCurrentTeb() 函数所返回的结构体指针即为 fs:[0x18] 的值,里面的值即为TEB的结构体指针,对比数据窗口即可发现

fs:[0]的值即为TEB的起始地址。

上面简单的介绍了什么是TEB和获取方式,下面正式开始了解TEB的结构:

因为TEB的结构MSDN中没有明确的说明,这里我们利用windbg和符号文件查看它的数据结构:
因为每个OSTEB的形态稍微不同(我们常用到的每一个结构体成员大致都没变化),所以我们在这里所用到的环境为: Windows XP SP3 
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

这里我们详细的介绍常用的结构体成员及作用:

1.

+0x000 NtTib            : _NT_TIB

TEB的结构体的第一个成员NtTib即为我们常说的TIB

TIB(Thread Information Block,线程信息块)

https://en.wikipedia.org/wiki/Win32_Thread_Information_Block#Contents_of_the_TIB_(32-bit_Windows)

typedef struct _NT_TIB          //sizeof  1ch  
{  
 00h   struct _EXCEPTION_REGISTRATION_RECORD  *ExceptionList; 
 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;  

  • ExceptionList:即为指向_EXCEPTION_REGISTRATION_RECORD结构体的链表指针(SEH)
  • StackBase:这里为线程堆栈顶部
  • StackLimit :这里为线程堆栈底部
  • Self:这为_NT_TIB结构体的自引用指针,即为NtCurrentTeb() 函数所读出的TEB结构体指针

2.

+0x020 ClientId         : _CLIENT_ID

这个结构体成员挺有趣的,我们用windbg查询下结构:


  • UniqueProcess:这个为当前进程的的Pid,可用函数 GetCurrentProcessId() 访问当前结构体成员获取进程标识符:


可以看到TEB+0x20即为 UniqueProcess 的成员变量。

  • UniqueThread: 这个为当前进程的的Tid,可用函数 GetCurrentThreadId() 访问当前结构体成员获取线程标识符:

可以看到TEB+0x20即为 UniqueThread 的成员变量。

3.

+0x030 ProcessEnvironmentBlock : Ptr32 _PEB

这个即为PEB结构体的指针,所以说一般 fs:[0x30] 即为PEB的起始地址。

什么是PEB?

PEB( Process Envirorment Block ,进程环境块)

PEB是存放着进程信息的结构体

https://msdn.microsoft.com/en-us/library/aa813706.aspx

线程TEB结构体中,每个TEB+0x30(fs:[0x30])中都指向同一个地址(TEB.ProcessEnvironmentBlock

So。我们可以用fs:[0x30]来访问PEB的结构体地址


这里我们可以看到 [TEB.ProcessEnvironmentBlock] = =   fs:[0x30],而EPEBX寄存器默认为PEB的结构体地址

下面我们用windbg查看下PEB的数据结构:

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

下面我来举例几个常用的结构体成员,有些在Anti Deugging中都有应用:


  • +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 中获取该模块的基址和其他信息:
ntdll!_PEB_LDR_DATA  
   +0x000 Length            //结构体大小 
   +0x004 Initialized      //进程是否初始化完成
   +0x008 SsHandle 
   +0x00c InLoadOrderModuleList : _LIST_ENTRY
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY  
   +0x024 EntryInProgress
   +0x028 ShutdownInProgress
   +0x02c ShutdownThreadId

InLoadOrderModuleList、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(位或) 的结果
     

问:网上不是有很多“TEB.PEB.SEH”的这类文章和资料吗?为什么还要“重复发帖”?

答:这些知识也许很老,很多东西前辈们都是介绍过的,但是我看了很多帖子,前辈们对于这种简单的东西都是一笔带过,只提到

了“TEB.PEB.SEH”等字样,我发的这几篇帖子只是更为全面的介绍“TEB.PEB.SEH”之间的关系,也是这些日子来对我所学的知识的整理。



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞5
打赏
分享
最新回复 (19)
雪    币: 5
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx_会飞的鱼 2018-1-7 13:32
2
1
不错    不错    谢谢    大佬      能带我一起学内核编程么?
雪    币: 775
活跃值: (2292)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
AperOdry 2018-1-7 16:04
3
0
对于  Ldr  的知识与拓展太多了,有时间我开一个帖子详细为大家介绍及xxoo
雪    币: 775
活跃值: (2292)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
AperOdry 2018-1-7 20:50
4
0
wx_会飞的鱼 不错 不错 谢谢 大佬 能带我一起学内核编程么?
内核的话我也是菜鸡呀,倒是师傅可以带带我
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
聖blue 2018-1-7 22:15
5
0
不错!
雪    币: 9
活跃值: (115)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
yber 2018-1-8 21:15
6
0
谢谢分享!
雪    币: 688
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
maomaolk 2018-2-20 11:25
7
0
Mark
雪    币: 688
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
maomaolk 2018-4-2 16:53
8
0
Mark
雪    币: 12144
活跃值: (2652)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rongge 2018-4-2 19:13
9
0
我想知道windbg可以获得类或结构的成员类型和名字?
雪    币: 688
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
maomaolk 2018-4-2 20:25
10
0
有符号库的,  可以在网上搜下。  symbol
雪    币: 775
活跃值: (2292)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
AperOdry 2018-4-2 21:41
11
0
楼上正解
雪    币: 9
活跃值: (115)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
yber 2018-5-9 23:54
12
0
感谢仔细解答
雪    币: 1115
活跃值: (1921)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Oday小斯 2018-5-10 02:10
13
0
很早就学了,但没像你这样仔细总结过,腻害
雪    币: 183
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
丶EchoTo 2018-5-15 21:28
14
0
不错不错,又让我加深了对它们的印象
雪    币: 1164
活跃值: (1162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cmputer 2019-2-13 09:35
15
0
纠个错
“这里判断参数是否为0,也就是取自身的模块句柄 (ImaheBase)”-----ImageBase那里书写错误一个字母啦
雪    币: 13450
活跃值: (1185)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
严启真 2019-2-14 08:51
16
0
感谢楼主分享这么好的东西,受益匪浅…
雪    币: 3676
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
老牜lyh 2019-2-14 13:09
17
0
谢谢师傅,分享好知识,收益匪浅
雪    币: 131
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
unfixedBug 2019-2-14 18:18
18
0
非常感谢扫盲贴
雪    币:
活跃值: (68)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
mb_zmejeric 2021-10-6 15:52
19
0
为啥和Windows官方给的结构不一样啊……多出来好多。
雪    币: 47
活跃值: (356)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xuha 2023-4-26 21:35
20
0
最近开始学习驱动和内核相关知识,内核中的好多结构看起来很复杂呀
游客
登录 | 注册 方可回帖
返回