Skip to content

Instantly share code, notes, and snippets.

@gremlinbeet
Created May 12, 2025 20:07
Show Gist options
  • Save gremlinbeet/4960774f8a08bff6b1667eb69da24f7b to your computer and use it in GitHub Desktop.
Save gremlinbeet/4960774f8a08bff6b1667eb69da24f7b to your computer and use it in GitHub Desktop.

Revisions

  1. gremlinbeet created this gist May 12, 2025.
    107 changes: 107 additions & 0 deletions PsSyscallProviderDispatch.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    // Pseudocode and structs for nt!PsSyscallProviderDispatch.
    // For ntosknrl win11 24H2 10.0.26100.1742.
    // Restored by Cyra, adjusted by @sixtyvividtails.
    //
    // See actual research:
    // by @gal_kristal: https://gist.github.com/Kristal-g/eec050b3fcea2a77715ef0cff4acf841
    // by @0xfluxsec: https://fluxsec.red/alt-syscalls-for-windows-11


    // name's mine // @gal_kristal: _PS_SYSCALL_PROVIDER_SERVICE_DESCRIPTOR_GROUP
    struct $SVC_DESCRIPTOR
    {
    /*00*/ void* HandlersBase; // all syscall handlers are at HandlersBase + offset
    /*08*/ $SVC_TABLE* LowTable; // for syscall numbers < 0x1000
    /*10*/ $SVC_TABLE* HighTable; // for syscall numbers >= 0x1000
    /*18*/ // size
    };


    // name's mine // @gal_kristal: _PS_SYSCALL_PROVIDER_SERVICE_DESCRIPTOR
    struct $SVC_TABLE
    {
    /*00*/ uint SyscallEntriesCount; // number of entries in table, up to 0x1000
    /*04*/ $SYSCALL_ENTRY SyscallEntry[]; // indexed from 0 to SyscallEntriesCount-1
    /*4004*/ // maximum size
    };


    // name's mine // @gal_kristal: _PS_SYSCALL_PROVIDER_SERVICE_ENTRY
    struct $SYSCALL_ENTRY
    {
    uint StackArgsCount: 4; // number of non-register arguments
    uint NeedsGenericDispatch: 1; // PspSyscallProviderServiceDispatch[Generic]
    uint Reserved: 3;
    uint PackedOffset: 24; // real offset = PackedOffset << 4

    operator uint&() { return *(uint*)this; }
    };


    // Up to 0x20 distinct descriptors allowed system-wide.
    // Each process bound to one via EPROCESS.SyscallProviderDispatchContext.Slot.
    $SVC_DESCRIPTOR PspServiceDescriptorGroupTable[0x20];



    // Invoked from nt!KiSystemCall64 when
    // (ETHREAD.Tcb.Header.Minimal or ETHREAD.Tcb.Header.AltSyscall)
    //
    // Return values:
    // <1: handled, trapFrame->Rax contains return status
    // =1: needs regular syscall dispatch in KiSystemCall64
    // >1: raise STATUS_INVALID_SYSTEM_SERVICE
    schar PsSyscallProviderDispatch(_Inout_ _KTRAP_FRAME *trapFrame):
    ETHREAD* currentThread = PsGetCurrentThread()
    if currentThread->Tcb.Header.Minimal:
    PsPicoSystemCallDispatch(trapFrame) // invokes PspPicoProviderRoutines[1]
    return 0

    // notice potential TOCTOU? Hint: NtSetContextThread (most likely unusable)
    uint syscallNumber = trapFrame->Rax & ~0x6000
    uint syscallIndex = syscallNumber & 0xFFF
    bool isHighSyscall = (syscallNumber & 0x1000) != 0
    EPROCESS* currentProcess = IoThreadToProcess(currentThread)
    uint slot = currentProcess->SyscallProviderDispatchContext.Slot
    if slot >= 0x20:
    KeBugCheckEx(0x1E0, 5, slot, currentProcess->SyscallProvider, 0)
    $SVC_DESCRIPTOR& svcDescriptor = PspServiceDescriptorGroupTable[slot]
    $SVC_TABLE* svcTable = isHighSyscall? svcDescriptor.HighTable: svcDescriptor.LowTable
    if not svcTable:
    return 1 // needs regular dispatch
    if syscallIndex >= svcTable->SyscallEntriesCount:
    trapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE // 0xC000001C
    return 0
    $SYSCALL_ENTRY syscallEntry = svcTable->SyscallEntry[syscallIndex]
    if syscallEntry == 0:
    return 1 // needs regular dispatch
    if syscallEntry == 1:
    return 2 // raise STATUS_INVALID_SYSTEM_SERVICE

    if isHighSyscall:
    NTSTATUS st = PspEnsureGuiThreadAndBatchFlush(currentThread)
    if st == STATUS_UNSUCCESSFUL:
    // transform status if needed using extra table of bytes beyond packed shadow table
    schar* shadowSyscallInfo = (schar*)KeServiceDescriptorTableShadow[1].Base
    + sizeof(uint) * KeServiceDescriptorTableShadow[1].Limit
    if shadowSyscallInfo[syscallIndex] == 1:
    st = STATUS_INVALID_SYSTEM_SERVICE // was not intended to be called
    if FAILED(st):
    trapFrame->Rax = st
    return 0

    // unlike regular syscall packed tables, offset here is unsigned; so one can specify
    // driver image base as svcDescriptor.HandlersBase, then use RVAs for handlers
    uint offset = syscallEntry.PackedOffset << 4
    void* syscallHandler = (char*)svcDescriptor.HandlersBase + offset // function to invoke
    NTSTATUS st = STATUS_SUCCESS
    if syscallEntry.NeedsGenericDispatch:
    int rez = PspSyscallProviderServiceDispatchGeneric(trapFrame, syscallHandler,
    syscallEntry.StackArgsCount, syscallNumber, &st)
    if rez:
    return (schar)rez
    else:
    st = PspSyscallProviderServiceDispatch(trapFrame, syscallHandler,
    syscallEntry.StackArgsCount)
    trapFrame->Rax = st
    return 0