8-跨段提权与调用门

上一篇文章使用 jmp far 指令实现代码跨段,本质上就是改变 cs 段寄存器。但是我们发现,无论如何,jmp far 也无法更改 CPL。即使你的 RPL = 0,也是徒劳。

有没有办法更改 cs 段寄存器,同时也更改 CPL?答案是肯定的。本篇提到了调用门只是其中的一种方法,还有其它方法,后文会陆续介绍。

1. 在 3 环能读取高 2G 内存吗?

回答这个问题最笨的方法就是做一个实验。

int main() {
  int x = *(int*)0x8003f000;
  printf("%08x\n", x);
  return 0; 
}

上面这段代码,如果你运行通过了,保护模式你也不用学了。高2G内存是被页机制所保护,不要慌,知道即可,马上就会到页知识。CPU只允许CPL为0、1、2的程序访问高2G内存。无论如何,在3环下你也读不了这个地址的内存。

唯一的方法就是,让你的特权级变成0、1、或者2。这意味着,你得想办法把你的CS段寄存器的后两位修改为 0、1、2。为了后文实验方便,我们以后只说把特权级改为 0.

通过 jmp 是行不通的,因为 jmp 不能提权。

2. 调用门

调用门,是CPU提供给我们的一个功能,它允许 3 环程序(CPL=3)通过这扇“门”达到修改 cs 段寄存器的目的,同时达到提权的目的。

“门”,是一种系统段描述符(段描述符的 S=0),这个描述符的结构和数据段描述符和代码段描述符有很大区别,这种描述符中嵌入了选择子。如果你在“门”嵌入DPL=0的代码段选择子,那么你在 3 环,就可以通过这扇门,到达0环领空,这时候你的CPL=3就变成CPL=0。

调用门就具备了这种功能。你可以在调用门中嵌入选择子 0x0008,这个选择子指向的是 DPL = 0的代码段。然后使用 call far + 调用门描述符的段选择子,跨段到 0x0008 指向的代码段。

3. call far 指令对堆栈的影响

3.1 跨段提权

如果你的程序发生提权,该指令首先会切换堆栈。

切换堆栈的意思是,改变 ss 段寄存器的值。还记得当时是如何讲解 CPL 的概念的吗?没错,cs 或 ss 段寄存器的最低 2 位的值。

倘若你的程序发生提权,这时候 cs 的低 2 位变成了 0,那么 ss 的低两位不变,岂不是很矛盾?所以,提权的时候,切换栈是必须的。

那么问题来了,cs 段的选择子我们可以填进调用门描述符里去,ss 段的选择子从何处而来?这是一个很深刻的话题,第13篇任务状态段将会给出答案。

这里我们只关心,call far 指令会在新栈 ss0 (表示0环栈)中压入哪些值?

不妨看下面的图。

这里写图片描述

图1 CPU会自动的在0环栈中压入 ss3, esp3,cs3,eip3

当使用 call far 指令提权的时候,发生栈的切换。同时,CPU在0环栈中压入3环栈和栈指针,以及3环cs段选择子,以及返回地址 eip3。如果CPU不保存ss3,当调用门结束返回的时候,如何找的到 3 环栈呢?如果CPU不保存 3 环 cs 段选择子,如何能够再退回到原来 CPL=3的权限呢?仔细想想,CPU做这些事情是很有道理的。

3.2 跨段不提权

这种情况,要简单很多,不提权,意味着,不需要切换栈,也不需要保存3环栈段寄存器 ss 和 esp了。它的堆栈变化图如下。

这里写图片描述

4. 总结

本篇简单讲解了如何进行跨段权切换,以及权限切换发生的一些细节。后文重点讲解调用门的两个实验。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值