运行时程序扩展工程——从「分析」进入「修改与扩展」的工程化

一句话

「找到指令并调用它」不是一步,而会自然分叉出一整套运行时修改/扩展工程。 Shellcode、DLL、Hook、Trampoline、Signature、线程管理不是零散技巧,分别属于「代码载体、控制流、定位、运行时管理、维护」这些工程阶段——分析链回答「它怎么工作」,扩展链回答「我怎么改变或扩展它」。


一、从「分析」进入「执行扩展」

分析链(逆向):

1
游戏 → 数据 → 地址 → 状态 → 指令 → 函数 → 系统 → 机制

目标从「我想知道它怎么工作」变成「我想改变或扩展它」,就进入另一条链:

1
2
分析结果 → 确定修改点 → 确定执行方式 → 准备代码载体 → 建立执行入口
→ 处理执行上下文 → 处理并发/线程 → 执行扩展逻辑 → 恢复/继续原程序 → 验证稳定性

这称为运行时程序扩展工程(Runtime Modification / Extension)


二、「调用指令」本身分三层

1
2
3
A. 修改已有数据    Player.Health → Write → 新值(最低层)
B. 修改已有代码 原代码 A→B→C 变成 A→X→B→C(X 需要自己的代码)
C. 调用原程序能力 找到已有函数 → 理解参数 → 构造上下文 → 调用

修改代码/调用功能都需要「自己的代码」放在哪里——于是出现代码载体(code storage)+ 控制流转移(control-flow redirection)。空白地址只是实现手段之一,不是核心概念。


三、代码载体:Shellcode vs DLL

新代码空间来自不同机制:

1
2
3
4
5
6
代码载体
├── 原程序已有空间
├── 模块自身已有空间
├── 新分配的可执行内存
├── 外部模块
└── 其他宿主机制
  • Shellcode:代码片段,尽量独立、直接执行——「我只需要在这里执行一小段逻辑」
  • DLL:扩展模块,有数据/函数/状态/多个模块/完整工程——「我要给目标程序增加一个相对完整的软件模块」

从工程角度:Shellcode 更接近「代码片段」,DLL 更接近「扩展模块」


四、真正困难的是运行时安全性

把逻辑注入多线程共享状态的游戏循环后:

1
游戏线程 → 原逻辑 → 注入的逻辑 → 原逻辑继续

产生大量工程问题:执行上下文、线程安全、同步、锁、阻塞、死锁、竞态、栈状态、寄存器状态、异常处理、生命周期、内存有效性、调用约定。

「能执行」只是第一层,「不破坏原程序」才是第二层。

线程处理应独立成一个阶段:

1
2
确定执行点 → 确定执行线程 → 判断执行频率 → 判断执行时间 → 判断是否允许阻塞
→ 判断共享数据 → 确定同步方式 → 确定异常处理 → 确定退出方式

例如「每帧执行」和「后台线程执行」是完全不同的工程设计:

1
2
3
游戏线程   → 同步任务 / 快速任务
后台线程 → IO / 网络 / 计算 / 数据处理
线程之间 → 消息 / 队列 / 共享状态 / 事件 / 同步机制

五、特征码定位 = 定位稳定性工程

它解决「程序版本变化后,原地址还能不能找到」:

1
固定地址 → 不稳定 → 寻找稳定特征 → Signature / Pattern → 重新定位

这是定位稳定性工程,不只是逆向技术。


六、整个体系:十大子系统

1
2
3
4
5
6
7
8
9
10
11
游戏程序分析与扩展工程
├── ① 目标分析
├── ② 数据分析 数值定位 / 地址分析 / 指针分析 / 数据结构恢复
├── ③ 状态分析 状态变化 / 状态关系 / 状态机恢复
├── ④ 指令分析 指令 / 基本块 / 函数 / 调用关系 / 控制流
├── ⑤ 系统分析 游戏对象 / Component / System / Gameplay
├── ⑥ 定位工程 地址 / Pointer / Module+Offset / Signature
├── ⑦ 代码扩展 原代码空间 / 外部代码空间 / Shellcode / DLL/模块
├── ⑧ 控制流修改 跳转 / Hook / Trampoline / 原逻辑恢复
├── ⑨ 运行时管理 Thread / Synchronization / Exception / Lifecycle / Resource
└── ⑩ 验证与维护 功能验证 / 稳定性 / 性能 / 版本适配 / 回归验证

七、层次关系与工程方向

1
游戏世界 → 游戏机制 → 游戏系统 → 函数 → 指令 → 地址 → 内存 → 机器状态

分析手段反方向(从机器状态往上恢复),扩展手段再往下(让修改长期存在):

1
2
3
4
内存 → 地址定位 → 数据识别 → 状态识别 → 指令定位 → 函数恢复
→ 系统恢复 → 游戏机制理解 → 修改/扩展

修改 → 定位稳定性 → 版本适配 → 线程安全 → 异常安全 → 性能 → 自动化

最终与软件工程形成镜像:

  • 软件工程:人类需求 → 游戏设计 → 系统设计 → 对象/数据 → 程序代码 → 指令 → 内存
  • 逆向工程:内存 → 地址 → 数据 → 指令 → 函数 → 对象 → 系统 → 游戏机制
  • 调试工程:横跨中间,找「预期状态 vs 实际状态」的差异
  • 运行时修改/扩展:已知程序 → 确定修改目标 → 确定代码载体 → 建立控制流 → 处理执行上下文 → 处理线程/生命周期 → 运行 → 验证 → 版本适配

与其他线的关系

  • 与逆向工程论(07-工程控制/07):07 讲逆向的分析侧(还原);本文讲逆向之后的分叉——修改与扩展的执行侧
  • 与逆向信息保存方法(07-工程控制/09):09 讲如何保存找功能的思路与知识;本文讲找到之后如何把修改做对、做稳(能执行只是第一层,不破坏原程序才是第二层)
  • 与拆解程序(12-游戏/13):拆解程序的修改六级(改数据/改状态/改行为/改控制流/扩展功能/调用能力)即本文「调用指令三层」的展开