首页
社区
课程
招聘
[原创]分享下自己学习TEB和PEB的心得
发表于: 2013-7-21 22:50 43397

[原创]分享下自己学习TEB和PEB的心得

2013-7-21 22:50
43397
前几天在找资料的时候发现一些有趣的东西,是线程的TEB和进程的PEB结构,在好奇心下,稍微学习了下,从而得到了一种获取当前进程名的方法。先把代码贴上来。
#include "windows.h"
#include "stdio.h"
int main(void)
{
LPSTR name;
__asm{
mov eax,fs:[0x18]
mov eax,[eax+0x30]
mov eax,[eax+0xc]
mov eax,[eax+0xc]
mov eax,[eax+0x30]
mov name,eax
}
wprintf(L"%s\n",name);
return 0;
}
这段测试代码就能获取当前进程的名字。
现在稍微说下上面这段汇编代码是什么意思。
TEB:
即Thread Environment Block ,它记录的相关线程的信息,每一个线程都有自己的TEB,每个TEB都有自己的TIB(Thread Information Block),即线程信息块。
FS:[0x18]是什么呢?
用OD,随便打开一个程序,然后在寄存器中可以看到

在Command中,输入 dd 7FFDF000就可以看到:
7FFDF000  0012FFC4  (指向 SEH 链指针)
7FFDF004  00130000  (线程堆栈顶部)
7FFDF008  0012E000  (线程堆栈底部)
7FFDF00C  00000000
7FFDF010  00001E00
7FFDF014  00000000
7FFDF018  7FFDF000
7FFDF01C  00000000
7FFDF020  000025DC
7FFDF024  00001750  (线程 ID)
7FFDF028  00000000
7FFDF02C  7FFDF02C  (指向线程局部存储指针)
7FFDF030  7FFDE000
7FFDF034  00000000  (上个错误 = ERROR_SUCCESS)
对比以下资料可以对比看到,FS:[0x18]即为指向TEB自身
TEB包含了若干指针,各偏移说明如下:
FS:[000]   指向SEH链指针
FS:[004]  线程堆栈顶部
FS:[008] 线程堆栈底部
FS:[00C]  SubSystemTib
FS:[010]  FiberData
FS:[014] ArbitraryUserPointer
FS:[018]  指向TEB自身
FS:[020] 进程PID
FS:[024] 线程ID
FS:[02C] 指向线程局部存储指针
FS:[030] PEB结构地址(进程结构)
FS:[034] 上个错误号
在windbg下看到TEB结构:
kd> dt 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
所以FS:[0x18]指向TEB本身,[eax+0x30]就是PEB所在地址。
接下来看PEB结构:
typedef struct _PEB {               // Size: 0x1D8
    000h    UCHAR           InheritedAddressSpace;
    001h    UCHAR           ReadImageFileExecOptions;
    002h    UCHAR           BeingDebugged;              //Debug运行标志
    003h    UCHAR           SpareBool;
    004h    HANDLE          Mutant;
    008h    HINSTANCE       ImageBaseAddress;           //程序加载的基地址
    00Ch    struct _PEB_LDR_DATA    *Ldr                //Ptr32 _PEB_LDR_DATA
    010h    struct _RTL_USER_PROCESS_PARAMETERS  *ProcessParameters;
    014h    ULONG           SubSystemData;
    018h    HANDLE          DefaultHeap;
    01Ch    KSPIN_LOCK      FastPebLock;
    020h    ULONG           FastPebLockRoutine;
    024h    ULONG           FastPebUnlockRoutine;
    028h    ULONG           EnvironmentUpdateCount;
    02Ch    ULONG           KernelCallbackTable;
    030h    LARGE_INTEGER   SystemReserved;
    038h    struct _PEB_FREE_BLOCK  *FreeList
    03Ch    ULONG           TlsExpansionCounter;
    040h    ULONG           TlsBitmap;
    044h    LARGE_INTEGER   TlsBitmapBits;
    04Ch    ULONG           ReadOnlySharedMemoryBase;
    050h    ULONG           ReadOnlySharedMemoryHeap;
    054h    ULONG           ReadOnlyStaticServerData;
    058h    ULONG           AnsiCodePageData;
    05Ch    ULONG           OemCodePageData;
    060h    ULONG           UnicodeCaseTableData;
    064h    ULONG           NumberOfProcessors;
    068h    LARGE_INTEGER   NtGlobalFlag;               // Address of a local copy
    070h    LARGE_INTEGER   CriticalSectionTimeout;
    078h    ULONG           HeapSegmentReserve;
    07Ch    ULONG           HeapSegmentCommit;
    080h    ULONG           HeapDeCommitTotalFreeThreshold;
    084h    ULONG           HeapDeCommitFreeBlockThreshold;
    088h    ULONG           NumberOfHeaps;
    08Ch    ULONG           MaximumNumberOfHeaps;
    090h    ULONG           ProcessHeaps;
    094h    ULONG           GdiSharedHandleTable;
    098h    ULONG           ProcessStarterHelper;
    09Ch    ULONG           GdiDCAttributeList;
    0A0h    KSPIN_LOCK      LoaderLock;
    0A4h    ULONG           OSMajorVersion;
    0A8h    ULONG           OSMinorVersion;
    0ACh    USHORT          OSBuildNumber;
    0AEh    USHORT          OSCSDVersion;
    0B0h    ULONG           OSPlatformId;
    0B4h    ULONG           ImageSubsystem;
    0B8h    ULONG           ImageSubsystemMajorVersion;
    0BCh    ULONG           ImageSubsystemMinorVersion;
    0C0h    ULONG           ImageProcessAffinityMask;
    0C4h    ULONG           GdiHandleBuffer[0x22];
    14Ch    ULONG           PostProcessInitRoutine;
    150h    ULONG           TlsExpansionBitmap;
    154h    UCHAR           TlsExpansionBitmapBits[0x80];
    1D4h    ULONG           SessionId;
} PEB, *PPEB;

