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
  • 2,591
  • 2
  • 18
  • 40
  • 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
    push rbx
    xor rbx,rbx
    xor rax,rax
    mov rbx, qword ptr gs:[00000030h]
    mov rax, rbx
    pop rbx
    ret
GetTEBAsm64 endp

GetPEBAsm64 proc
    push rbx
    xor rbx,rbx
    xor rax,rax
    mov rbx, qword ptr gs:[00000060h]
    mov rax, rbx
    pop rbx
    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.

Mecanik
  • 1,369
  • 1
  • 12
  • 37
1

Declare function prototype and link against ntdll.dll.

Jozo121
  • 11
  • 1
  • 3
  • 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
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
  • 2,591
  • 2
  • 18
  • 40