Files
winterknife-EVENSTAR/ReadIDTDbgExt/Src/ReadInterruptDescriptorTable.cpp
2025-06-29 14:02:31 -04:00

206 lines
7.6 KiB
C++

// ========================================================================
// File: ReadInterruptDescriptorTable.cpp
//
// Author: winterknife
//
// Description: Source file that contains the necessary routines to read and
// parse all the gate descriptors in the Interrupt Descriptor Table (IDT)
//
// Modifications:
// 2025-06-23 Created
// 2025-06-29 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/ReadInterruptDescriptorTable.h"
#include "../Inc/DbgExt.h"
#include <Shlwapi.h>
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
_Use_decl_annotations_
VOID __stdcall help(
HANDLE hCurrentProcess,
HANDLE hCurrentThread,
QWORD qwCurrentPc,
DWORD dwProcessor,
PCSTR strArgs
) {
UNREFERENCED_PARAMETER(hCurrentProcess);
UNREFERENCED_PARAMETER(hCurrentThread);
UNREFERENCED_PARAMETER(qwCurrentPc);
UNREFERENCED_PARAMETER(dwProcessor);
UNREFERENCED_PARAMETER(strArgs);
dprintf(
"Help for debugger extension DLL ReadIDTDbgExt.dll\n"
" help - Show help menu\n"
" read_idt - Read and parse the gate descriptors in the Interrupt Descriptor Table (IDT)\n"
);
}
_Use_decl_annotations_
VOID __stdcall read_idt(
HANDLE hCurrentProcess,
HANDLE hCurrentThread,
QWORD qwCurrentPc,
DWORD dwProcessor,
PCSTR strArgs
) {
UNREFERENCED_PARAMETER(hCurrentProcess);
UNREFERENCED_PARAMETER(hCurrentThread);
UNREFERENCED_PARAMETER(qwCurrentPc);
UNREFERENCED_PARAMETER(strArgs);
// Reload symbols
ReloadSymbols(NULL);
dprintf("[!] Current processor number = %d\n", dwProcessor);
// Init local variables
QWORD qwIdtBaseKva = 0;
QWORD qwIdtLimit = 0;
QWORD qwKpcrKva = 0;
QWORD qwKprcbKva = 0;
DWORD dwKinterruptTableBaseOffset = 0;
QWORD qwKinterruptTableBaseKva = 0;
DWORD dwIndex = 0;
INTERRUPT_TRAP_GATE_DESCRIPTOR interruptTrapGateDescriptor; ZERO_MEMORY(&interruptTrapGateDescriptor, sizeof(INTERRUPT_TRAP_GATE_DESCRIPTOR));
QWORD qwInterruptHandlerKva = 0;
QWORD qwKinterruptKva = 0;
CHAR charrSymbolName[MAX_PATH]; ZERO_MEMORY(&charrSymbolName, sizeof(charrSymbolName));
DWORD_PTR dwptrDisplacement = 0;
CHAR charrBuffer[MAX_PATH]; ZERO_MEMORY(&charrBuffer, sizeof(charrBuffer));
// Determine if the target uses 64-bit pointers
if (!IsPtr64()) {
dprintf("[-] IA-32 target is not supported by this extension!\n");
goto cleanup;
}
// Read IDT Base Address
if (!GetExpressionEx("@idtr", &qwIdtBaseKva, NULL)) {
dprintf("[-] Error evaluating MASM expression!\n");
goto cleanup;
}
dprintf("[+] IDT Base Address=0x%I64X\n", qwIdtBaseKva);
// Read IDT Limit
if (!GetExpressionEx("@idtl", &qwIdtLimit, NULL)) {
dprintf("[-] Error evaluating MASM expression!\n");
goto cleanup;
}
dprintf("[+] IDT Limit=0x%X\n", qwIdtLimit);
// Get Kernel Processor Control Region (KPCR) KVA
if (!GetExpressionEx("@$pcr", &qwKpcrKva, NULL)) {
dprintf("[-] Error evaluating MASM expression!\n");
goto cleanup;
}
dprintf("[+] nt!_KPCR KVA=0x%I64X\n", qwKpcrKva);
// Get Kernel Processor Control Block (KPRCB) KVA
if (!ReadPointer((qwKpcrKva + 0x20), &qwKprcbKva)) {
dprintf("[-] Error reading pointer!\n");
goto cleanup;
}
dprintf("[+] nt!_KPRCB KVA=0x%I64X\n", qwKprcbKva);
// Get interrupt object table base offset
// WinDbg command: dt nt!_KPRCB InterruptObject
if (GetFieldOffset("nt!_KPRCB", "InterruptObject", &dwKinterruptTableBaseOffset)) {
dprintf("[-] Error getting structure offset!\n");
goto cleanup;
}
// Get interrupt object table base KVA
qwKinterruptTableBaseKva = qwKprcbKva + dwKinterruptTableBaseOffset;
dprintf("[+] nt!_KPRCB.InterruptObject[0] KVA=0x%I64X\n", qwKinterruptTableBaseKva);
// The Interrupt Descriptor Table (IDT) associates each exception or interrupt vector with a gate descriptor for the procedure used to service the associated exception or interrupt
// The IDT is an array of 16-byte descriptors (in IA-32e mode)
// There are only 256 interrupt or exception vectors so the IDT should contain a maximum of 256 descriptors
// The IDT lies in the KVAS
// In IA-32e mode, there can be two types of entries in the IDT: interrupt gate descriptor and trap gate descriptor
// When an exception/interrupt is handled through an interrupt gate, the EFLAGS.IF flag is automatically cleared, which disables maskable hardware interrupts
// If an exception/interrupt is handled through a trap gate, the EFLAGS.IF flag is not cleared
// Vector numbers in the range 0 through 31 are reserved by the Intel 64 and IA-32 architectures for architecture-defined exceptions and interrupts
// Vector numbers in the range 32 to 255 are designated as user-defined interrupts and are not reserved by the Intel 64 and IA-32 architecture
for (dwIndex = 0; dwIndex < 256; dwIndex++) {
if (!ReadMemory((qwIdtBaseKva + (dwIndex * sizeof(INTERRUPT_TRAP_GATE_DESCRIPTOR))), &interruptTrapGateDescriptor, sizeof(INTERRUPT_TRAP_GATE_DESCRIPTOR), NULL)) {
dprintf("[-] Error reading virtual memory!\n");
goto cleanup;
}
// Check for empty descriptor slots
// All empty descriptor slots in the IDT should have the present flag for the descriptor set to 0
if (interruptTrapGateDescriptor.P == 0) {
continue;
}
// Get the address of the entry point of the Interrupt Service Routine (ISR)
qwInterruptHandlerKva = __ll_lshift(interruptTrapGateDescriptor.OffsetHigh, 32) + __ll_lshift(interruptTrapGateDescriptor.OffsetMiddle, 16) + interruptTrapGateDescriptor.OffsetLow;
// Get the interrupt object corresponding to the interrupt vector from the array of interrupt object pointers
if (!ReadPointer((qwKinterruptTableBaseKva + (dwIndex * sizeof(PVOID))), &qwKinterruptKva)) {
dprintf("[-] Error reading pointer!\n");
goto cleanup;
}
// Get the ISR KVA from the interrupt object
if (qwKinterruptKva) {
if (!ReadPointer((qwKinterruptKva + 0x20), &qwInterruptHandlerKva)) {
dprintf("[-] Error reading pointer!\n");
goto cleanup;
}
if (!qwInterruptHandlerKva) {
if (!ReadPointer((qwKinterruptKva + 0x18), &qwInterruptHandlerKva)) {
dprintf("[-] Error reading pointer!\n");
goto cleanup;
}
}
}
// Get the symbol name
GetSymbol(qwInterruptHandlerKva, charrSymbolName, &dwptrDisplacement);
wnsprintfA(charrBuffer, MAX_PATH, "%s+0x%X", charrSymbolName, (WORD)dwptrDisplacement);
// Display IDT gate descriptor
dprintf("----------------------------------------------------------------------\n");
dprintf("[+] Vector Number: 0x%X (0n%d)\n", dwIndex, dwIndex);
if (interruptTrapGateDescriptor.Type == 14)
dprintf("[+] Type: Interrupt Gate\n");
else if (interruptTrapGateDescriptor.Type == 15)
dprintf("[+] Type: Trap Gate\n");
dprintf("[+] Segment Selector=0x%X\n", interruptTrapGateDescriptor.SegmentSelector);
if (dwptrDisplacement)
dprintf("[+] ISR KVA=0x%I64X (%s)\n", qwInterruptHandlerKva, charrBuffer);
else
dprintf("[+] ISR KVA=0x%I64X (%s)\n", qwInterruptHandlerKva, charrSymbolName);
if (interruptTrapGateDescriptor.IST)
dprintf("[+] IST=0x%X\n", interruptTrapGateDescriptor.IST);
dprintf("[+] DPL=0x%X\n", interruptTrapGateDescriptor.DPL);
dprintf("----------------------------------------------------------------------\n");
}
// Cleanup
cleanup:
return;
}
#pragma endregion