Saltar al contenido
Lectura7 minPreview

Herramientas: de file y objdump al intérprete de Python

Un script se lee con un editor; un binario compilado hay que mirarlo por dentro sin ejecutarlo. Empiezo por el binario porque es lo que va a encontrar en cuanto suba de nivel.

Ficha de file y strings

file identifica el tipo real de un archivo por sus primeros bytes, sin fiarse de la extensión. strings ("cadenas") imprime las secuencias legibles de 4 o más caracteres: mensajes, rutas, URLs.

file [-b] ARCHIVO...
strings [-n MINIMO] [-e CODIFICACION] ARCHIVO
OpciónQué haceEjemplo
file -bSolo el tipo, sin repetir el nombrefile -b crackme
strings -nLargo mínimo de cadena (por defecto 4)strings -n 8 crackme
strings -e lBusca texto UTF-16, el de muchos .exe de Windowsstrings -e l app.exe

Un ELF de Linux compilado desde un C de diez líneas (salida ilustrativa):

$ file crackme
crackme: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3f1c…, for GNU/Linux 3.2.0, not stripped
$ strings crackme | grep -i clave
Clave correcta
Clave incorrecta

not stripped significa que conserva los nombres de las funciones. Va a ver revisar en vez de sub_1149.

Ficha de objdump

objdump (object dump, "volcado de objeto", de las binutils de GNU) con -d desensambla un ejecutable.

objdump -d [-M intel] [--disassemble=FUNCION] ARCHIVO
OpciónQué haceEjemplo
-dDesensambla las secciones de códigoobjdump -d crackme
-M intelSintaxis Intel en vez de AT&Tobjdump -d -M intel crackme
--disassemble=Solo una función, si hay símbolosobjdump --disassemble=revisar crackme

El comienzo de revisar, ilustrativo, compilado sin optimizar:

0000000000001149 <revisar>:
    1149:	55                   	push   %rbp
    114a:	48 89 e5             	mov    %rsp,%rbp
    114d:	89 7d fc             	mov    %edi,-0x4(%rbp)
    1150:	81 7d fc 39 05 00 00 	cmpl   $0x539,-0x4(%rbp)
    1157:	0f 94 c0             	sete   %al

Lo que importa es cmpl $0x539: compara el argumento con 0x539, o sea 1337. Lo anterior es la preparación de cualquier función.

$ objdump -d verificador.py
objdump: verificador.py: file format not recognized

No es un binario: es texto, se lee con un editor.

Pasadas unas treinta instrucciones, yo dejo objdump y abro Ghidra, que la NSA liberó en 2019: su descompilador muestra pseudocódigo parecido a C (necesita Java). En terminal está radare2: r2 -A crackme, afl lista funciones y pdf @ main desensambla main.

Python para deshacer transformaciones

Abra el intérprete con python3 (en Windows, py). Casi todo crackme combina estas operaciones sobre bytes:

OperaciónIdaVuelta
XORx ^ kx ^ k (se deshace sola)
Rotar 3 bits a la izquierda((x << 3) | (x >> 5)) & 0xFF((x >> 3) | (x << 5)) & 0xFF
Invertir el ordenv[::-1]v[::-1]
Texto a númeroslist(s.encode())bytes(v).decode()

El & 0xFF recorta a un byte. Si lo olvida (Python 3.12):

>>> bytes([(200 << 3)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: bytes must be in range(0, 256)

CyberChef hace XOR y rotaciones (From Decimal, XOR, Rotate right); para reordenar índices, Python es más directo.