更新于2022-10-19
PS:请学习完前三章后观看本章
linux内核定义的控制寄存器(control register)共有5个,分别为cr0
cr1
cr2
cr3
cr4
,这5个控制寄存器在内核中扮演了非常重要的角色,需要牢记
cr0
cr0寄存器中的 PE (page enable)
表示模式,1表示保护模式,0表示实模式。
cr0寄存器中的 PG
表示是否开启分页,PG=1 PE=1
才开启分页模式,其他情况都不能开启
cr1
cr1寄存器被保留了,暂时没有作用
cr2
cr2寄存器用于存储触发缺页异常的线性地址(虚拟地址)
cr3
cr3寄存器用于保存页全局目录表PGD(page global directory)
的地址
linux系统采用四级页表PGD->PUD->PMD->PTE
KPTI(Kernel Page Table Isolation)
KPTI是内核用于隔离kernel和user的PGD
的机制。
显然,开启了该保护是由于修改了cr3寄存器的值来更换 不同的页表
但是为了提高切换页表的速度,kernel页表和user页表是很接近的
user_pgd_addr = kernel_pgd_addr + 0x1000
反应到cr3寄存器上即翻转cr3[12]
这里需要知道的是 kernel页表保存了用户态和内核态空间的完整映射。
而 用户态页表只保留了用户态空间的完整映射和部分内核态空间的映射(系统调用入口点、中断处理等等)
对于绕过kpti的保护,我们只需要执行内核中的swapgs_restore_regs_and_return_to_usermode
函数来返回用户态即可(不使用swapgs、iretq)
这个函数的功能相当于
mov rdi, cr3
or rdi, 0x1000
mov cr3, rdi
pop rax
pop rdi
swapgs
iretq
在rop绕过时需要执行如下操作
↓ wapgs_restore_regs_and_return_to_usermode
0 // padding
0 // padding
user_shell_addr
user_cs
user_rflags
user_sp
user_ss
感谢arttnba3 blog
详细描述了kpti及其绕过手法
cr4
cr4寄存器结构如下
SMAP/SMEP
其中需要我们关注的是cr4[20]
和cr4[21]
,标志位为1时表示开启SMAP/SMEP,标志位为0时表示关闭。
SMAP(Supervisor Mode Access Prevention)/SMEP(Supervisor Mode Execution Prevention)
SMAP开启时,kernel无法访问user地址的内存,SMEP开启时,kernel无法执行user地址的代码。
但是显然,如果内核代码存在栈溢出问题可以让我们使用rop,或许我们可以利用rop修改cr4寄存器的 SMAP/SMEP标志位来使得kernel可以访问并执行 user的代码。
references
https://www.cnblogs.com/HcyRcer/p/16559321.html
arttnba3 blog
详细描述了kpti及其绕过手法