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

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

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

SMEP & SMAP实验:构造IDT后门第一步:编译以下代码第二步:构造IDT后门第三步:运行程序第四步:验证SMEP第五步:修改代码,再次运行第六步:验证SMAP第七步:使用STAC指令

结语参考资料

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

#include

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节。

参考资料

bilibili周壑:x64内核研究系列教程

🌈 相关推荐

僵尸世界大战存档位置介绍
365bet备用网站

僵尸世界大战存档位置介绍

📅 09-02 👁️ 3044
鳳梨怎麼催熟,如何判斷鳳梨是否成熟 | 飲食指南
365网络股份有限公司总部

鳳梨怎麼催熟,如何判斷鳳梨是否成熟 | 飲食指南

📅 08-16 👁️ 2428
世界杯数据揭秘
365bet备用网站

世界杯数据揭秘

📅 07-29 👁️ 9426