要點回顧
執行調用門的指令: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。由於會修改標誌寄存器,所以在進行中斷提權的時候需要先保存一份到堆棧中。
調用門和中斷門的區別
- 調用門通過call far指令執行,但中斷門通過int指令執行
- 調用門查GDT表 中斷門查IDT表
- call cs:eip中的CS是段選擇子,由三部分組成。但int [index]指令中的index只是索引,中斷門不檢查RPL,只檢查CPL
- 調用門可以有參數,但中斷門沒有
- 調用門提權時push了四個寄存器:EIP(返回地址) CS ESP SS,返回時用RETF指令返回。中斷門提權時push了五個寄存器:EIP(返回地址) CS EFLAGS ESP SS,返回時用IRETD指令返回
l cs:eip中的CS是段選擇子,由三部分組成。但int [index]指令中的index只是索引,中斷門不檢查RPL,只檢查CPL
4. 調用門可以有參數,但中斷門沒有
5. 調用門提權時push了四個寄存器:EIP(返回地址) CS ESP SS,返回時用RETF指令返回。中斷門提權時push了五個寄存器:EIP(返回地址) CS EFLAGS ESP SS,返回時用IRETD指令返回