# 1. 开篇：为什么人类看不懂反汇编？

**也许不是所有的人都不适合看反汇编，总有人天赋异禀？就像传说中的“人肉逆向机”一样。**

**反正我是做不到的啦～～**

**我只是个普通的平凡人类～～**

**平凡的人类有自己的笨办法～～**

## 身为人类的局限

人类短期记忆的容量大概在7个数字左右（左右范围是5到9个）这是著名的心理学家。。。。（嗯。。。他的名字超过了7个字母，所以我没记住）的研究结果。

ref:1956年George Miller论文 <http://www.psychspace.com/psych/viewnews-12308>

有兴趣的可以去：<https://humanbenchmark.com/tests/number-memory> 自己测试一下“你”是不是有独特的记忆天赋，反正我这个人经常忘掉东西。

而常用的指令集比如x86\_64，哪怕把RIP/RBP/RSP/段寄存器/标志位全不算，剩下的寄存器还有10多个呢。要知道，记住一个寄存器的状态可比记一个数字难多了；更别说ARM指令这些了。

## 看不懂的汇编和GOTO

汇编语言的设计就不是给人类看的。我举个最典型的例子，条件分支。

比如这样的代码

```jsx
if (a == b && a == c) {
	//do something
} else {
	//do something
}
```

编译成汇编后因为标志位的比较是独立的，汇编代码可能是这样，不再会有if/else和while/for等高级的“结构化”语意，整个代码“变成了GOTO形态”。

```jsx
cmp a,b
jz LABEL_1
cmp a,c
jz_LABEL_1
```

在编程世界中，为了所谓的“可读性”很多地方会“禁止使用GOTO语句”，我不想讨论这个规范这是否合理；但是汇编语言可以认为是整个代码中只有goto语句，那可不得看不懂吗。

> <https://www.zhihu.com/question/535563255>

## 来捣乱的编译器与伟大的F5

看不懂汇编流程和记不住寄存器状态，他们还都不是主要的麻烦，可以通过反复训练+足够多的经验弥补。

最麻烦的还是编译器的优化，最典型的就是 指令选择+指令调度+寄存器分配+窥孔优化 （这几个话题每个都值得后面单独开一张来讲）

最终变成了一团奇奇怪怪的东西，尤其是大型软件中超大函数的反编译，单纯的阅读+理解汇编会带来超过极限的生理负担。

幸好，我们还有反编译器来缓解这种问题。感谢伟大的F5。

## 为什么要学习这部分知识？

既然，人类的局限告诉我们：人类不适合直接阅读机器语言的反汇编。

而逆向工程，尤其是对复杂软件的逆向工程，逆向目的往往不是看懂代码的每一处，而是在理解一段段业务在做什么，确认输入输出。

伟大的F5按钮，会极大的加速这个过程，大大的降低逆向工程的大脑负担。

**“但是，如果F5坏了或者不好用了怎么办！！！？？”**

这在逆向工作中太常见了，我举几个大家一定遇到过的例子：

* 花指令
* switch跳转识别不出来
* IDA说什么什么sp-error栈平衡错误是啥意思，咋解决
* F5代码里充满了goto，根本看不懂
* F5代码全是结构体偏移的指针计算，根本不想看
* 他这个二进制是c++、go、rust写的，简直一坨
* 代码混淆技术
* <省略>

那么为什么会有这些问题，能不能解决，怎么解决？

应该在哪一步编写插件？应该如何编写插件定制优化？

如果理解了反编译器的内部构造，就能回答这些问题并解决困难。
