3

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

Oriel Cochavi
  • 345
  • 1
  • 4
  • 12
  • 2
    Where are you putting your return value? Apparently you are loading it into RAX but then it's getting overwritten by the pop. Check how you're supposed to return the value in your ABI. – Javier Martín May 18 '16 at 00:37
  • I deleted the push/pop. and this is the way to return the value according to some instruction. https://deviorel.wordpress.com/2015/01/19/compiling-64-bit-assembler-code-in-visual-studio-2014/ – Oriel Cochavi May 18 '16 at 00:45
  • 2
    Another way to get a pointer to the `PEB` of any process, without resorting to assembly at all, is to use [`NtQueryInformationProcess()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280.aspx): "*When the `ProcessInformationClass` parameter is `ProcessBasicInformation`, the buffer pointed to by the `ProcessInformation` parameter should be large enough to hold a single `PROCESS_BASIC_INFORMATION` structure ... [whose] `PebBaseAddress` member points to a `PEB` structure.*" – Remy Lebeau May 18 '16 at 01:32
  • See [How to get the Process Environment Block (PEB) from extern process?](http://stackoverflow.com/questions/5454667/) for more details about dealing with 32bit vs 64bit PEBs, and Windows 8+ (which changes the location of the 32bit PEB). – Remy Lebeau May 18 '16 at 01:35
  • 3
    Not sure how you got the impression that `GetModuleHandle` returns the PEB. – Raymond Chen May 18 '16 at 03:08
  • I don't want to use WINAPI functions in the program itself (if I use them It'll be for checking things only). I saw in some posts that GetModuleHandle(0) returns the PEB address. anyway, if I want for the DLL to work only on x64 OS, can't I relay on the x64 PEB location (as shown in here: http://nagareshwar.securityxploded.com/2013/09/21/using-peb-to-get-base-address-of-kernelbase-dll/)? – Oriel Cochavi May 18 '16 at 06:54
  • Just call the API. That's why it's there. Note that the technique in the article you linked relies on undocumented behavior and it can therefore change at any time. – Raymond Chen May 18 '16 at 16:48

4 Answers4

7

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;
Sirmabus
  • 636
  • 8
  • 8
2

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.

Jens
  • 8,423
  • 9
  • 58
  • 78
2

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;
}
UnrealDan
  • 21
  • 1
1

Get_Ldr_Addr didnt save your result.

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