Windows x64内核学习笔记(三)—— SMEP & SMAP

SMEP & SMAP

SMEP:位于Cr4的第20位,作用是让处于内核权限的CPU无法执行用户代码。
SMAP:位于Cr4的第21位,作用是让处于内核权限的CPU无法读写用户代码。

关于控制寄存器各个标志位的具体含义可参考Intel开发手册卷3第2.5节。
在这里插入图片描述

实验:构造IDT后门

描述:尝试在x64系统中构造IDT后门

第一步:编译以下代码

//x64asm.asm
option casemap:none

EXTERN x:qword

.DATA

.CODE

IntEntry	PROC
		iretq
IntEntry	ENDP

go	PROC
		int 21h
		ret
go	ENDP

END
//test.c
#include <windows.h>
#include <stdio.h>

extern "C" void IntEntry();
extern "C" void go();
extern "C" ULONG64 x;

ULONG64 x;

void main()
{
	if ((ULONG64)IntEntry != 0x0000000100001000)
	{
		printf("wrong IntEntry at %p \n", IntEntry);
		system("pause");
		exit(-1);
	}

	go();
	printf("%p \n", x);
	system("pause");
}

x64asm.asm属性
在这里插入图片描述
在这里插入图片描述
项目属性
在这里插入图片描述
在这里插入图片描述

第二步:构造IDT后门

IntEntry函数表示手动构造IDT后门的入口地址,笔者环境下的地址为0x100001002

这里选择将后门写到IDT[0x21]的位置,Win10系统没有占用这个位置,里面保存的是IDT的基地址,可以看一下。
在这里插入图片描述

那么,只要构造好中断门描述符,并写到IDT[0x21]就可以了。

构造好的中断门描述符(可以从IDT[3]的位置拷贝一份进行修改):

低四字节:0000ee00`00101000 高四字节:00000000`00000001

将构造好中断门描述符写入IDT[0x21]
在这里插入图片描述

查看写入的IDT后门解析情况,目标地址已经成功指向后门函数的地址。
在这里插入图片描述

第三步:运行程序

注意:运行程序前可以先给虚拟机打个快照。

运行结果:系统卡死,且WinDbg无法中断。
在这里插入图片描述
其实这个时候产生了三重错误(三重错误的概念在VT系列笔记中提到过),因此WinDbg也无法接管。

正常来说,在x86系统中构造IDT后门,只要权限和地址正确,就能够正常调用。

而从Windows 8的某一版本开始,开始引入了一些保护机制,即在Cr4中加入SMEP和SMAP这两个标志位,用于防止内核权限的CPU读写或执行用户代码。

回滚快照,看一下程序运行前Cr4的值:
在这里插入图片描述
可以看到,此时SMEP和SMAP两个标志位都为1。

第四步:验证SMEP

在WinDbg中将SMEP位改为0。
在这里插入图片描述
然后再次运行程序,运行结果:
在这里插入图片描述

可以看到,此时已经可以正常运行了,程序成功走到了后门函数并返回。

由于我们目前还未加入修改变量x的代码,因此读出来的值是0,是正常的。

第五步:修改代码,再次运行

将后门函数的代码修改为如下,重新编译

IntEntry	PROC
		mov rax, qword ptr [0fffff8034b290fd0h]		// gdt[4]
		mov x, rax
		iretq
IntEntry	ENDP

0fffff8034b290fd0h这个值是通过windbg读取的,指向gdt表的第4项
在这里插入图片描述
目的是尝试让程序通过后门函数读取0环的内存。

运行结果
在这里插入图片描述
系统再次卡死,这次是由于触发了SMAP保护。

第六步:验证SMAP

回滚快照,下面来验证下SMAP位,记得先将IDT设置好。
在这里插入图片描述

然后把SMAP和SMEP都置为0:
在这里插入图片描述
再次运行程序,运行结果:
在这里插入图片描述

此时,由于又解除了SMAP保护,程序已经能成功从0环读取数据了。

第七步:使用STAC指令

描述:STAC指令相当于Set AC,用于设置AC标志位,能暂时解除系统的一些保护,包括SMAP保护。
在这里插入图片描述
再次回滚快照,这次我们只清除Cr4的SMEP位,保留SMAP位,注意构造IDT后门。
在这里插入图片描述
将后门函数的代码修改为如下,重新编译:

IntEntry	PROC
		mov rax, qword ptr [0fffff8034b290fd0h]
		stac	;如果找不到这条指令,可以emit对应的字节码
		mov x, rax
		iretq
IntEntry	ENDP

运行结果:
在这里插入图片描述

可以看到,在不解除SMAP位的情况下,使用STAC指令后依然能够读到0环内存。

结语

那么通过以上内容,我们了解并验证了SMEP/SMAP这两个标志位的作用。

事实上,就算解除了SMEP和SMAP保护,目前也只能访问和执行一部分0环内存,这是因为还存在「内核页表隔离」机制,这是后话了。

关于SMAP保护的具体实现可参考Intel开发手册卷3第4.6节。

参考资料

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值