🎨 颜色标记说明

  • 粉色:特别重要、主线必掌握、优先复盘的内容。
  • 蓝色:核心概念、术语、分类名。
  • 橙色:需要关注的边界、易错点、注意事项。
  • 绿色:解释类内容、帮助理解知识点。

返回:全书总览 · 上一章:工具与环境 · 下一章:启动函数与用户入口

类型不会完整保存在机器代码里

反汇编通常只能直接告诉我访问宽度和指令语义,不能自动还原源码类型。

1
mov eax, dword ptr [ebp+8]

这里只能确定读取 4 Byte。它可能是 intunsigned int、指针、枚举或浮点数的原始位模式,必须结合后续使用判断。

类型恢复是一组证据的交叉验证,不是由单条 MOV 指令决定。

整数与符号

有符号和无符号整数采用相同位模式,差异体现在解释和指令选择上。

线索 有符号倾向 无符号倾向
扩展 MOVSX MOVZX
除法 IDIV DIV
乘法 IMUL MUL
大小比较 JL/JG JB/JA

整数溢出时:

  • CF 主要描述无符号进位或借位。
  • OF 主要描述有符号结果超出范围。

浮点数

浮点数采用 IEEE 754 编码。常见观察点:

  • x87 代码使用浮点寄存器栈 ST(0) 等。
  • SSE/AVX 代码使用 XMM/YMM 寄存器。
  • 标量单精度常见 SS 后缀,双精度常见 SD 后缀。
1
2
movss xmm0, dword ptr [value]
addss xmm0, xmm1

调试器中的十六进制位模式和浮点显示是同一组字节的不同解释。

字符和字符串

单个字符本质上是整数编码。字符串需要同时判断:

  • 元素宽度是 1 Byte 还是 2 Byte。
  • 采用 ASCII、当前代码页还是 Unicode。
  • 是否以零结尾。
  • 指针指向只读常量区、栈还是堆。
1
2
41 42 43 00             → "ABC"
41 00 42 00 43 00 00 00 → L"ABC" 的常见 UTF-16LE 表现

布尔类型

源码中的 bool 通常占 1 Byte,但编译器在寄存器中可能使用更宽的临时值。

1
2
test eax, eax
setne al

SETcc 把条件结果归一化为 01。不过条件判断本身只要求零与非零,不应假设所有真值在中间过程都等于 1。

地址、指针与引用

地址是数值,指针是带有目标类型语义的变量,引用在编译后通常也通过地址实现。

1
2
3
int value = 7;
int* p = &value;
int& r = value;

逆向时重点观察:

  • 指针值是否落在有效内存区域。
  • 解引用时的访问宽度。
  • 指针加减时的步长。
  • 参数在函数内是否先被解引用再访问。
1
2
mov eax, [ebp+8]   ; 取得地址
mov ecx, [eax] ; 解引用读取 4 Byte

引用通常不能仅靠局部反汇编与指针严格区分,要结合函数原型和调用点。

常量

#define 在预处理阶段替换,不一定留下独立对象;const 具有类型,可能拥有存储空间,也可能被编译器直接传播。

1
mov eax, 64h

这个 64h 可能来自字面量、宏或 const,只靠机器代码通常无法恢复源码写法。

看到立即数时优先恢复它在算法中的语义,不要急着断言源码使用了宏还是常量对象。

类型恢复顺序

  1. 确定读写宽度。
  2. 观察有符号或无符号指令。
  3. 跟踪数据来源和目标区域。
  4. 查看调用 API 所要求的类型。
  5. 在所有调用点验证候选原型。

学习检查清单

检查项 状态
能从比较和扩展指令判断符号倾向 待复盘
能区分整数位模式与浮点解释 待复盘
能识别窄字符和 UTF-16LE 字符串 待复盘
能说明指针步长由目标类型决定 待复盘
能解释为什么引用和指针难以仅靠局部代码区分 待复盘