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]的位置拷贝一份进行修改):
低四字节:
0000
ee00`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节。
参考资料
- bilibili周壑:x64内核研究系列教程