JIURL玩玩Win2k进程线程篇 PEB
作者: JIURL
日期: 2003-7-30
PEB,Process Environment Block ,进程环境块。位于用户地址空间。在地址 0x7FFDF000 处。所以用户进程可以直接访问自己的 PEB 结构。Win2k Build 2195 中进程的 EPROCESS 结构偏移+1b0 处的 *Peb 也指向 PEB 结构。在 undocumented.ntinternals.net (需要注意的是这是个非官方的站点)我们可以找到 PEB 及其相关结构的定义。我们首先列出结构的定义,然后对一些内容进行说明。
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN Spare;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA LoaderData;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PPEBLOCKROUTINE FastPebLockRoutine;
PPEBLOCKROUTINE FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PPVOID KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PPVOID ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PPVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubSystem;
ULONG ImageSubSystemMajorVersion;
ULONG ImageSubSystemMinorVersion;
ULONG GdiHandleBuffer[0x22];
ULONG PostProcessInitRoutine;
ULONG TlsExpansionBitmap;
BYTE TlsExpansionBitmapBits[0x80];
ULONG SessionId;
} PEB, *PPEB;
typedef void (*PPEBLOCKROUTINE)(PVOID PebLock);
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StdInputHandle;
HANDLE StdOutputHandle;
HANDLE StdErrorHandle;
UNICODE_STRING CurrentDirectoryPath;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingPositionLeft;
ULONG StartingPositionTop;
ULONG Width;
ULONG Height;
ULONG CharWidth;
ULONG CharHeight;
ULONG ConsoleTextAttributes;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopName;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _RTL_DRIVE_LETTER_CURDIR {
USHORT Flags;
USHORT Length;
ULONG TimeStamp;
UNICODE_STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef struct _PEB_FREE_BLOCK {
_PEB_FREE_BLOCK *Next;
ULONG Size;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
我写了一个叫 JiurlPebSee 的程序来分析指定进程的 PEB。下面我结合 JiurlPebSee 的输出来对 PEB 及其相关结构的一些内容进行说明。
ProcessId(Decimal): 516
Explorer.exe:
PEB at 0x7ffdf000
LoaderData: 0x00071e90
ProcessParameters: 0x00020000
ProcessHeap: 0x00070000
NumberOfHeaps: 11
MaximumNumberOfHeaps: 16
*ProcessHeaps: 0x77fce380
7ffdf000: 00000000 ffffffff 00400000 00071e90
7ffdf010: 00020000 00000000 00070000 77fcd170
7ffdf020: 77f8aa4c 77f8aa7d 00000001 77e14380
7ffdf030: 00000000 00000000 00000000 00000000
7ffdf040: 77fcd1a8 03cfffff 00000000 7f6f0000
7ffdf050: 7f6f0000 7f6f0688 7ffa0000 7ffa0000
7ffdf060: 7ffd1000 00000001 00000000 00000000
7ffdf070: 079b8000 ffffe86d 00100000 00002000
7ffdf080: 00010000 00001000 0000000b 00000010
7ffdf090: 77fce380 00350000 00000000 00000014
7ffdf0a0: 77fcd348 00000005 00000000 00000893
7ffdf0b0: 00000002 00000002 00000004 00000000
7ffdf0c0: 00000000 00000000 00000002 00000000
7ffdf0d0: 00000004 00000000 b51003ba 391001e4
7ffdf0e0: 00000000 00000000 00000000 00000000
7ffdf0f0: 00000000 00000000 00000000 00000000
7ffdf100: 00000000 00000000 00000000 00000000
7ffdf110: 00000000 00000000 00000000 00000000
7ffdf120: 8204019c 7004019b cf04019e a104019d
7ffdf130: 00000000 00000000 00000000 00000000
7ffdf140: 00000000 00000000 00000000 00000000
7ffdf150: 77fcdcc0 00000000 00000000 00000000
7ffdf160: 00000000 00000000 00000000 00000000
7ffdf170: 00000000 00000000 00000000 00000000
7ffdf180: 00000000 00000000 00000000 00000000
7ffdf190: 00000000 00000000 00000000 00000000
7ffdf1a0: 00000000 00000000 00000000 00000000
7ffdf1b0: 00000000 00000000 00000000 00000000
7ffdf1c0: 00000000 00000000 00000000 00000000
7ffdf1d0: 00000000 00000000 00000000 00020000
7ffdf1e0: 7f6f06c2 00000000 00000000 00000000
7ffdf1f0: 00000000 00000000 00000000 00000000
7ffdf200: 00000000 00000000 00000000 00000000
...
我们以进程 Explorer.exe 进行分析。
LoaderData 是指向 PEB_LDR_DATA 的指针,通过 PEB_LDR_DATA ,我们可以找到进程载入的所有模组。
ProcessParameters 是指向 RTL_USER_PROCESS_PARAMETERS 的指针,RTL_USER_PROCESS_PARAMETERS 中是一些进程的参数。
进程通常有多个用户堆。ProcessHeap 是进程堆(默认的那个)的首地址。NumberOfHeaps 是当前进程的堆的个数。MaximumNumberOfHeaps 是进程的堆的最大个数。*ProcessHeaps 是一个堆指针数组的首地址,每个数组元素长4个字节,是一个堆的指针。
LoaderData at 0x00071e90
Length: 36 Bytes
Initialized: 1
SsHandle: 0x00000000
InLoadOrderModuleList
Flink: 0x00071ec0 Blink: 0x000a0508
InMemoryOrderModuleList
Flink: 0x00071ec8 Blink: 0x000a0510
InInitializationOrderModuleList
Flink: 0x00071f48 Blink: 0x000a0518
Module at 0x00071ec0
FullDllName: D:\WINNT\Explorer.exe
BaseDllName: Explorer.exe
BaseAddress: 0x00400000
SizeOfImage: 0x0003c000
Module at 0x00071f38
FullDllName: D:\WINNT\System32\ntdll.dll
BaseDllName: ntdll.dll
BaseAddress: 0x77f80000
SizeOfImage: 0x00079000
Module at 0x00072470
FullDllName: D:\WINNT\system32\ADVAPI32.DLL
BaseDllName: ADVAPI32.DLL
BaseAddress: 0x77d90000
SizeOfImage: 0x0005a000
...
从PEB可以找到 PEB_LDR_DATA ,PEB_LDR_DATA 中有三个双向循环链表的表头,分别是 InLoadOrderModuleList,InMemoryOrderModuleList,InInitializationOrderModuleList。
每个链表项都是一个 LDR_MODULE 结构。
ProcessParameters at 0x00020000
MaximumLength: 0x00001000
Length: 0x00000838
...
Environment at 0x00010000
00010000: 004c0041 0055004c 00450053 00530052 A.L.L.U.S.E.R.S.
00010010: 00520050 0046004f 004c0049 003d0045 P.R.O.F.I.L.E.=.
00010020: 003a0049 0044005c 0063006f 006d0075 I.:.\.D.o.c.u.m.
00010030: 006e0065 00730074 00610020 0064006e e.n.t.s. .a.n.d.
00010040: 00530020 00740065 00690074 0067006e .S.e.t.t.i.n.g.
...
00010340: 00640075 00000065 0069006c 003d0062 u.d.e...l.i.b.=.
00010350: 003a0047 004d005c 00630069 006f0072 G.:.\.M.i.c.r.o.
00010360: 006f0073 00740066 00560020 00730069 s.o.f.t. .V.i.s.
00010370: 00610075 0020006c 00740053 00640075 u.a.l. .S.t.u.d.
...
00010a70: 005c0031 00650054 0070006d 00540000 1.\.T.e.m.p...T.
...
00010b80: 003a0044 0057005c 004e0049 0054004e D.:.\.W.I.N.N.T.
00010b90: 00000000 00000000 00000000 00000000 ................
...
00010ff0: 00000000 00000000 00000000 00000000 ................
RTL_USER_PROCESS_PARAMETERS 中的 PVOID Environment; 指明了环境变量的地址。
从结构定义中就可以看出 是象 StdInputHandle,ImagePathName 这样的参数。
ProcessHeaps at 0x77fce380
ProcessHeaps[0]: 0x00070000
ProcessHeaps[1]: 0x00170000
ProcessHeaps[2]: 0x008c0000
ProcessHeaps[3]: 0x00cd0000
ProcessHeaps[4]: 0x00ed0000
ProcessHeaps[5]: 0x00f10000
ProcessHeaps[6]: 0x01290000
ProcessHeaps[7]: 0x013e0000
ProcessHeaps[8]: 0x01ce0000
ProcessHeaps[9]: 0x01f50000
ProcessHeaps[10]: 0x03bf0000
77fce380: 00070000 00170000 008c0000 00cd0000
77fce390: 00ed0000 00f10000 01290000 013e0000
77fce3a0: 01ce0000 01f50000 03bf0000 00000000
77fce3b0: 00000000 00000000 00000000 00000000
从 ProcessHeaps 数组,我们可以找到进程的每一个堆。
为了方便观察某个进程地址空间中内容,我写了一个叫 JiurlProcessMemSee 的程序,可以获得指定进程地址空间中的内容。
使用 KD(内核调试器) 我们也可以找到 PEB 及其相关结构的定义。
kd> !strct PEB
!strct PEB
struct _PEB (sizeof=488)
+000 byte InheritedAddressSpace
+001 byte ReadImageFileExecOptions
+002 byte BeingDebugged
+003 byte SpareBool
+004 void *Mutant
+008 void *ImageBaseAddress
+00c struct _PEB_LDR_DATA *Ldr
+010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters
+014 void *SubSystemData
+018 void *ProcessHeap
+01c void *FastPebLock
+020 void *FastPebLockRoutine
+024 void *FastPebUnlockRoutine
+028 uint32 EnvironmentUpdateCount
+02c void *KernelCallbackTable
+030 uint32 SystemReserved[2]
+038 struct _PEB_FREE_BLOCK *FreeList
+03c uint32 TlsExpansionCounter
+040 void *TlsBitmap
+044 uint32 TlsBitmapBits[2]
+04c void *ReadOnlySharedMemoryBase
+050 void *ReadOnlySharedMemoryHeap
+054 void **ReadOnlyStaticServerData
+058 void *AnsiCodePageData
+05c void *OemCodePageData
+060 void *UnicodeCaseTableData
+064 uint32 NumberOfProcessors
+068 uint32 NtGlobalFlag
+070 union _LARGE_INTEGER CriticalSectionTimeout
+070 uint32 LowPart
+074 int32 HighPart
+070 struct __unnamed3 u
+070 uint32 LowPart
+074 int32 HighPart
+070 int64 QuadPart
+078 uint32 HeapSegmentReserve
+07c uint32 HeapSegmentCommit
+080 uint32 HeapDeCommitTotalFreeThreshold
+084 uint32 HeapDeCommitFreeBlockThreshold
+088 uint32 NumberOfHeaps
+08c uint32 MaximumNumberOfHeaps
+090 void **ProcessHeaps
+094 void *GdiSharedHandleTable
+098 void *ProcessStarterHelper
+09c uint32 GdiDCAttributeList
+0a0 void *LoaderLock
+0a4 uint32 OSMajorVersion
+0a8 uint32 OSMinorVersion
+0ac uint16 OSBuildNumber
+0ae uint16 OSCSDVersion
+0b0 uint32 OSPlatformId
+0b4 uint32 ImageSubsystem
+0b8 uint32 ImageSubsystemMajorVersion
+0bc uint32 ImageSubsystemMinorVersion
+0c0 uint32 ImageProcessAffinityMask
+0c4 uint32 GdiHandleBuffer[34]
+14c function *PostProcessInitRoutine
+150 void *TlsExpansionBitmap
+154 uint32 TlsExpansionBitmapBits[32]
+1d4 uint32 SessionId
+1d8 void *AppCompatInfo
+1dc struct _UNICODE_STRING CSDVersion
+1dc uint16 Length
+1de uint16 MaximumLength
+1e0 uint16 *Buffer
kd> !strct PEB_LDR_DATA
!strct PEB_LDR_DATA
struct _PEB_LDR_DATA (sizeof=36)
+00 uint32 Length
+04 byte Initialized
+08 void *SsHandle
+0c struct _LIST_ENTRY InLoadOrderModuleList
+0c struct _LIST_ENTRY *Flink
+10 struct _LIST_ENTRY *Blink
+14 struct _LIST_ENTRY InMemoryOrderModuleList
+14 struct _LIST_ENTRY *Flink
+18 struct _LIST_ENTRY *Blink
+1c struct _LIST_ENTRY InInitializationOrderModuleList
+1c struct _LIST_ENTRY *Flink
+20 struct _LIST_ENTRY *Blink
kd> !strct RTL_USER_PROCESS_PARAMETERS
!strct RTL_USER_PROCESS_PARAMETERS
struct _RTL_USER_PROCESS_PARAMETERS (sizeof=656)
+000 uint32 MaximumLength
+004 uint32 Length
+008 uint32 Flags
+00c uint32 DebugFlags
+010 void *ConsoleHandle
+014 uint32 ConsoleFlags
+018 void *StandardInput
+01c void *StandardOutput
+020 void *StandardError
+024 struct _CURDIR CurrentDirectory
+024 struct _UNICODE_STRING DosPath
+024 uint16 Length
+026 uint16 MaximumLength
+028 uint16 *Buffer
+02c void *Handle
+030 struct _UNICODE_STRING DllPath
+030 uint16 Length
+032 uint16 MaximumLength
+034 uint16 *Buffer
+038 struct _UNICODE_STRING ImagePathName
+038 uint16 Length
+03a uint16 MaximumLength
+03c uint16 *Buffer
+040 struct _UNICODE_STRING CommandLine
+040 uint16 Length
+042 uint16 MaximumLength
+044 uint16 *Buffer
+048 void *Environment
+04c uint32 StartingX
+050 uint32 StartingY
+054 uint32 CountX
+058 uint32 CountY
+05c uint32 CountCharsX
+060 uint32 CountCharsY
+064 uint32 FillAttribute
+068 uint32 WindowFlags
+06c uint32 ShowWindowFlags
+070 struct _UNICODE_STRING WindowTitle
+070 uint16 Length
+072 uint16 MaximumLength
+074 uint16 *Buffer
+078 struct _UNICODE_STRING DesktopInfo
+078 uint16 Length
+07a uint16 MaximumLength
+07c uint16 *Buffer
+080 struct _UNICODE_STRING ShellInfo
+080 uint16 Length
+082 uint16 MaximumLength
+084 uint16 *Buffer
+088 struct _UNICODE_STRING RuntimeData
+088 uint16 Length
+08a uint16 MaximumLength
+08c uint16 *Buffer
+090 struct _RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32]
uint16 Flags
uint16 Length
uint32 TimeStamp
struct _STRING DosPath
uint16 Length
uint16 MaximumLength
char *Buffer
kd> !strct RTL_DRIVE_LETTER_CURDIR
!strct RTL_DRIVE_LETTER_CURDIR
struct _RTL_DRIVE_LETTER_CURDIR (sizeof=16)
+00 uint16 Flags
+02 uint16 Length
+04 uint32 TimeStamp
+08 struct _STRING DosPath
+08 uint16 Length
+0a uint16 MaximumLength
+0c char *Buffer
kd> !strct PEB_FREE_BLOCK
!strct PEB_FREE_BLOCK
struct _PEB_FREE_BLOCK (sizeof=8)
+0 struct _PEB_FREE_BLOCK *Next
+4 uint32 Size
欢迎交流,欢迎交朋友,