[保護模式]中斷門

要點回顧

執行調用門的指令: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。由於會修改標誌寄存器,所以在進行中斷提權的時候需要先保存一份到堆棧中。

調用門和中斷門的區別

  1. 調用門通過call far指令執行,但中斷門通過int指令執行
  2. 調用門查GDT表 中斷門查IDT表
  3. call cs:eip中的CS是段選擇子,由三部分組成。但int [index]指令中的index只是索引,中斷門不檢查RPL,只檢查CPL
  4. 調用門可以有參數,但中斷門沒有
  5. 調用門提權時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指令返回

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章