Windows x64中断门提权 R3调用R0函数

声明:
(1)本篇文章实验针对 未开启内核隔离(KPTI) 的Window10系统
(2)本次实验的实现 并不代表R3调用R0可以完全只由Ring3完成


win10并不使用调用门、陷阱门、任务门,  一律只用中断门,本次实验采用中断门提权实现R3调用R0函数。
没开启KPTI, Cr3始终为内核Cr3。

环境工具

(1) 调式工具:Windbg
(2) 虚拟机:windows10 19044.2846
(3) IDE: VS2019


一、原理分析

1.IDT表、中断描述符

中断:只使用一张IDT表,内核可以根据栈上的CS判断先前模式。

IDT表地址位于KPCR偏移0x38处

nt!_KPCR
+0x038 IdtBase : Ptr64 _KIDTENTRY64

64位中断门描述符:
x64中断门描述符

图来自Intel 第3卷 Figure 6-7. 64-Bit IDT Gate Descriptors
参照此图方便后续构造中断门


2.Fs、Gs寄存器

X86:0环时FS指向KPCR,3环时FS指向TEB
X64:0环时GS指向KPCR,3环时GS指向TEB
FSGS的基址在3个MSR寄存器中:
-
IA32_FS_BASE (下标0xC0000100)
IA32_GS_BASE (下标0xC0000101)
IA32_KERNEL_GS_BASE (下标0xC0000102)


3.简单分析3环进0环过程

(1) 分析int 3中断

windbg输入指令: !idt

!idt
可看到3号中断函数KiBreakpointTrap,这是因为笔者的测试机是未开启KPTI的.
而在开启KPTI时:3号中断函数调用的是KiBreakpointTrapShadow

用IDA对内核文件ntoskrnl.exe的KiBreakpointTrapShadow分析

kibts
由IDA分析可知,KiBreakpointTrapShadow 只是做了一些调用0环函数前的准备行为,如切换内核Cr3,切换内核rsp,切换内核gs等, 最后跳到了KiBreakpointTrap真正执行中断函数。

而未开启KPTI时,中断函数并不是KiBreakpointTrapShadow而是KiBreakpointTrap,而KiBreakpointTrap中并没有这些进内核的准备行为,笔者猜测进KiBreakpointTrap前肯定还执行过类似的代码, 目前还未查到

后面本人通过构建中断门进行测试发现,进去中断函数时rsp已经切换为0环的rsp, _KTrap_Frame的那5个寄存器也在栈中, cr3本身就是内核cr3 ,不需要改, 但是gs还没修改, 所以我们的构建中断门函数代码里边只用修改gs就可以调用内核函数了


二、代码实现

1.配置项目

1.创建vs空项目, 笔者项目名为IntGate
2.创建main.cpp文件和x64asm.asm文件(asm文件随便创建一个文件后, 将后缀为.asm就行)

3.右键项目->生成依赖性->生成自定义, 第四个打上勾

ro1
ro2

4.右键x64asm.asm,按如下图选择

在这里插入图片描述

5、打开项目属性设置固定基址, 并关闭增量链接

a1
a2

2.代码实现

代码如下(部分硬编码的地方需要更改):

main.cpp

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

extern "C" void InterruptEntry();
extern "C" void CaseInterrupt();



int main()
{
    
    
	printf("InterruptEntry Addr:%p\n", (ULONG64)InterruptEntry);
	// 笔者InterruptEntry为0x0000000140001200
	if ((ULONG64)InterruptEntry != 0x0000000140001200)
	{
    
    
		printf("InterruptEntry地址与中断门构建的地址不一样\n");
		system("pause");
		return 0;
	}
	system("pause");

	CaseInterrupt();

	system("pause");
	return 0;
}

x64asm.asm

option casemap:none

.data
pStr db 'I am the DbgPrint func', 0DH, 0AH

.code

InterruptEntry proc
	;切换gs
	swapgs

	;调用DbgPrint函数. 为方便直接用windbg查了之后将函数地址写成硬编码了
	mov rax,0fffff8047e7647b0h
	sub rsp,20h
	lea rcx,[pStr]
	call rax
	add rsp,20h

	; 恢复gs
	swapgs
	iretq
InterruptEntry endp


CaseInterrupt proc
	int 0fh ;f号中断系统未使用
	ret
CaseInterrupt endp


end

windbg配置

1.构建中断门
笔者InterruptEntry地址为0x0000000140001200,中断门属性就填3号中断的属性,地址填0x0000000140001200

 windbg:
 eq idtr+f0 4000ee00`00101200
 eq idtr+f8 00000000`00000001
 !idt f

windbg1

2.设置Cr4寄存器中SMEP和SMAP, 把3去掉就行

windbg2


运行截图

在这里插入图片描述


三、参考资料

如有错误, 还请大佬指正

猜你喜欢

转载自blog.csdn.net/deadpoolwilson12/article/details/130367254
今日推荐