Created
May 12, 2025 20:07
-
-
Save gremlinbeet/4960774f8a08bff6b1667eb69da24f7b to your computer and use it in GitHub Desktop.
Revisions
-
gremlinbeet created this gist
May 12, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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