Evolution of Process Environment Block (PEB)

Over one year ago I’ve published unified definition of PEB for x86 and x64 Windows (PEB32 and PEB64 in one definition). It was based on PEB taken from Windows 7 NTDLL symbols, but I was pretty confident that it should work on other versions of Windows as well. Recently someone left a comment under mentioned post: “Good, but its only for Windows 7”. It made me curious if it is really ‘only for Win7’. I was expecting that there might be some small differences between some field names, or maybe some new fields added at the end, but the overall structure should be the same. I’ve no other choice but to check it myself. I’ve collected 108 different ntdll.pdb/wntdll.pdb files from various versions of Windows and dumped _PEB structure from them (Dia2Dump ftw!). Here are some statistics:

  • _PEB was defined in 80 different PDBs (53 x86 PEBs and 27 x64 PEBs)

  • There was 11 unique PEBs for x86, and 8 unique PEBs for x64 (those numbers doesn’t sum up, as starting from Windows 2003 SP1 there is always match between x86 and x64 version)

  • The total number of collected different _PEB definitions is equal to 11

I’ve put all the collected informations into nice table (click the picture to open PDF):

PEB Evolution

PEB Evolution PDF

Left column of the table represents x86 offset, right column is x64 offset, green fields are supposed to be compatible across all windows versions starting from XP without any SP and ending at Windows 8 RTM, red (pink?, rose?) fields should be used only after careful verification if they’re working on a target system. At the top of the table, there is row called NTDLL TimeStamp, it is not the timestamp from the PE header but from the Debug Directory (IMAGE_DIRECTORY_ENTRY_DEBUG, LordPE can parse this structure). I’m using this timestamp as an unique identifier for NTDLL version, this timestamp is also stored in PDB files.

Now I can answer initial question: “Is my previous PEB32/PEB64 definition wrong ?” Yes and No. Yes, because it contains various fields specific for Windows 7 thus it can be considered as wrong. No, because most of the fields are exactly the same across all Windows versions, especially those fields that are usually used in third party software. To satisfy everyone, I’ve prepared another version of PEB32/PEB64 definition:

#pragma pack(push)
#pragma pack(1)
template <class T>
struct LIST_ENTRY_T
{
	T Flink;
	T Blink;
};
 
template <class T>
struct UNICODE_STRING_T
{
	union
	{
		struct
		{
			WORD Length;
			WORD MaximumLength;
		};
		T dummy;
	};
	T _Buffer;
};
 
template <class T, class NGF, int A>
struct _PEB_T
{
	union
	{
		struct
		{
			BYTE InheritedAddressSpace;
			BYTE ReadImageFileExecOptions;
			BYTE BeingDebugged;
			BYTE _SYSTEM_DEPENDENT_01;
		};
		T dummy01;
	};
	T Mutant;
	T ImageBaseAddress;
	T Ldr;
	T ProcessParameters;
	T SubSystemData;
	T ProcessHeap;
	T FastPebLock;
	T _SYSTEM_DEPENDENT_02;
	T _SYSTEM_DEPENDENT_03;
	T _SYSTEM_DEPENDENT_04;
	union
	{
		T KernelCallbackTable;
		T UserSharedInfoPtr;
	};
	DWORD SystemReserved;
	DWORD _SYSTEM_DEPENDENT_05;
	T _SYSTEM_DEPENDENT_06;
	T TlsExpansionCounter;
	T TlsBitmap;
	DWORD TlsBitmapBits[2];
	T ReadOnlySharedMemoryBase;
	T _SYSTEM_DEPENDENT_07;
	T ReadOnlyStaticServerData;
	T AnsiCodePageData;
	T OemCodePageData;
	T UnicodeCaseTableData;
	DWORD NumberOfProcessors;
	union
	{
		DWORD NtGlobalFlag;
		NGF dummy02;
	};
	LARGE_INTEGER CriticalSectionTimeout;
	T HeapSegmentReserve;
	T HeapSegmentCommit;
	T HeapDeCommitTotalFreeThreshold;
	T HeapDeCommitFreeBlockThreshold;
	DWORD NumberOfHeaps;
	DWORD MaximumNumberOfHeaps;
	T ProcessHeaps;
	T GdiSharedHandleTable;
	T ProcessStarterHelper;
	T GdiDCAttributeList;
	T LoaderLock;
	DWORD OSMajorVersion;
	DWORD OSMinorVersion;
	WORD OSBuildNumber;
	WORD OSCSDVersion;
	DWORD OSPlatformId;
	DWORD ImageSubsystem;
	DWORD ImageSubsystemMajorVersion;
	T ImageSubsystemMinorVersion;
	union
	{
		T ImageProcessAffinityMask;
		T ActiveProcessAffinityMask;
	};
	T GdiHandleBuffer[A];
	T PostProcessInitRoutine;
	T TlsExpansionBitmap;
	DWORD TlsExpansionBitmapBits[32];
	T SessionId;
	ULARGE_INTEGER AppCompatFlags;
	ULARGE_INTEGER AppCompatFlagsUser;
	T pShimData;
	T AppCompatInfo;
	UNICODE_STRING_T<T> CSDVersion;
	T ActivationContextData;
	T ProcessAssemblyStorageMap;
	T SystemDefaultActivationContextData;
	T SystemAssemblyStorageMap;
	T MinimumStackCommit;
};
 
typedef _PEB_T<DWORD, DWORD64, 34> PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> PEB64;
#pragma pack(pop)

Above version is system independent as all fields that are changing across OS versions are marked as _SYSTEM_DEPENDENT_xx. I’ve also removed all fields from the end that were added after Widnows XP.

Comments (9)

  1. 15:33, March 2, 2013Bartosz Wójcik  / Reply

    Good job Re :)

  2. 22:08, March 4, 20130xdabbad00  / Reply

    Great work! Really nice way to visualize it. Very thorough.

  3. 09:13, March 10, 2013ZigD  / Reply

    Nice work and research :)

  4. 12:40, March 10, 2013Hors  / Reply

    Good job!

  5. 03:43, July 25, 2013genuine  / Reply

    Best work ive seen on this structure, nice PDF doc. :)

  6. 02:42, July 15, 2014cool_guy  / Reply

    PDF link is not working

    • 13:35, July 20, 2014ReWolf  / Reply

      It works for me. If it returns ‘403 Forbidden’ then try multiple times, some times there are some problems with my hosting.

  7. 01:16, April 3, 2015hwang  / Reply

    how can i know the base address of PEB in virtual memory. i tried to read that structure but i dont know exact location of PEB.

    • 21:08, April 6, 2015ReWolf  / Reply

      To get 32-bit PEB from 32-bit process:

      	BYTE* _teb = (BYTE*)__readfsdword(0x18);
      	PEB32* _peb = *(PEB32**)(_teb + 0x30);

      To get 64-bit PEB from 64-bit process:

      	BYTE* _teb = (BYTE*)__readgsqword(0x30);
      	PEB64* _peb = *(PEB64**)(_teb + 0x60);

      To get 64-bit PEB from 32-bit WoW64 process:

      	BYTE* _teb = (BYTE*)__readfsdword(0x18) - 0x2000;
      	DWORD64 _peb = *(DWORD64*)(_teb + 0x60);

      There are some magic consts in above snippets, but at least You don’t need to define TEB32/TEB64 structures to use them. Third snippet may not work on Windows 8+, I can’t test it on this platform at the moment.

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pingbacks (2)

  1. 02:04, November 29, 2015Favicon of blog.rewolf.plTerminus Project launch.