Introducción al reversing
La ingeniería inversa (reversing) es el arte de entender cómo funciona un programa sin tener su código fuente, partiendo solo del binario compilado. Se usa para analizar malware, encontrar vulnerabilidades, saltarse protecciones (licencias, DRM), entender protocolos propietarios, y resolver retos de CTF. Consiste en traducir el código máquina de vuelta a algo comprensible —ensamblador y, con decompiladores, pseudo-C— y razonar sobre su lógica.
Para qué se usa
Sección titulada «Para qué se usa»- análisis de malware: entender qué hace un ejecutable sospechoso (ver malware)- búsqueda de vulnerabilidades: encontrar bugs en software sin fuente (pwn)- bypass de protecciones: licencias, DRM, anti-cheat, comprobaciones- interoperabilidad: entender formatos/protocolos propietarios- CTF: resolver retos de "crackme" (encontrar la contraseña/flag)Estático vs dinámico
Sección titulada «Estático vs dinámico»Las dos grandes aproximaciones, complementarias:
Análisis estático (ver rev-static) examinar el binario SIN ejecutarlo -> desensamblar/decompilar, leer la lógica, strings, imports -> seguro (no ejecutas malware), pero más laboriosoAnálisis dinámico (ver rev-dynamic) ejecutar el binario y observarlo -> debugger, trazas, monitorizar syscalls/APIs, ver la memoria en vivo -> rápido para entender comportamiento, pero ejecutas el código (riesgo en malware)En la práctica se combinan: estático para mapear la lógica, dinámico para confirmar y para lo que es difícil de seguir estáticamente (código ofuscado, descifrado en runtime).
Primer contacto con un binario
Sección titulada «Primer contacto con un binario»file binario # tipo, arquitectura, ¿stripped? ¿static?strings binario # cadenas legibles: mensajes, rutas, URLs, pistasstrings -e l binario # strings unicode (Windows)checksec --file=binario # mitigaciones (si es ELF)nm binario / readelf -s # símbolos (si no está stripped)ltrace / strace ./binario # llamadas a librería/sistema (dinámico rápido)strings es el primer paso siempre: a menudo revela contraseñas, mensajes de error, nombres de funciones, o la propia flag.
Formatos de binario
Sección titulada «Formatos de binario»ELF Linux (ejecutables, .so)PE Windows (.exe, .dll)Mach-O macOS/iOS# además: .NET (IL, decompilable casi al fuente con dnSpy/ILSpy),# Java (bytecode -> jd-gui), Python (pyc -> decompyle3), etc.Los lenguajes con bytecode (.NET, Java, Python) son mucho más fáciles de revertir (casi se recupera el fuente); C/C++ compilado a nativo es lo más difícil.
Herramientas (panorama)
Sección titulada «Herramientas (panorama)»# decompiladores/desensambladores (estático)Ghidra gratuito, potente, decompilador a pseudo-C (NSA) -> el estándar libreIDA Pro el estándar comercial; IDA Free limitadoBinary Ninja, radare2/cutter, Hopper# debuggers (dinámico)gdb + pwndbg/GEF (Linux), x64dbg (Windows), lldb# utilidadesstrings, file, nm, objdump, readelf, ltrace/strace# bytecode: dnSpy/ILSpy (.NET), jadx/jd-gui (Java/Android)Flujo de trabajo típico (un crackme)
Sección titulada «Flujo de trabajo típico (un crackme)»1. file + strings + checksec -> primera idea2. abrir en Ghidra -> localizar main / la función de comprobación3. leer la lógica (pseudo-C): ¿cómo valida la contraseña/flag?4. si está claro -> deducir la entrada correcta5. si hay ofuscación/cifrado -> dinámico (gdb): poner breakpoints, ver memoria en runtime6. (si procede) parchear el binario para saltarse la comprobaciónPara la defensa (anti-reversing)
Sección titulada «Para la defensa (anti-reversing)»El reversing se dificulta —no se impide— con protecciones que se cubren en rev-antidebug:
- ofuscación del código y de strings- packers / cifrado del ejecutable (se descifra en runtime)- anti-debugging / anti-VM / detección de análisis- comprobaciones de integridad (anti-tampering)# para proteger propiedad intelectual o malware; para el analista, son obstáculos a sortearChecklist de dominio
Sección titulada «Checklist de dominio»- file/strings/checksec como primer contacto
- Diferenciar estático vs dinámico y cuándo usar cada uno
- Reconocer el formato (ELF/PE/Mach-O/bytecode)
- Abrir un binario en Ghidra y localizar main/lógica
- Leer pseudo-C y seguir la lógica de validación
- ltrace/strace para ver llamadas rápidamente
- Combinar estático + dinámico en código ofuscado
- Resolver un crackme básico (deducir/parchear)