Click here to Skip to main content
Click here to Skip to main content

Get interrupt vector information in Windows

, 18 Jul 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
An article about obtaining interrupt vector information in a Windows system

Introduction

This article explains how to get interrupt vector information in a Windows system. Before reading this article, you will need to familiarise yourself with: INTERRUPT, IDT, IVT and IRQ. This article will not explain these subjects. I recommend that you search the web for more information if you are not familiar with them, as I have written this article under the assumption that you are.

IDT in Windows

IDT stands for Interrupt Descriptor Table. Such tables contain Interrupt information of the i386 Processor in Protected Mode, not Real Mode. These tables consist of 8 bytes and there is a lot of information about the Table that you can easily find out. IDT is an essential component of the Operating System's kernel. When the Operating System transitions from Real Mode to Protected Mode, OSs make an IDT. IDTs are able to change because Windows supports the Plug and Play feature.

IDTs have an opportunity to remap by system. IOAPICs have something to do with this remapping operation. See the DataSheet of 82093AA I/O Advanced Programmable Interrupt Controller for more information. IOAPIC makes IRQ and remaps IRQ to IDT. You can see current the remapping status of IRQ and IDT by typing !ioapic in Windbg. This is the result of !ioapic:

kd> !ioapic
IoApic @ FEC00000  ID:1 (11)  Arb:1000000
Inti00.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti01.: 00000993  Vec:93  LowestDl  Lg:01000000      edg  high             
Inti02.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti03.: 000009b2  Vec:B2  LowestDl  Lg:01000000      edg  high             
Inti04.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti05.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti06.: 000109b3  Vec:B3  LowestDl  Lg:01000000      edg  high       masked
Inti07.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti08.: 000008d1  Vec:D1  FixedDel  Lg:01000000      edg  high             
Inti09.: 0000e9b1  Vec:B1  LowestDl  Lg:01000000      lvl  low        rirr  
Inti0A.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti0B.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti0C.: 000009a3  Vec:A3  LowestDl  Lg:01000000      edg  high             
Inti0D.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti0E.: 00000962  Vec:62  LowestDl  Lg:01000000      edg  high             
Inti0F.: 00000982  Vec:82  LowestDl  Lg:01000000      edg  high             
Inti10.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti11.: 0000a983  Vec:83  LowestDl  Lg:01000000      lvl  low              
Inti12.: 0000a963  Vec:63  LowestDl  Lg:01000000      lvl  low              
Inti13.: 0000a973  Vec:73  LowestDl  Lg:01000000      lvl  low              
Inti14.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti15.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti16.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked
Inti17.: 000100ff  Vec:FF  FixedDel  PhysDest:00      edg  high       masked

How to resolve an IDT vector

There are many methods to resolve IDT vectors.

  1. Use APIC
  2. Scan kernel memory
  3. Use the kernel API function

Using APIC

If you want to know more about the "Use APIC" method, see the APIC document. Intel recommends mapping IOAPIC to 0xFEC00000. Surely it can replace to another address, but Windows doesn't. In the following results, we can appreciate that Windows follows the IOAPIC document's recommendation.

kd> !ioapic
IoApic @ FEC00000  ID:1 (11)  Arb:1000000

Now the memory (0xFEC00000) contains IDT vector information. These methods are fully explained in the CodeProject article found here.

Scanning kernel memory

Next, we can scan kernel memory space. This is a traditional and hazardous method. It is described in the eEye Security White Paper, which was published in 2005. This method's main premise is that hal.dll's memory space contains IDT and IRQ information and that we can obtain this address by scanning the memory space. This method's implementation is very small, so we can use it in stark a environment.

mov esi, dword ptr ds:[0ffdff038h] ; Get base address of IDT
lodsd
cdq
lodsd ; Get pointer into NTOSKRNL
@base_loop:
dec eax
cmp dword ptr [eax], 00905a4dh ; Check for MZ signature
jnz @base_loop
jecxz @hal_base ; NTOSKRNL base is in EAX
xchg edx, eax
mov eax, [edx+590h] ;Get a pointer to a HAL function
xor ecx, ecx
jmp @base_loop ;Find HAL base address
@hal_base:
mov edi, eax ;HAL base in EDI
mov ebp, edx ;NTOSKRNL base in EBP
cld
mov eax, 41413d00h ;Signature bytes "=AA\0"
xor ecx, ecx
dec cx
shr ecx, 4
repnz scasd ;Get offset to table
or ecx, ecx
jz @no_table
lea edi, [edi+01ch] ;Get pointer to Vector table

This code:

  1. Gets ntoskrnl's base address
  2. Moves to the hal functions's area
  3. Finds until =AA\0, which means IRQ0's information =AA\0 is 0x41413d00h

Using kernel API

These two methods are not reliable. They appear to be an effective way to control APIC, but Windows can change these addresses to indirect addresses. So, it's not a very effective way to do things. The second method of finding memory isn't a good method by itself. Also, =AA\0 is too specific to use in all environments. We can solve these problems with HalGetInterruptVector, which is the kernel API. This function is declared in ntddk.h.

NTHALAPI
ULONG
HalSetBusData(
    IN BUS_DATA_TYPE BusDataType,
    IN ULONG BusNumber,
    IN ULONG SlotNumber,
    IN PVOID Buffer,
    IN ULONG Length
    );

BUS_DATA_TYPE is declared in ntddk.h.

typedef enum _BUS_DATA_TYPE {
    ConfigurationSpaceUndefined = -1,
    Cmos,
    EisaConfiguration,
    Pos,
    CbusConfiguration,
    PCIConfiguration,
    VMEConfiguration,
    NuBusConfiguration,
    PCMCIAConfiguration,
    MPIConfiguration,
    MPSAConfiguration,
    PNPISAConfiguration,
    SgiInternalConfiguration,
    MaximumBusDataType
} BUS_DATA_TYPE, *PBUS_DATA_TYPE;

You can call a function such as:

KIRQL sIrql;
KAFFINITY sAffinity;
ULONG uVector;
ULONG uInterruptNumber = 1;

uVector = 
    HalGetInterruptVector(EisaConfiguration/*Bus Data Type*/, 
    0, uInterruptNumber, uInterruptNumber, &sIrql, &sAffinity);
uVector = uVector & 0xFF;

This function is described in MSDN. When you pass the IRQ number to BusInterruptLevel and BusInterruptVector, the function returns the index of the IDT vector. This returned value is bigger by 0x100 than original value. We must odds 0x100 or mask with 0xFF.

History

  • 18 July, 2007 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Yonghwi Kwon
Software Developer
United States United States
I started to write software since 1999 and have developed various products including security solutions and system utilities.
 
Microsoft Visual C++ MVP (from 2008 to present)
Website: http://rodream.net

Comments and Discussions

 
GeneralRootkit Hook Detection PinmemberRandor19-Jul-07 0:27 
GeneralRe: Rootkit Hook Detection PinmemberKwon Yong Hwi19-Jul-07 2:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 18 Jul 2007
Article Copyright 2007 by Yonghwi Kwon
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid