首页
社区
课程
招聘
[原创]ROP(Return-Oriented Programming)返回导向编程 · 游戏安全相关技术边界探索
发表于: 1天前 648

[原创]ROP(Return-Oriented Programming)返回导向编程 · 游戏安全相关技术边界探索

1天前
648

系列目录(共四篇)

  1. ROP 是什么,原理,初步认识 ROP(本文)
  2. 初步探索 — 基于ROP技术弹个MessageBox & 安全退出
  3. 深入探索 — 挖掘ROP在游戏安全领域的能力边界
  4. 反作弊对抗相关思考 & 检测手段

1,ROP 是什么,原理,初步认识 ROP

1, ROP 为返回导向编程技术,基于 ret = pop + jmp 这一技术细节。假设我们在栈上合适的位置放置一个地址,配合 ret 指令的执行,就可以达到修改 RIP 的效果,从而可以可控地改变 CPU 执行流。

2, 更进一步,假设我们在栈上多个合适位置放置多个地址,再配合 ret 指令,理论上就可以达到多次控制 CPU 执行流的可能。这就是 ROP。

一个最简单的模型:

                    线程栈                         高地址
                    ┌────────────────────────────────┐
                    │  地址 F                        │
                    │  地址 E                        │
                    │  地址 D                        │
                    │  地址 C                        │
                    │  地址 B                        │
                    │  地址 A          ← RSP         │
                    └────────────────────────────────┘
                                                   低地址

假设地址 A、地址 B、地址 C …… 地址 F 都指向任意不同的 ret 指令的地址。

  • 假设地址 A = ntdll.dll 中任意一个 ret 指令的地址
  • 假设地址 B = user32.dll 中任意一个 ret 指令的地址
  • 假设地址 C = kernel32.dll 中任意一个 ret 指令的地址
  • …
  • 假设地址 F = dxgi.dll 中任意一个 ret 指令的地址

则神奇的现象发生了:当执行 ret 指令的时候,ret = 弹出地址 A + JMP 地址 A + RSP 指向地址 B = RIP 跳到 ntdll.dll 中。由于地址 A 指向的是 ret 指令,则继续 ret = 弹出地址 B + JMP 地址 B + RSP 指向地址 C = RIP 跳到 user32.dll 中。依此类推,栈上地址 C 至 F 会按同样方式连环触发 ret,最终 RIP 进入 dxgi.dll。

以上是一个无聊的、漫无目的的多模块横跳。只不过,这也就是 ROP 的核心思想,即:基于精心构造的栈布局,从而操控 CPU 指令流。


先介绍 2 个工具:

  • Hawkeye ROP:Windows gadget 搜索工具(小零件搜索工具)
  • Hawkeye Lab:Windows 游戏内核级作弊检测 / 评估工具

更进一步: 假设我们打算调用 HDC hDC = GetDC(NULL);。在 x64 调用约定下,rcx、rdx、r8、r9 依次承载前四个参数;对 GetDC(NULL) 而言,需要先把第一个参数置为 0,再转入 GetDC 执行。处理第一个参数时,直觉上会去找 mov rcx, 0; ret 这类 gadget——一条指令完成赋值并返回。但在真实模块里,这种「写寄存器 + 立刻 ret」的组合并不常见,往往并不好找。更务实的做法是换一条等效路径:在栈上预先放好常数 0,再用 pop rcx; ret 把它弹进 rcx(具体布局见后文「线程栈示意」)。

先介绍如下, 我们以 notepad.exe 为例。

1, Hawkeye ROP 的作用就是搜索 gadget(代码小零件)。这里我们发现 pop rcx; ret 组合的小零件非常多,如图 2。一般而言,我们更加喜欢 ntdll.dll 中的小零件。原因: 几乎每个进程都会加载 ntdll。

2, Hawkeye Lab:gadget 找到之后,也是需要验证的。毕竟可执行代码区中,有些地方是被重定位修复的,而被修复的地方碰巧也会命中小零件的二进制码序列,而这个我们尽量不要用。

3, 小零件 gadget 是不需要指令对齐的。如图 1,pop rcx; ret 的二进制码是:0x59 0xC3。我们完全可以把 0x00007ffc8e5877fe 地址拿来当小零件地址,这是没有任何问题的。Hawkeye ROP 工具支持截断搜索能力。

图片描述

图 1. pop rcx; ret 指令与截断地址示例。

图片描述

图 2. Hawkeye ROP 搜索 pop rcx; ret(notepad 示例)。

线程栈示意(pop rcx; ret 时的布局):

                    线程栈                         高地址
                    ┌────────────────────────────────┐
                    │  地址 E                        │
                    │  地址 D                        │  (4)
                    │  地址 C                        │  (3)
                    │  地址 B  下一个 gadget 地址    │  (2)
                    │  0ull            ← RSP         │  (1)
                    └────────────────────────────────┘
                                                   低地址

假设此刻 RIP -> 7ffc8e58429e;RSP -> (1) 会怎么样?

  1. 执行 pop rcx = 弹出 0ull 给 rcx + RSP 移动到 (2)
  2. 执行 ret = 弹出下一个 gadget 地址给 RIP + RSP 移动到 (3)

结果就是 RIP 开始执行第二个 gadget。至此,完成了 rcx = 0 的赋值操作。

那么 ROP 核心是什么呢? 现在我们应该知道了:ROP 的核心就是在栈上精心布局、一步步的行动。


ROP 与 ShellCode 有何不同?

从实现方式、检测面与开发成本上,可以这样对照理解:

  1. ShellCode 本身是一段可执行指令,通常需要在目标进程里分配或映射可执行内存,并把 RIP 引到该处。
  2. ShellCode 字节序列较固定,容易被做特征 / 签名;在开启 DEP / NX 时,「写入再执行」的路径往往直接受阻。
  3. ShellCode 编写相对自由:可按意图安排 push / pop 等指令,一般不必像 ROP 那样为栈上每一格做精确规划。
  4. ROP 几乎不注入完整指令块,而是串联进程内已有的 gadget;攻击意图主要体现在栈上的返回地址链,难以用固定指令模板做特征。
  5. ROP 控制流在既有模块的代码段里跳转,对 DEP / NX 相对宽松;CET 等强化控制流完整性的机制则另当别论(本系列后文再谈)。
  6. ROP 实现门槛更高:即便有 gadget 搜索工具或 AI 辅助,仍常因小零件不足而换模块、改方案。
  7. ROP 不能随意选用带 push / pop 的 gadget,否则会打乱栈布局。胜负手仍在于对栈的精细设计与逐步推进。

本篇小结

本篇从 ret 与栈的关系入手,说明 ROP 的本质:在栈上排好一串返回地址,用多次 ret 把 RIP 逐步导到进程内已有的 gadget,从而可控地改变执行流。

  • 以 GetDC(NULL) 为例:x64 下需令 rcx = 0;理想的 mov rcx, 0; ret 在常见模块里往往难找,更务实的路径是栈上放 0,配合 pop rcx; ret。
  • Hawkeye ROP 负责搜索 gadget,Hawkeye Lab 负责在真实进程里验证;选型时注意重定位误命中,并理解「截断地址」与指令对齐在文中的含义。
  • 与 ShellCode 对照:ROP 一般不另写、注入一段 shellcode,而是复用进程里已有的 gadget,因此对 DEP / NX 更友好,但栈布局约束更强、工程成本更高;CET 等保护措施随着硬件和Win11的迭代将会越来普及。

下一篇:将以Notepad进程为目标进行实验,用完整 ROP 链弹 MessageBox 并安全退出。
同时我们一起面对Shadow space。看看影子空间对于ROP的影响。


开源

本系列相关 Hawkeye 开源仓库:


下一节: 初步探索 — 基于ROP技术弹个MessageBox & 安全退出。


冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
点赞 ・0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回