所以接下来,eax+0xc里面就是指向_PEB_LDR_DATA的指针。[eax+0xc]就是_PEB_LDR_DATA的地址。再往下看

typedef struct _PEB_LDR_DATA
{
 ULONG         Length;                             // 00h
 BOOLEAN       Initialized;                        // 04h
 PVOID         SsHandle;                           // 08h
 LIST_ENTRY    InLoadOrderModuleList;              // 0ch
 LIST_ENTRY    InMemoryOrderModuleList;            // 14h
 LIST_ENTRY    InInitializationOrderModuleList;    // 1ch
}
    PEB_LDR_DATA,
    *PPEB_LDR_DATA;                                 // 24h

[eax+0xc](第二个[eax+0xc])存储的就是InLoadOrderModuleList的地址。那 LIST_ENTRY InLoadOrderModuleList是个什么东西呢?
nt!_LIST_ENTRY
   +0x000   Flink       : Ptr32 _LIST_ENTRY     //表示从前往后
   +0x004   Blink       : Ptr32 _LIST_ENTRY     //表示从后往前
LIST_ENTRY InLoadOrderModuleList指向一个LDR_MODULE结构,InMemoryOrderModuleList和InInitializationOrderModuleList也同样指向这样一个结构,只不过不是同一成员。
nt!_LDR_DATA_TABLE_ENTRY
  +0x000 InLoadOrderLinks : _LIST_ENTRY
  +0x008 InMemoryOrderLinks : _LIST_ENTRY
  +0x010 InInitializationOrderLinks : _LIST_ENTRY
  +0x018 DllBase          : Ptr32 Void
  +0x01c EntryPoint      : Ptr32 Void
  +0x020 SizeOfImage      : Uint4B
  +0x024 FullDllName      : _UNICODE_STRING
  +0x02c BaseDllName      : _UNICODE_STRING
  +0x034 Flags            : Uint4B
  +0x038 LoadCount        : Uint2B
  +0x03a TlsIndex        : Uint2B
  +0x03c HashLinks        : _LIST_ENTRY
  +0x03c SectionPointer  : Ptr32 Void
  +0x040 CheckSum        : Uint4B
  +0x044 TimeDateStamp    : Uint4B
  +0x044 LoadedImports    : Ptr32 Void
  +0x048 EntryPointActivationContext : Ptr32 Void
  +0x04c PatchInformation : Ptr32 Void
