Receive TEB info using PS`

Discussion in 'Scripting' started by Dark Vador, Sep 10, 2025.

  1. Dark Vador

    Dark Vador X Æ A-12

    Feb 2, 2011
    4,806
    7,075
    150
    #1 Dark Vador, Sep 10, 2025
    Last edited: Sep 10, 2025
    this script will get you TEB address, like origional C` assembly code
    support for x86 x64 instruction // # gs:[30h] // # fs:[18h]
    from there you can get process id, Env` block, lot of useful info.
    All the properties you can get can be found here.

    TEB
    https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm

    how it work?
    you can't just call, gs:[30h] using ps`, not supported
    you can do, built dummy delegate, attach to memory
    this memory can be written with shell code,
    AKA Assmably code, as byte's.
    than, just call the delegate, to run your Assm` code.:D

    how to convert assm` code to byte's ?
    ask chatGpt or gemini, they good at that.
    just make sure delegate signature is match ass`m code.

    why it look very suspicious ?
    that also kind a way to inject bad code to process,
    so, beware what you running.
    you can run legit notepad with bad memory and than notepa will run as usual
    meanwhile, some malware will sit on your computer,
    run under legit process :D

    is it low level ?
    the only most low level way to call pure assmebly using powershell
    didnt find other way, other than using c Compiler :cool:

    Code.!

    Code:
    using namespace System.Reflection
    using namespace System.Reflection.Emit
    using namespace System.Runtime.InteropServices
    using namespace System.Management.Automation
    
    # Thread Environment Block
    # https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
    
    Function Get-TebPointer {
    if (!([PSTypeName]'TEB').Type) {
        Add-Type -TypeDefinition @"
        using System;
        using System.Runtime.InteropServices;
     
        public static class TEB {
            public delegate IntPtr GetPebAddressDelegate();
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern IntPtr VirtualAlloc(IntPtr a, uint b, uint c, uint d);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool VirtualFree(IntPtr a, uint b, uint c);
        }
    "@ -PassThru | Out-Null
    }
        $asmCode = if ([IntPtr]::Size -gt 4) {
            [byte[]] @(
                # mov rax,
                0x65, 0x48, 0x8B, 0x04, 0x25,
                # gs:[30h]
                0x30, 0x00, 0x00, 0x00,
                # ret
                0xC3
            )
        } else {
            [byte[]] @(
                # mov eax,
                0x64, 0xA1,
                #fs:[18h]
                0x18, 0x00, 0x00, 0x00,
                # retn
                0xC3
            )
        }
        $TepPtr = [IntPtr]::Zero
        $TepPtr = [TEB]::VirtualAlloc(0, $asmCode.Length, 12288, 64)
        if ($TepPtr -eq [IntPtr]::Zero) {
            $lastError = [Marshal]::GetLastWin32Error()
            throw "Failed to allocate memory. Win32 Error: $lastError"
        }
        [marshal]::Copy($asmCode, 0x0, $TepPtr, $asmCode.Length)
        try {
            $Func = [Marshal]::GetDelegateForFunctionPointer($TepPtr,[TEB+GetPebAddressDelegate])
            return $Func.Invoke()
        }
        finally {
            $Func = $null
            [TEB]::VirtualFree($TepPtr, 0, 0x8000) | Out-Null
        }
    }
    
    $tebPtr = Get-TebPointer
    $is64Bit = [IntPtr]::Size -eq 8
    $offBase = [PSCustomObject]@{
        procID   = if ($is64Bit) { 0x40 } else { 0x20 }
        envBlock = if ($is64Bit) { 0x60 } else { 0x30 }
        ntBuild  = if ($is64Bit) { 0x120 } else { 0xAC }
    }
    
    $ProcID = [Marshal]::ReadIntPtr(
        [IntPtr]::Add($tebPtr, $offBase.procID), 0x00)
    $EnvPtr = [Marshal]::ReadIntPtr(
        $tebPtr, $offBase.envBlock)
    $Build = [int][Marshal]::ReadInt16(
        $EnvPtr, $offBase.ntBuild)
    
    Clear-Host
    Write-Host
    write-host "Process ID --> $ProcID"
    write-host "Nt Build   --> $Build"
    write-host "Peb Addr   --> $EnvPtr"
    write-host
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  2. Dark Vador

    Dark Vador X Æ A-12

    Feb 2, 2011
    4,806
    7,075
    150
    #2 Dark Vador, Sep 12, 2025
    Last edited: Sep 12, 2025
    (OP)
    Darki add now few comment's,
    i think they usefull.
    help undersand this asm` s**ti code

    the first question, come to my mind is,
    since TEB is act` GS/FS at 0x00,
    why you need such --> mov rax, gs:[0x30]
    well, it store value at rax, value of [Read Pointer at gs:[0x30] --> AKA self de reference
    and this value is actualy is a pointer to gs:[0x00], the start of TEB str`
    and than, we can Add [Add offset to Pointer], Move [Move == Add offset, Read value]
    And than let's say,

    we we pointer for ClientID, which is TEB & 0x40
    add rax, 0x40 // gs:[0x40]

    Or Read value of 0x60, and get Pointer for PEB block
    mov rax, [rax + 0x60] // gs:[0x60]

    what is definition / difference between add / move
    so, most accurate definition i saw is
    • ADD is for addition/subtraction.
    • MOV is to move a value to a certain place in memory
    ~~~~~~~

    How it basicly work.
    Code:
        Online x86 / x64 Assembler and Disassembler
        https://defuse.ca/online-x86-assembler.htm
    
        add rax, 0x??           --> Add 0x?? Bytes, From Position
        mov Type, [Type + 0x??] --> Move to 0x?? Offset, read Value
    
        So,
        Example Read Pointer Value,
        & Also,
        Add 0x?? From Value
    
        // Return to gs:[0x00], store value at rax
        // (NtCurrentTeb) -eq ([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))
        // ([marshal]::ReadIntPtr((NtCurrentTeb),0x40)) -eq ([marshal]::ReadIntPtr((([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))),0x40))
        ** mov rax, gs:[0x30]
    
        // Move (de-ref`) -or Add\[+], and store value
        ** mov Type, [Type + 0x??]
        ** add rax,  0x??
    
        // Ret value
        ** Ret
    
    Inst` & Text
    Code:
        if ($is64) {
            $addClient = [byte[]]@([byte]0x48,[byte]0x83,[byte]0xC0,[byte]0x40)  # add rax, 0x40          // gs:[0x40]
            $movPeb    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x60)  # mov rax, [rax + 0x60]  // gs:[0x60] // RtlGetCurrentPeb
            $movLdr    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x18)  # mov rax, [rax + 0x18]
            $movParams = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x20)  # mov rax, [rax + 0x20]
            $basePtr   = [byte[]]@([byte]0x65,[byte]0x48,[byte]0x8B,[byte]0x04,  # mov rax, gs:[0x30]     #// Self dereference pointer at gs:[0x30],
                                   [byte]0x25,[byte]0x30,[byte]0x00,[byte]0x00,                           #// so, effectually, return to gs->0x0
                                   [byte]0x00)
        }
        else {
            $addClient = [byte[]]@([byte]0x83,[byte]0xC0,[byte]0x20)             # add eax, 0x20          // fs:[0x20]
            $movPeb    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x30)             # mov eax, [eax + 0x30]  // fs:[0x30] // RtlGetCurrentPeb
            $movLdr    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x0C)             # mov eax, [eax + 0x0c]
            $movParams = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x10)             # mov eax, [eax + 0x10]
            $basePtr   = [byte[]]@([byte]0x64,[byte]0xA1,[byte]0x18,             # mov eax, fs:[0x18]     #// Self dereference pointer at fs:[0x18],
                                   [byte]0x00,[byte]0x00,[byte]0x00)                                      #// so, effectually, return to fs->0x0
        }
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  3. Dark Vador

    Dark Vador X Æ A-12

    Feb 2, 2011
    4,806
    7,075
    150
    #3 Dark Vador, Sep 14, 2025 at 20:20
    Last edited: Sep 14, 2025 at 20:31
    (OP)
    Darki got some time to play with Asm (mostly ask AI` bot, how to build the nececery inst`)
    yes, darki still dont know assmebly, but darki will learn, someday. (maybe the basic)
    So, after little play, i got some interesting results.

    -SelfCheck Mode, check value against API Result,
    -Mode --> like it sound
    Code:
            # Mode options for retrieving the TEB address:
            # Return   -> value returned directly in CPU register
            # Pinned   -> use a managed variable pinned in memory
            # Buffer   -> use an unmanaged temporary buffer
            # GCHandle -> use a GCHandle pinned buffer
            # Remote   -> placeholder mode (not supported in this host) // work only in C# enviroment.!
    
    $Method --> ZwAllocateVirtualMemory -or ZwAllocateVirtualMemoryEx
    ---- >
    Call without parametes --> Get TEB [GS/FS Offset 0x0]
    Optional Offset --> i was very nice.
    Add the most important Stract` you will ever need.
    Code:
            [switch]$ClientID,
            [switch]$Peb,
            [switch]$Ldr,
            [switch]$Parameters,
    
    Self Check -->!
    Code:
    GetCurrentProcessId Test
    TEB offset 0x40 value: 4868
    ClientID Process Pointer: 4868
    GetCurrentProcessId(): 4868
    
    GetCurrentThreadId Test
    TEB offset 0x48 value: 10676
    ClientID Thread Pointer: 10676
    GetCurrentThreadId(): 10676
    
    RtlGetCurrentPeb Test
    TEB offset 0x60 value: 529731895296
    NtCurrentTeb -Peb returned: 529731895296
    RtlGetCurrentPeb(): 529731895296
    
    RtlGetCurrentServiceSessionId Test
    Service Session Id: 0
    PEB offset 0x90 value: 0
    
    RtlGetCurrentTransaction Test
    Current Transaction: 0
    PEB offset 0x17B8 value: 0
    
    RtlGetCurrentUmsThread Test
    TEB offset 0x1480 value: 0
    Status: 0xC00000BB
    UMS TEB pointer: 0
    
    NtCurrentTeb Mode Test
    WARNING: Mode: Return.   TypeOf:GetAddress
    Default Mode Ptr: 529893228544
    WARNING: Mode: Return.   TypeOf:GetAddress
    Return Mode Ptr: 529893228544
    WARNING: Mode: Buffer.   TypeOf:GetAddressByPointer
    Buffer Mode Ptr: 529893228544
    WARNING: Mode: [REF].    TypeOf:GetAddressByReference
    Pinned Mode Ptr: 529893228544
    WARNING: Mode: GCHandle. TypeOf:GetAddressByPointer
    GCHandle Mode Ptr: 529893228544
    
    Remote Mode Test
    * Manual Check
    Callback TEB: 0x7B56600000
    PID: 4868, TID: 10676
    PID match? True, TID match? True
    * Callback Check
    WARNING: Mode 'Remote' is not supported in this host yet. Skipping execution.
    
    Code --> !
    Code:
    <#
    * Thread Environment Block (TEB)
    * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
    
    * Process Environment Block (PEB)
    * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/peb/index.htm
    
    [TEB]
    --> NT_TIB NtTib; 0x00
    ---->
        Struct {
        ...
        PNT_TIB Self; <<<<< 0x30
        } NT_TIB
    #>
    Function NtCurrentTeb {
        param (
            # Mode options for retrieving the TEB address:
            # Return   -> value returned directly in CPU register
            # Pinned   -> use a managed variable pinned in memory
            # Buffer   -> use an unmanaged temporary buffer
            # GCHandle -> use a GCHandle pinned buffer
            # Remote   -> placeholder mode (not supported in this host)
            [Parameter(Mandatory = $false, Position = 1)]
            [ValidateSet("Return" ,"Pinned", "Buffer", "GCHandle", "Remote")]
            [string]$Mode = "Return",
    
            # Allocation method for virtual memory
            [Parameter(Mandatory = $false, Position = 2)]
            [ValidateSet("Base", "Extend")]
            [string]$Method = "Base",
    
            # Optional flags to select which fields to read from TEB/PEB
            [switch]$ClientID,
            [switch]$Peb,
            [switch]$Ldr,
            [switch]$Parameters,
     
            # Enable logging/debug output
            [Parameter(Mandatory = $false, Position = 7)]
            [switch]$Log = $false,
    
            # Self Check Function
            [Parameter(Mandatory = $false, Position = 8)]
            [switch]$SelfCheck
        )
    
    if ($SelfCheck) {
        Clear-Host
        Write-Host
        $isX64 = [IntPtr]::Size -gt 4
    
        Write-Host "`nGetCurrentProcessId Test" -ForegroundColor Green
        $Offset = if ($isX64) {0x40} else {0x20}
        $procPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), $Offset)
        Write-Host ("TEB offset 0x{0:X} value: {1}" -f $Offset, $procPtr)
        $clientIDProc = [Marshal]::ReadIntPtr((NtCurrentTeb -ClientID), 0x0)
        Write-Host ("ClientID Process Pointer: {0}" -f $clientIDProc)
        Write-Host ("GetCurrentProcessId(): {0}" -f [TEB]::GetCurrentProcessId())
    
        Write-Host "`nGetCurrentThreadId Test" -ForegroundColor Green
        $threadPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), ($Offset + [IntPtr]::Size))
        Write-Host ("TEB offset 0x{0:X} value: {1}" -f ($Offset + [IntPtr]::Size), $threadPtr)
        $clientIDThread = [Marshal]::ReadIntPtr((NtCurrentTeb -ClientID), [IntPtr]::Size)
        Write-Host ("ClientID Thread Pointer: {0}" -f $clientIDThread)
        Write-Host ("GetCurrentThreadId(): {0}" -f [TEB]::GetCurrentThreadId())
    
        Write-Host "`nRtlGetCurrentPeb Test" -ForegroundColor Green
    
        # Offset-based read from TEB
        $Offset = if ($isX64) {0x60} else {0x30}
        $pebPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), $Offset)
        Write-Host ("TEB offset 0x{0:X} value: {1}" -f $Offset, $pebPtr)
    
        # Using NtCurrentTeb -Peb mode
        $pebViaFunction = NtCurrentTeb -Peb
        Write-Host ("NtCurrentTeb -Peb returned: {0}" -f $pebViaFunction)
    
        # Using [TEB] helper function
        $pebViaTEB = [TEB]::RtlGetCurrentPeb()
        Write-Host ("RtlGetCurrentPeb(): {0}" -f $pebViaTEB)
    
        Write-Host "`nRtlGetCurrentServiceSessionId Test" -ForegroundColor Green
        $serviceSessionId = [TEB]::RtlGetCurrentServiceSessionId()
        Write-Host ("Service Session Id: {0}" -f $serviceSessionId)
        $Offset = if ($isX64) {0x90} else {0x50}
        $sessionPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Peb), $Offset)
        Write-Host ("PEB offset 0x{0:X} value: {1}" -f $Offset, $sessionPtr)
    
        Write-Host "`nRtlGetCurrentTransaction Test" -ForegroundColor Green
        $transaction = [TEB]::RtlGetCurrentTransaction()
        Write-Host ("Current Transaction: {0}" -f $transaction)
        $Offset = if ($isX64) {0x17B8} else {0x0FAC}
        $txnPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Peb), $Offset)
        Write-Host ("PEB offset 0x{0:X} value: {1}" -f $Offset, $txnPtr)
    
        Write-Host "`nRtlGetCurrentUmsThread Test" -ForegroundColor Green
        $Offset = if ($isX64) {0x1480} else {0x0E10}
        $umsPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), $Offset)
        Write-Host ("TEB offset 0x{0:X} value: {1}" -f $Offset, $umsPtr)
    
        $ppTEB = [IntPtr]::new(1)
        $status = [TEB]::RtlGetCurrentUmsThread([ref]$ppTEB)
        Write-Host ("Status: 0x{0:X}" -f $status)
        Write-Host ("UMS TEB pointer: {0}" -f $ppTEB)
    
        Write-Host "`nNtCurrentTeb Mode Test" -ForegroundColor Green
        $defaultPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Log), [IntPtr]::Size)
        Write-Host ("Default Mode Ptr: {0}" -f $defaultPtr)
        $returnPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Return -Log), [IntPtr]::Size)
        Write-Host ("Return Mode Ptr: {0}" -f $returnPtr)
    
        $bufferPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Buffer -Log), [IntPtr]::Size)
        Write-Host ("Buffer Mode Ptr: {0}" -f $bufferPtr)
        $pinnedPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Pinned -Log), [IntPtr]::Size)
        Write-Host ("Pinned Mode Ptr: {0}" -f $pinnedPtr)
        $gcHandlePtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode GCHandle -Log), [IntPtr]::Size)
        Write-Host ("GCHandle Mode Ptr: {0}" -f $gcHandlePtr)
    
        if (!$isX64) { return }
    
        Write-Host "`nRemote Mode Test" -ForegroundColor Green
        Write-Host "* Manual Check" -ForegroundColor Magenta
        $callbackDelegate = [TEB]::GetCallback()
        $callbackDelegate.Invoke((NtCurrentTeb))
        Write-Host "* Callback Check" -ForegroundColor Magenta
        NtCurrentTeb -Mode Remote
    
        Write-Host
        return
    }
    
    if ($Ldr -or $Parameters) {
      $Peb = $true
    }
    if ($Ldr -and $Parameters) {
        throw "Cannot specify both -Ldr and -Parameters. Choose one."
    }
    if ($ClientID -and $Peb) {
        throw "Cannot specify both -ClientID and -Peb. Choose one."
    }
    
    if ($Mode -eq 'Remote') {
        Write-Warning "Mode 'Remote' is not supported in this host yet. Skipping execution."
        return
    }
    
    if (!([PSTypeName]'TEB').Type) {
        Add-Type -TypeDefinition @"
        using System;
        using System.Runtime.InteropServices;
    
        public static class TEB {
    
            public delegate IntPtr GetAddress();
            public delegate void   GetAddressByPointer(IntPtr Ret);
            public delegate void   GetAddressByReference(ref IntPtr Ret);
    
            [UnmanagedFunctionPointer(CallingConvention.StdCall)]
            public delegate void CallbackDelegate(IntPtr value);
    
            public static CallbackDelegate GetCallback()
            {
                return new CallbackDelegate((IntPtr val) =>
                {
                    IntPtr uniqueProcessIdPtr = Marshal.ReadIntPtr(val, 0x40);
                    IntPtr uniqueThreadIdPtr = Marshal.ReadIntPtr(val, 0x48);
    
                    uint pidApi = GetCurrentProcessId();
                    uint tidApi = GetCurrentThreadId();
    
                    long pidFromTeb64 = uniqueProcessIdPtr.ToInt64();
                    uint pidFromTeb32 = (uint)pidFromTeb64;
    
                    long tidFromTeb64 = uniqueThreadIdPtr.ToInt64();
                    uint tidFromTeb32 = (uint)tidFromTeb64;
    
                    Console.WriteLine("Callback TEB: 0x{0:X}", val.ToInt64());
                    Console.WriteLine("PID: {0}, TID: {1}", pidFromTeb32, tidFromTeb32);
                    Console.WriteLine("PID match? {0}, TID match? {1}", pidApi==pidFromTeb32, tidApi==tidFromTeb32);
                });
            }
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr CreateRemoteThreadEx(
                IntPtr hProcess,
                IntPtr lpThreadAttributes,       // SECURITY_ATTRIBUTES*; null => IntPtr.Zero
                UIntPtr dwStackSize,
                IntPtr lpStartAddress,           // LPTHREAD_START_ROUTINE (function pointer)
                IntPtr lpParameter,              // LPVOID
                uint dwCreationFlags,
                IntPtr lpAttributeList,          // LPPROC_THREAD_ATTRIBUTE_LIST; null => IntPtr.Zero
                out uint lpThreadId               // optional thread id; out 0 if not needed
            );
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern uint WaitForSingleObject(
                IntPtr hHandle,
                uint dwMilliseconds
            );
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int ZwAllocateVirtualMemory(
                IntPtr ProcessHandle,
                ref IntPtr BaseAddress,
                UIntPtr ZeroBits,
                ref UIntPtr RegionSize,
                uint AllocationType,
                uint Protect
            );
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int ZwAllocateVirtualMemoryEx(
                IntPtr ProcessHandle,
                ref IntPtr BaseAddress,
                ref UIntPtr RegionSize,
                uint AllocationType,
                uint Protect,
                IntPtr ExtendedParameters,
                uint ParameterCount
            );
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int ZwFreeVirtualMemory(
                IntPtr ProcessHandle,
                ref IntPtr BaseAddress,
                ref UIntPtr RegionSize,
                uint FreeType
            );
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern uint GetCurrentProcessId();
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern uint GetCurrentThreadId();
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr RtlGetCurrentPeb();
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr RtlGetCurrentServiceSessionId();
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr RtlGetCurrentTransaction();
    
            [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int RtlGetCurrentUmsThread(ref IntPtr ppTEB);
        }
    "@ -PassThru | Out-Null
    }
    function Build-ASM-Shell {
    
        <#
        Online x86 / x64 Assembler and Disassembler
        https://defuse.ca/online-x86-assembler.htm
    
        add rax, 0x??           --> Add 0x?? Bytes, From Position
        mov Type, [Type + 0x??] --> Move to 0x?? Offset, read Value
    
        So,
        Example Read Pointer Value,
        & Also,
        Add 0x?? From Value
    
        // Return to gs:[0x00], store value at rax
        // (NtCurrentTeb) -eq ([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))
        // ([marshal]::ReadIntPtr((NtCurrentTeb),0x40)) -eq ([marshal]::ReadIntPtr((([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))),0x40))
        ** mov rax, gs:[0x30]
    
        // Move (de-ref`) -or Add\[+], and store value
        ** mov Type, [Type + 0x??]
        ** add rax,  0x??
    
        // Ret value
        ** Ret
        #>
    
        $shellcode        = [byte[]]@()
        $is64             = [IntPtr]::Size -gt 4
        $ret              = [byte[]]([byte]0xC3)
    
        if ($is64) {
            $addClient = [byte[]]@([byte]0x48,[byte]0x83,[byte]0xC0,[byte]0x40)  # add rax, 0x40          // gs:[0x40]
            $movPeb    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x60)  # mov rax, [rax + 0x60]  // gs:[0x60] // RtlGetCurrentPeb
            $movLdr    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x18)  # mov rax, [rax + 0x18]
            $movParams = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x20)  # mov rax, [rax + 0x20]
            $basePtr   = [byte[]]@([byte]0x65,[byte]0x48,[byte]0x8B,[byte]0x04,  # mov rax, gs:[0x30]     #// Self dereference pointer at gs:[0x30],
                                   [byte]0x25,[byte]0x30,[byte]0x00,[byte]0x00,                           #// so, effectually, return to gs->0x0
                                   [byte]0x00)
            $InByRef  = [byte[]]@([byte]0x48,[byte]0x89,[byte]0x01)              # mov [rcx], rax         #// moves the 64-bit value from the RAX register
                                                                                                          #// into the memory location pointed to by the RCX register.
        }
        else {
            $addClient = [byte[]]@([byte]0x83,[byte]0xC0,[byte]0x20)             # add eax, 0x20          // fs:[0x20]
            $movPeb    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x30)             # mov eax, [eax + 0x30]  // fs:[0x30] // RtlGetCurrentPeb
            $movLdr    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x0C)             # mov eax, [eax + 0x0c]
            $movParams = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x10)             # mov eax, [eax + 0x10]
            $basePtr   = [byte[]]@([byte]0x64,[byte]0xA1,[byte]0x18,             # mov eax, fs:[0x18]     #// Self dereference pointer at fs:[0x18],
                                   [byte]0x00,[byte]0x00,[byte]0x00)                                      #// so, effectually, return  to fs->0x0
            $InByRef = [byte[]]@(
                [byte]0x8B, [byte]0x4C, [byte]0x24, [byte]0x04,                  # mov ecx, [esp + 4]     ; load first argument pointer from stack into ECX
                [byte]0x89, [byte]0x01                                           # mov [ecx], eax         ; store 32-bit value from EAX into memory pointed by ECX
            )
        }
    
        if ($Mode -eq 'Remote') {
     
            # Test only, work well in C#, PS` well, no,
            # and it also x64 version.!
    
            # x64 shellcode: call callback with TEB as argument
            [byte[]] $shellcode = [byte[]]@(
                # Save the callback pointer from rcx to rax
                0x48, 0x89, 0xC8,       # mov rax, rcx
    
                # Get the TEB address from gs:[0x30] and store it in rcx
                0x65, 0x48, 0x8B, 0x0C, 0x25, 0x30, 0x00, 0x00, 0x00, # mov rcx, gs:[0x30]
    
                # Align the stack to a 16-byte boundary.
                0x48, 0x83, 0xEC, 0x28, # sub rsp, 40
    
                # Call the function pointer saved in rax
                0xFF, 0xD0,             # call rax
    
                # Restore the stack
                0x48, 0x83, 0xC4, 0x28, # add rsp, 40
    
                # Return from the shellcode
                0xC3                    # ret
            )
            return $shellcode
        }
    
    
        $shellcode = $basePtr
        if ($ClientID) { $shellcode += $addClient }
        if ($Peb) {
            $shellcode += $movPeb
            if ($Ldr) { $shellcode += $movLdr }
            if ($Parameters) { $shellcode += $movParams }
        }
        if ($Mode -ne "Return") {$shellcode += $InByRef}
        $shellcode += $ret
        $shellcode
    }
     
        $shellcode = Build-ASM-Shell
        $len = $shellcode.Length
        $baseAddress = [IntPtr]::Zero
        $regionSize = [uintptr]::new($len)
     
        $ntStatus = if ($Method -eq "Base") {
            [TEB]::ZwAllocateVirtualMemory(
               [IntPtr]::new(-1),
               [ref]$baseAddress,
               [UIntPtr]::new(0x00),
               [ref]$regionSize,
               0x3000, 0x40)
        } else {
            [TEB]::ZwAllocateVirtualMemoryEx(
               [IntPtr]::new(-1),
               [ref]$baseAddress,
               [ref]$regionSize,
               0x3000, 0x40,
               [IntPtr]0,0)
        }
    
        if ($Mode -eq 'Remote') {
            $callbackDelegate = [TEB]::GetCallback()
            $callbackHandle = [GCHandle]::Alloc($callbackDelegate)
            $callbackPtr = [Marshal]::GetFunctionPointerForDelegate($callbackDelegate)
    
            # Create remote thread to execute shellcode with callback pointer
            $createdThreadId = 0
            $Prochandle = [Process]::GetCurrentProcess().Handle
            $threadHandle = [TEB]::CreateRemoteThreadEx(
                $Prochandle,            # pseudo handle // [IntPtr]::new(-1)
                [IntPtr]::Zero,         # no SECURITY_ATTRIBUTES
                [UIntPtr]::Zero,        # default stack size
                $baseAddress,           # shellcode start
                $callbackPtr,           # passed in RCX
                0,                      # run immediately
                [IntPtr]::Zero,         # no attributes
                [ref]$createdThreadId
            )
            $callbackHandle.Free()
    
            if ($threadHandle -eq [IntPtr]::Zero) {
                Write-Host "CreateRemoteThreadEx failed: $([Marshal]::GetLastWin32Error())"
            } else {
                Write-Host "Thread created. TID = $createdThreadId"
                [TEB]::WaitForSingleObject($threadHandle, 0xFFFFFFFF)
            }
        }
    
    
        if ($ntStatus -ne 0) {
            throw "ZwAllocateVirtualMemory failed with result: $ntStatus"
        }
    
        try {
            $Address = [IntPtr]::Zero
            [marshal]::Copy($shellcode, 0x00, $baseAddress, $len)
    
            switch ($Mode) {
              "Return" {
                if ($log) {
                   Write-Warning "Mode: Return.   TypeOf:GetAddress"
                }
                $Address = [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddress]).Invoke()
              }
              "Buffer" {
                if ($log) {
                   Write-Warning "Mode: Buffer.   TypeOf:GetAddressByPointer"
                }
                $baseAdd = [marshal]::AllocHGlobal([IntPtr]::Size)
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByPointer]).Invoke($baseAdd)
                $Address = [marshal]::ReadIntPtr($baseAdd)
                [marshal]::FreeHGlobal($baseAdd)
              }
              "GCHandle" {
                if ($log) {
                   Write-Warning "Mode: GCHandle. TypeOf:GetAddressByPointer"
                }
                $gcHandle = [GCHandle]::Alloc($Address, [GCHandleType]::Pinned)
                $baseAdd = $gcHandle.AddrOfPinnedObject()
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByPointer]).Invoke($baseAdd)
                $gcHandle.Free()
              }
              "Pinned" {
                if ($log) {
                   Write-Warning "Mode: [REF].    TypeOf:GetAddressByReference"
                }
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByReference]).Invoke([ref]$Address)
              }
            }
            return $Address
        }
        finally {
            [TEB]::ZwFreeVirtualMemory(
                [IntPtr]::new(-1),
                [ref]$baseAddress,
                [ref]$regionSize,
                0x4000) | Out-Null
        }
    }
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  4. Dark Vador

    Dark Vador X Æ A-12

    Feb 2, 2011
    4,806
    7,075
    150
    #4 Dark Vador, Sep 16, 2025 at 19:45
    Last edited: Sep 16, 2025 at 20:00
    (OP)
    So, darky, tried move lot of C# logic, into PS`1
    and now remote method, work from ps`1,
    So, it now have Ret Method, Using Params Intptr, By Ref,
    and also by call back delegate, Defination --> in C# Code,
    logic now fully managed by powershell.
    this is very intersting way, to use callback + ASM with powershell.

    So, my first attemp's, ended with ISE crash or fail,
    after few day's, we got a progres. now all work. as it should
    for both arch' x64, x86. And also run fine in ISE enviroment.

    Also, delegate now accept 2 paraemters [this, pTeb], to make asm' logic OK
    [or start overwrite parameters, less ok, but work.!]

    this also can be useful for other things, not just for TEB address
    i think i will use it in future, BUT even for TEB address, its still a good ide'a

    And also mimic same Macro as NtCurrentTeb which cant be accable in managed code
    for safety reason i guess :D
    Code:
    using namespace System
    using namespace System.Diagnostics
    using namespace System.Reflection
    using namespace System.Reflection.Emit
    using namespace System.Management.Automation
    using namespace System.Runtime.InteropServices
    
    <#
    * Thread Environment Block (TEB)
    * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
    
    * Process Environment Block (PEB)
    * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/peb/index.htm
    
    [TEB]
    --> NT_TIB NtTib; 0x00
    ---->
        Struct {
        ...
        PNT_TIB Self; <<<<< gs:[0x30] / fs:[0x18]
        } NT_TIB
    #>
    if (!([PSTypeName]'TEB').Type) {
    $TEB = @"
    using System;
    using System.Runtime.InteropServices;
    
    public static class TEB
    {
        public delegate IntPtr GetAddress();
        public delegate void GetAddressByPointer(IntPtr Ret);
        public delegate void GetAddressByReference(ref IntPtr Ret);
    
        public static IntPtr CallbackResult;
    
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void CallbackDelegate(IntPtr callback, IntPtr TEB);
    
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void RemoteThreadDelgate(IntPtr callback);
    
        public static CallbackDelegate GetCallback()
        {
            return new CallbackDelegate((IntPtr del, IntPtr val) =>
            {
                CallbackResult = val;
            });
        }
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int ZwAllocateVirtualMemory(
            IntPtr ProcessHandle,
            ref IntPtr BaseAddress,
            UIntPtr ZeroBits,
            ref UIntPtr RegionSize,
            uint AllocationType,
            uint Protect
        );
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int ZwAllocateVirtualMemoryEx(
            IntPtr ProcessHandle,
            ref IntPtr BaseAddress,
            ref UIntPtr RegionSize,
            uint AllocationType,
            uint Protect,
            IntPtr ExtendedParameters,
            uint ParameterCount
        );
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int ZwFreeVirtualMemory(
            IntPtr ProcessHandle,
            ref IntPtr BaseAddress,
            ref UIntPtr RegionSize,
            uint FreeType
        );
    
        [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint GetCurrentProcessId();
    
        [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint GetCurrentThreadId();
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr RtlGetCurrentPeb();
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr RtlGetCurrentServiceSessionId();
    
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr RtlGetCurrentTransaction();
    }
    "@
    Add-Type -TypeDefinition $TEB -ErrorAction Stop
    }
    Function NtCurrentTeb {
        param (
            # Mode options for retrieving the TEB address:
            # Return   -> value returned directly in CPU register
            # Pinned   -> use a managed variable pinned in memory
            # Buffer   -> use an unmanaged temporary buffer
            # GCHandle -> use a GCHandle pinned buffer
            # Remote   -> using Callback, to receive to TEB pointer
            [Parameter(Mandatory = $false, Position = 1)]
            [ValidateSet("Return" ,"Pinned", "Buffer", "GCHandle", "Remote")]
            [string]$Mode = "Return",
    
            # Allocation method for virtual memory
            [Parameter(Mandatory = $false, Position = 2)]
            [ValidateSet("Base", "Extend")]
            [string]$Method = "Base",
    
            # Optional flags to select which fields to read from TEB/PEB
            [switch]$ClientID,
            [switch]$Peb,
            [switch]$Ldr,
            [switch]$Parameters,
     
            # Enable logging/debug output
            [Parameter(Mandatory = $false, Position = 7)]
            [switch]$Log = $false,
    
            # Self Check Function
            [Parameter(Mandatory = $false, Position = 8)]
            [switch]$SelfCheck
        )
    
        function Build-ASM-Shell {
    
            <#
            Online x86 / x64 Assembler and Disassembler
            https://defuse.ca/online-x86-assembler.htm
    
            add rax, 0x??           --> Add 0x?? Bytes, From Position
            mov Type, [Type + 0x??] --> Move to 0x?? Offset, read Value
    
            So,
            Example Read Pointer Value,
            & Also,
            Add 0x?? From Value
    
            // Return to gs:[0x00], store value at rax
            // (NtCurrentTeb) -eq ([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))
            // ([marshal]::ReadIntPtr((NtCurrentTeb),0x40)) -eq ([marshal]::ReadIntPtr((([Marshal]::ReadIntPtr((NtCurrentTeb), 0x30))),0x40))
            ** mov rax, gs:[0x30]
    
            // Move (de-ref`) -or Add\[+], and store value
            ** mov Type, [Type + 0x??]
            ** add rax,  0x??
    
            // Ret value
            ** Ret
            #>
    
            $shellcode        = [byte[]]@()
            $is64             = [IntPtr]::Size -gt 4
            $ret              = [byte[]]([byte]0xC3)
    
            if ($is64) {
                $addClient = [byte[]]@([byte]0x48,[byte]0x83,[byte]0xC0,[byte]0x40)  # add rax, 0x40          // gs:[0x40]
                $movPeb    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x60)  # mov rax, [rax + 0x60]  // gs:[0x60] // RtlGetCurrentPeb
                $movLdr    = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x18)  # mov rax, [rax + 0x18]
                $movParams = [byte[]]@([byte]0x48,[byte]0x8B,[byte]0x40,[byte]0x20)  # mov rax, [rax + 0x20]
                $basePtr   = [byte[]]@([byte]0x65,[byte]0x48,[byte]0x8B,[byte]0x04,  # mov rax, gs:[0x30]     #// Self dereference pointer at gs:[0x30],
                                       [byte]0x25,[byte]0x30,[byte]0x00,[byte]0x00,                           #// so, effectually, return to gs->0x0
                                       [byte]0x00)
                $InByRef  = [byte[]]@([byte]0x48,[byte]0x89,[byte]0x01)              # mov [rcx], rax         #// moves the 64-bit value from the RAX register
                                                                                                              #// into the memory location pointed to by the RCX register.
            }
            else {
                $addClient = [byte[]]@([byte]0x83,[byte]0xC0,[byte]0x20)             # add eax, 0x20          // fs:[0x20]
                $movPeb    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x30)             # mov eax, [eax + 0x30]  // fs:[0x30] // RtlGetCurrentPeb
                $movLdr    = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x0C)             # mov eax, [eax + 0x0c]
                $movParams = [byte[]]@([byte]0x8B,[byte]0x40,[byte]0x10)             # mov eax, [eax + 0x10]
                $basePtr   = [byte[]]@([byte]0x64,[byte]0xA1,[byte]0x18,             # mov eax, fs:[0x18]     #// Self dereference pointer at fs:[0x18],
                                       [byte]0x00,[byte]0x00,[byte]0x00)                                      #// so, effectually, return  to fs->0x0
                $InByRef = [byte[]]@(
                    [byte]0x8B, [byte]0x4C, [byte]0x24, [byte]0x04,                  # mov ecx, [esp + 4]     ; load first argument pointer from stack into ECX
                    [byte]0x89, [byte]0x01                                           # mov [ecx], eax         ; store 32-bit value from EAX into memory pointed by ECX
                )
            }
    
            $shellcode = $basePtr
            if ($ClientID) { $shellcode += $addClient }
            if ($Peb) {
                $shellcode += $movPeb
                if ($Ldr) { $shellcode += $movLdr }
                if ($Parameters) { $shellcode += $movParams }
            }
            if ($Mode -ne "Return") {$shellcode += $InByRef}
            $shellcode += $ret
            $shellcode
        }
    
        if ($SelfCheck) {
            Clear-Host
            Write-Host
            $isX64 = [IntPtr]::Size -gt 4
    
            Write-Host "`nGetCurrentProcessId Test" -ForegroundColor Green
            $Offset = if ($isX64) {0x40} else {0x20}
            $procPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), $Offset)
            Write-Host ("TEB offset 0x{0:X} value: {1}" -f $Offset, $procPtr)
            $clientIDProc = [Marshal]::ReadIntPtr((NtCurrentTeb -ClientID), 0x0)
            Write-Host ("ClientID Process Pointer: {0}" -f $clientIDProc)
            Write-Host ("GetCurrentProcessId(): {0}" -f [TEB]::GetCurrentProcessId())
    
            Write-Host "`nGetCurrentThreadId Test" -ForegroundColor Green
            $threadPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), ($Offset + [IntPtr]::Size))
            Write-Host ("TEB offset 0x{0:X} value: {1}" -f ($Offset + [IntPtr]::Size), $threadPtr)
            $clientIDThread = [Marshal]::ReadIntPtr((NtCurrentTeb -ClientID), [IntPtr]::Size)
            Write-Host ("ClientID Thread Pointer: {0}" -f $clientIDThread)
            Write-Host ("GetCurrentThreadId(): {0}" -f [TEB]::GetCurrentThreadId())
    
            Write-Host "`nRtlGetCurrentPeb Test" -ForegroundColor Green
    
            # Offset-based read from TEB
            $Offset = if ($isX64) {0x60} else {0x30}
            $pebPtr = [Marshal]::ReadIntPtr((NtCurrentTeb), $Offset)
            Write-Host ("TEB offset 0x{0:X} value: {1}" -f $Offset, $pebPtr)
    
            # Using NtCurrentTeb -Peb mode
            $pebViaFunction = NtCurrentTeb -Peb
            Write-Host ("NtCurrentTeb -Peb returned: {0}" -f $pebViaFunction)
    
            # Using [TEB] helper function
            $pebViaTEB = [TEB]::RtlGetCurrentPeb()
            Write-Host ("RtlGetCurrentPeb(): {0}" -f $pebViaTEB)
    
            Write-Host "`nRtlGetCurrentServiceSessionId Test" -ForegroundColor Green
            $serviceSessionId = [TEB]::RtlGetCurrentServiceSessionId()
            Write-Host ("Service Session Id: {0}" -f $serviceSessionId)
            $Offset = if ($isX64) {0x90} else {0x50}
            $sessionPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Peb), $Offset)
            Write-Host ("PEB offset 0x{0:X} value: {1}" -f $Offset, $sessionPtr)
    
            Write-Host "`nRtlGetCurrentTransaction Test" -ForegroundColor Green
            $transaction = [TEB]::RtlGetCurrentTransaction()
            Write-Host ("Current Transaction: {0}" -f $transaction)
            $Offset = if ($isX64) {0x17B8} else {0x0FAC}
            $txnPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Peb), $Offset)
            Write-Host ("PEB offset 0x{0:X} value: {1}" -f $Offset, $txnPtr)
    
            Write-Host "`nNtCurrentTeb Mode Test" -ForegroundColor Green
            $defaultPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Log), [IntPtr]::Size)
            Write-Host ("Default Mode Ptr: {0}" -f $defaultPtr)
            $returnPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Return -Log), [IntPtr]::Size)
            Write-Host ("Return Mode Ptr: {0}" -f $returnPtr)
    
            $bufferPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Buffer -Log), [IntPtr]::Size)
            Write-Host ("Buffer Mode Ptr: {0}" -f $bufferPtr)
            $pinnedPtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Pinned -Log), [IntPtr]::Size)
            Write-Host ("Pinned Mode Ptr: {0}" -f $pinnedPtr)
            $gcHandlePtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode GCHandle -Log), [IntPtr]::Size)
            Write-Host ("GCHandle Mode Ptr: {0}" -f $gcHandlePtr)
            $callbackHandlePtr = [Marshal]::ReadIntPtr((NtCurrentTeb -Mode Remote -Log), [IntPtr]::Size)
            Write-Host ("Remote Mode Ptr: {0}" -f $callbackHandlePtr)
    
            Write-Host
            return
        }
    
        if ($Ldr -or $Parameters) {
          $Peb = $true
        }
        if ($Ldr -and $Parameters) {
            throw "Cannot specify both -Ldr and -Parameters. Choose one."
        }
        if ($ClientID -and $Peb) {
            throw "Cannot specify both -ClientID and -Peb. Choose one."
        }
    
        if ($Mode -eq 'Remote') {
            [TEB]::CallbackResult = 0
            $callback = [Teb]::GetCallback();
            $callbackPtr = [Marshal]::GetFunctionPointerForDelegate($callback);
    
            if ([IntPtr]::Size -eq 8)
            {
                $shellcode = [byte[]]@(
                    0x48, 0x89, 0xC8,                  ## mov rax, rcx      ## Move function address (first param) to rax.
                    0x65, 0x48, 0x8B, 0x14, 0x25, 0x30, 0x00, 0x00, 0x00, ## mov rdx, gs:[0x30]  ## Set second param (rdx) from a known memory location.
                    0x48, 0x83, 0xEC, 0x28,            ## sub rsp, 40       ## Allocate space on the stack for the call.
                    0xFF, 0xD0,                        ## call rax          ## Call the function using the address from rax.
                    0x48, 0x83, 0xC4, 0x28,            ## add rsp, 40       ## Clean up the stack.
                    0xC3                               ## ret               ## Return to the caller.
                );
            }
            elseif ([IntPtr]::Size -eq 4)
            {
                $shellcode = [byte[]]@(
                    0x64, 0xA1, 0x18, 0x00, 0x00, 0x00, ## mov eax, fs:[0x18] ## Get a specific address from the Thread Information Block.
                    0x50,                               ## push eax           ## Push this address onto the stack to use later.
                    0x8B, 0x44, 0x24, 0x08,             ## mov eax, [esp + 8] ## Get a second value (a function pointer or argument) from the stack.
                    0x50,                               ## push eax           ## Push this value onto the stack as well.
                    0xFF, 0x14, 0x24,                   ## call [esp]         ## Call the function whose address is now at the top of the stack.
                    0x83, 0xC4, 0x08,                   ## add esp, 8         ## Clean up the two values we pushed on the stack.
                    0xC3                                ## ret                ## Return to the calling code.
                )
            }
            $baseAddress = [IntPtr]::Zero;
            $regionSize = [UIntPtr]::new($shellcode.Length);
            $status = [TEB]::ZwAllocateVirtualMemory(
                [IntPtr]::new(-1),
                [ref] $baseAddress,
                [UIntPtr]::new(0x00),
                [ref] $regionSize,
                0x3000,   ## MEM_COMMIT | MEM_RESERVE
                0x40      ## PAGE_EXECUTE_READWRITE
            );
    
            if ($status -ne 0)
            {
                return;
            }
    
            ## Copy shellcode to allocated memory
            [Marshal]::Copy($shellcode, 0, $baseAddress, $shellcode.Length);
    
            $handle = [IntPtr]::Zero
            try
            {
                $Caller = [Marshal]::GetDelegateForFunctionPointer($baseAddress, [TEB+RemoteThreadDelgate]);
                $handle = [gchandle]::Alloc($Caller, [GCHandleType]::Normal)
                $Caller.Invoke($callbackPtr);
            }
            catch {}
            finally
            {
                Start-Sleep -Milliseconds 400
                if ($handle.IsAllocated) { $handle.Free() }
            }
    
            $status = [TEB]::ZwFreeVirtualMemory(
                [IntPtr]::new(-1),
                [ref] $baseAddress,
                [ref] $regionSize,
                0x8000 ## MEM_RELEASE
            );
    
            if ($Log) {
                Write-Warning "Mode: Remote. TypeOf: Callback Delegate"
            }
     
            if (-not [TEB]::CallbackResult -or [TEB]::CallbackResult -eq [IntPtr]::Zero) {
                throw "Failure to get results from callback!"
            }
    
            $isX64 = [IntPtr]::Size -eq 8
    
            if ($ClientID) {
                if ($isX64) {
                    return [IntPtr]::Add([TEB]::CallbackResult, 0x40)
                } else {
                    return [IntPtr]::Add([TEB]::CallbackResult, 0x20)
                }
            }
    
            if ($Peb) {
                if ($isX64) {
                    $CallbackResult = [Marshal]::ReadIntPtr([TEB]::CallbackResult, 0x60)
                    if ($Ldr) { $CallbackResult = [Marshal]::ReadIntPtr($CallbackResult, 0x18) }
                    if ($Parameters) { $CallbackResult = [Marshal]::ReadIntPtr($CallbackResult, 0x20) }
                } else {
                    $CallbackResult = [Marshal]::ReadIntPtr([TEB]::CallbackResult, 0x30)
                    if ($Ldr) { $CallbackResult = [Marshal]::ReadIntPtr($CallbackResult, 0x0c) }
                    if ($Parameters) { $CallbackResult = [Marshal]::ReadIntPtr($CallbackResult, 0x10) }
                }
                return $CallbackResult
            }
    
            return [TEB]::CallbackResult
        }
     
        $shellcode = Build-ASM-Shell
        $len = $shellcode.Length
        $baseAddress = [IntPtr]::Zero
        $regionSize = [uintptr]::new($len)
     
        $ntStatus = if ($Method -eq "Base") {
            [TEB]::ZwAllocateVirtualMemory(
               [IntPtr]::new(-1),
               [ref]$baseAddress,
               [UIntPtr]::new(0x00),
               [ref]$regionSize,
               0x3000, 0x40)
        } else {
            [TEB]::ZwAllocateVirtualMemoryEx(
               [IntPtr]::new(-1),
               [ref]$baseAddress,
               [ref]$regionSize,
               0x3000, 0x40,
               [IntPtr]0,0)
        }
    
    
        if ($ntStatus -ne 0) {
            throw "ZwAllocateVirtualMemory failed with result: $ntStatus"
        }
    
        try {
            $Address = [IntPtr]::Zero
            [marshal]::Copy($shellcode, 0x00, $baseAddress, $len)
    
            switch ($Mode) {
              "Return" {
                if ($log) {
                   Write-Warning "Mode: Return.   TypeOf:GetAddress"
                }
                $Address = [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddress]).Invoke()
              }
              "Buffer" {
                if ($log) {
                   Write-Warning "Mode: Buffer.   TypeOf:GetAddressByPointer"
                }
                $baseAdd = [marshal]::AllocHGlobal([IntPtr]::Size)
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByPointer]).Invoke($baseAdd)
                $Address = [marshal]::ReadIntPtr($baseAdd)
                [marshal]::FreeHGlobal($baseAdd)
              }
              "GCHandle" {
                if ($log) {
                   Write-Warning "Mode: GCHandle. TypeOf:GetAddressByPointer"
                }
                $gcHandle = [GCHandle]::Alloc($Address, [GCHandleType]::Pinned)
                $baseAdd = $gcHandle.AddrOfPinnedObject()
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByPointer]).Invoke($baseAdd)
                $gcHandle.Free()
              }
              "Pinned" {
                if ($log) {
                   Write-Warning "Mode: [REF].    TypeOf:GetAddressByReference"
                }
                [Marshal]::GetDelegateForFunctionPointer(
                    $baseAddress,[TEB+GetAddressByReference]).Invoke([ref]$Address)
              }
            }
            return $Address
        }
        finally {
            [TEB]::ZwFreeVirtualMemory(
                [IntPtr]::new(-1),
                [ref]$baseAddress,
                [ref]$regionSize,
                0x4000) | Out-Null
        }
    }
    
    NtCurrentTeb -SelfCheck
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...