Uninformed: Informative Information for the Uninformed

Vol 8» 2007.Sep


IDT

The Interrupt Descriptor Table (IDT) is a processor-relative structure that is used when dispatching interrupts. Interrupts are used by the processor as a means of interrupting program execution in order to handle an event. Interrupts can occur as a result of a signal from hardware or as a result of software asserting an interrupt through the int instruction[23]. The IDT contains 256 descriptors that are associated with the 256 interrupt vectors supported by the processor. Each IDT descriptor can be one of three types of gate descriptors (task, interrupt, trap) which are used to describe where and how control should be transferred when an interrupt for a particular vector occurs. The base address and limit of the IDT are stored in the idtr register which is populated through the lidt instruction. The current base address and limit of the idtr can be read using the sidt instruction.

The concept of an IDT hook has most likely been around since the origin of the concept of interrupt handling. In most cases, an IDT hook works by redirecting the procedure entry point for a given IDT descriptor to an alternative location. Conceptually, this is the same process involved in hooking any function pointer (which is described in more detail in 2.5). The difference comes as a result of the specific code necessary to hook an IDT descriptor.

On the x86 processor, each IDT descriptor is an eight byte data structure. IDT descriptors that are either an interrupt gate or trap gate descriptor contain the procedure entry point and code segment selector to be used when the descriptor's associated interrupt vector is asserted. In addition to containing control transfer information, each IDT descriptor also contains additional flags that further control what actions are taken. The Windows kernel describes IDT descriptors using the following structure:

kd> dt _KIDTENTRY
   +0x000 Offset           : Uint2B
   +0x002 Selector         : Uint2B
   +0x004 Access           : Uint2B
   +0x006 ExtendedOffset   : Uint2B

In the above data structure, the Offset field holds the low 16 bits of the procedure entry point and the ExtendedOffset field holds the high 16 bits. Using this knowledge, an IDT descriptor could be hooked by redirecting the procedure entry point to an alternate function. The following code illustrates how this can be accomplished:

typedef struct _IDT
{
  USHORT          Limit;
  PIDT_DESCRIPTOR Descriptors;
} IDT, *PIDT;

static NTSTATUS HookIdtEntry(
  IN UCHAR DescriptorIndex,
  IN ULONG_PTR NewHandler,
  OUT PULONG_PTR OriginalHandler OPTIONAL)
{
  PIDT_DESCRIPTOR Descriptor = NULL;
  IDT             Idt;

  __asm sidt [Idt]

  Descriptor = &Idt.Descriptors[DescriptorIndex];

  *OriginalHandler =
    (ULONG_PTR)(Descriptor->OffsetLow +
                (Descriptor->OffsetHigh << 16));

  Descriptor->OffsetLow  =
    (USHORT)(NewHandler & 0xffff);
  Descriptor->OffsetHigh =
    (USHORT)((NewHandler >> 16) & 0xffff);

  __asm lidt [Idt]

  return STATUS_SUCCESS;
}

In addition to hooking an individual IDT descriptor, the entire IDT can be hooked by creating a new table and then setting its information using the lidt instruction.

Category: Type I; although some portions of the IDT may be legitimately hooked.

Origin: The IDT hook has its origins in Interrupt Vector Table (IVT) hooks. In October, 1999, Prasad Dabak et al wrote about IVT hooks[31]. Sadly, they also seemingly failed to cite their sources. It's certain that IVT hooks have existed prior to 1999. The oldest virus citation the authors could find was from 1994, but DOS was released in 1981 and it is likely the first IVT hooks were seen shortly thereafter[7]. A patent that was filed in December, 1985 entitled Dual operating system computer talks about IVT ``relocation'' in a manner that suggests IVT hooking of some form[3].

Capabilities: Kernel-mode code execution.

Covertness: Detection of IDT hooks is often trivial and is a common practice for rootkit detection tools[32].