Assembling & Disassembling
Ahora que entendemos la estructura básica y los elementos de un archivo Assembly, podemos comenzar a ensamblarlo usando la herramienta nasm
. Toda la estructura del archivo de ensamblado que aprendimos en la sección anterior se basa en la estructura del archivo nasm
. Al ensamblar nuestro código con nasm
, este comprende las distintas partes del archivo y luego las ensambla correctamente para que puedan ejecutarse durante el tiempo de ejecución.
Después de ensamblar nuestro código con nasm
, podemos enlazarlo usando ld
para utilizar varias características y bibliotecas del sistema operativo.
Assembling
Primero, copiaremos el siguiente código en un archivo llamado helloWorld.s
.
Nota: los archivos de ensamblado suelen usar las extensiones .s
o .asm
. Usaremos .s
en este módulo.
No es necesario seguir utilizando tabulaciones para separar las partes de un archivo de ensamblado, ya que esto fue solo para fines demostrativos. Podemos escribir el siguiente código en nuestro archivo helloWorld.s
:
global _start
section .data
message db "Hello HTB Academy!"
length equ $-message
section .text
_start:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, length
syscall
mov rax, 60
mov rdi, 0
syscall
Observa cómo usamos equ
para calcular dinámicamente la longitud de message
, en lugar de usar un valor estático como 18
. Esto será muy útil más adelante. Una vez hecho esto, ensamblaremos el archivo usando nasm
con el siguiente comando:
nasm -f elf64 helloWorld.s
Nota: El flag -f elf64
se usa para indicar que queremos ensamblar un código en ensamblador de 64 bits. Si quisiéramos ensamblar un código de 32 bits, usaríamos -f elf
.
Este comando debería generar un archivo objeto helloWorld.o
, que se ensambla en código máquina junto con los detalles de todas las variables y secciones. Sin embargo, este archivo aún no es ejecutable.
Linking
El paso final es enlazar nuestro archivo usando ld
. El archivo objeto helloWorld.o
, aunque ensamblado, aún no puede ejecutarse. Esto se debe a que muchas referencias y etiquetas utilizadas por nasm
deben resolverse en direcciones reales, además de enlazar el archivo con varias bibliotecas del sistema operativo que puedan ser necesarias.
Es por esto que un binario en Linux se llama ELF
, que significa Executable and Linkable Format
. Para enlazar un archivo usando ld
, podemos utilizar el siguiente comando:
ld -o helloWorld helloWorld.o
Nota: si estuviéramos ensamblando un binario de 32 bits, necesitaríamos agregar el flag '-m elf_i386
'.
Una vez que enlazamos el archivo con ld
, deberíamos tener el archivo ejecutable final:
./helloWorld
Hello HTB Academy!
Hemos ensamblado y enlazado con éxito nuestro primer archivo de ensamblado. Estaremos ensamblando, enlazando y ejecutando nuestro código frecuentemente a lo largo de este módulo, así que construyamos un simple script en bash
para hacerlo más fácil:
#!/bin/bash
fileName="${1%%.*}" # remove .s extension
nasm -f elf64 ${fileName}".s"
ld ${fileName}".o" -o ${fileName}
[ "$2" == "-g" ] && gdb -q ${fileName} || ./${fileName}
Ahora podemos escribir este script en assembler.sh
, darle permisos ejecutables con chmod +x
y luego ejecutarlo en nuestro archivo de ensamblado. Ensamblará, enlazará y ejecutará el archivo:
./assembler.sh helloWorld.s
Hello HTB Academy!
¡Genial! Antes de continuar, desensamblemos y examinemos nuestros archivos para aprender más sobre el proceso que acabamos de realizar.
Disassembling
Para desensamblar un archivo, usaremos la herramienta objdump
, que vuelca el código de máquina de un archivo e interpreta las instrucciones en ensamblador de cada código hexadecimal. Podemos desensamblar un binario usando el flag -D
.
Nota: también utilizaremos el flag -M intel
, para que objdump
escriba las instrucciones en la sintaxis Intel, que es la que estamos usando, como discutimos anteriormente.
Comencemos desensamblando nuestro archivo ejecutable final ELF
:
objdump -M intel -d helloWorld
helloWorld: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: b8 01 00 00 00 mov eax,0x1
401005: bf 01 00 00 00 mov edi,0x1
40100a: 48 be 00 20 40 00 00 movabs rsi,0x402000
401011: 00 00 00
401014: ba 12 00 00 00 mov edx,0x12
401019: 0f 05 syscall
40101b: b8 3c 00 00 00 mov eax,0x3c
401020: bf 00 00 00 00 mov edi,0x0
401025: 0f 05 syscall
Podemos ver que nuestro código en ensamblador original se conserva en gran medida, con el único cambio siendo 0x402000
utilizado en lugar de la variable message
y reemplazando la constante length
con su valor de 0x12
. También vemos que nasm
cambió eficientemente nuestros registros de 64-bit
a subregistros de 32-bit
donde fue posible, para usar menos memoria, como cambiar mov rax, 1
a mov eax,0x1
.
Si quisiéramos mostrar solo el código en ensamblador, sin el código de máquina ni las direcciones, podríamos agregar los flags --no-show-raw-insn --no-addresses
, de la siguiente manera:
objdump -M intel --no-show-raw-insn --no-addresses -d helloWorld
helloWorld: file format elf64-x86-64
Disassembly of section .text:
<_start>:
mov eax,0x1
mov edi,0x1
movabs rsi,0x402000
mov edx,0x12
syscall
mov eax,0x3c
mov edi,0x0
syscall
Nota: Ten en cuenta que objdump
ha cambiado la tercera instrucción a movabs
. Esto es lo mismo que mov
, por lo que en caso de necesitar reensamblar el código, puedes cambiarlo nuevamente a mov
.
El flag -d
solo desensamblará la sección .text
de nuestro código. Para volcar cualquier cadena, podemos usar el flag -s
y agregar -j .data
para examinar solo la sección .data
. Esto significa que tampoco necesitamos agregar -M intel
. El comando final es el siguiente:
objdump -sj .data helloWorld
helloWorld: file format elf64-x86-64
Contents of section .data:
402000 48656c6c 6f204854 42204163 6164656d Hello HTB Academ
402010 7921 y!
Como podemos ver, la sección .data
contiene efectivamente la variable message
con la cadena Hello HTB Academy!
. Esto debería darnos una mejor idea de cómo nuestro código fue ensamblado en código de máquina y cómo se ve después de ensamblarlo. A continuación, repasaremos los conceptos básicos de la depuración de código, que es una habilidad crítica que necesitamos aprender.