再编译逆向工程得到的源代码,能不能得到与原来相同的的二进进制代码呢?有多困难?之前逆向了某款路由,好奇之下做了一点实验,发现除非在编译器、编译选项、编码风格方面完全一样,同时知识水平和相关经验也非常重要。
 
编译器。一方面,相同版本的编译器可能应用了不同的版本的补丁;另一方面,构建编译器本身的选项也许也会对生成的目标有影响。某二进制使用GCC 4.8.3编译,通过strings命令发现其编译选项是“ -msoft-float -mllsc -mplt -mno-shared -g”。但使用自己构建的编译器(使用buildroot构建)时,使用相同编译选项编译得到目标文件,然后使用strings指令查看生效的编译选项变成“-msoft-float -mllsc -mplt -mno-shared -march=mips32r2 -mabi=32 -g”,编译器自动增加了新的选项。另外还发现,自己构建的编译器编译生成的目标在存储延时槽位置缺少nop指令。
 
编译选项。尤其是优化相关的编译选项对生成的二进制文件影响很大。
 
编码风格。假设使用-g选项,那么由于C99允许在执行语句之后定义变量,这样的话,数组的初始代码可能出现函数执行语句之前,也可能出现在执行语句之后,完全取决于编码习惯。不难想象,其它差别也很容易产生不同的二进制。
 
知识水平和经验。比如memcpy,在某些条件下,即使不指定任何优化选项,编译时也会被优化为简单的访存指令,而不会出现memcpy的调用指令。
 
综上,产生完全一致的二进制非常困难,有时甚至完全不可能。