07-逆向工程
逆向工程论——从二进制还原出设计与机制
逆向工程不是「看汇编」,也不是「照着抄」——它是一套与软件工程平行的工程化流程:从可运行的二进制/程序出发,逐层还原出结构、行为与设计推断。核心是「从机器状态还原人类意图」。这一条线讲:逆向工程是什么(与调试/静态分析的区别)、记什么(对象关系>地址)、怎么证明(证据链)、怎么工程化(三大流程 + 26 步)。
一、逆向工程是什么:从实现反推设计软件工程与逆向工程是两条方向相反的构造/还原链:
12软件工程:人类意图 → 需求 → 设计 → 实现 → 机器状态(构造)逆向工程:机器状态 → 实现 → 结构 → 设计 → 人类意图(还原)
逆向工程的核心问题只有一个:
这个东西是怎么做出来的?
输入是已有软件/二进制,输出是:结构、行为、设计推断——原程序的行为模型 + 结构模型 + 数据模型。
例如拿一个 Windows .exe:
1234567891011121314151617EXE ├─ PE结构 ├─ Import / Export / Section / Entry Point ...
06-验证
验证——做出来的东西是否符合预期
测试 = 自动化断言「代码按设计工作」(对不对)。验证 = 判断「做出来的东西是否符合预期、有没有价值」(好不好、能不能用、有没有意义)。 测试可以自动化,验证往往需要人、AI、Bot 参与。对普通软件,验证≈功能验收;对游戏,验证是另一套东西——可通关性、可玩性、新手体验、趣味性——这些不能靠 gtest 断言,必须有人玩、自动玩、模拟世界运行。
一、测试 vs 验证1234567891011测试:自动化断言「代码按设计工作」 → 单元测试、集成测试、E2E → 回答「对不对」——功能有没有实现 → 可以自动化,结果确定(通过/失败) → 依据:设计文档、功能点、接口验证:判断「做出来的东西是否符合预期、有没有价值」 → 可通关性、可玩性、新手体验、趣味性、性能 → 回答「好不好、能不能用、有没有意义」——体验是否符合预期 → 往往需要人/AI/Bot 参与,结果有程度(好玩/一般/劝退) → 依据:设计意图、玩家体验、世界规则
游戏测试最核心的一点:普通软件主要验证「功能有没有实现」;游戏还要验证「设计的世 ...
05-测试
测试——从最小单元到完整系统的自动化断言
测试 = 自动化断言「代码按设计工作」。 一个程序拆成了系统、模块、函数,测试就是把每一层「按设计工作」用可重复的断言锁死。测试不是一种,而是一串从最小单元到完整系统的步骤——每一步测的东西不同、依据不同、工具不同。本篇讲这条链:CLI/GUI/游戏/网络四种程序类型各自怎么测,重点展开游戏(引擎系统 + 游戏系统)。
一、测试链:从最小单元到完整系统测试是一条从内到外的链,每一环测的是不同层级的「按设计工作」:
123456789101112131415单元测试 最小逻辑单元(算法 / 纯函数 / 组件数据)—— 不依赖外部 ↓系统测试 多个系统组合(ECS 系统协作)—— 真实内部数据 ↓数据驱动 配置文件 / 数据合法性(字段、数值范围、引用) ↓状态测试 状态转换合法性(合法转换允许、非法转换禁止) ↓关卡/场景 地图 / 场景数据(内容完整性、可达性、数值) ↓集成测试 完整流程链路(不跳层,真实数据串联多个接口) ↓用户流程 用户视角完整 ...
04-复刻软件
复刻软件——从成品反推设计并重新实现
复刻软件不是「照着抄」,而是「逆向设计」:从一个成熟产品反推出它的功能、状态、数据模型与交互,形成规格,再用自己的技术重新实现一个行为等价的新软件。它和逆向工程是两条不同的线——复刻在产品层面反推设计(不碰二进制),逆向在二进制层面还原机制。这一条线是工程控制主题「三种起点(演化/复刻/原创)」中「复刻」这一起点的完整展开。
一、复刻的本质:逆向设计,不是照抄很多人以为复刻是几十个人把软件每个按钮点一遍照着写,其实成熟的团队几乎不会这样做,他们有一套非常工程化的方法。
12原创是"演化"出来的——花几年试错复刻是"逆向设计"出来的——直接观察成熟产品
原创是在一个巨大方案空间里搜索:100 个决策 × 每个 5 种方案 = 5^100,几年时间大部分花在试错/推翻/重构。
后来者是在已验证方案附近继续搜索——不用再踩坑。所以成熟产品最大的价值不是代码,而是完成了「探索空间的收敛」。
后来者节省的主要不是编码时间,而是产品探索和方案验证的时间。这也是为什 ...
03-审查-用头文件验证依赖
审查——用头文件验证依赖关系
审查(Review)是工程控制的一种手段:在代码合入之前,检查它是否符合设计。依赖关系是审查的重点之一——而头文件是审查依赖关系最便宜的工具:不运行代码,看 include 关系就能验证「谁依赖谁」是否符合设计。这一条线:审查时怎么用头文件、能发现什么、不能发现什么。
一、审查依赖关系的目标设计阶段定了依赖规则(谁能依赖谁),实现阶段要验证代码遵守了没有:
1234567设计的依赖规则: 入口层 → 业务层 → 基础设施层(单向,不跨层) 业务系统 ← 入口系统;业务系统不依赖入口系统 A 依赖 B,B 不依赖 A(无环)审查要验证的: 实际代码的依赖 == 设计的依赖?
审查依赖 = 对照「设计允许的依赖」检查「代码实际的依赖」。
二、用头文件审查:方法头文件是依赖关系的静态表达(见依赖关系主题 04),审查时直接读它:
12345审查步骤: 1. 列出要审查模块的头文件包含关系 2. 画静态依赖图(谁 include 谁) 3. 对照设计的依赖规则 4. 标出违规:反向依赖、循环依赖、依赖泄漏、隐式依赖
123456 ...
02-过程与流程
过程与流程——变化、步骤、方法与实现的层次一句话
过程回答「系统要经历什么变化」;流程回答「我们按什么步骤让它发生」;方法回答「每一步采用什么技术」;实现则是最终的代码。
一、过程 vs 流程
过程(Process):描述「事情是怎样发生和变化的」——对象状态的变化。
流程(Flow / Workflow):描述「步骤按什么顺序执行」——人为设计的控制结构。
从例子理解(做饭)过程:
12买菜 → 洗菜 → 切菜 → 炒菜 → 装盘 (事情的发展过程)食材状态:生菜 → 洗净 → 切块 → 加热 → 熟菜(对象状态的变化)
流程:
123开始 → 选择菜单 → 买菜 → 做菜 → 吃饭 → 结束有菜?├─ 是 → 做饭 └─ 否 → 买菜
核心区别对照表
方面
过程
流程
关注点
变化
顺序
研究对象
状态演化
步骤组织
问题
发生了什么变化
先做什么后做什么
表达
状态、阶段
节点、连线
强调
因果
控制
软件中的区别
例子
属于
关注点
程序执行流程 if/else
流程(控制流)
判断、分支、顺序 ...
01-工程控制
工程控制——失控类型、六字模型与统一闭环一句话
软件工程控制 = 控制「做什么、做到什么程度、怎么做」。工程问题可以归纳为四类失控,用六字模型(做/对/全/适/整/快)逐一应对,最后用反馈闭环让每次修正都从问题产生处重新执行。
一、四类失控与六字模型四类失控
问题
现象
控制方法
不做(漏做)
忘记实现、忘记测试、遗漏需求
Checklist、需求追踪、覆盖率、Review
少做(欠缺)
功能实现了一半、异常没处理、边界没考虑
Definition of Done、测试、Review、规范
多做(过度)
过度设计、提前优化、写很多没人用的代码
YAGNI、需求边界、架构约束、阶段目标
乱做(混乱)
代码耦合、职责不清、命名混乱
分层、模块化、代码规范、重构
四个问题分别对应不同的工程手段。
1. 防止漏做(Don’t Miss)12345需求 ├── 登录 ├── 注册 ├── 找回密码 └── 修改密码
开发时每一项都必须对应:需求 → 设计 → 代码 → 测试 → 验收。任何一个没有对应,就 ...
07-CLI程序的设计顺序
CLI 程序的设计顺序——从不成形想法到静态库的双向闭环
设计起点线说「CLI 先设计入口参数」。这一篇把这句话展开成完整的 CLI 程序设计顺序:从用户不成形想法开始 → 分析 → 程序类型判断 → CLI 需求 → 用户操作 → CLI 能力需求 → API 能力匹配 → 发现缺口回跳静态库流程 → 设计 → 编码 → 审查 → 编译 → 测试。CLI 不是静态库 API 的包装器,而是需求的提出者——它通过与静态库之间的「API 缺口反馈」形成双向演化闭环。
一、CLI 是什么:不是包装器,而是消费者1.1 错误的流程123静态库API ↓CLI代码
这种「API 列表 → 生成 CLI 代码」的流程容易退化成「为了调用 API 而写的适配程序」:
123没有查询功能? → AI自己mock一个返回值没有导出功能? → AI写假文件没有状态接口? → AI伪造状态
因为它的目标变成:让代码编译通过。
1.2 正确的流程CLI 是需求的提出者,不是 API 的被动消费者:
123CLI想法 → CLI需求分析 → CLI功能点设计 → CLI需要什么能力→ API能 ...
06-七个分析维度
七个分析维度——分析任何程序的完整方法
分析一个程序,不能只画一张「分层架构图」。一个真正完整的工程分析,往往是把结构、调用链、启动链、生命周期、数据流、业务流、状态变化七张图叠起来。这一条线是「分析任何程序」的完整方法论:五个观察维度扩展为七个,用 HTTP 服务器作为贯穿例子(它恰好把七个维度全部暴露得很清楚),并给出最终原则。
一、五个观察维度(后扩展为七个)把「软件结构」与「软件运行」两套视角合起来,可以整理成:
123451. 代码组装位置2. 调用链3. 启动流4. 生命周期5. 运行流
分层回答「代码怎么组织」;调用链回答「谁调用谁」;启动流回答「怎么起来」;生命周期回答「怎么存在」;运行流回答「运行时怎么变化」。
二、HTTP 不只是「通信协议」更准确地说:
123HTTP├── 通信协议└── 应用层请求入口
12客户端 → HTTP Request → HTTP Server → HTTP Parser → Router → Handler→ Service → Domain/Algorithm → Database
POST /login 是业务入 ...
05-通信程序的设计顺序
通信程序的设计顺序——从协议到组件的向内倒推
设计起点线说「通信程序先设计协议」。这一篇把这句话展开成完整的先后顺序:协议 → 组件 → 接口 → 实现 → 接口测试 → 框架化 → 组装。每一步都是同一条原则——先设计对外的控制面,再逐层向内。这是设计起点线(各种程序先设计什么)在通信程序上的完整展开。
一、起点:通信程序先设计协议设计起点线已经给出结论:通信程序的对外控制面是协议。
12两个独立运行的系统(客户端、服务器)互不共享内存,唯一能对齐的就是「协议」——双方按什么规则交换什么消息。
所以通信程序的第一步不是写 EventLoop,而是先定协议:
12345Client → ServerLOGIN { username, password }Server → ClientLOGIN_RESULT { success, token }
协议是通信程序的第一个设计对象——后面所有接口都围绕它展开。
二、完整顺序:七步倒推协议定了之后,剩下的步骤是「从外到内」的逐层倒推:
12345678910111213① 协议设计 ...
