Linux下C程序的反彙編
前言:本文主要介紹幾種反彙編的方法。
gcc
gcc的完整編譯過程大致爲:預處理->編譯->彙編->鏈接
前三個步驟分別對應了-E、-S、-c三個選項。
今天我要介紹的第一種方法就是使用-S這個選項。
源程序main.c:
/*************************************************************************
> File Name: main.c
> Author: AnSwEr
> Mail: [email protected]
> Created Time: 2015年12月08日 星期二 20時06分19秒
************************************************************************/
#include<stdio.h>
int 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的具體過程:
參考: https://github.com/1184893257/simplelinux/blob/master/gcc.md#top
編譯階段 | 命令 | 截斷後的產物 |
---|---|---|
C源程序 | ||
預處理 | gcc -E | 替換了宏的C源程序(沒有了#define,#include…), 刪除了註釋 |
編譯 | gcc -S | 彙編源程序 |
彙編 | gcc -c | 目標文件,二進制文件, 允許有不在此文件中的外部變量、函數 |
鏈接 | gcc | 可執行程序,一般由多個目標文件或庫鏈接而成, 二進制文件,所有變量、函數都必須找得到 |
objdump
objdump是linux下一款反彙編工具,能夠反彙編目標文件、可執行文件。
主要選項:
objdump -f
顯示文件頭信息
objdump -d
反彙編需要執行指令的那些section
objdump -D
與-d類似,但反彙編中的所有section
objdump -h
顯示Section Header信息
objdump -x
顯示全部Header信息
objdump -s
將所有段的內容以十六進制的方式打印出來
目標文件
反彙編:
gcc -c -o main.o main.c
objdump -s -d main.o > main.o.txt
查看彙編文件:
main.o: 文件格式 elf64-x86-64
Contents 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 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a <main+0xa>
a: 83 c0 01 add $0x1,%eax
d: 89 05 00 00 00 00 mov %eax,0x0(%rip) # 13 <main+0x13>
13: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 19 <main+0x19>
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 <main+0x2a>
2a: b8 00 00 00 00 mov $0x0,%eax
2f: 5d pop %rbp
30: c3 retq
可執行文件
反彙編:
gcc -o main main.c
objdump -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 <printf@plt-0x10>:
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 <printf@plt>:
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:彙編我已經忘得差不多了。
參考
反饋與建議
- 微博:@AnSwEr不是答案
- github:AnSwErYWJ
- 博客:AnSwEr不是答案的專欄