zoukankan      html  css  js  c++  java
  • 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      打印符号表
    c++filt 把c++符号unmangle
    strip    把调试信息删除
    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 trace=mmap2,open,mprotect |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 <condition>,但这玩意一旦设上不是一般的慢啊。。。


    gdb中的bt和info frame命令常用来看堆栈信息和函数调用关系。但有时因为bug栈被写坏了,但如果不是被写得很坏,查看栈的内容常通常能找到一些线索:
    (gdb) x/40x $sp
    该命令是查看$sp指向区域的40个byte的内存内容。该命令也可用来查看任意指定地址的内存内容。


    关于gdb常用的功能:http://wiki.ubuntu.org.cn/%E7%94%A8GDB%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F
    其它的一些gdb使用备忘:http://blog.csdn.net/ariesjzj/article/details/6913671 

    一些相关资料
    http://www.linuxforums.org/articles/understanding-elf-using-readelf-and-objdump_125.html

    http://bbs.chinaunix.net/thread-1972423-1-1.html

    elfutils-0.148: http://www.linux.it/~rubini/docs/binfmt/binfmt.html

    GNU binutils & libbfd: http://www.gnu.org/software/binutils/

    参考:
    http://blog.csdn.net/ariesjzj/article/details/7689120
  • 相关阅读:
    微信小程序里自定义组件,canvas组件没有效果
    微信小程序填坑之路(三):布局适配方案(rpx、px、vw、vh)
    小程序checkbox调整大小
    css让文字竖着排列 writing-mode 属性
    微信小程序 位置定位position详解,相对定位relative,绝对定位absolute相关问题
    小程序国际化实现方式
    mybatis plus 学习
    cesium js学习一加载三维模型【转】
    cesiumjs学习笔记之三——cesium-navigation插件 【转】
    局域网Cesium离线影像及瓦片影像地图加载【转】
  • 原文地址:https://www.cnblogs.com/reddusty/p/4840514.html
Copyright © 2011-2022 走看看