【Java精品源码栏目提醒】:网学会员为广大网友收集整理了,二进制代码的阅读20130406 - 其它资料,希望对大家有所帮助!
Linux 下二进制代码的阅读大多数时候,我们研究的是如何阅读源代码。
但在一些情况下,比如源代码不公开或得到源代码的代价很高的情况下,我们又不得不需要了解程序的行为,这 时阅读二进制文件就非常重要。
假设现在有一个二进制可执行文件,我们木有源代码,但要了解它的实现,这里仅简单列出一些常用的工具。
阅读方式可分为两个方面:静态阅读和动态阅读。
静态阅读首先,file 命令可以查看可执行文件的大体信息。
比如是哪种格式的,哪个体系结构的,有没有调试信息等。
这些决定了需要用哪个版本的工具进行进一 步查看。
比如如果是 arm 体系的可执行文件就可用 arm toolchain 里的工具,如 arm-eabi-objdump,arm-eabi-gdb等。
众所周知,GNU Binutils 提供了一系列解析和操作二进制文件的工具,最常用的如 objdump,其最主要的功能之一是反汇编:objdump -d libxxx.so其它常用选项包括:-x 打印所有头信息-s 打印所有段的内容-S 将反汇编和源代码一起打印-r 打印重定位表-R 打印动态重定位表-D 打印所有段,即不止代码段-t 打印符号表,和 nm 的功能类似,但格式不一样-T 只打印动态链接的符号表项等等。
readelf 命令主要用于查看 elf 文件的元信息(如段信息等)。
如查看可执行文件的头信息:readelf -h libxxx.so其它常用选项包括:-s 打印符号表-r 打印重定位表-l 打印装载属性-S 打印段表等等。
除了以上两个用得最多的,其它一些辅助工具有时也必不可少:nm 打印符号表cfilt 把 c符号 unmanglestrip 把调试信息删除strings 看文件中的字符串ldd: 查看依赖关系等等动态阅读要了解可程序的行为,最可靠的还是看二进制文件跑起来时的样子。
很多时候,由于运行环境复杂,特别是多线程情况下,动态阅读能发现很多静态阅读所不可能发现的东西。
首先,在/proc/pid(pid 为进程号)下记录了二进制文件跑起来后的很多信息,如通过/proc/pid/maps 可以知道该程序链接了哪些库,分别被加载在了什么地方(这样,知道了错误地址,理论上就可以找到相应库的对应反汇编代码。
),/proc/pid/mem 是进程所用的内存镜像, /proc/pid/stat 则记录了中断统计信息等。
/proc/pid/cmdline 则记录了启动程序的命令行。
其次,通过 trace(strace,lstrace)可以看程序有哪些系统调用。
strace 用于跟踪系统调用,ltrace 用于跟踪动态库调用。
如对于在/proc/pid/maps 中看到的一些匿名内存映射,想要看它们是在什么时候或是在哪被创建可以用:strace -f -p 3742 -e tracemmap2openmprotect tee tmp.trace其中 3742 为进程 ID。
这里只过滤出关于内存映射的函数。
最后,指令级动态阅读的神器还属 gdb。
在 gdb 中查看寄存器信息可用:gdb i r在调试过程中打印出反汇编代码可用gdb disass addr或者gdb x/10i addr然后就可以和 objdump 出来的反汇编结合着看了。
如 GOT 表之类的信息在静态阅读时是无意义的,只有这时才能看。
各种 break point 能让我们迅速定位到我们关注的地方:watch point 在指定数据被访问时程序停止。
break point 在指定代码被执行时程序停止。
因为很多时候库不带 symbol,所以得直接设在地址上 break addr。
catch point 在指定事件发生时程序停止,如进程创建,动态链接库加载及异常。
条件断点有时很有用:break ... if ltconditiongt,但这玩意一旦设上不是一般的慢啊。
。
。
gdb 中的 bt 和 info frame 命令常用来看堆栈信息和函数调用关系。
但有时因为 bug 栈被写坏了,但如果不是被写得很坏,查看栈的内容常通常能找到一些线索:gdb x/40x sp该命令是查看sp 指向区域的 40 个 byte 的内存内容。
该命令也可用来查看任意指定地址的内存内容。
关于 gdb 常用的功能:http://wiki.ubuntu.org.cn/E794A8GDBE8B083E8AF95E7A88BE5BA8F其它的一些 gdb 使用备忘:http://blog.csdn.net/ariesjzj/article/details/6913671一些相关资料http://www.linuxforums.org/articles/understanding-elf-using-readelf-and-objdump