HOOK系列中,包括應用程式HOOK程式設計、IDT和IOAPIC程式設計,其中IOPIC顧名思義I/O ADVANCED PROGRAMMABLE INTERRUPT CONTROLLER中斷控制器。在Windows 中有固定的兩個位址進行操作,第一、I/O寄存器選擇寄存器,其位址是0xfec00000;另一個是I/O視窗寄存器,位址是0xfec00010。這兩個位址不像通用寄存器一樣能直接通路,必須映射大一片虛拟記憶體中操作。
IDT是中斷描述符清單,IOAPIC的目的就是告訴指定的CPU的IRQ号,用于IDT查詢中斷服務位址。
是以如果想修改中斷的處理過程,首先需要修改IOAPIC的中斷号,在通過IDT修改中斷服務函數,這樣就可以達到過濾和擷取資料的目的,如下代碼;
// 選擇寄存器。選擇寄存器雖然是32位的寄存器,但是隻使用
// 低8位,其他的位都被保留。
P2C_U8 *io_reg_sel;
// 視窗寄存器,用來讀寫被選擇寄存器選擇的值,是32位的。
P2C_U32 *io_win;
P2C_U32 ch,ch1;
// 定義一個實體位址,這個位址為0xfec00000。正是IOAPIC
// 寄存器組在Windows上的開始位址
PHYSICAL_ADDRESS phys ;
PVOID paddr;
RtlZeroMemory(&phys,sizeof(PHYSICAL_ADDRESS));
phys.u.LowPart = 0xfec00000;
// 實體位址是不能直接讀寫的。MmMapIoSpace把實體位址映射
// 為系統空間的虛拟位址。0x14是這片空間的長度。
paddr = MmMapIoSpace(phys, 0x14, MmNonCached);
// 如果映射失敗了就傳回0.
if (!MmIsAddressValid(paddr))
return 0;
// 選擇寄存器的偏移為0
io_reg_sel = (P2C_U8 *)paddr;
// 視窗寄存器的偏移為0x10.
io_win = (P2C_U32 *)((P2C_U8 *)(paddr) + 0x10);
// 選擇第0x12,剛好是irq1的項
*io_reg_sel = 0x12;
ch = *io_win;
// 如果new_ch不為0,我們就設定新值。并傳回舊值。
if(new_ch != 0)
{
ch1 = *io_win;
ch1 &= 0xffffff00;
ch1 |= (P2C_U32)new_ch;
*io_win = ch1;
KdPrint(("p2cSeachOrSetIrq1: set %2x to irq1./r/n",(P2C_U8)new_ch));
}
// 視窗寄存器裡讀出的值是32位的,但是我們隻需要
// 一個位元組就可以了。這個位元組就是中斷向量的值。
// 一會我們要修改這個值。
ch &= 0xff;
MmUnmapIoSpace(paddr, 0x14);
KdPrint(("p2cSeachOrSetIrq1: the old vec of irq1 is %2x./r/n",(P2C_U8)ch));
return (P2C_U8)ch;