• 基于GCC的工具objdump实现反汇编


    一:objdump介绍

            在 Linux中,一切皆文件。 Linux 编程实际上是编写处理各种文件的代码。系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和多样的用途。

            目标文件是包含带有附加地址和值的助记符号的路线图。这些符号可以用来对各种代码段和数据段进行命名,包括经过初始化的和未初始化的。它们也可以用来定位嵌入的调试信息,就像语义 Web,非常适合由程序进行阅读。

            objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。

            另外需要讲一下符号表,后面会用到。我们平时无论是在Linux上还是windows上用到的可执行程序。可执行程序的生成并不是一蹴而就而是代码经过预处理,编译,汇编和链接而成。编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的。链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的目标文件和系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做链接器(Linker)。经过编译链接后,代码中的各种符号都被分配了地址,并将各种信息记录在符号表中。

            符号表用来体现作用域可见性信息,符号表中语言符号可分为关键字符号操作符符号标识符符号。

    符号表的作用:

    •  收集符号属性;(词法分析)
    • 上下文语义的合法性检查的依据;(语法分析)
    • 作为目标代码生成阶段地址分配的依据;(语义分析)

    符号表中的标识符一般设置的属性项目有:

    • 符号名
    • 符号的类型
    • 符号的存储类别
    • 符号的作用域及可视性
    • 符号变量的存储分配信息
    • 符号的其它属性

    二:objdump参数

    选项详细选项描述
    -a--archive-headers显示档案库的成员信息,类似 ls -l 将 lib*.a 的信息列出。
    -b bfdname--target=bfdname指定目标码格式。这不是必须的,objdump 能自动识别许多格式,比如: objdump -b oasys -m vax -h fu.o 显示 fu.o 的头部摘要信息,明确指出该文件是 Vax 系统下用 Oasys 编译器生成的目标文件。objdump -i 将给出这里可以指定的目标码格式列表。
    -C--demangle将底层的符号名解码成用户级名字,除了去掉所开头的下划线之外,还使得C++函数名以可理解的方式显示出来。
    -g--debugging显示调试信息。企图解析保存在文件中的调试信息并以 C 语言的语法显示出来。仅仅支持某些类型的调试信息。有些其他的格式被 readelf -w 支持。
    -e--debugging-tags类似 -g 选项,但是生成的信息是和 ctags 工具相兼容的格式。
    -d--disassemble从 objfile 中反汇编那些特定指令机器码的 section。
    -D--disassemble-all与 -d 类似,但反汇编所有 section.
    --prefix-addresses反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。
    -EB
    -EL--endian={big|little}指定目标文件的小端。这个项将影响反汇编出来的指令。在反汇编的文件没描述小端信息的时候用。例如 S-records.
    -f--file-headers显示 objfile 中每个文件的整体头部摘要信息。
    -h--section-headers --headers显示目标文件各个section的头部摘要信息。
    -H--help简短的帮助信息。
    -i--info显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
    -j name--section=name仅仅显示指定名称为 name 的 section 的信息
    -l--line-numbers用文件名和行号标注相应的目标代码,仅仅和 -d、-D 或者 -r 一起使用使用 -ld 和使用 -d 的区别不是很大,在源码级调试的时候有用,要求编译时使用了 -g 之类的调试编译选项。
    -m machine--architecture=machine指定反汇编目标文件时使用的架构,当待反汇编文件本身没描述架构信息的时候(比如 S-records),这个选项很有用。可以用 -i 选项列出这里能够指定的架构.
    -r--reloc显示文件的重定位入口。如果和 -d 或者 -D 一起使用,重定位部分以反汇编后的格式显示出来。
    -R--dynamic-reloc显示文件的动态重定位入口,仅仅对于动态目标文件意义,比如某些共享库。
    -s--full-contents显示指定 section 的完整内容。默认所有的非空 section 都会被显示。
    -S--source尽可能反汇编出源代码,尤其当编译的时候指定了 -g 这种调试参数时,效果比较明显。隐含了 -d 参数。
    --show-raw-insn反汇编的时候,显示每条汇编指令对应的机器码,如不指定 --prefix-addresses,这将是缺省选项。
    --no-show-raw-insn反汇编时,不显示汇编指令的机器码,如不指定 --prefix-addresses,这将是缺省选项。
    --start-address=address从指定地址开始显示数据,该选项影响 -d、-r 和 -s 选项的输出。
    --stop-address=address显示数据直到指定地址为止,该项影响 -d、-r 和 -s 选项的输出。
    -t--syms显示文件的符号表入口。类似于 nm -s 提供的信息
    -T--dynamic-syms显示文件的动态符号表入口,仅仅对动态目标文件意义,比如某些共享库。它显示的信息类似于 nm -D | --dynamic 显示的信息。
    -V--version版本信息
    --all-headers-x显示所可用的头信息,包括符号表、重定位入口。-x 等价于 -a -f -h -r -t 同时指定。
    -z--disassemble-zeroes一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。
    @file可以将选项集中到一个文件中,然后使用这个 @file 选项载入

     三:实践

    1. 查看C程序的汇编代码和源代码

     创建一个test.c并生成可执行文件test

    gcc -g test.c -o test
    1. #include
    2. int add(int a, int b)
    3. {
    4. return a+b;
    5. }
    6. int sub(int a, int b)
    7. {
    8. return a-b;
    9. }
    10. int main()
    11. {
    12. int a = 88;
    13. int b = 66;
    14. int sum = add(a, b);
    15. printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
    16. int dif = sub(a, b);
    17. printf("a=%d, b=%d, a-b=%d\n", a, b, dif);
    18. }
    1. objdump -D test | less
    2. objdump -S test | less

    objdump -D命令来查看test的汇编代码。

    objdump -S命令来以汇编和源代码的形式查看test的代码。

    2. 查看可执行文件中函数调用的地址

    可以使用以下命令来查看可执行文件中的函数调用地址:

    objdump -d -j .plt test

    3. 查看共享库中函数的地址

    可以使用以下命令来查看共享库中函数的地址:

    objdump -T /lib/libc.so.6

    上述命令将显示共享库libc.so.6中所有函数的地址。

    4. 查看可执行文件中的符号表

    可以使用以下命令来查看可执行文件中的符号表:

    objdump -t test

    可以在符号表中找到sub,add的地址 

    1. [root@localhost testEg]# objdump -t test
    2. test: file format elf64-x86-64
    3. SYMBOL TABLE:
    4. 0000000000400238 l d .interp 0000000000000000 .interp
    5. 0000000000400254 l d .note.ABI-tag 0000000000000000 .note.ABI-tag
    6. 0000000000400274 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id
    7. 0000000000400298 l d .gnu.hash 0000000000000000 .gnu.hash
    8. 00000000004002b8 l d .dynsym 0000000000000000 .dynsym
    9. 0000000000400318 l d .dynstr 0000000000000000 .dynstr
    10. 0000000000400358 l d .gnu.version 0000000000000000 .gnu.version
    11. 0000000000400360 l d .gnu.version_r 0000000000000000 .gnu.version_r
    12. 0000000000400380 l d .rela.dyn 0000000000000000 .rela.dyn
    13. 0000000000400398 l d .rela.plt 0000000000000000 .rela.plt
    14. 00000000004003c8 l d .init 0000000000000000 .init
    15. 00000000004003f0 l d .plt 0000000000000000 .plt
    16. 0000000000400420 l d .plt.got 0000000000000000 .plt.got
    17. 0000000000400430 l d .text 0000000000000000 .text
    18. 0000000000400634 l d .fini 0000000000000000 .fini
    19. 0000000000400640 l d .rodata 0000000000000000 .rodata
    20. 0000000000400678 l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr
    21. 00000000004006c0 l d .eh_frame 0000000000000000 .eh_frame
    22. 0000000000600e10 l d .init_array 0000000000000000 .init_array
    23. 0000000000600e18 l d .fini_array 0000000000000000 .fini_array
    24. 0000000000600e20 l d .jcr 0000000000000000 .jcr
    25. 0000000000600e28 l d .dynamic 0000000000000000 .dynamic
    26. 0000000000600ff8 l d .got 0000000000000000 .got
    27. 0000000000601000 l d .got.plt 0000000000000000 .got.plt
    28. 0000000000601028 l d .data 0000000000000000 .data
    29. 000000000060102c l d .bss 0000000000000000 .bss
    30. 0000000000000000 l d .comment 0000000000000000 .comment
    31. 0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
    32. 0000000000600e20 l O .jcr 0000000000000000 __JCR_LIST__
    33. 0000000000400460 l F .text 0000000000000000 deregister_tm_clones
    34. 0000000000400490 l F .text 0000000000000000 register_tm_clones
    35. 00000000004004d0 l F .text 0000000000000000 __do_global_dtors_aux
    36. 000000000060102c l O .bss 0000000000000001 completed.6355
    37. 0000000000600e18 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
    38. 00000000004004f0 l F .text 0000000000000000 frame_dummy
    39. 0000000000600e10 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
    40. 0000000000000000 l df *ABS* 0000000000000000 test.c
    41. 0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
    42. 00000000004007f0 l O .eh_frame 0000000000000000 __FRAME_END__
    43. 0000000000600e20 l O .jcr 0000000000000000 __JCR_END__
    44. 0000000000000000 l df *ABS* 0000000000000000
    45. 0000000000600e18 l .init_array 0000000000000000 __init_array_end
    46. 0000000000600e28 l O .dynamic 0000000000000000 _DYNAMIC
    47. 0000000000600e10 l .init_array 0000000000000000 __init_array_start
    48. 0000000000400678 l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
    49. 0000000000601000 l O .got.plt 0000000000000000 _GLOBAL_OFFSET_TABLE_
    50. 0000000000400630 g F .text 0000000000000002 __libc_csu_fini
    51. 0000000000601028 w .data 0000000000000000 data_start
    52. 000000000040051d g F .text 0000000000000014 add
    53. 000000000060102c g .data 0000000000000000 _edata
    54. 0000000000400634 g F .fini 0000000000000000 _fini
    55. 0000000000000000 F *UND* 0000000000000000 printf@@GLIBC_2.2.5
    56. 0000000000000000 F *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5
    57. 0000000000601028 g .data 0000000000000000 __data_start
    58. 0000000000000000 w *UND* 0000000000000000 __gmon_start__
    59. 0000000000400648 g O .rodata 0000000000000000 .hidden __dso_handle
    60. 0000000000400640 g O .rodata 0000000000000004 _IO_stdin_used
    61. 00000000004005c0 g F .text 0000000000000065 __libc_csu_init
    62. 0000000000601030 g .bss 0000000000000000 _end
    63. 0000000000400430 g F .text 0000000000000000 _start
    64. 000000000060102c g .bss 0000000000000000 __bss_start
    65. 0000000000400547 g F .text 0000000000000070 main
    66. 0000000000601030 g O .data 0000000000000000 .hidden __TMC_END__
    67. 0000000000400531 g F .text 0000000000000016 sub
    68. 00000000004003c8 g F .init 0000000000000000 _init

    5. 查看.o文件的信息

    objdump -h test.o

    紧接着可以用nm查看函数和全局变量,静态变量

    1. [root@localhost testEg]# nm test.o
    2. 0000000000000000 T add
    3. 000000000000002a T main
    4. U printf
    5. 0000000000000014 T sub

    局部变量不会生成符号,最终是分配在栈内存中,不会在函数外部被引用

  • 相关阅读:
    基于JSP的记账管理系统【数据库设计、源码、开题报告】
    Biome-BGC生态系统模型与Python融合
    【VisualStudio使用】快捷键
    Windows Server 安装docker
    无胁科技-TVD每日漏洞情报-2022-11-17
    【菜鸟入门!】Matlab零基础快速入门教程
    记录获取蓝鲸智云token的过程
    前端开发常用网站
    java毕业设计木材产销系统的生产管理模块mybatis+源码+调试部署+系统+数据库+lw
    【AcWing 学习】图论与搜索
  • 原文地址:https://blog.csdn.net/qq_27071221/article/details/134297683