Exploring PEB (Process Environment Block)

    <-- x64lab Multilanguage Enhanced Ide
    Copyright (c) 2009-2011, Marc Rainer Kranz
    All rights reserved. -->
            MPL 1.1 License



When Windows Kernel loads a 64bit executable image in memory
it builds automagically a PEB for it. You can find useful links on my website relating to the PEB structure, documented and undocumented fields.
The PEB i report here can be found at [gs:60h].

Please, NOTE: these informations are under construction. They may
be not error-free or they may change from version to version of the Windows
64bit OS. Take care when using these informations. If You don't know what You are doing with it, avoid to do it. Anyway, i am not responsible for any damage caused by any use of those informations below, etc. as stated in the MPL 1.1 license.

Ok, the PEB is a Process Environment Block full of useful things about the current running executable. It looks like the following structure on my 6.0.6002 version OS:

  struct PEB

              db ?                       ;--- BYTE Reserved1[1];
              db ?                       ;--- BYTE Reserved1[1];
BeingDebugged db ?          ;--- BYTE BeingDebugged
              db 21 dup (?) ;--- BYTE Reserved2[21]
LoaderData        dq ?      ;--- PPEB_LDR_DATA LoaderData
ProcessParameters dq ?      ;--- PRTL_USER_PROCESS_PARAMETERS
                db 144 dup (?)
NumberOfProcessors dd ?
                db 92 dup (?)
OSMajVer        dd ?
OSMinVer        dd ?
OSBuildNum      dw ?
                dw ?
OSPlatformId    dd ?
imgSubSys       dd ?
imgSubSysMajVer dd ?
imgSubSysMinVer dd ?
                db 252 dup (?)
ppInitRoutine   dq ?          ;--- PPS_POST_PROCESS_INIT_ROUTINE
                db 136 dup(?) ;--- BYTE Reserved4[136];
SessionId       dd ?          ;--- ULONG SessionId;
  ends

After some more hacking i find
PPEB_LDR_DATA looking like the following

  struct PEB_LDR_DATA

Length          dd ?     ;--- ULONG Length
Initialized     dd ?     ;--- BOOLEAN Initialized
SsHandle        dq ?     ;--- PVOID SsHandle
loadOrder    LIST_ENTRY  ;--- InLoadOrderModuleList
memOrder     LIST_ENTRY  ;--- InMemoryOrderModuleList
initOrder    LIST_ENTRY  ;--- InInitializationOrderModuleList
  ends


where each LIST_ENTRY has the following format

  struct LIST_ENTRY

flink    dq ?
blink    dq ?
  ends

Now one important section of the PEB resides in the
RTL_USER_PROCESS_PARAMETERS block pointed by ProcessParameters.
Here the structure:

  struct RTL_USER_PROCESS_PARAMETERS
MaximumLength  dd ?  ;--- ULONG MaximumLength;
Length         dd ?  ;--- ULONG Length;
Flags          dd ?  ;--- ULONG Flags;
DebugFlags     dd ?  ;--- ULONG DebugFlags;

ConsoleHandle   dq ? ;--- PVOID ConsoleHandle (at  10h)
ConsoleFlags    dd ? ;--- ULONG ConsoleFlags
                dd ?
StdInputHandle  dq ? ;--- HANDLE StdInputHandle (at 20h)
StdOutputHandle dq ? ;--- HANDLE StdOutputHandle

StdErrorHandle  dq ?  ;--- HANDLE StdErrorHandle (at 30h)
                dq ?
CurrentDirectoryPath   dq ?  ;--- UNICODE_STRING CurrentDirectoryPath
CurrentDirectoryHandle dq ?  ;--- HANDLE CurrentDirectoryHandle

              dq ?    ;--- at 50h
DllPath       dq ?    ;--- UNICODE_STRING DllPath

              dq ? ;--- at 60h
ImagePathName dq ? ;--- UNICODE_STRING ImagePathName
              dq ? ;--- at 70h
CommandLine   dq ? ;--- UNICODE_STRING CommandLine

Environment           dq ? ;--- PVOID Environment (at 80h)
StartingPositionLeft  dd ? ;--- ULONG StartingPositionLeft
StartingPositionTop   dd ? ;--- ULONG StartingPositionTop
 
Width      dd ?  ;--- ULONG Width   (at 90h)
Height     dd ?  ;--- ULONG Height
CharWidth  dd ?  ;--- ULONG CharWidth
CharHeight dd ?  ;--- ULONG CharHeight

ConsoleTextAttributes dq ?  ;--- ULONG ConsoleTextAttributes (at A0h)
                      dq ?

WindowFlags     dd 0  ;--- ULONG WindowFlags (at B0h)
ShowWindowFlags dd 0  ;--- ULONG ShowWindowFlags
WindowTitle     dq ?  ;--- UNICODE_STRING WindowTitle (at B8h)
                dq ?  ;--- at C0
DesktopName dq ? ;--- UNICODE_STRING DesktopName C8
            dq ? ;--- UNICODE_STRING ShellInfo
            dq ? ;--- UNICODE_STRING RuntimeData
            dq ? ;--- RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
  ends

One valid item in the
LIST_ENTRY (flink or blink) mentioned above points
to the following
LDR_DATA_TABLE_ENTRY layout. A LIST_ENTRY is an item of a double linked list.

  struct LDR_DATA_TABLE_ENTRY
loadOrder   LIST_ENTRY ;--- at 0
memOrder    LIST_ENTRY ;--- at 10h
initOrder   LIST_ENTRY ;--- at 20h
BaseAddress dq ?     ;--- at 30h
EntryPoint  dq ?     ;--- at 38h
SizeOfImage dd ?     ;--- at 40h
            dd ?
            dw ?     ;--- at 48h
FullLen     dw ?     ;--- at 4Ah
            dd ?
FullDllName dq ?     ;--- at 50h
            dw ?
BaseLen     dw ?     ;--- at 5Ah
            dd ?
BaseDllName dq ?     ;--- at 60h
Flags       dd ?
LoadCount   dw ?
TlsIndex    dw ?
HashTableEntry LIST_ENTRY
TimeDateStamp  dd ?
               dd ?
               dq ?
  ends
 
Note that once you have accesssed the PEB_LDR_DATA   to take one of the
default orders, Load, Memory or Initialization order, your LDR_DATA_TABLE_ENTRY will be offseted of respectively +0,+10h,+20h,
exactly a multiple of the size of a LIST_ENTRY, example


    mov rsi,[.peb.LoaderData]

    mov rdx,[.pld.memOrder.blink]  ;--- accessing it by memOrder at +10h

    virtual at rdx
        .lmod LDR_DATA_TABLE_ENTRY
    end virtual
 
    sub rdx,10h     ;<---
    mov rbx,[.lmod.BaseAddress]

In a near future i will provide some source code and executable to
see it in action in debugger.