从TEB到PEB再到SEH(一)
本帖最后由 Aperodry 于 2018-1-10 18:59 编辑下面我们开始初步了解和认识TEB,如有错误还请各位指正!什么是TEB
TEB(Thread Environment Block,线程环境块)
线程环境块中存放着进程中所有线程的各种信息
这里我们了解到了TEB即为线程环境块, 进程中每一条线程都对应着的自己的“TEB”。
TEB的访问方法:
ntdll.NtCurrentTeb() 函数用来返回当前线程的TEB结构体指针
从图中我们可以看到NtCurrentTeb() 函数所返回的结构体指针即为 fs: 的值,里面的值即为TEB的结构体指针,对比数据窗口即可发现fs:的值即为TEB的起始地址。
上面简单的介绍了什么是TEB和获取方式,下面正式开始了解TEB的结构:
因为TEB的结构MSDN中没有明确的说明,这里我们利用windbg和符号文件查看它的数据结构:
因为每个OS中TEB的形态稍微不同(我们常用到的每一个结构体成员大致都没变化),所以我们在这里所用到的环境为: 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 : Uint4B
+0x0ac UserReserved : Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1: Ptr32 Void
+0x1a4 ExceptionCode : Int4B
+0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1 : 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: Uint4B
+0x7c4 glDispatchTable: Ptr32 Void
+0xb68 glReserved1 : 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 : Uint2B
+0xe0c DeallocationStack : Ptr32 Void
+0xe10 TlsSlots : Ptr32 Void
+0xf10 TlsLinks : _LIST_ENTRY
+0xf18 Vdm : Ptr32 Void
+0xf1c ReservedForNtRpc : Ptr32 Void
+0xf20 DbgSsReserved : Ptr32 Void
+0xf28 HardErrorsAreDisabled : Uint4B
+0xf2c Instrumentation: 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 : 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 //sizeof1ch
{
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: 即为PEB的起始地址。
什么是PEB?
PEB( Process Envirorment Block ,进程环境块)
PEB是存放着进程信息的结构体
https://msdn.microsoft.com/en-us/library/aa813706.aspx
线程TEB结构体中,每个TEB+0x30(fs:)中都指向同一个地址(TEB.ProcessEnvironmentBlock)So。我们可以用fs:来访问PEB的结构体地址
这里我们可以看到 = = fs:,而EP中 EBX寄存器默认为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 : Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : 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: Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : 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”之间的关系,也是这些日子来对我所学的知识的整理。
Sorry,刚才编辑错了,如有错误请管理指出!
写的很详细,两篇文章一起,这篇加精华鼓励,期待楼主更多分享。 本帖最后由 amonsonic 于 2018-7-6 11:13 编辑
我纠正一下错误
补充
Self:这为_NT_TIB结构体的自引用指针,即为NtCurrentTeb() 函数所读出的TEB结构体指针
self是tib自身引用指针而用。索然说它是teb指针也没有问题(因为teb指针第一个成员就是tib, 所以说teb=tib指针)
错误:
可以看到TEB+0x20即为 UniqueThread 的成员变量。
错了,应该是teb+0x24才是threadid VEH不讲讲吗? bester 发表于 2018-1-7 21:39
VEH不讲讲吗?
VEH我觉得没什么可讲的 ,后面讲SEH ,VEH没什么必要 好厉害!!!!!!! 图看不了。 2013年 发表于 2018-1-7 22:37
图看不了。
图片重新上传了,现在看得见嘛 ? Aperodry 发表于 2018-1-7 22:53
图片重新上传了,现在看得见嘛 ?
图片现在可以看到了,多谢楼主~ 标记一下 回头看看 可以看出这是一个双向链表,链表中存放着 _LDR_DATA_TABLE_ENTRY 的结构体信息:
我觉得你这句写的还不够好, 按照MSDN解释
可以看出这是一个双向链表指向进程装载的模块,结构中的每个指针,指向了一个LDR_DATA_TABLE_ENTRY我觉得这样比较好 收藏先。。。。