Last active
June 4, 2021 14:49
-
-
Save Barakat/89002a26937a2da353868fc5130812a5 to your computer and use it in GitHub Desktop.
Windows x86 Interrupt Descriptor Table (IDT) hooking driver
This file contains 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 characters
// | |
// Windows x86 Interrupt Descriptor Table (IDT) hook test | |
// | |
// Barakat Soror (https://twitter.com/barakatsoror) | |
// | |
#include <Windows.h> | |
int main(void) | |
{ | |
OutputDebugStringA("[*] USER: Triggering interrupt\n"); | |
__try | |
{ | |
// | |
// Triggers Divide-By-Zero exception | |
// | |
volatile int A = 1; | |
volatile int B = 0; | |
volatile int C = A / B; | |
(void)C; | |
} | |
__except (GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) | |
{ | |
} | |
OutputDebugStringA("[*] USER: No BSOD :D!!!\n"); | |
return 0; | |
} |
This file contains 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 characters
// | |
// Windows x86 Interrupt Descriptor Table (IDT) hook driver | |
// | |
// Barakat Soror (https://twitter.com/barakatsoror) | |
// | |
#include <wdm.h> | |
#include <intrin.h> | |
#ifndef _X86_ | |
#error "Only x86 is supported" | |
#endif | |
#pragma pack(push) | |
#pragma pack(1) | |
typedef struct _INTERRUPT_DESCRIPTOR_TABLE | |
{ | |
UINT16 Offset0; | |
UINT16 Unused0; | |
UINT8 Unused1; | |
UINT8 Unused2; | |
UINT16 Offset1; | |
} INTERRUPT_DESCRIPTOR_TABLE, *PINTERRUPT_DESCRIPTOR_TABLE; | |
typedef struct _INTERRUPT_DESCRIPTOR_TABLE_REGISTER | |
{ | |
UINT16 Unused0; | |
PINTERRUPT_DESCRIPTOR_TABLE InterruptDescriptorTable; | |
} INTERRUPT_DESCRIPTOR_TABLE_REGISTER, *PINTERRUPT_DESCRIPTOR_TABLE_REGISTER; | |
#pragma pack(pop) | |
// | |
// Stub assembly function for preparing the hook | |
// | |
extern LONG InterruptServiceRoutineHookStub; | |
// | |
// The original value of the real interrupt service routine | |
// | |
LONG InterruptServiceRoutineReal; | |
// | |
// Target interrupt number we want to hook (Divide-By-Zero interrupt) | |
// | |
static const ULONG TargetInterruptNumber = 0; | |
// | |
// The actual hook | |
// | |
VOID | |
NTAPI | |
InterruptServiceRoutineHook(VOID) | |
{ | |
DbgPrint("[*] InterruptServiceRoutineHook has been called!\n"); | |
} | |
// | |
// Load the IDT register and get the address of the table | |
// | |
static | |
PINTERRUPT_DESCRIPTOR_TABLE | |
GetCurrentProcessorInterruptDescriptorTable(VOID) | |
{ | |
INTERRUPT_DESCRIPTOR_TABLE_REGISTER Register; | |
__sidt(&Register); | |
return Register.InterruptDescriptorTable; | |
} | |
// | |
// | |
// | |
static | |
LONG | |
GetInterruptServiceRoutine(PINTERRUPT_DESCRIPTOR_TABLE Table, ULONG InterruptNumber) | |
{ | |
return (LONG)((Table[InterruptNumber].Offset1 << 16) | Table[InterruptNumber].Offset0); | |
} | |
// | |
// | |
// | |
static | |
VOID | |
SetInterruptServiceRoutine(PINTERRUPT_DESCRIPTOR_TABLE Table, ULONG InterruptNumber, LONG Value) | |
{ | |
// | |
// Disable interrupts on the current processor, patch the IDT and reenable interrupts | |
// | |
_disable(); | |
// | |
// Read the CR0 value | |
// | |
const unsigned long cr0 = __readcr0(); | |
// | |
// Set the 16th bit (write-protection) to zero | |
// | |
__writecr0(cr0 & 0xfffeffffUL); | |
// | |
// Patch the table | |
// | |
Table[InterruptNumber].Offset0 = (ULONG)Value & 0xffff; | |
Table[InterruptNumber].Offset1 = (ULONG)Value >> 16; | |
// | |
// Restore the processor state | |
// | |
__writecr0(cr0); | |
_enable(); | |
} | |
// | |
// Driver unload routine | |
// | |
static | |
VOID | |
_Function_class_(DRIVER_UNLOAD) | |
DriverUnload(PDRIVER_OBJECT DriverObject) | |
{ | |
UNREFERENCED_PARAMETER(DriverObject); | |
DbgPrint("[*] DriverEntry: Unhooking active processors IDTs\n"); | |
// | |
// Iterate over each active processor and pin the current thread to that processor | |
// | |
KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); | |
KAFFINITY Affinity; | |
for (Affinity = 1; ActiveProcessors; Affinity <<= 1, ActiveProcessors >>= 1) | |
{ | |
if (ActiveProcessors & 1) | |
{ | |
KeSetSystemAffinityThread(Affinity); | |
const PINTERRUPT_DESCRIPTOR_TABLE Table = GetCurrentProcessorInterruptDescriptorTable(); | |
DbgPrint("[*] Pinning thread to CPU #%lu to unhook its IDT\n", (ULONG)Affinity); | |
// | |
// Restore the value of the interrupt service routine | |
// | |
SetInterruptServiceRoutine(Table, TargetInterruptNumber, InterruptServiceRoutineReal); | |
} | |
} | |
KeRevertToUserAffinityThread(); | |
DbgPrint("[*] DriverEntry: Driver has been unloaded\n"); | |
} | |
// | |
// Driver entry point | |
// | |
NTSTATUS | |
NTAPI | |
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) | |
{ | |
UNREFERENCED_PARAMETER(RegistryPath); | |
DriverObject->DriverUnload = DriverUnload; | |
DbgPrint("[*] DriverEntry: Hooking active processors IDTs\n"); | |
// | |
// Iterate over each active processor and pin the current thread to that processor | |
// | |
KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); | |
KAFFINITY Affinity; | |
for (Affinity = 1; ActiveProcessors; Affinity <<= 1, ActiveProcessors >>= 1) | |
{ | |
if (ActiveProcessors & 1) | |
{ | |
KeSetSystemAffinityThread(Affinity); | |
const PINTERRUPT_DESCRIPTOR_TABLE Table = GetCurrentProcessorInterruptDescriptorTable(); | |
DbgPrint("[*] Pinning thread to CPU #%lu to hook its IDT\n", (ULONG)Affinity); | |
// | |
// Backup the original value of the interrupt service routine | |
// | |
InterlockedCompareExchange(&InterruptServiceRoutineReal, | |
GetInterruptServiceRoutine(Table, TargetInterruptNumber) | |
, 0); | |
// | |
// Hook the interrupt service routine | |
// | |
SetInterruptServiceRoutine(Table, TargetInterruptNumber, InterruptServiceRoutineHookStub); | |
} | |
} | |
KeRevertToUserAffinityThread(); | |
DbgPrint("[*] DriverEntry: Driver has been loaded\n"); | |
return STATUS_SUCCESS; | |
} |
This file contains 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 characters
; | |
; Windows x86 Interrupt Descriptor Table (IDT) hook driver assembly stub | |
; | |
; Barakat Soror (https://twitter.com/barakatsoror) | |
; | |
.model flat, stdcall | |
extern InterruptServiceRoutineReal : dword | |
InterruptServiceRoutineHook proto near stdcall | |
public InterruptServiceRoutineHookStub | |
.data | |
InterruptServiceRoutineHookStub dword offset InterruptServiceRoutineHookStub_ | |
.code | |
InterruptServiceRoutineHookStub_ proc | |
; Store registers | |
pushad | |
pushfd | |
push fs | |
push ds | |
push es | |
; Setup segement selectors for the kernel, backup cx first | |
push cx | |
mov cx, 30h | |
mov fs, cx | |
mov cx, 23h | |
mov ds, cx | |
mov es, cx | |
pop cx | |
; Call our hook | |
call InterruptServiceRoutineHook | |
; Restore everything | |
pop fs | |
pop ds | |
pop es | |
popfd | |
popad | |
; Jump to the read routine | |
jmp [InterruptServiceRoutineReal] | |
InterruptServiceRoutineHookStub_ endp | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment