GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo desensamblar un ejecutable binario en Linux para obtener el código de ensamblaje?

Esta respuesta es específica para x86. Herramientas portátiles que pueden desmontar AArch64, MIPS o cualquier código de máquina que incluya objdump y llvm-objdump .

Desensamblador de Agner Fog, objconv , es bastante agradable. Agregará comentarios a la salida del desensamblado para problemas de rendimiento (como el temido bloqueo de LCP de las instrucciones con constantes inmediatas de 16 bits, por ejemplo).

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

(No reconoce - como abreviatura de stdout, y por defecto genera un archivo con un nombre similar al archivo de entrada, con .asm añadido.)

También agrega objetivos de bifurcación al código. Otros desensambladores generalmente desensamblan las instrucciones de salto con solo un destino numérico y no colocan ningún marcador en un objetivo de bifurcación para ayudarlo a encontrar la parte superior de los bucles y así sucesivamente.

También indica los NOP más claramente que otros desensambladores (aclarando cuándo hay relleno, en lugar de desarmarlo como una instrucción más).

Es de código abierto y fácil de compilar para Linux. Puede desensamblarse en sintaxis NASM, YASM, MASM o GNU (AT&T).

Salida de muestra:

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

Tenga en cuenta que esta salida está lista para ensamblarse nuevamente en un archivo de objeto, por lo que puede modificar el código en el nivel de fuente de asm, en lugar de con un editor hexadecimal en el código de la máquina. (Por lo tanto, no está limitado a mantener las cosas del mismo tamaño). Sin cambios, el resultado debería ser casi idéntico. Sin embargo, podría no serlo, ya que el desmontaje de cosas como

  (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

no tiene nada en la fuente para asegurarse de que se ensambla a la codificación más larga que deja espacio para reubicaciones para reescribirlo con un desplazamiento de 32 bits.

Si no desea instalarlo objconv, GNU binutils objdump -Mintel -d es muy útil y ya estará instalado si tiene una configuración normal de gcc de Linux.


Una alternativa interesante a objdump es gdb. No tienes que ejecutar el binario o tener información de depuración.

$ 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 información completa de depuración es aún mejor.

(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 tiene una opción similar (-S)


No creo gcc tiene una bandera para ello, ya que es principalmente un compilador, pero otra de las herramientas de desarrollo de GNU sí lo tiene. objdump toma un -d /--disassemble bandera:

$ objdump -d /path/to/binary

El desmontaje se ve así:

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. Cómo llegó Linux al mainframe

  2. ¿Cómo desensamblar, modificar y luego volver a ensamblar un ejecutable de Linux?

  3. ¿Cómo obtener la cantidad de CPU en Linux usando C?

  4. ¿Cómo obtener el nombre de usuario en C/C++ en Linux?

  5. ¿Cómo determinar si un archivo binario de Linux es de 32 bits o de 64 bits?

Cómo obtener el tamaño de un directorio en Linux

Cómo obtener el tamaño de un directorio en Linux

Cómo obtener noticias al instante desde la línea de comandos en Linux

Cómo obtener el nombre de archivo de la ruta completa en Linux

Cómo obtener la cantidad de procesadores/núcleos en Linux

¿Cómo obtener el tamaño físico de un archivo en Linux?