J. Doe J. Doe - 14 days ago 8
C Question

How to correctly dump IDT entries in amd64?

The following code:

Header:

// InterruptDescriptorTable.h

#define MAX_IDT_ENTRIES 256

#define MAKELONG(a, b) ((unsigned long) (((unsigned short)(a)) | ((unsigned long) ((unsigned) (b))) << 16 ))

/* SIDT returns IDT in following format */
#pragma pack(1)
typedef struct
{
unsigned short IDTLimit;
unsigned short LowIDTBase;
unsigned short HighIDTBase;

} s_idt_info;
#pragma pack()

/* entry in IDT ( interrupt gate ) */
#pragma pack(1)
typedef struct
{
unsigned short LowOffset;
unsigned short selector;
unsigned char unused_lo;
unsigned char segment_type:4;
unsigned char system_segment_flag:1;
unsigned char DPL:2; // Descriptor Privilege Level
unsigned char P:1; // Present
unsigned short HighOffset;

} s_idt_entry;
#pragma pack()


Main:

// driver.c
#include <ntddk.h>

#include "InterruptDescriptorTable.h"

const WCHAR deviceNameBuffer[] = L"\\Device\\MyDevice";

PDEVICE_OBJECT g_RootkitDevice; // pointer to device object

NTSTATUS
//STDCALL
_DriverDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
return STATUS_SUCCESS;
}

VOID
//STDCALL
_DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload() !\n");
return;
}

NTSTATUS
_DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DbgPrint("DriverEntry() !\n");

s_idt_info idt_info; // returned by sidt
s_idt_entry *idt_entries; // obtained from idt_info
unsigned int count;
unsigned long addr;

// load idt_info
__asm ("sidt %0" : "=w" (idt_info));

idt_entries = (s_idt_entry*) (long long)MAKELONG(idt_info.LowIDTBase, idt_info.HighIDTBase);

for(count = 0; count < MAX_IDT_ENTRIES; ++count)
{
s_idt_entry *i = &idt_entries[count];

addr = MAKELONG(i->LowOffset, i->HighOffset);

DbgPrint("Interrupt %d, %lu", count, addr);
}

DriverObject->DriverUnload = _DriverUnload;

return STATUS_SUCCESS;
}


Is compiled to a .sys file using using MinGW-x64 (GCC) in Code::Blocks.

When Inserted into a Windows 7-64bit VM running on VirtualBox, it generates the following BSOD:
enter image description here

I noticed it only happens when I attempt to print the variable 'addr'. No idea why exactly or how to fix it. Printing 'count' twice is just fine.

The following code is used to load / unload the driver:
http://pastebin.com/0Axy4WkZ

Answer

you use wrong definition for IDT structs in 64 bit mode. correct code for amd64 is next:

union KIDTENTRY64
{
    struct
    {
        USHORT OffsetLow;
        USHORT Selector;
        USHORT IstIndex:3;
        USHORT Reserved0:5;
        USHORT Type:5;
        USHORT Dpl:2;
        USHORT Present:1;
        USHORT OffsetMiddle;
        ULONG OffsetHigh;
        ULONG Reserved1;
    };
    UINT64 Alignment;
};

struct KDESCRIPTOR64
{
    USHORT Pad[3];
    USHORT Limit;
    PVOID Base;
};

void DumpIDT()
{
#ifdef _AMD64_

    KDESCRIPTOR64 descr; 
    __sidt(&descr.Limit);

    if (ULONG n = (descr.Limit + 1)/ sizeof(KIDTENTRY64))
    {
        int i = 0;
        KIDTENTRY64* pidte = (KIDTENTRY64*)descr.Base;

        do 
        {
            ULONG_PTR addr = ((ULONG_PTR)pidte->OffsetHigh << 32) + 
                ((ULONG_PTR)pidte->OffsetMiddle << 16) + pidte->OffsetLow;

            DbgPrint("Interrupt %u -> %p\n", i++, addr);

        } while (pidte++, --n);
    }
#endif  
}