转自:
前言:本文主要介绍几种反汇编的方法。
gcc
gcc的完整编译过程大致为:预处理->编译->汇编->链接
前三个步骤分别对应了-E、-S、-c三个选项。
今天我要介绍的第一种方法就是使用-S这个选项。
源程序main.c:
/************************************************************************* > File Name: main.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年12月08日 星期二 20时06分19秒 ************************************************************************/ #includeint i = 1; int main(void) { ++i; printf("%d\n",i); return 0; }
执行以下命令:
gcc -S -o main.s main.c
查看汇编源程序main.s:
.file "main.c" .globl i .data .align 4 .type i, @object .size i, 4 i: .long 1 .section .rodata .LC0: .string "%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl i(%rip), %eax addl $1, %eax movl %eax, i(%rip) movl i(%rip), %eax movl %eax, %esi movl $.LC0, %edi movl $0, %eax call printf movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" .section .note.GNU-stack,"",@progbits
哈哈,大家看是不是成功了?至于汇编程序的具体解释则不在本文的讨论范畴。
最后介绍一下gcc的具体过程:
参考:编译阶段 | 命令 | 截断后的产物 |
---|---|---|
C源程序 | ||
预处理 | gcc -E | 替换了宏的C源程序(没有了#define,#include…), 删除了注释 |
编译 | gcc -S | 汇编源程序 |
汇编 | gcc -c | 目标文件,二进制文件, 允许有不在此文件中的外部变量、函数 |
链接 | gcc | 可执行程序,一般由多个目标文件或库链接而成, 二进制文件,所有变量、函数都必须找得到 |
objdump
objdump是linux下一款反汇编工具,能够反汇编目标文件、可执行文件。
主要选项:
objdump -f 显示文件头信息objdump -d 反汇编需要执行指令的那些sectionobjdump -D 与-d类似,但反汇编中的所有sectionobjdump -h 显示Section Header信息 objdump -x 显示全部Header信息 objdump -s 将所有段的内容以十六进制的方式打印出来
目标文件
反汇编:
gcc -c -o main.o main.cobjdump -s -d main.o > main.o.txt
- 1
- 2
查看汇编文件:
main.o: 文件格式 elf64-x86-64Contents of section .text: 0000 554889e5 8b050000 000083c0 01890500 UH.............. 0010 0000008b 05000000 0089c6bf 00000000 ................ 0020 b8000000 00e80000 0000b800 0000005d ...............] 0030 c3 . Contents of section .data: 0000 01000000 .... Contents of section .rodata: 0000 25640a00 %d.. Contents of section .comment: 0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4. 0010 382e322d 31397562 756e7475 31292034 8.2-19ubuntu1) 4 0020 2e382e32 00 .8.2. Contents of section .eh_frame: 0000 14000000 00000000 017a5200 01781001 .........zR..x.. 0010 1b0c0708 90010000 1c000000 1c000000 ................ 0020 00000000 31000000 00410e10 8602430d ....1....A....C. 0030 066c0c07 08000000 .l...... Disassembly of section .text: 0000000000000000: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a a: 83 c0 01 add $0x1,%eax d: 89 05 00 00 00 00 mov %eax,0x0(%rip) # 13 13: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 19 19: 89 c6 mov %eax,%esi 1b: bf 00 00 00 00 mov $0x0,%edi 20: b8 00 00 00 00 mov $0x0,%eax 25: e8 00 00 00 00 callq 2a 2a: b8 00 00 00 00 mov $0x0,%eax 2f: 5d pop %rbp 30: c3 retq
可执行文件
反汇编:
gcc -o main main.cobjdump -s -d main > main.txt
查看汇编文件(由于文件较大,只取部分展示):
Disassembly of section .init:00000000004003e0 <_init>: 4003e0: 48 83 ec 08 sub $0x8,%rsp 4003e4: 48 8b 05 0d 0c 20 00 mov 0x200c0d(%rip),%rax # 600ff8 <_DYNAMIC+0x1d0> 4003eb: 48 85 c0 test %rax,%rax 4003ee: 74 05 je 4003f5 <_init+0x15> 4003f0: e8 3b 00 00 00 callq 400430 <__gmon_start__@plt> 4003f5: 48 83 c4 08 add $0x8,%rsp 4003f9: c3 retq Disassembly of section .plt: 0000000000400400: 400400: ff 35 02 0c 20 00 pushq 0x200c02(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 400406: ff 25 04 0c 20 00 jmpq *0x200c04(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 40040c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400410 : 400410: ff 25 02 0c 20 00 jmpq *0x200c02(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 400416: 68 00 00 00 00 pushq $0x0 40041b: e9 e0 ff ff ff jmpq 400400 <_init+0x20>
linux 下目标文件(默认扩展名是.o)和可执行文件都是 ELF 格式(文件内容按照一定格式进行组织)的二进制文件; 类似的,Windows 下 VISUAL C++ 编译出来的目标文件 (扩展名是.obj)采用 COFF 格式,而可执行文件 (扩展名是.exe)采用 PE 格式, ELF 和 PE 都是从 COFF 发展而来的。
因为 linux 下目标文件和可执行文件的内容格式是一样的, 所以 objdump 既可以反汇编可执行文件也可以反汇编目标文件。
总结
掌握了反汇编的方法,当你的程序遇到一些未知的变量错误等,可以直接反汇编来查看汇编代码,一切一目了然。PS:汇编我已经忘得差不多了。
参考
反馈与建议
- 微博:
- github:
- 博客:
版权声明:本文为博主原创文章,未经博主允许不得转载。 http://blog.csdn.net/u011192270/article/details/50224267