5 符号和剥离的二进制文件

符号和剥离的二进制文件

符号信息

高级源代码(如C代码)均以有意义的、人类可读的函数和变量命名为中心。编译程序时,编译器会翻译符号,这些符号会跟踪其名称,并记录哪些二进制代码和数据对应哪个符号。

image-20240426095025621

用到了 readelf来显示符号❶。

请注意,在许多不熟悉的符号中,main函数❷有一个符号。你可以看到它指定了当二进制文件加载到内存时main将驻留的地址(0x400526)。输出还显示main的代码大小(32字节),并指出你正在处理一个函数符号(类型为 FUNC)。

符号信息可以作为二进制文件的一部分,或者以单独的符号文件形式转译,它有各种风格。链接器只需要基本符号,但为了调试,可以转译出更广泛的信息。

调试符号提供了源 代码行和二进制指令之间的完整映射关系,甚至描述了函数的参数、堆栈帧信息等。对于ELF二进制文件,调试符号通常以DWARF格式生成,而PE二进制文件通常使用专有的Microsoft可移植调试(如PDB)格式。DWARF信息通常嵌在二进制文件中,而PDB则以单独的符号文件的形式存在。

符号信息对于二进制分析非常有用。一组定义良好的函数符号可以使反汇编更加容易,这是因为可以将每个函数符号作为反汇编的起点。这样可以减少意外将数据反汇编为代码(这会导致在反汇编输出中出现伪指令)的可能性。知道二进制文件的哪些部分属于哪个函数以及调用了什么函数,使得逆向工程师更容易划分和理解代码在做什么。

可以使用readelf解析符号,也可以使用像libbfd这样的库以编程方式解析符号。还有诸如libdwarf之类的库,这些库是专门为解析DWARF调试符号而设计的.

剥离二进制文件

GCC的默认行为是不自动剥离新编译的二进制文件。

如果你想知道带符号的二进制文件最终是如何被剥离的,可使用strip命令,

image-20220923090805952

示例二进制文件现在已被剥离❶,如file输出❷所确认的那样。在.dynsym符号表❸中只剩下少量符号。当二进制文件加载到内存中时,这些符号用于解决动态依赖关系,如对动态库的引用,但在反汇编时这些符号并没有太大的用处。所有其他的符号,包括主函数的符号都已经消失了。