编译器会将数据放入PE或ELF文件的.text部分吗?如果是,原因何在?

人气:808 发布:2022-10-16 标签: x86 cpu decompiler compiler-optimization

问题描述

所以刚才有人问了一个问题:

Why do Compilers put data inside .text(code) section of the PE and ELF files and how does the CPU distinguish between data and code?

但最上面的答案是文本部分没有数据,编译器不会这样做!

但我遇到了一些二进制文件,在ollydbg中调试时,我在.text中看到了一些奇怪的字节,我猜它们可能是数据,我仍然读到了声称数据可能在.text部分内的论文

这实际上是静态反汇编是一个无法确定的问题(至少学术论文声称是这样)的原因,因为他们说数据可能在文本部分,而我们永远不知道

所以我想一劳永逸地解决这个问题,如果您想回答这个问题,请提供来源:

编译器是否将数据放入.Text部分?如果是,您知道哪些编译器和编译器版本会执行此操作?

如果他们这样做,为什么会这样?我读了我链接的问题的答案,但我无法理解它,因为我不是真正的硬件专家,所以你们能提供一个更简单的解释,软件开发人员可以理解的东西吗?

这是我们无法区分可执行文件中的数据和代码的另一个来源:

https://www.usenix.org/legacy/publications/library/proceedings/usenix03/tech/full_papers/prasad/prasad_html/node5.html

区分二进制文件中的代码和数据是一个根本无法确定的问题

推荐答案

对于x86,GCC/clang/icc/msvc不会将数据和代码混在一起,因为这是没有意义的,就像我在链接的问题上回答的那样。(不包括即时数据,显然,这些数据将作为指令的一部分进行解码)。.text节的结尾和.rodata节的开头可能在文本段内相邻,但这不是您的意思。

对于非x86 ELF二进制文件(例如ARM),它们确实混合了代码和只读数据,以允许仅具有12位或更小偏移量的PC相对加载适合固定宽度的加载指令。

混淆的x86二进制文件肯定会混入一些数据,或者只是使反汇编变得困难,所以看起来可能会有一些数据。对于没有被故意混淆的编译器生成的代码,静态反汇编通常很容易。任何混淆反汇编的东西都会让它看起来像是可能的数据。是的,这是无法决定的。

在我的链接答案中,我没有说过混合代码+常量的二进制代码不存在。我只是说普通的优化编译器不会这样做,而且它没有性能优势。只有反逆向工程的优势,假设数据是只读的,在性能上有很小的代价。(如果数据是读/写的,则开销非常大。)

二进制混淆是人们在商业软件上真正使用的东西。你在野外发现二进制文件不能干净地拆卸,我一点也不惊讶。但这是在编译之后完成的,从编译器输出生成一个新的模糊二进制文件。(或者可能使用编译器插件?我真的不确定)。但并不是编译器正确的在做这件事,这是构建工具链中较晚的一步。我想,卖二进制混淆软件的人卖的是二进制>二进制转换器,而不是编译器。

我在任何Linux发行版(例如,/usr/bin或/usr/lib中的内容)上分解GCC/clang输出时从未遇到过任何问题。没有调试符号,你会得到巨大的指令块,但反汇编并不会与执行到达它的方式不同步。函数之间的填充是在函数底部的retjmp之后正常解码的长NOP。或者使用MSVC,填充是单字节的int3指令,它不会像00 00字节(add [rax], al)那样取消对下一个函数开始的解码。

注意您的声明(存在混淆的二进制程序)与链接的论文中提出的更强有力的声明之间的差异来自另一个问题(优化编译器出于性能原因而积极地这样做,包括在x86上)。

如果您想要实现必须适用于每个二进制文件的二进制重写,那么是的,您遇到了一个大问题。但是,如果您只需要关心非模糊编译器输出,这就容易多了。

574