How to get the Process Environment Block (PEB) address using assembler (x64 OS)?

13,086

Solution 1

Just two comments.

No need to push/pop rax because it's a scratch or volatile register on Windows, see the caller/callee saved registers. In particular, rax will hold the return value for your function.

It often helps to step through the machine code when you call GetModuleHandle() and compare it with your own assembly code. You'll probably encounter something like this implementation.

Solution 2

If you don't mind C. Works in Microsoft Visual Studio 2015. Uses the "__readgsqword()" intrinsic.

#include <winnt.h>
#include <winternl.h>

// Thread Environment Block (TEB)
#if defined(_M_X64) // x64
PTEB tebPtr = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#else // x86
PTEB tebPtr = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#endif

// Process Environment Block (PEB)
PPEB pebPtr = tebPtr->ProcessEnvironmentBlock;

Solution 3

I like Sirmabus' answer but I much prefer it with simple C casts and the offsetof macro:

PPEB get_peb()
{
#if defined(_M_X64) // x64
    PTEB tebPtr = (PTEB)__readgsqword(offsetof(NT_TIB, Self));
#else // x86
    PTEB tebPtr = (PTEB)__readfsdword(offsetof(NT_TIB, Self));
#endif
    return tebPtr->ProcessEnvironmentBlock;
}

Solution 4

Get_Ldr_Addr didnt save your result.

you should not protect rax by push and pop because rax is the return value

Share:
13,086
Oriel Cochavi
Author by

Oriel Cochavi

Updated on June 05, 2022

Comments

  • Oriel Cochavi
    Oriel Cochavi almost 2 years

    I'm trying to get PEB address of the current process with assembler.

    the cpp file:

    #include <iostream>
    //#include <windows.h>
    
    extern "C" int* __ptr64 Get_Ldr_Addr();
    
    int main(int argc, char **argv)
    {
        std::cout << "asm     " << Get_Ldr_Addr() << "\n";
        //std::cout <<"peb     "<< GetModuleHandle(0) << "\n";
    
        return 0;
    }
    

    the asm file:

    .code
    
    Get_Ldr_Addr proc
        push rax
        mov rax, GS:[30h]
        mov rax, [rax + 60h]
        pop rax
        ret
    Get_Ldr_Addr endp
    
    end
    

    But I get different addresses from the GetModuleHandle(0) and the Get_Ldr_Addr()!

    what is the problem? doesn't is suppose to be the same?

    Q: If the function is external, it will check the PEB of the process that called it or of the function's dll (it suppose to be a dll)?

    Tnx