GNU/Linux >> Linux Esercitazione >  >> Linux

Come disassemblare un eseguibile binario in Linux per ottenere il codice assembly?

Questa risposta è specifica per x86. Strumenti portatili in grado di disassemblare AArch64, MIPS o qualsiasi altro codice macchina includa objdump e llvm-objdump .

Il disassemblatore di Agner Fog, objconv , è molto carino. Aggiungerà commenti all'output di disassemblaggio per problemi di prestazioni (come il temuto stallo LCP da istruzioni con costanti immediate a 16 bit, per esempio).

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

(Non riconosce - come abbreviazione di stdout, e l'impostazione predefinita è l'output in un file con un nome simile al file di input, con .asm aggiunto.)

Aggiunge anche obiettivi di ramo al codice. Altri disassemblatori di solito disassemblano le istruzioni di salto con solo una destinazione numerica e non mettono alcun indicatore su un obiettivo di diramazione per aiutarti a trovare la parte superiore dei loop e così via.

Inoltre indica i NOP in modo più chiaro rispetto ad altri disassemblatori (rendendo chiaro quando c'è riempimento, piuttosto che disassemblarlo come un'altra istruzione).

È open source e facile da compilare per Linux. Può essere smontato nella sintassi NASM, YASM, MASM o GNU (AT&T).

Esempio di output:

; 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
...

Nota che questo output è pronto per essere riassemblato in un file oggetto, quindi puoi modificare il codice a livello di sorgente asm, piuttosto che con un editor esadecimale sul codice macchina. (Quindi non sei limitato a mantenere le cose della stessa dimensione.) Senza modifiche, il risultato dovrebbe essere quasi identico. Potrebbe non esserlo, però, dal momento che lo smontaggio di cose come

  (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

non ha nulla nel codice sorgente per assicurarsi che venga assemblato alla codifica più lunga che lascia spazio ai riposizionamenti per riscriverlo con un offset a 32 bit.

Se non vuoi installarlo objconv, GNU binutils objdump -Mintel -d è molto usabile e sarà già installato se hai una normale configurazione gcc di Linux.


Un'interessante alternativa a objdump è gdb. Non devi eseguire il binario o avere 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)

Con le informazioni di debug complete è ancora meglio.

(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 ha un'opzione simile (-S)


Non credo gcc ha un flag per questo, poiché è principalmente un compilatore, ma un altro degli strumenti di sviluppo GNU sì. objdump prende un -d /--disassemble bandiera:

$ objdump -d /path/to/binary

Lo smontaggio è simile a questo:

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:come ottenere in modo affidabile il nome del sistema operativo?

  2. Linux:come verificare se un binario Linux è stato compilato come codice indipendente dalla posizione?

  3. Come posso ottenere lo stato della tastiera in Linux?

  4. Come smontare, modificare e poi rimontare un eseguibile Linux?

  5. Come ottenere il numero di CPU in Linux usando C?

Come Linux è arrivato al mainframe

Come ottenere la dimensione di una directory in Linux

Come ottenere la dimensione di una directory in Linux

Come ottenere notizie istantaneamente dalla riga di comando in Linux

Come ottenere il nome del file dal percorso completo in Linux

Come ottenere il numero di processori/core in Linux