002、基本数据类型的表现形式
类型不会完整保存在机器代码里
反汇编通常只能直接告诉我访问宽度和指令语义,不能自动还原源码类型。
1 | mov eax, dword ptr [ebp+8] |
这里只能确定读取 4 Byte。它可能是 int、unsigned 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 | movss xmm0, dword ptr [value] |
调试器中的十六进制位模式和浮点显示是同一组字节的不同解释。
字符和字符串
单个字符本质上是整数编码。字符串需要同时判断:
- 元素宽度是 1 Byte 还是 2 Byte。
- 采用 ASCII、当前代码页还是 Unicode。
- 是否以零结尾。
- 指针指向只读常量区、栈还是堆。
1 | 41 42 43 00 → "ABC" |
布尔类型
源码中的 bool 通常占 1 Byte,但编译器在寄存器中可能使用更宽的临时值。
1 | test eax, eax |
SETcc 把条件结果归一化为 0 或 1。不过条件判断本身只要求零与非零,不应假设所有真值在中间过程都等于 1。
地址、指针与引用
地址是数值,指针是带有目标类型语义的变量,引用在编译后通常也通过地址实现。
1 | int value = 7; |
逆向时重点观察:
- 指针值是否落在有效内存区域。
- 解引用时的访问宽度。
- 指针加减时的步长。
- 参数在函数内是否先被解引用再访问。
1 | mov eax, [ebp+8] ; 取得地址 |
引用通常不能仅靠局部反汇编与指针严格区分,要结合函数原型和调用点。
常量
#define 在预处理阶段替换,不一定留下独立对象;const 具有类型,可能拥有存储空间,也可能被编译器直接传播。
1 | mov eax, 64h |
这个 64h 可能来自字面量、宏或 const,只靠机器代码通常无法恢复源码写法。
看到立即数时优先恢复它在算法中的语义,不要急着断言源码使用了宏还是常量对象。
类型恢复顺序
- 确定读写宽度。
- 观察有符号或无符号指令。
- 跟踪数据来源和目标区域。
- 查看调用 API 所要求的类型。
- 在所有调用点验证候选原型。
学习检查清单
| 检查项 | 状态 |
|---|---|
| 能从比较和扩展指令判断符号倾向 | 待复盘 |
| 能区分整数位模式与浮点解释 | 待复盘 |
| 能识别窄字符和 UTF-16LE 字符串 | 待复盘 |
| 能说明指针步长由目标类型决定 | 待复盘 |
| 能解释为什么引用和指针难以仅靠局部代码区分 | 待复盘 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ruiqy~!





















