[保护模式]中断门
文章目錄
- 要點回顧
- 中斷門
- IDT
- 中斷門描述符
- 中斷門實驗
- 示例代碼
- 構造中斷門描述符
- 修改IDT表
- 中斷現場
- 中斷返回
- 為什么會PUSH EFLAGS寄存器
- 調用門和中斷門的區別
要點回顧
執行調用門的指令:call cs:eip。其中cs是段選擇子,包含了查找GDT表的索引。但當CPU遇到了如下指令:int [index],查詢的卻是另外一張表,這張表叫IDT
中斷門
IDT
IDT表全稱為中斷描述符表,包含三種描述符:任務門描述符 中斷門描述符和陷阱門描述符。每個描述符占8個字節。但要注意的是,IDT表的第一個元素不是NULL。
通過int [index]這條指令,CPU會索引到IDT表。后面的index表示查IDT表項的下標。對比調用門,中斷門沒有了RPL,所以CPU只會校驗CPL。
中斷門描述符
中斷門實驗
示例代碼
#include <stdio.h> #include <stdlib.h> #include <windows.h>void __declspec(naked) IdtEntry() {__asm{int 3;iretd;} }void go() {__asm int 0x20; }int main() {printf("%p", IdtEntry);__asm{int 3;}go();system("pause"); }構造中斷門描述符
首先查看一下要跳轉到的函數地址
函數地址為00401040
offset31-16:0040 P:1 DPL:11 S:0-->E TYPE:E 8-0:保留位 Segment Selector:0008 offset:1040 #段描述符 0040EE00`00081040修改IDT表
首先查看IDT表
kd> dq idtr L40 80b95400 83e88e00`00084fc0 83e88e00`00085150 80b95410 00008500`00580000 83e8ee00`000855c0 80b95420 83e8ee00`00085748 83e88e00`000858a8 80b95430 83e88e00`00085a1c 83e88e00`00086018 80b95440 00008500`00500000 83e88e00`00086478 80b95450 83e88e00`0008659c 83e88e00`000866dc 80b95460 83e88e00`0008693c 83e88e00`00086c2c 80b95470 83e88e00`000872fc 83e88e00`000876b0 80b95480 83e88e00`000877d4 83e88e00`00087914 80b95490 00008500`00a00000 83e88e00`00087a80 80b954a0 83e88e00`000876b0 83e88e00`000876b0 80b954b0 83e88e00`000876b0 83e88e00`000876b0 80b954c0 83e88e00`000876b0 83e88e00`000876b0 80b954d0 83e88e00`000876b0 83e88e00`000876b0 80b954e0 83e88e00`000876b0 83e88e00`000876b0 80b954f0 83e88e00`000876b0 83e28e00`00089af8 80b95500 00000000`00080000 00000000`00080000 80b95510 00000000`00080000 00000000`00080000 80b95520 00000000`00080000 00000000`00080000 80b95530 00000000`00080000 00000000`00080000 80b95540 00000000`00080000 00000000`00080000 80b95550 83e8ee00`0008463a 83e8ee00`000847c0 80b95560 83e8ee00`000848fc 83e8ee00`00085498 80b95570 83e8ee00`00083fee 83e88e00`000876b0 80b95580 83e88e00`000836b0 83e88e00`000836ba 80b95590 83e88e00`000836c4 83e88e00`000836ce 80b955a0 83e88e00`000836d8 83e88e00`000836e2 80b955b0 83e88e00`000836ec 83e28e00`00089104 80b955c0 83e88e00`00083700 83e88e00`0008370a 80b955d0 83e88e00`00083714 83e88e00`0008371e 80b955e0 83e88e00`00083728 83e88e00`00083732 80b955f0 83e88e00`0008373c 83e88e00`00083746找到下標為0x20的那一項,也就是80b95500這個未被使用的位置。修改IDT表
kd> eq 80b95500 0040EE00`00081040修改完成之后可以在PC Hunter中看到修改后的效果,軟件顯示這個地方被HOOK,當前函數地址為我們指定的0x00401040
中斷現場
將程序編譯后放到虛擬機運行,windbg第一次產生中斷,此時中斷于用戶層,查看一下當前的寄存器
Break instruction exception - code 80000003 (first chance) 001b:00401062 cc int 3 kd> r eax=00000008 ebx=7ffdf000 ecx=74b49a18 edx=74b910a4 esi=74b92108 edi=001f40b0 eip=00401062 esp=0012ff44 ebp=0012ff88 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 001b:00401062 cc int 3- eip=00401062
- esp=0012ff44
- cs=001b
- ss=0023
- efl=00000216
繼續運行,windbg產生第二次中斷,此時中斷于內核層,查看一下當前的寄存器環境
kd> g Break instruction exception - code 80000003 (first chance) 00401040 cc int 3 kd> r eax=00000008 ebx=7ffdf000 ecx=74b49a18 edx=74b910a4 esi=74b92108 edi=001f40b0 eip=00401040 esp=8d113c9c ebp=0012ff88 iopl=0 nv up di pl nz ac pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000016 00401040 cc int 3- eip=00401040 我們指定的EIP
- esp=8d113c9c 零環的堆棧
- cs=0008 我們指定的段選擇子
- ss=0010 零環的SS段寄存器
接著查看一下堆棧的變化
kd> dd esp 8d113c9c 00401065 0000001b 00000216 0012ff44 8d113cac 00000023 00000000 00000000 00000000 8d113cbc 00000000 0000027f 00000000 00000000 8d113ccc 00000000 00000000 00000000 00001f80 8d113cdc 0000ffff 00000000 00000000 00000000 8d113cec 00000000 00000000 00000000 00000000 8d113cfc 00000000 00000000 00000000 00000000 8d113d0c 00000000 00000000 00000000 00000000- 00401065 三環的EIP(返回地址)
- 0000001b 三環的CS段選擇子
- 00000216 三環的EFLAGS寄存器
- 0012ff44 三環的ESP
- 00000023 三環的SS段寄存器
可以看到和調用門不同的是,中斷門比調用門多保存了一個EFLAGS寄存器
中斷返回
中斷門在沒有提權的時候,會向堆棧push3個值,分別是:CS EFLAGS EIP(返回地址)。在提升權限的時候,會向堆棧push5個值,分別是SS ESP EFLAGS CS EIP
在中斷門中,棧里面保存的寄存器值發生了變化,不能再用RETF進行返回,而應該通過IRET/IRETD指令返回
為什么會PUSH EFLAGS寄存器
在使用中斷門提權的時候,CPU會將EFLAGS寄存器中的IF中斷標志位修改為0。由于會修改標志寄存器,所以在進行中斷提權的時候需要先保存一份到堆棧中。
調用門和中斷門的區別
l cs:eip中的CS是段選擇子,由三部分組成。但int [index]指令中的index只是索引,中斷門不檢查RPL,只檢查CPL
4. 調用門可以有參數,但中斷門沒有
5. 調用門提權時push了四個寄存器:EIP(返回地址) CS ESP SS,返回時用RETF指令返回。中斷門提權時push了五個寄存器:EIP(返回地址) CS EFLAGS ESP SS,返回時用IRETD指令返回
總結