当目标代码执行完毕,需要返回控制权给原代码时,将产生返回控制权行为。返回控制权行为,比转移控制权行为简单得多。因为,一切条件已经在交出控制权之前准备完毕,返回时仅需出栈就行了。
1、 near call的返回
近调用情况下,段不改变,即 CS 不改变,权限级别不改变。从栈中pop返回地址到EIP寄存器时,需进行 limit 的检查。
2、 直接控制权转移的返回(far call或far jmp)
直接转移返回到相同权限级别,发生跨段的返回,权限不变。这时,CS 被从栈中 pop 出来的 CS 值加载进去,处理器会检查 CPL 与这个 pop 出来的选择子(calling procedure CS)中的RPL进行检查,相等则属相级返回。
3、 利用各种门符进行向高权限代码转移后的返回
★ 检查保存在 called procedure stack中的原calling procedure CS的RPL域以确保是从高权限向低权限代码返回。
★ 原 calling procedure CS及EIP被 pop到 CS及 EIP 寄存器中。
★ 若有参数时,called procedureESP需恢复栈结构(加上相应参数 size)
★ 原 calling procedure SS及 ESP被 pop到 SS及 ESP寄存器中。
★ 若有参数时,原 calling procedure ESP 需恢复结构(加上相应参数 size)。
★ 恢复原 calling procedureCS后,将检查每个segment selector(DS、ES、FS及GS),假如数据段权限高于CS,则被加载null segment selector。
操作系统必须至少建立一个TSS,4个权限级别的堆栈结构(stack segment selector及stack pointer)必须被定义。
一、 堆栈及栈指针的权限级别:
★ 3 级:stack selector及stack pointer存储在SS寄存器及 ESP 寄存器中
★ 0、1及2级:相应的stack selector及stack pointer存储在TSS相应的域中。
二、当发生向高权限级别代码转移时,发生堆栈的切换:
★ 根据CPL(转移时CPL改变)在TSS得到相应级别的堆栈结构(SS及ESP)
★ 进行栈结构检查,包括limit检查、stack segment descriptor一系列的检查后,stack selector 及 stack pointer加载到 SS及 ESP寄存器。
★ 将原来级别的(权限低)stack selector及stack pointer压入新的堆栈中(权限高),这个过程是:加载新的SS及ESP时,先临时保存旧的SS及ESP,再将临时保存旧的SS及ESP压入新的堆栈中。
★ 若有参数,则压入参数(参数个数定义在call gate中的param count域)
★ 压入返回地址(CS及EIP)
★ 若有错误码,则压入错误码。
注意事项:
★ call gate 允许最多31个参数,在调用者的堆栈里。发生切换时,将从调用者的堆栈里复制到新的堆栈里。
切换后堆栈结构图:
calling procedure called procedure
… … |
param1 |
Param2 |
Param3 |
… … |
… … |
calling SS |
calling ESP |
param1 |
param2 |
param3 |
calling CS |
calling EIP |
... ... |
… …
|
-
顶
- 0
-
踩
- 0