"Fast System Call" implementation of NTCALL --------------------------------------------- Windows NT/x86 uses for system calls (= NTCALLs -> user-mode/kernel-mode -> Intel: ring-3/ring-0 transitions) interrupt 0x2e. Handler for Int 0x2e has name KiSystemService and is used for KM/KM transitions too. It is well documented, everyone knows (or can read/find) how this interface works, what happens inside. Windows 2000/x86 has in addition built-in support for transitions via "Fast System Call" instructions SYSENTER/SYSEXIT. Descriptions for those Pentium II+ instructions can be found in Intel Architecture Software Developer's Manual Volume 2: Instruction Set Reference, pages 721..727 (3-681..3-687). Handler for SYSENTER has name KiFastCallEntry and is located at ~ KiSystemService-0x100 in ntoskrnl.exe. ------------------------------------------------------------------------------ Let's admit KiFastCallEntry is invoked by ring-3 SYSENTER stub similar to INT2E stub (-> Int 0x2e is replaced with SYSENTER): FastCallRing3Stub: MOV EAX, NTCALLnumber LEA EDX, [ESP+4] ;pointer to parameters SYSENTER ;JMP FastCallEntry RET xxx Here is the prologue of KiFastCallEntry: MOV ESP, SS:[0xFFDFF040] MOV ESP, [ESP+4] ;this is ring-0 stack for FastCall PUSH 0x23 ;imitate ring-3_SS PUSH EDX ;ring-3_ESP + 4 (see LEA EDX, [ESP+4] above) SUB DWORD PTR [ESP], 4 ;ring-3_ESP + 4 - 4 (-> ring-3_ESP) PUSHFD OR DWORD PTR [ESP], 0x200 ;imitate ring-3_EFlags, IRQs enabled PUSH 0x1B ;imitate ring-3_CS PUSH ECX ;this should be ring-3_EIP ? ;..fill in KeTrapFrame ;..go to common NTCALL dispatch code Imitation is clear: common NTCALL dispatch code uses pointers to the stack as it would be set by Int 0x2e (from protected mode ring-3). ECX should contain ring-3_EIP. Then I suggest this form of FastCallRing3Stub: MOV EAX, NTCALLnumber LEA EDX, [ESP+4] LEA ECX, SYSEXIThere ;or shorter MOV ECX, OFFSET SYSEXIThere SYSENTER SYSEXIThere: RET xxx Here comes the epilogue (common for KiSystemService and KiFastCallEntry) as a part of KiServiceExit (similar code is used in KiSetLowWaitHighThread too): TEST KeFeatureBits, 0x1000 ;Does CPU support Fast System Call? JZ ReturnFromInterrupt ; no -> iret TEST DWORD PTR [ESP+4], 1 ;Invoked from ring-3? JZ ReturnFromInterrupt ; no -> iret TEST DWORD PTR [ESP+8], 0x20000 ;Invoked from V86? JNZ ReturnFromInterrupt ; yes -> iret POP EDX ;ring-3_EIP ADD ESP, 8 ;remove imitation (CS and EFlags) POP ECX ;ring-3_ESP STI SYSEXIT ReturnFromInterrupt: IRETD (There is also KiServiceExit2 which is KiServiceExit without SYSEXIT stuff) ------------------------------------------------------------------------------ So we've seen SYSEXIT but where is SYSENTER? Logically, it should be inside user-mode components. Int 0x2e is extensively used inside ntdll.dll, user32.dll, gdi32.dll, imm32.dll, winsrv.dll. But they don't contain SYSENTER nowadays. So what are the perspectives? I think future service packs or the next NT versions will contain 2 types of user DLLs: 1st for poor CPUs (standard Int 0x2e), 2nd for Pentium II+ CPUs (SYSENTER). Or there will be only one type of user DLL with something like: MOV EAX, NTCALLnumber LEA EDX, [ESP+4] TEST CPUfeatures, SupportsFastCall JE DoInt2e LEA ECX, SYSENTERhere SYSENTER DoInt2e: INT 0x2e SYSENTERhere: RET xxx If ECX will be used as I suggest I would add to KiFastCallEntry for sure: ;... CMP ECX, MmUserProbeAddress JAE ThrowAccessViolation ;... What can cause difficulties is SYSENTER from V86 mode. ------------------------------------------------------------------------------ Hooking KiFastCall will not be as simple as hooking KiSystemService: kernel-mode tools will have to read/write to MSRs or will have to overwrite KiFastCallEntry's begin (with INT 3, JMP, ...). ------------------------------------------------------------------------------ EliCZ, Jan-25-2000