编译是单向门:源码→机器码信息有损,回不去原样——逆向工程就是从成品往回猜源码:反汇编器把机器码翻成汇编(忠实但难读),反编译器试图翻回高级语言(好读但失真)。合法与违法的边界画在许可证和用途上。
上游:2-1 的「源代码→编译→执行文件」是本篇的顺过程;3-14 的内存与 6-19 的漏洞分析都靠逆向手段。下游:安全研究(6-19)、恶意软件分析、兼容性移植是三大正当用途。
一、编译为什么不可逆
2-1 讲过编译链:源码 →(编译器)→ 机器码。回不去的原因:
- 信息丢弃:变量名变地址(student_name→[rbp-0x18])、注释蒸发、控制流拍平、常量内联——这些「给人看的信息」机器不需要,编译时就丢了;
- 一对多:同一句 C++ 可以编出多种机器码,同一串机器码也能对应多种源码——没有唯一解。
二、反汇编器:忠实但难读
反汇编(disassembly)=机器码→汇编,一一对应、无损,但读的是汇编(3-14 的寄存器、栈、跳转全要上手):
机器码(十六进制) 反汇编输出
55 push rbp
48 89 e5 mov rbp, rsp
89 7d fc mov [rbp-4], edi ← 参数 1 进了栈,变量名无从考证
...
代表工具:IDA Pro(业界标准)、Ghidra(NSA 开源)、objdump(免费)。
三、反编译器:好读但失真
反编译(decompilation)=汇编→类 C 伪代码,尽量恢复控制结构与类型:
// Ghidra 风格的反编译输出(看个气质即可)
int check_password(char *input) {
int ok = strncmp(input, "s3cret", 6); // 字符串常量还认得出
if (ok == 0) return 1; // 但原变量名/注释/结构体名全没了
return 0;
}
- 高级语言里信息量保留越多越容易还原:C/C++(编译型)难;Java/.NET 字节码带符号表,反编译几乎「高清还原」(jd-gui 一键出码)——所以 Java 混淆器是刚需;Python 的
.pyc同理(uncompyle6 能还原),发布靠打包加密而非指望秘密。 - 逆向的正当代价:即使工具齐全,读懂大型二进制仍以人月计——逆向慢是防御的一部分。
四、合法边界
- 可以:自己软件调试、漏洞研究/CTF、恶意软件分析、互操作性协议还原(历史判例支持)、安全审计;
- 看协议:多数商业 EULA 明文禁止逆向——违反是合同问题;开源软件(6-17)源码都给了,无需逆向;
- 不行:破解授权/盗版分发、窃取商业秘密(中国《著作权法》《计算机软件保护条例》框架内逆向有合法空间,但绕过技术保护措施另受规管)。
动手 Demo:亲手「反汇编」一段 Python 字节码
Python 源码先编译成字节码再跑——dis 模块能看到这层「汇编」:
import dis
def check(score):
if score >= 60:
return "pass"
return "fail"
dis.dis(check) # 反汇编:字节码 → 人类可读指令
看到什么算成功(输出节选):
LOAD_FAST 0 (score)
LOAD_CONST 1 (60)
COMPARE_OP >=
POP_JUMP_IF_FALSE ...
LOAD_CONST 2 ('pass')
RETURN_VALUE
读结果:变量名还在(Python 字节码带符号信息——这正是它「好反编译」的原因);若把函数名改成 f、变量改成 a,输出立刻跟着变——符号是逆向的第一线索,混淆就是故意抹掉它。
30 秒实验
跑 import py_compile; py_compile.compile("demo.py") 生成 .pyc;再跑 python -c "import dis, marshal; ..." 太绕——简单版:直接 dis.dis 一个你写过的函数,对照源码逐行认指令。体会「高级语言→指令」的距离——C++ 编译到机器码的距离比这远百倍。
常见误区
- 「反编译能还原出完整源码」——只能得到功能等价的伪代码;变量名、注释、原始结构永久丢失。
- 「逆向只属于黑客」——杀毒厂商每天逆向病毒、游戏公司逆向作弊器、标准联盟逆向旧协议做兼容——逆向是安全行业的日常工具。
- 「开源了就不用逆向」——是的,而且这正是开源(6-17)的安全红利:审计明着来。
自测三问(点击展开)
1. **编译为什么不可逆?** 答:变量名/注释/结构等信息编译时被丢弃,机器码到源码没有唯一映射。 2. **反汇编与反编译的差别?** 答:反汇编=机器码→汇编(无损忠实);反编译=→类高级语言伪代码(好读但失真)。 3. **哪些逆向用途是正当的?** 答:漏洞研究、恶意软件分析、互操作兼容、自有软件调试审计。- ☑ 6-18 完成 —— 单向门的回程票:反汇编与反编译
- ☐ 下一节 6-19 漏洞、安全漏洞、缓冲区溢出
相关笔记
- 编译与解释 —— 顺过程在这篇
- 指针与内存 —— 读汇编的前置知识
- 许可协议 —— 合法边界的一部分
- ⌨️ 编程原理 · 索引 —— 全课路线图