Skip to content

Instantly share code, notes, and snippets.

@Barakat
Last active October 8, 2023 05:43
Show Gist options
  • Save Barakat/7e01524fbf2a55031fb2f2d4edf1d8bd to your computer and use it in GitHub Desktop.
Save Barakat/7e01524fbf2a55031fb2f2d4edf1d8bd to your computer and use it in GitHub Desktop.
sysenter/KiFastCallEntry/IA32_SYSENTER_EIP hooking driver for Windows x86
//
// sysenter/KiFastCallEntry/IA32_SYSENTER_EIP hooking driver
//
// Barakat Soror (https://twitter.com/barakatsoror)
//
#include <wdm.h>
#include <intrin.h>
#ifndef _X86_
#error "Only x86 is supported"
#endif
//
// This is the MSR address of the value that will be loaded in EIP when sysenter is requested. Windows
// stores a pointer to KiFastCallEntry. This MSR has a "Core" scope. Meaning each "physical core" will have
// its own value.
//
// https://www.felixcloutier.com/x86/sysenter
// https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-1350.html
//
#define IA32_SYSENTER_EIP 0x176
//
// If you disassemble any service, you will see that it moves the service index to EAX in the first
// instruction. The index is right after the first byte of the MOV opcode. This behavior looks stable
// and is used by Sysinternals Procmon.
//
//
// 0: kd > u ZwCreateFile L4
// ntdll!NtCreateFile:
// 770655c8 b842000000 mov eax, 42h
// 770655cd ba0003fe7f mov edx, offset SharedUserData!SystemCallStub(7ffe0300)
// 770655d2 ff12 call dword ptr[edx]
// 770655d4 c22c00 ret 2Ch
//
// Another method is linearly search the table for the function instead. But the previous method does the job.
//
#define GET_SERVICE_INDEX(Service) *((PULONG_PTR) ((PCHAR)(Service) + 1))
//
// Target system call we want to hook
//
ULONG_PTR TargetSystemCallIndex;
//
// Value of the original MSR value
//
ULONG_PTR KiFastCallEntryReal;
//
// These events are just to ensure that the hook will be used and stopped being used on all cores at
// the same time
//
static KEVENT EnterKiFastCallEntryHookEvent;
static KEVENT ExitKiFastCallEntryHookEvent;
//
// This is a stub code written in assembly to store/restore CPU registers, set selector registers, then
// it will call the real KiFastCallEntryHook
//
extern VOID KiFastCallEntryHookStub(VOID);
//
// Our real hook function. It will always be running at PASSIVE_LEVEL
//
VOID
NTAPI
KiFastCallEntryHook(ULONG_PTR SystemCallIndex, ULONG_PTR SavedStackPointer)
{
if (KeReadStateEvent(&EnterKiFastCallEntryHookEvent) != 0 && KeReadStateEvent(&ExitKiFastCallEntryHookEvent) == 0)
{
if (SystemCallIndex == TargetSystemCallIndex)
{
DbgPrint("[!] KiFastCallEntryHook (eax = %p, edx = %p)\n", SystemCallIndex, SavedStackPointer);
}
}
}
//
// Device unload procedure
//
static
VOID
_Function_class_(DRIVER_UNLOAD)
DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("[!] DRIVER UNLOAD\n");
//
// Signal hook disabling
//
KeSetEvent(&ExitKiFastCallEntryHookEvent, 0, FALSE);
//
// Remove all hooks and restore the real sysenter handlers
//
KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
KAFFINITY Affinity;
for (Affinity = 1; ActiveProcessors != 0; Affinity <<= 1, ActiveProcessors >>= 1)
{
if (ActiveProcessors & 1)
{
KeSetSystemAffinityThread(Affinity);
DbgPrint("[!] UNHOOKING A LOGICAL PROCESSOR\n");
__writemsr(IA32_SYSENTER_EIP, KiFastCallEntryReal);
}
}
//
// Revert the thread to its original affinity
//
KeRevertToUserAffinityThread();
}
//
// Driver entry point
//
NTSTATUS
NTAPI
_Function_class_(DRIVER_INITIALIZE)
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = DriverUnload;
DbgPrint("[!] DRIVER LOAD\n");
//
// Store the real sysenter handler value of any core
//
KiFastCallEntryReal = (ULONG_PTR)__readmsr(IA32_SYSENTER_EIP);
//
// Read the service index
//
TargetSystemCallIndex = GET_SERVICE_INDEX(ZwCreateFile);
//
// Create notification events
//
KeInitializeEvent(&EnterKiFastCallEntryHookEvent, NotificationEvent, FALSE);
KeInitializeEvent(&ExitKiFastCallEntryHookEvent, NotificationEvent, FALSE);
//
// We will pin the thread on each logical core and update its IA32_SYSENTER_EIP
//
KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
KAFFINITY Affinity;
for (Affinity = 1; ActiveProcessors != 0; Affinity <<= 1, ActiveProcessors >>= 1)
{
if (ActiveProcessors & 1)
{
KeSetSystemAffinityThread(Affinity);
DbgPrint("[!] HOOKING A LOGICAL PROCESSOR\n");
__writemsr(IA32_SYSENTER_EIP, (ULONG_PTR)&KiFastCallEntryHookStub);
}
}
//
// Revert the thread to its original affinity
//
KeRevertToUserAffinityThread();
//
// Enable the hook
//
KeSetEvent(&EnterKiFastCallEntryHookEvent, 0, FALSE);
return STATUS_SUCCESS;
}
;
; sysenter/KiFastCallEntry/IA32_SYSENTER_EIP hooking driver
;
; Barakat Soror (https://twitter.com/barakatsoror)
;
.model flat, stdcall
KiFastCallEntryHook proto near stdcall,
SystemCallIndex:dword,
SavedStackPointer:dword
extern KiFastCallEntryReal: dword
public KiFastCallEntryHookStub
.code
KiFastCallEntryHookStub proc
; At this point, the cs and ss segment selectors have kernel-mode selectors
; (IA32_SYSENTER_CS, IA32_SYSENTER_CS + 8), and the stack pointer (ESP) points
; to valid kernel stack (IA32_SYSENTER_ESP). We need to store registers so we
; can restore their contents after calling our hook, and fix the remaining selectors
; because they are still using user-mode selectors
; Store general registers and EFLAGS on the stack
pushad
pushfd
push fs
push ds
push es
; The segement selectors (fs, ds, es) will be holding user-mode selectors
; so we need to set them to the kernel-mode selectors (fs = 0x30, ds = es = 0x23)
push cx
; Load 0x30 into fs segment selector
mov cx, 30h
mov fs, cx
; Load 0x23 into ds and es segment selectors
mov cx, 23h
mov ds, cx
mov es, cx
pop cx
; Call our hook and pass the system call index (eax) and the user stack pointer (edx)
invoke KiFastCallEntryHook, eax, edx
; Restore register values
pop es
pop ds
pop fs
popfd
popad
; Jump to the real sysenter handler
jmp [KiFastCallEntryReal]
KiFastCallEntryHookStub endp
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment