Recently I was writing small piece of code that uses both versions of PEB structure (x86 and x64). Being tired of having two separate definitions I decided to look into the Windows Research Kernel (WRK) sources and check how Microsoft is handling this structure. Original definition is in “pebteb.h” file and it is pretty smart, everything is defined through a series of macros and then included in a very “specific” way:

1 2 3 4 5 6 7 #define PEBTEB_BITS 32 #include "pebteb.h" #undef PEBTEB_BITS #define PEBTEB_BITS 64 #include "pebteb.h" #undef PEBTEB_BITS #define PEBTEB_BITS 32 #include "pebteb.h" #undef PEBTEB_BITS #define PEBTEB_BITS 64 #include "pebteb.h" #undef PEBTEB_BITS

I’ve decided to do it in a similar fashion, but I’d rather use templates instead of macros. All code is wrapped in #pragma pack(1) to avoid any problems with structure alignment on different architectures:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 #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 BitField ; } ; T dummy01 ; } ; T Mutant ; T ImageBaseAddress ; T Ldr ; T ProcessParameters ; T SubSystemData ; T ProcessHeap ; T FastPebLock ; T AtlThunkSListPtr ; T IFEOKey ; T CrossProcessFlags ; T UserSharedInfoPtr ; DWORD SystemReserved ; DWORD AtlThunkSListPtr32 ; T ApiSetMap ; T TlsExpansionCounter ; T TlsBitmap ; DWORD TlsBitmapBits [ 2 ] ; T ReadOnlySharedMemoryBase ; T HotpatchInformation ; 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 ; 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 ; T FlsCallback ; LIST_ENTRY_T < T > FlsListHead ; T FlsBitmap ; DWORD FlsBitmapBits [ 4 ] ; T FlsHighIndex ; T WerRegistrationData ; T WerShipAssertPtr ; T pContextData ; T pImageHeaderHash ; T TracingFlags ; } ; typedef _PEB_T < DWORD, DWORD64, 34 > PEB32 ; typedef _PEB_T < DWORD64, DWORD, 30 > PEB64 ; #pragma pack(pop) #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 BitField; }; T dummy01; }; T Mutant; T ImageBaseAddress; T Ldr; T ProcessParameters; T SubSystemData; T ProcessHeap; T FastPebLock; T AtlThunkSListPtr; T IFEOKey; T CrossProcessFlags; T UserSharedInfoPtr; DWORD SystemReserved; DWORD AtlThunkSListPtr32; T ApiSetMap; T TlsExpansionCounter; T TlsBitmap; DWORD TlsBitmapBits[2]; T ReadOnlySharedMemoryBase; T HotpatchInformation; 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; 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; T FlsCallback; LIST_ENTRY_T<T> FlsListHead; T FlsBitmap; DWORD FlsBitmapBits[4]; T FlsHighIndex; T WerRegistrationData; T WerShipAssertPtr; T pContextData; T pImageHeaderHash; T TracingFlags; }; typedef _PEB_T<DWORD, DWORD64, 34> PEB32; typedef _PEB_T<DWORD64, DWORD, 30> PEB64; #pragma pack(pop)

Above definitions were compiled as x86 and x64 code and works well (at least on Windows 7 x64 :)). You may freely use above code in your projects.