再VC++6.0中,以debug模式运行,在 mov eax,fs:[0x18]

mov eax,[eax+0x30]
mov eax,[eax+0xc]
mov eax,[eax+0xc]
结束后,可以看到 eax中值为十进制的6234696,对应16进制的00x5f2248,这个地址就是LDR_DATA_TABLE_ENTRY的首地址了。

可以看到,从005F2248地址开始:
+0x000 InLoadOrderLinks : _LIST_ENTRY                    //005F22D8,7784788c(双向链表指针)
  +0x008 InMemoryOrderLinks : _LIST_ENTRY             //005f22e0,77847894 (双向链表指针)
  +0x010 InInitializationOrderLinks : _LIST_ENTRY   //00000000,00000000 (双向链表指针)
  +0x018 DllBase          : Ptr32 Void   //00400000
  +0x01c EntryPoint      : Ptr32 Void   //00401260
  +0x020 SizeOfImage      : Uint4B   //0002A000,对应10进制就是172032大小,点开文件,  右键属性,可以看到编译好的文件占用空间大小  恰好为168KB(172032字节)
  +0x024 FullDllName      : _UNICODE_STRING   //006C006A,005F2020
  +0x02c BaseDllName      : _UNICODE_STRING   //001E001A,005F206e
  +0x034 Flags            : Uint4B  //00004000
  +0x038 LoadCount        : Uint2B  //FFFF
  +0x03a TlsIndex        : Uint2B  //0000
  +0x03c HashLinks        : _LIST_ENTRY  //7784A600
  +0x03c SectionPointer  : Ptr32 Void  //7784A600
  +0x040 CheckSum        : Uint4B  //7784A600
  +0x044 TimeDateStamp    : Uint4B  //51EB862F
  +0x044 LoadedImports    : Ptr32 Void  //51EB862F
  +0x048 EntryPointActivationContext : Ptr32 Void      //00000000
  +0x04c PatchInformation : Ptr32 Void  //00000000

接下来,只要mov eax,[eax+0x28]就能够得到完整路径名字。
在控制台上能够输出  D:\VC6++CN\MyProjects\findmyname\Debug\findmyname.exe
只要mov eax,[eax+0x30]就能够得到进程本身名字。
在控制台上能够输出  findmyname.exe
有个疑问就是为什么不是 mov eax,[eax+0x24]而是mov eax,[eax+0x28],
为什么不是mov eax,[eax+0x2c]而是mov eax,[eax+0x30]?
因为内存中看到 0x006C006A和0x001E001A的内存区域内容全为“????”,貌似都没有初始化。
我的猜测就是由于自己所用的机器是32位的,所以取的地址是后8个byte的,而64位机器应该就是+0x24和+0x2c,这些都是猜测,也不知道是否正确,或者说自己的计算机操作系统是win7的,真正的原因不是特别清楚。期待高人解答!
-----------------分割线-----------------
自己遗留的问题,经人点播,终于弄清楚了。
+0x024 FullDllName      : _UNICODE_STRING   //006C006A,005F2020
  +0x02c BaseDllName      : _UNICODE_STRING   //001E001A,005F206e
