(轉自:https://blog.csdn.net/u011192270/article/details/50224267)
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
- 1
檢視彙編源程式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 <[email protected]>
4003f5: 48 83 c4 08 add $0x8,%rsp
4003f9: c3 retq
Disassembly of section .plt:
0000000000400400 <[email protected]>:
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 <[email protected]>:
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:彙編我已經忘得差不多了。
參考
- https://github.com/1184893257/simplelinux
回報與建議
- 微網誌:@AnSwEr不是答案
- github:AnSwErYWJ
- 部落格:AnSwEr不是答案的專欄
版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/u011192270/article/details/50224267