利用 iret 修改 CS 和 IP(即 CS:EIP)的核心是:在栈上伪造一个中断返回帧,然后执行 iret 指令 ,CPU 会从栈顶弹出 EIP、CS、EFLAGS 并加载到寄存器中,从而实现跳转。
基本步骤(以 x86 32 位为例)
-
准备栈顶布局 (从高地址到低地址,即
iret执行前的ESP指向最低地址):[EIP] ← 目标偏移
[CS] ← 目标代码段选择子
[EFLAGS]← 标志寄存器值 -
如果需要同时修改
SS和ESP(特权级变化时),还需额外压入ESP和SS。 -
让
ESP指向上述栈帧的底部 (即EIP所在地址)。 -
执行
iret,CPU 自动完成:-
pop EIP -
pop CS -
pop EFLAGS -
如果特权级发生变化(例如从内核返回用户态),还会继续
pop ESP和pop SS。
-
典型应用场景
-
内核漏洞利用 :在内核态修改线程的内核栈,伪造返回帧,使
iret返回到用户态 shellcode。 -
任务切换:在裸机或操作系统内核中手动切换任务(保留原任务寄存器状态)。
-
调试/测试:直接改变 CPU 执行流。
示例代码(32 位保护模式)
cpp
; 假设当前 CPL = 0,要跳转到段 0x08,偏移 0x1234
push dword 0x00000246 ; EFLAGS (IF=1, 保留其他位)
push dword 0x08 ; CS
push dword 0x1234 ; EIP
iret
注意事项
这种技术常被用于恶意代码或内核提权。在正常开发中请勿滥用;理解原理有助于防御此类攻击(如检查栈帧完整性、启用 SMEP/SMAP 等)。
安全提示
-
特权级检查 :如果目标
CS的 RPL(请求特权级)高于当前 CPL,iret会触发一般保护异常(GPF)。要降低特权级(如从 Ring 0 到 Ring 3),需要同时提供用户态的SS和ESP,栈帧扩展为:bash[EIP] [CS] [EFLAGS] [ESP] [SS] -
栈对齐 :
iret要求栈指针 4 字节对齐(32 位)或 8 字节对齐(64 位)。 -
EFLAGS 合法性:某些位(如 VM、RF)不能被随意设置,否则可能引发异常。
这种技术常被用于恶意代码或内核提权。在正常开发中请勿滥用;理解原理有助于防御此类攻击(如检查栈帧完整性、启用 SMEP/SMAP 等)。