_UNICODE_STRING也是一个结构,大意了。
typedef struct _UNICODE_STRING {
  USHORT  Length;     //UNICODE占用的内存字节数,个数*2;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING ,*PUNICODE_STRING;

所以006C006A中存放的1C 00 1E 00指的是 字符串占用的字节数1C=28,1E=30字节,在内存中得到印证,1C是不包括终止符的长度,1E是总长度,包括终止符长度。
ok问题完美解决,开心!

以上就是小菜鸟的心得体会,希望能对大家的学习带来点灵感。

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (32)
雪    币: 112
活跃值: (57)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
2
你将外链图片换成Pediy的附件好么?
2013-7-21 23:23
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
撸主辛苦了。。。图片还回来吧
2013-7-22 00:04
0
雪    币: 166
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
啥意思,图片以附件的形式传上来吗?
2013-7-22 00:37
0
雪    币: 112
活跃值: (57)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
5
http://bbs.pediy.com/showpost.php?postid=292659
2013-7-22 02:23
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
你的文章在不错,可惜图片都没片啊,您那里是看不到么。反正就是贴的图片挂了
2013-7-22 09:27
0
雪    币: 1042
活跃值: (470)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
图片不能外链~ 直接上传到论坛里,再贴出来
2013-7-22 09:44
0
雪    币: 114
活跃值: (180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好详细,谢谢分享。
2013-7-22 11:48
0
雪    币: 166
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
已经弄好了哦
2013-7-22 12:43
0
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
豁然开让。。。。。。。。。。。
2013-7-22 13:45
0
雪    币: 340
活跃值: (51)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
11
我是来找茬的,嘿嘿

#include <stdio.h>
#include <conio.h>
#include <windows.h>

int main(void)//LZ这里打错了吧,你打成"vodi"
{
	LPSTR name;
	__asm
	{
		mov eax,fs:[0x18]
		mov eax,[eax+0x30]
		mov eax,[eax+0xc]
		mov eax,[eax+0xc]
		mov eax,[eax+0x30]
		mov name,eax
	}
	wprintf(L"%s\n",name);
	return 0;
}
2013-7-22 19:08
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
哈哈,支持楼主啊。
2013-7-22 19:34
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
那个,发现TEB里边似乎不包含有线程的状态信息啊,比如状态是挂起,还是执行等。
+0x040 Win32ThreadInfo  : Ptr32 Void 不知这个里边有包含没啊。
撸主,这个是您的下一个研究课题哦
2013-7-22 19:45
0
雪    币: 400
活跃值: (632)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
不错...........
2013-7-22 21:03
0
雪    币: 166
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
哇咔咔,好的,试着学习,哈哈,别称呼您了,我只是个后知后觉的小菜鸟。。
2013-7-22 22:42
0
雪    币: 166
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
嘿嘿,已经更正了。。这就是菜鸟常犯错误啊。。
2013-7-22 22:44
0
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
支持原创
2013-7-23 21:51
0
雪    币: 9560
活跃值: (2391)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
mark一下
2013-7-23 22:39
0
雪    币: 1501
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
我也是来找茬的~
LIST_ENTRY InLoadOrderModuleList指向一个LDR_MODULE结构,InMemoryOrderModuleList和InInitializationOrderModuleList也同样指向这样一个结构。

他们指向的是同一个结构中不同的部分,加上这句,不容易误导读者~
2013-7-25 10:18
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
几天没来了。看看楼主。。。
2013-7-26 08:20
0
雪    币: 341
活跃值: (85)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
21
中文say goodbye
2013-7-26 11:49
0
雪    币: 166
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
哈,是的
2013-7-26 11:59
0
雪    币: 65
活跃值: (545)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
#include "stdio.h"
#include <locale.h>
#include "windows.h"

int main(void)
{
        setlocale(LC_ALL, "chs" );     //
        LPWSTR name;
        __asm
        {
                mov eax,fs:[0x18]
                mov eax,[eax+0x30]
                mov eax,[eax+0x0c]
                mov eax,[eax+0x0c]
                mov eax,[eax+0x30]     ;mov eax,[eax+0x28]
                mov name,eax
        }
        wprintf(L"%s\n",name);
        return 0;
}
2013-7-26 16:25
0
雪    币: 5
活跃值: (56)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
感谢分享..学习了...
2013-7-26 16:32
0
雪    币: 170
活跃值: (187)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
前来学习一下TEB
2013-7-26 22:42
0
游客
登录 | 注册 方可回帖
返回
//