天天看點

Linux下C程式的反彙編【轉】(轉自:https://blog.csdn.net/u011192270/article/details/50224267)Linux下C程式的反彙編

(轉自: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:彙編我已經忘得差不多了。

參考

  1. https://github.com/1184893257/simplelinux

回報與建議

  • 微網誌:@AnSwEr不是答案
  • github:AnSwErYWJ
  • 部落格:AnSwEr不是答案的專欄

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/u011192270/article/details/50224267

繼續閱讀