0

Windows stores the TEB in FS (32bit) or GS (64bit) segment register. In a program using NtCurrentPeb() the x86 instruction is mov rax, gs:60h. The 0x60 value is offsetof(TEB, ProcessEnvironmentBlock).

To use this in a program I've to include both Windows.h and Winternl.h header file which has bunch of other #define. As the question said I want to use the function without these header file and by directly accessing the segment register. I've also made a separate header file with the TEB and PEB structure. So how can I do that? I was thinking with __asm keyword and a typedef NtCurrentTeb() or something.

Biswapriyo
  • 3,491
  • 3
  • 22
  • 42
  • you want programming for windows without windows header files ? wwhy you not want include `windows.h` ? you of course can use `__readfsdword` and `__readgsqword`, etc. but what sense in all this ? – RbMm Oct 02 '18 at 21:02
  • `__asm` is not supported in 64 bit builds – Paul Sanders Oct 02 '18 at 21:12
  • `__readfsdword` not macro but inline function for *cl* compiler. how not use windows headers or `__readfsdword` help you *to deep dive in API and ABI.* ? – RbMm Oct 02 '18 at 21:15
  • You have this marked as both 'assembly' and 'c.' Does that mean you are coding in assembler? Using VStudio? Gcc? Using hardware specific features (like `gs:` or `fs:`) isn't going to have a generic solution. – David Wohlferd Oct 02 '18 at 22:35

3 Answers3

3

I really do not understand why you answered your own question incompletely. This confuses further readers because you did not provide the appropriate answer to the question itself.

You do not need to use ASM for this, you can use intrinsic functions like so:

#ifdef _M_X64
    auto pPEB = (PPEB)__readgsqword(0x60);
#elif _M_IX86
    auto pPEB = (PPEB)__readfsdword(0x30);
#else
    #error "PPEB Architecture Unsupported"
#endif

But to answer the actual question, here is how to do is via ASM:

x64 ASM (TEB/PEB):

GetTEBAsm64 proc
    mov rax, qword ptr gs:[00000030h]
    ret
GetTEBAsm64 endp

GetPEBAsm64 proc
    mov rax, qword ptr gs:[00000060h]
    ret
GetPEBAsm64 endp

x86 - PEB:

__asm
    {
    mov eax, dword ptr fs : [00000030h]
    mov peb, eax
}

x86 - TEB:

__asm
    {
        mov eax, dword ptr fs : [00000018h]
        mov teb, eax
    }

I strongly hope that my answer is clear and that someone else in the future can benefit from it.

dialer
  • 4,348
  • 6
  • 33
  • 56
Mecanik
  • 1,539
  • 1
  • 20
  • 50
  • Why not make `GetTEBAsm64` look like `mov rax, qword ptr gs:[00000030h]` `ret` . A lot of unnecessary code. Same for `GetPEBAsm64` – Michael Petch Jul 17 '22 at 01:10
  • @MichaelPetch Well... I don't even like using ASM in projects. I find intrinsic nicer. But the OP needed a solution so... :) – Mecanik Jul 17 '22 at 03:17
  • I agree about the intrinsics and it is the best way to do it. I was just curious about the bloat in the asm. No problem. I only came across your answer as the code was referenced in another question today. – Michael Petch Jul 17 '22 at 04:02
  • @MichaelPetch I see, well, it's good that I`m popular LOL. – Mecanik Jul 17 '22 at 04:16
1

Declare function prototype and link against ntdll.dll.

Jozo121
  • 21
  • 1
  • 4
  • 1
    for what need link against ntdll.dll ? `NtCurrentTeb()` not require this. if implement `NtCurrentPeb()` by read `ProcessEnvironmentBlock` value from teb - again - for what `ntdll.dll` here if we nothing call from it ? – RbMm Oct 03 '18 at 00:01
  • @RbMm `NtCurrentTeb` is not only an inline function from the Windows headers, but it also exists as a public function with the same name in `ntdll.dll` (but only in the 32 bit version of the DLL). – dialer Jul 18 '22 at 13:45
  • @dialer really exist in 32bit version of the DLL (but not in 64). not view any sense use this import, when exist macro and for both 32/64 – RbMm Jul 18 '22 at 15:03
  • @RbMm The public symbol allows interop from other programming languages and technologies which cannot access `fs` and `gs` directly. But the fact that it doesn't exist in 64bit is very limiting, of course. – dialer Jul 18 '22 at 15:08
0

To read from gs or fs segment register, I have used this assembly in Visual Studio. Create a C/C++ empty project in Visual Studio with these settings enabled. fs or gs segment register provides NT_TIB structure in 32 bit and 64 bit Windows respectively. TEB is at 0x30 offset in NT_TIB structure. So the assembly in 64 bit will be: mov rax, gs:[30h].

Here is a sample source code to get current directory of an executable file:

  • ProcParam.asm:
.code

ProcParam PROC

mov rax, gs:[30h]      ; TEB from gs in 64 bit only
mov rax, [rax+60h]     ; PEB
mov rax, [rax+20h]     ; RTL_USER_PROCESS_PARAMETERS
ret

ProcParam ENDP

end
  • main.c:
#include <stdio.h>

typedef struct _UNICODE_STRING {
    unsigned short Length;
    unsigned short MaximumLength;
    wchar_t* Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _CURDIR {
    UNICODE_STRING DosPath;
    void* Handle;
} CURDIR, *PCURDIR;

/*Extracted from ntdll.pdb file*/

typedef struct _RTL_USER_PROCESS_PARAMETERS {
    unsigned int MaximumLength;
    unsigned int Length;
    unsigned int Flags;
    unsigned int DebugFlags;
    void* ConsoleHandle;
    unsigned int ConsoleFlags;
    void* StandardInput;
    void* StandardOutput;
    void* StandardError;
    CURDIR CurrentDirectory;
    /*Many more*/
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

PRTL_USER_PROCESS_PARAMETERS ProcParam(void);

int main(void)
{
    wprintf(L"%s\n", ProcParam()->CurrentDirectory.DosPath.Buffer);
}
Biswapriyo
  • 3,491
  • 3
  • 22
  • 42