VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Gaining important datas from PEB under NT boxes

29a [6]
March 2002

[Back to index] [Comments]


After some years of using it, you are very familiar with SEH - Structured Exception Handling. When you set a exception frame you use more or less the same code snippet which works with the fs selector. Probably you also know that this selector points to a data structure known as TEB ie Thread Environment Block. This structure contains a lot of more or less useful values and structures and - what is important for us - also a pointer to PEB - Process Environment Block.

struct TEB {
        struct _NT_TIB NtTib;
        void* EnvironmentPointer;
        struct _CLIENT_ID ClientId;
        void* ActiveRpcHandle;
        void* ThreadLocalStoragePointer;
        struct _PEB* ProcessEnvironmentBlock;   ; offset 30h
        struct _ACTIVATION_CONTEXT_STACK ActivationContextStack;

This is also the first use of PEB in virus coding. Since PEB under NT is always mapped at address 7FFDF000h (ie below 80000000h becoz above is the memory occupied by the NT kernel and drivers) but under Win9x it is always above 80000000h in the shared memory region we can use it for differentiating these operating system families. See this code snippet from Win2k.TaiChi:

Operating system families differentiating

        mov eax, dword ptr fs:[30h]     ; gimme the PEB pointer
        test eax, eax                   ; it is above 80000000h ?
        js jmp_to_host                  ; if yep end ...
                                        ; runned under WinNT box

Getting the kernel32.dll base from PEB

For us will be important two data structures in PEB - PEB_LDR_DATA and RTL_USER_PROCESS_PARAMETERS. First we will use PEB_LDR_DATA which is at PEB:0ch offset to locate the kernel32.dll image base.

struct PEB_LDR_DATA {
        DWORD Length;                                           ; 0
        BYTE Initialized;                                       ; 4
        void* SsHandle;                                         ; 8
        struct LIST_ENTRY InLoadOrderModuleList;                ; 0ch
        struct LIST_ENTRY InMemoryOrderModuleList;              ; 14h
        struct LIST_ENTRY InInitializationOrderModuleList;      ; 1ch

struct LIST_ENTRY {
        struct LIST_ENTRY* Flink;       ; 0
        struct LIST_ENTRY* Blink;       ; 4

On the first sight it could look out a little bit confusing. But it isn't believe me. Let's have a deeper look at the PEB_LDR_DATA structure. For our needs we will use that data structure at address PEB:PEB_LDR_DATA:1ch. This is the list of initialization order of modules (ie dlls). Because it is the LIST_ENTRY what in fact is the two ways list (forwards and backwards) we'll go forward to the first module in the list. If we would need image base of ntdll.dll this would be the right entry for us. But because we want the kernel32.dll image base we go forward again and that's exactly what we need. Let's have a look at the code snippet (hope it will be less confusing :))

Getting kenel32.dll image base

        mov eax, dword ptr fs:[30h]     ; PEB base in eax
        mov eax, dword ptr [eax+0ch]    ; goto PEB_LDR_DATA

        mov esi, dword ptr [eax+1ch]    ; get the first entry in the
                                        ; InitOrderModuleList
        ; now the esi points to the LIST_ENTRY entry which also contains
        ; (besides others) the image base of ntdll.dll
        ; *esi
        ;       dd      *forwards_in_the_list   ; esi+0
        ;       dd      *backwards_in_the_list  ;    +4
        ;       dd      imagebase_of_ntdll.dll  ;    +8
        ;       ...
        ;       dd      imagetimestamp          ;    +44h

        lodsd                           ; we go forwards
        mov ebx, dword ptr [eax+08h]    ; and finally we get the image base
                                        ; of kernel32.dll

We can of course go forward again in the list and then we could find informations about other modules in the chain (if other we're imported by the program of course ...)

Getting the current directory from PEB

Now the time has come to have a look at RTL_USER_PROCESS_PARAMETERS structure. This structure is located at PEB:10h. First let's have a look at it's entries.

        DWORD MaximumLength;
        DWORD Length;
        DWORD Flags;
        DWORD DebugFlags;
        void* ConsoleHandle;
        DWORD ConsoleFlags;
        void* StandardInput;
        void* StandardOutput;
        void* StandardError;
        struct CURDIR CurrentDirectory;
        struct UNICODE_STRING DllPath;
        struct UNICODE_STRING ImagePathName;
        struct UNICODE_STRING CommandLine;
        void* Environment;
        DWORD StartingX;
        DWORD StartingY;
        DWORD CountX;
        DWORD CountY;
        DWORD CountCharsX;
        DWORD CountCharsY;
        DWORD FillAttribute;
        DWORD WindowFlags;
        DWORD ShowWindowFlags;
        struct UNICODE_STRING WindowTitle;
        struct UNICODE_STRING DesktopInfo;
        struct UNICODE_STRING ShellInfo;
        struct UNICODE_STRING RuntimeData;

struct CURDIR {
        struct UNICODE_STRING DosPath;
        void* Handle;

        WORD Length;
        WORD MaximumLength;
        DWORD* Buffer;

As you might see there is a lot of very usefull datas. For example CommandLine, StandardInput, StandardOutput and others. We will use this structure to get the current directory. Because it's not a lot to explain let's go directly to the code snippet.

Getting current directory

        mov eax, dword ptr fs:[30h]     ; goto PEB
        mov eax, dword ptr [eax+10h]    ; goto RTL_USER_PROCESS_PARAMETERS
        add eax, 24h                    ; goto CurrentDirectory
        mov eax, dword ptr [eax+4]      ; gimme unicode_buffer
        ; now in eax we have the pointer to the unicode current directory
        ; you can convert it to ansi or work with it as it is ...


You could see, that in PEB but also in TEB there are a lot of useful informations. A lot of functions of Win32 api are touching exactly these structures. Go on with exploring them with reverse engineering (mainly ntdll.dll) and show us what you'll get ...

Ratter/29A - I'm a stranger in the world I haven't made.
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka