GNU/Linux >> Znalost Linux >  >> Linux

Jak rozebrat binární spustitelný soubor v Linuxu, abyste získali kód sestavení?

Tato odpověď je specifická pro x86. Přenosné nástroje, které mohou rozebrat AArch64, MIPS nebo jakýkoli jiný strojový kód včetně objdump a llvm-objdump .

Disassembler Agnera Foga, objconv , je docela pěkný. Do výstupu rozebrání přidá komentáře pro problémy s výkonem (jako je například obávané zastavení LCP z instrukcí s 16bitovými okamžitými konstantami).

objconv  -fyasm a.out /dev/stdout | less

(Nerozpozná - jako zkratka pro stdout a výchozí nastavení pro výstup do souboru podobného názvu jako vstupní soubor, s .asm připnuté.)

Do kódu také přidává cíle větví. Jiné disassemblery obvykle rozebírají instrukce skoku pouze s číselným určením a na cíl větve nevkládají žádnou značku, která by vám pomohla najít vrchol smyček a tak dále.

Označuje také NOP jasněji než jiné disassemblery (dává jasně najevo, kdy je tam vycpávka, spíše než aby to rozebíral jako další pokyn.)

Je to open source a snadno se kompiluje pro Linux. Lze jej rozložit do syntaxe NASM, YASM, MASM nebo GNU (AT&T).

Ukázkový výstup:

; Filling space: 0FH
; Filler type: Multi-byte NOP
;       db 0FH, 1FH, 44H, 00H, 00H, 66H, 2EH, 0FH
;       db 1FH, 84H, 00H, 00H, 00H, 00H, 00H

ALIGN   16

foo:    ; Function begin
        cmp     rdi, 1                                  ; 00400620 _ 48: 83. FF, 01
        jbe     ?_026                                   ; 00400624 _ 0F 86, 00000084
        mov     r11d, 1                                 ; 0040062A _ 41: BB, 00000001
?_020:  mov     r8, r11                                 ; 00400630 _ 4D: 89. D8
        imul    r8, r11                                 ; 00400633 _ 4D: 0F AF. C3
        add     r8, rdi                                 ; 00400637 _ 49: 01. F8
        cmp     r8, 3                                   ; 0040063A _ 49: 83. F8, 03
        jbe     ?_029                                   ; 0040063E _ 0F 86, 00000097
        mov     esi, 1                                  ; 00400644 _ BE, 00000001
; Filling space: 7H
; Filler type: Multi-byte NOP
;       db 0FH, 1FH, 80H, 00H, 00H, 00H, 00H

ALIGN   8
?_021:  add     rsi, rsi                                ; 00400650 _ 48: 01. F6
        mov     rax, rsi                                ; 00400653 _ 48: 89. F0
        imul    rax, rsi                                ; 00400656 _ 48: 0F AF. C6
        shl     rax, 2                                  ; 0040065A _ 48: C1. E0, 02
        cmp     r8, rax                                 ; 0040065E _ 49: 39. C0
        jnc     ?_021                                   ; 00400661 _ 73, ED
        lea     rcx, [rsi+rsi]                          ; 00400663 _ 48: 8D. 0C 36
...

Všimněte si, že tento výstup je připraven k sestavení zpět do objektového souboru, takže kód můžete vyladit na úrovni zdroje asm, spíše než pomocí hex-editoru ve strojovém kódu. (Nejste tedy omezeni na udržování stejné velikosti.) Beze změn by měl být výsledek téměř totožný. Možná tomu tak není, protože rozebírání věcí jako

  (from /lib/x86_64-linux-gnu/libc.so.6)

SECTION .plt    align=16 execute                        ; section number 11, code

?_00001:; Local function
        push    qword [rel ?_37996]                     ; 0001F420 _ FF. 35, 003A4BE2(rel)
        jmp     near [rel ?_37997]                      ; 0001F426 _ FF. 25, 003A4BE4(rel)

...    
ALIGN   8
?_00002:jmp     near [rel ?_37998]                      ; 0001F430 _ FF. 25, 003A4BE2(rel)

; Note: Immediate operand could be made smaller by sign extension
        push    11                                      ; 0001F436 _ 68, 0000000B
; Note: Immediate operand could be made smaller by sign extension
        jmp     ?_00001                                 ; 0001F43B _ E9, FFFFFFE0

