linux内核基础 四 控制寄存器

2022-10-19

更新于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及其绕过手法