(13)中斷門

hambaga發表於2020-09-29

一、中斷門描述符

在這裡插入圖片描述

可以看到,中斷門的結構和呼叫門非常像,主要是TYPE域,0x6表示16位中斷門,0xE表示32位中斷門。和呼叫門不同,中斷門不能傳參。

中斷門儲存在IDT表中,IDT表除了儲存中斷門描述符,還有任務門和陷阱門描述符。

使用呼叫門的方法是 CALL FAR,而使用中斷門的方法是 INT N,其中,N表示中斷門描述符在IDT表中的下標。

和呼叫門一樣,中斷門也可以用來提權。不提權時,INT N 會依次壓棧CS,EFLAG EIP;提權時,會依次壓棧 SS ESP EFLAG CS EIP。這說明使用中斷門會對EFLAG進行修改。

二、自己實現中斷門

首先定義一個裸函式,在裡面讀取一下IDT表的第一項,以證明自己的CPL是0.

// INTGate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>

BYTE IDTItem0[8];

// R0 函式,讀取了IDT表第一項
// 004113A0
void __declspec(naked) R0Function()
{
	__asm
	{
		//int 3 // 除錯用的
		pushad
		pushfd
		mov eax,0x8003f400
		mov ebx,[eax]
		mov ecx,[eax+0x4]
		mov dword ptr ds:[IDTItem0],ebx
		mov dword ptr ds:[IDTItem0+0x4],ecx
		popfd
		popad
		iretd // iret 會藍屏,因為 iret的硬編碼是66CF,32位下應該使用iretd,硬編碼是CF
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	__asm 
	{
		INT 0x20
	}
	printf("%08x %08x\n", *(PDWORD)IDTItem0, *(PDWORD)((PBYTE)IDTItem0+0x4));
	getchar();
	return 0;
}

然後構造一個提權中斷門,DPL可以是0或3,都試試:

0041 13A0

0041EE00`000813A0
eq 8003f500 0041EE00`000813A0

00418E00`000813A0
eq 8003f500 00418E00`000813A0

然後在IDT表裡尋找一個P=0的無效項,把我們設計的第一個中斷門描述符填進去:
在這裡插入圖片描述


這裡下標是0x20,所以中斷指令是 INT 0x20,執行結果如下:
在這裡插入圖片描述

這個是DPL=3的版本,然後我們再試試DPL=0:

在這裡插入圖片描述

發現被當成無效中斷了:
在這裡插入圖片描述

於是,得出結論,CPL=DPL時,才能成功觸發中斷。

三、在呼叫門中實現使用IRETD返回,在中斷門中實現用RETF返回.

在這裡插入圖片描述

在中斷門中用RETF返回,只需將[ESP+0x8]寫到EFLAG,然後讓ESP 和 SS向低地址移動4位元組即可。

// INTGate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>

BYTE IDTItem0[8];

// R0 函式,讀取了IDT表第一項
// 004113A0
void __declspec(naked) R0Function()
{
	__asm
	{
		//int 3 // 除錯用的
		pushad
		pushfd
		mov eax,0x8003f400
		mov ebx,[eax]
		mov ecx,[eax+0x4]
		mov dword ptr ds:[IDTItem0],ebx
		mov dword ptr ds:[IDTItem0+0x4],ecx

		// 要求用 retf 返回
		add esp,0x2c		// esp指向eflags
		popfd				// esp指向3環esp
		mov eax,[esp]		// 將原ESP和SS向低地址移動4位元組
		mov [esp-0x4],eax
		mov eax,[esp+0x4]
		mov [esp],eax

		sub esp,0x30		// 還原esp
		popfd
		popad

		retf
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	__asm 
	{
		INT 0x20
	}
	printf("%08x %08x\n", *(PDWORD)IDTItem0, *(PDWORD)((PBYTE)IDTItem0+0x4));
	getchar();
	return 0;
}


在這裡插入圖片描述

在呼叫門中用IRETD返回,只需將ESP和SS向高地址移動4位元組,將EFLAG寫到[ESP+0x8]即可。

// INTGate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

DWORD dwHigh2GValue;

// 該函式通過 CALL FAR 呼叫,使用呼叫門提權,擁有0環許可權
// 00411480
void __declspec(naked) FunctionHas0CPL()
{
	__asm
	{
		pushad
		pushfd

		// 讀取了GDT表第二項的低4位元組
		mov eax,0x8003f008
		mov eax,[eax]
		mov dwHigh2GValue,eax

		// 要求用 iretd 返回		
		add esp,0x30		// esp指向ss
		
		mov eax,[esp]		// 將原ESP和SS向高地址移動4位元組
		mov [esp+0x4],eax
		mov eax,[esp-0x4]
		mov [esp],eax
		pushfd
		sub esp,0x2c		// 還原esp

		popfd
		popad

		iretd
	}
}

int main(int argc, char* argv[])
{
	char buff[6] = {0,0,0,0,0x48,0};
	__asm
	{
		call fword ptr [buff] // 長呼叫,使用呼叫門提權
	}
	printf("%08x\n",dwHigh2GValue);
	getchar();
	return 0;
}

在這裡插入圖片描述

相關文章