⌨️ 第六章 Web技术与安全
📄 本篇一句话

编译是单向门:源码→机器码信息有损,回不去原样——逆向工程就是从成品往回猜源码:反汇编器把机器码翻成汇编(忠实但难读),反编译器试图翻回高级语言(好读但失真)。合法与违法的边界画在许可证和用途上。

📝 在本章的位置

上游: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;
}

四、合法边界

动手 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++ 编译到机器码的距离比这远百倍。

常见误区

自测三问(点击展开) 1. **编译为什么不可逆?** 答:变量名/注释/结构等信息编译时被丢弃,机器码到源码没有唯一映射。 2. **反汇编与反编译的差别?** 答:反汇编=机器码→汇编(无损忠实);反编译=→类高级语言伪代码(好读但失真)。 3. **哪些逆向用途是正当的?** 答:漏洞研究、恶意软件分析、互操作兼容、自有软件调试审计。

相关笔记