要点回顾
- 通过前文知道JMP FAR可以实现段间跳转,如果要实现跨段的调用就必须要学习CALL FAR,也就是长调用。
- CALL FAR 比 JMP FAR 要复杂,JMP并不影响堆栈,而CALL指令会影响。
短调用
指令格式:CALL 立即数/寄存器/内存
发生改变的寄存器:ESP、EIP
长调用(跨段不提权)
指令格式:CALL CS:EIP(EIP是废弃的)
并不使用后面的EIP,EIP是被废弃的。
主要是CS段寄存器中的段选择子,通过段选择子去查询GDT表找一个段描述符,且该段描述符必须是调用门。
- 想跳到另一个段中,需要提供一个段选择子。
- 如果目标段与当前段是同级别的,比如CPL都是3,称为跨段不提权。
- 如果是这种情况,堆栈的变化与短调用不同的是:会先压入调用者的CS,把当前CS段选择子压入堆栈中,然后执行。并且ESP+8,ESP+8以后指向的仍然是返回地址。
这个时候,如果执行完了长调用,如果想返回就不能像原来短调用使用RET来返回,如果使用RET是没有办法把CS段选择子赋值回去的。
- 长调用执行后,需要使用长返回(RETF)来从另一个段跳转回来。
- 修改ESP,并将原来保存的段选择子重新赋值给CS段寄存器。
发生改变的寄存器:ESP、EIP、CS
长调用(跨段并提权)
指令格式:CALL CS:EIP(EIP是废弃的)
执行前:3环权限
执行后:0环权限
当跨段提权的时候,执行后的堆栈已经不是原来的堆栈了。且CS、ESP、CS都发生了切换。
发生改变的寄存器:ESP、EIP、CS、SS
总结
- 跨段调用时,一旦有权限切换,伴随着的就有堆栈的切换。
- CS的权限一旦改变,SS的权限也要随着改变,CS与SS的等级必须一样。
- JMP FAR 只能跳转到同级非一致代码段,但 CALL FAR 可以通过调用门提权,提升 CPL 的权限。
思考
SS 与 ESP 从哪里来?参见 TSS 段。