SMEP和SMAP
SMEP在CR4寄存器的第20位,SMAP在CR4寄存器的第21位
简单来说
- 当SMEP启用时,内核不能执行来自用户层地址的指令
当SMAP启用时,内核不能读写来自用户层地址
- 若
EFLAGS.AC
标志位置位,则SMAP失效
- 若
验证SMEP
/********************* main.cpp *****************************/
#include <stdio.h>
#include <Windows.h>
extern "C" void Message(); // 0x00000001400010E0
extern "C" void int21(); // 21号中断基本没用
extern "C" ULONG64 x;
ULONG64 x;
int main(void)
{
printf("Func: 0x%p\n", Message);
if(ULONG64(Message) != 0x00000001400010E0) { // Message函数的地址
printf("Message Func Address Error\n");
exit(1);
}
int21();
system("pause");
return 0;
}
/********************* myasm.asm *****************************/
option casemap:none
extern MessageBoxA:proc
extern ExitProcess:Proc
includelib user32.lib
includelib kernel32.lib
extern x:qword
.const
MYMSG1 db "Hello World", 0
TITLE1 db "x64 asm", 0
.code
Message proc
iretq
Message endp
int21 proc
int 21h
ret
int21 endp
end
修改idt 21,指向函数Message
,接着运行,直接崩溃蓝屏
然后将CR4的第20位置0,然后重复实验,正常运行
验证SMAP
修改验证代码,关闭SMEP的前提下在Message
函数中,读取R0地址,赋给变量x,然后打印出来,这里读取idtr的第一项
...
int21();
printf("idtr[0]: %#x\n", x); // 打印
system("pause");
...
...
Message proc
; stac
mov rax, qword ptr [0fffff80342672000h]
mov x, rax
iretq
Message endp
...
再次运行,依然会崩溃蓝屏
然后将CR4的第21位置0,然后重复实验,正常运行
除了修改CR4的第21位,还可以利用stac
指令来开启SMAP许可(在内核中就是这么做的,因为在内核中,有些时候是需要读写R3的地址,例如参数返回值的拷贝工作)
其原理是:EFLAGS
寄存器中有个AC
标志位,当AC标志位置位时,SMAP就不再检测
clac
指令用于清除EFLAGS
的AC
标志位