nemá ve zdroji nic, co by zajistilo, že se sestaví do delšího kódování, které ponechává prostor pro přemístění, aby jej přepsal s 32bitovým offsetem.

Pokud jej nechcete instalovat objconv, GNU binutils objdump -Mintel -d je velmi použitelný a bude již nainstalován, pokud máte normální nastavení Linuxu gcc.


Zajímavou alternativou k objdumpu je gdb. Nemusíte spouštět binární soubor ani mít debuginfo.

$ gdb -q ./a.out 
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) info functions 
All defined functions:

Non-debugging symbols:
0x00000000004003a8  _init
0x00000000004003e0  [email protected]
0x00000000004003f0  [email protected]
0x0000000000400400  _start
0x0000000000400430  deregister_tm_clones
0x0000000000400460  register_tm_clones
0x00000000004004a0  __do_global_dtors_aux
0x00000000004004c0  frame_dummy
0x00000000004004f0  fce
0x00000000004004fb  main
0x0000000000400510  __libc_csu_init
0x0000000000400580  __libc_csu_fini
0x0000000000400584  _fini
(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004fb <+0>:     push   %rbp
   0x00000000004004fc <+1>:     mov    %rsp,%rbp
   0x00000000004004ff <+4>:     sub    $0x10,%rsp
   0x0000000000400503 <+8>:     callq  0x4004f0 <fce>
   0x0000000000400508 <+13>:    mov    %eax,-0x4(%rbp)
   0x000000000040050b <+16>:    mov    -0x4(%rbp),%eax
   0x000000000040050e <+19>:    leaveq 
   0x000000000040050f <+20>:    retq   
End of assembler dump.
(gdb) disassemble fce
Dump of assembler code for function fce:
   0x00000000004004f0 <+0>:     push   %rbp
   0x00000000004004f1 <+1>:     mov    %rsp,%rbp
   0x00000000004004f4 <+4>:     mov    $0x2a,%eax
   0x00000000004004f9 <+9>:     pop    %rbp
   0x00000000004004fa <+10>:    retq   
End of assembler dump.
(gdb)

S úplnými informacemi o ladění je to ještě lepší.

(gdb) disassemble /m main
Dump of assembler code for function main:
9       {
   0x00000000004004fb <+0>:     push   %rbp
   0x00000000004004fc <+1>:     mov    %rsp,%rbp
   0x00000000004004ff <+4>:     sub    $0x10,%rsp

10        int x = fce ();
   0x0000000000400503 <+8>:     callq  0x4004f0 <fce>
   0x0000000000400508 <+13>:    mov    %eax,-0x4(%rbp)

11        return x;
   0x000000000040050b <+16>:    mov    -0x4(%rbp),%eax

12      }
   0x000000000040050e <+19>:    leaveq 
   0x000000000040050f <+20>:    retq   

End of assembler dump.
(gdb)

objdump má podobnou možnost (-S)


Nemyslím si, že gcc má pro to příznak, protože je to primárně kompilátor, ale jiný z vývojových nástrojů GNU ano. objdump trvá -d /--disassemble příznak:

$ objdump -d /path/to/binary

Demontáž vypadá takto:

080483b4 <main>:
 80483b4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483b8:   83 e4 f0                and    $0xfffffff0,%esp
 80483bb:   ff 71 fc                pushl  -0x4(%ecx)
 80483be:   55                      push   %ebp
 80483bf:   89 e5                   mov    %esp,%ebp
 80483c1:   51                      push   %ecx
 80483c2:   b8 00 00 00 00          mov    $0x0,%eax
 80483c7:   59                      pop    %ecx
 80483c8:   5d                      pop    %ebp
 80483c9:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483cc:   c3                      ret    
 80483cd:   90                      nop
 80483ce:   90                      nop
 80483cf:   90                      nop

Linux
  1. Linux – jak vytvořit záplatu ignorující rozdíly v odsazení v kódu?

  2. Jak mohu získat stav klávesnice v Linuxu?

  3. Jak získat uživatelské jméno v C/C++ v Linuxu?

  1. Jak určíte umístění knihoven do binárního souboru? (linux)

  2. Jak zjistit, zda je linuxový binární soubor 32bitový nebo 64bitový?

  3. Jak mohu bezpečně spustit nedůvěryhodný spustitelný soubor na linuxu?

  1. Jak se Linux dostal k sálovému počítači

  2. Linux – jak spolehlivě získat název operačního systému?

  3. Jak získat fyzickou velikost souboru v Linuxu?