个人微薄: weibo.com/manuscola
分类: LINUX
2013-05-13 22:29:17
如果我们将ELF格式的可执行文件执行两次eu-strip,产生的可执行程序和执行一次eu-strip得到的可执行程序是不是一模一样,我说的一模一样是指完全一样,MD5值都一样。
我为什么问这个问题,原因是我在工作中不小心将可执行文件eu-strip了两次,每次都保存了符号表到另一个ELF文件,执行1次eu-strip和执行2次,对于可执行程序而言,没有区别,因为第一次就将符号表清除了,第二次的eu-strip不过是走走过场(因为毕竟没有符号表可以清除了),文件不应该发生任何变化。
是这样吗?我很吃惊的发现,文件的MD5居然不同,也就是文件不一样。
我们以一个最简单的hello
world 解释这件事情:我们写一个最简单hello程序:
可执行程序hello经过一次eu-strip之后,程序变成了hello.1同时生成了符号表文件hello.sym.1,对hello在进行一次eu-strip,程序变成了hello.2,同时,生成了hello.sym.2,对hello程序再次eu-strip,程序编程了hello.3,符号表变成了hello.sym.3。OK我们可以罢手了。
原始的hello程序是有符号表信息的,所以一次eu-strip生成的hello.sym.1里面含有符号表信息,所以hello.sym.1比较大,但是将原始hello程序,两次eu-stirp,生成的hello.sym.2已经没有任何的符号表信息了,所以比较小,同理,hello.sym.3也没有符号表信息,也比较小。
那么hello.1作为一次阉割符号表的产物,hello.2作为两次阉割符号表的产物,从我们的常理出发,阉割一次和阉割两次,没区别,两个可执行程序应该一摸一样才对。事实上,不太一样。
我用vbindiff工具比较两者,输出如下:
WHY?
这牵扯到了.gnu_debuglink的内容了。
我们用eu-strip 将符号表信息保存到另外文件的时候,我们的elf格式的二进制程序会增加一个段:
这个段分两个部分:
1保存符号表信息的那个文件的文件名
2 保存符号表信息的文件的CRC32校验值。
如上图所示,分成两个部分。第一部分表示我的符号表存储在hello.sym.1文件内。这是符合我们操作的,我们的确是将原始程序hello 阉割成hello.1,同时将符号表保存在了hello.sym.1。后面的0x24684896是啥东东?就是我们说的第二部分hello.sym.1文件的CRC32校验值。我用cksfv计算了hello.sym.1的CRC32,结果时0x96486824。看起来不一样,但是请注意,我的机器是little endian的。所以的确相等。
hello.2和hello.sym.2关系也是如此,请看下图:
有人说我将hello.2再次阉割一次,阉割成hello.3,同时生成hello.sym.3,hello.sym.2和hello.sym.3同样是无实质意义的阉割,这样hello.sym.2和hello.sym.3 总一模一样了吧。
很不幸,让人吐血的是,仍然不一样。
WHY?
hello.sym.2是从hello.1生成的,hello.1里面有.gnu.debuglink的值,即hello.sym.1的CRC32的值,所以hello.sym.2中也记录hello.sym.1的CRC32的值。同样道理,hello.sym.3里面记录了hello.sym.2的CRC32的值,两者不同所以hello.sym.2和hello.sym.3并不相同。有点绕,呵呵,试试就是hello.sym.1000也不会和hello.sym.999相同,哪怕不考虑文件名的不同,仅仅是CRC32的值也决定了永不相同。
gnu_debuglink 详解.pdf
参考文献: