Quelques commandes reviennent si souvent, du désassemblage à la construction d’un exploit, qu’il vaut mieux les avoir sous la main plutôt que de les redécouvrir à chaque fois.
De l’assembleur au binaire, et retour
# Assembleur → hexadécimal
rasm2 -a x86 -b 64 'mov rax, rbx'
# Hexadécimal → assembleur
rasm2 -a x86 -b 64 -d 4889d8
# Compiler un objet depuis de l'assembleur NASM
nasm -f elf64 asm-code.s -o elf-object.o
# Compiler un objet depuis du C, sans fonctions builtin du compilateur
gcc -fno-builtin -c c-code.c -o elf-object.o
# Lier en exécutable minimal, sans libc ni point d'entrée standard
gcc obj.o -static -nostartfiles -nostdlib -o exec.elf
# Désassembler en syntaxe Intel
objdump -M intel -d exec.elf
# Ne désassembler que .text
objdump -M intel -d -j .text exec.elf
# Extraire le code d'un ELF pour en faire un shellcode brut
objcopy -j .text -O binary exec.elf shellcode.bin
# Tracer les appels systèmes d'un programme
strace -f -e trace=execve,read,write,exit ./exec.elf
# Afficher l'en-tête ELF (-a pour tout afficher)
readelf -h exec.elfDeux remarques pratiques complètent cette liste. Pour exporter une fonction écrite en assembleur, il faut la déclarer en symbole global. Et si _start sert conventionnellement de point d’entrée, rien n’oblige à en définir un explicitement — selon la chaîne de liaison choisie, un simple label suffit.
Respecter la convention d’appel
Pour passer des arguments à une fonction écrite à la main, il faut respecter la convention de registres de la plateforme visée. Sous Linux/BSD/macOS, c’est l’ABI System V AMD64 qui prévaut — la plus courante en environnement Unix, et celle qu’on retrouve dans l’immense majorité des exercices.
Sous GDB / GEF
Les commandes de navigation les plus fréquentes : break <fonction> ou break <adresse> pour poser un point d’arrêt, next pour exécuter la ligne courante sans entrer dans un appel, step pour au contraire y entrer.
GEF ajoute quelques réglages utiles à la configuration :
gef config gef.bruteforce_main_arena True
gef config context.show_opcodes_size 8
à placer dans son .gdbinit pour les rendre permanents.
Lire un dump mémoire sans se tromper
En affichant un groupe d’octets, GDB/GEF montre la valeur interprétée — ce qui, sauf pour une chaîne de caractères, inverse l’ordre réel de stockage en mémoire (voir la note sur l’endianness) : les octets écrits en dernier apparaissent en premier à l’affichage.
gef➤ x/w 0x7fffffffd639
0x7fffffffd639: 0x64f7fe1e
gef➤ x/4b 0x7fffffffd639
0x7fffffffd639: 0x1e 0xfe 0xf7 0x64