Saltar al contenido

Packers y unpacking: por qué un binario ‘pesa poco y hace mucho’

    Packers y unpacking:

    por qué un binario ‘pesa poco y hace mucho’

    Malware y Reversing  |  unfantasmaenelsistema.com

    Abres una muestra en el desensamblador y te encuentras un puñado de instrucciones, casi ningún import y una sección de código con aspecto de ruido. No es que el malware sea simple: es que lo que estás viendo es un stub de descompresión, y el programa de verdad está comprimido o cifrado dentro del fichero, esperando a que ese stub lo reconstruya en memoria cuando el proceso arranca. Eso es un packer.

    Entender el empaquetado es un paso obligado antes de reversar en serio: sin desempaquetar, el análisis estático no llega a ninguna parte y las firmas basadas en contenido fallan. Este artículo explica, a alto nivel, qué hace un packer, cómo se reconoce un binario empaquetado, cómo se deshace un empaquetado estándar como UPX y cuál es la idea del desempaquetado dinámico, sin entrar en técnicas de evasión. Todos los ejemplos son de lectura y comprobación sobre muestras en un laboratorio aislado.

    Qué aprenderás en este artículo

    Qué hace exactamente un packer: compresión o cifrado más un stub que restaura en memoria · La diferencia entre packers legítimos, protectores comerciales y crypters a medida · Las señales que delatan un binario empaquetado: entropía, imports, secciones y entry point · Desempaquetado estático de UPX con upx -d y por qué solo funciona con el formato original · La idea del desempaquetado dinámico: dejar que se descomprima y volcar desde memoria · Qué es el anti-unpacking y cuándo conviene parar y pasar a una sandbox

    1. Qué hace un packer

    Un packer toma un ejecutable ya compilado y produce otro ejecutable funcionalmente equivalente pero con el código y los datos originales transformados: comprimidos, cifrados o ambas cosas. Ese contenido transformado se guarda dentro del nuevo fichero, normalmente en una o varias secciones nuevas. El entry point del binario ya no apunta al programa original, sino a un pequeño trozo de código añadido —el stub o unpacking stub— cuya tarea es revertir la transformación.

    Cuando el sistema lanza el binario empaquetado, se ejecuta primero el stub: reserva memoria, descomprime o descifra el código original en ella, reconstruye la tabla de importaciones (que el cargador de Windows no ha podido resolver porque estaba empaquetada), aplica las relocations que hagan falta y, por último, salta al Original Entry Point (OEP), la primera instrucción del programa real. A partir de ahí el proceso se comporta como si nunca hubiera estado empaquetado. Ese salto al OEP es el momento clave para quien analiza: si consigues capturar la memoria del proceso justo después, tienes el binario desempaquetado.

    El empaquetado nació por motivos legítimos: reducir el tamaño de distribución cuando el ancho de banda era caro, y dificultar la copia trivial de recursos o cadenas. Hoy sus dos usos dominantes son proteger propiedad intelectual (licencias, antitrampas de videojuegos) y, en el lado ofensivo, romper las firmas estáticas de los antivirus: el mismo malware reempaquetado con una clave distinta produce un fichero con hash nuevo y contenido irreconocible.

    2. Familias: de UPX a los crypters a medida

    No todos los empaquetados cuestan lo mismo de deshacer. Conviene situar la muestra en una de estas categorías antes de invertir tiempo:

    CategoríaEjemplosObjetivoDificultad de desempaquetado
    Packer de compresión abiertoUPX, UPack, FSGReducir tamaño; formato documentado y reversibleBaja: a menudo hay un desempaquetador oficial
    Instalador autoextraíbleNSIS, Inno Setup, 7-Zip SFXDistribuir software; no oculta, empaquetaBaja: herramientas dedicadas extraen el contenido
    Protector comercialThemida, VMProtect, Enigma, ASProtectAntipiratería; virtualización de código y anti-debug fuerteAlta: pensado para resistir el análisis
    Crypter / packer a medidaCódigo propio de un actor o de un builder de mercado negroEvadir AV/EDR; suele añadir anti-análisisVariable: de trivial a muy costoso
    .NET packer / protectorConfuserEx, .NET Reactor, packers de ILOfuscar ensamblados gestionadosMedia: existen des-ofuscadores específicos (de4dot, etc.)

    UPX (Ultimate Packer for eXecutables) es el caso de referencia porque es libre, muy usado y simétrico: el mismo binario `upx` que comprime sabe descomprimir, siempre que la cabecera UPX del fichero esté intacta. Muchos actores lo usan tal cual por comodidad; otros lo aplican y luego manipulan la cabecera o los nombres de sección para que `upx -d` falle, aunque el algoritmo siga siendo el de UPX. Distinguir «UPX de verdad» de «UPX modificado» es una de las primeras preguntas del triaje.

    3. Cómo se reconoce un binario empaquetado

    Ninguna señal aislada es concluyente, pero la combinación de varias lo es. Estas son las que se miran, todas sobre el fichero en disco y sin ejecutarlo:

    • Entropía alta y homogénea: una o varias secciones con entropía de Shannon por encima de ~7,2 (sobre 8) indican contenido comprimido o cifrado. Si la sección de código está en 7,9, ahí no hay instrucciones legibles.
    • Tabla de importaciones mínima: dos o tres DLL y un puñado de funciones, típicamente LoadLibrary, GetProcAddress, VirtualAlloc y VirtualProtect. El programa real resolverá sus imports en tiempo de ejecución; la tabla estática está vacía a propósito.
    • Nombres de sección atípicos: `UPX0`, `UPX1`, `.themida`, `.vmp0`, `.enigma1`, secciones sin nombre o con bytes no imprimibles, o nombres duplicados.
    • Descuadre de tamaños: una sección con VirtualSize grande y SizeOfRawData cero o muy pequeño (el stub la llenará al arrancar); o `SizeOfImage` muy por encima del tamaño del fichero.
    • Entry point fuera de lo normal: la primera instrucción cae en la última sección, o en una sección de datos, en lugar de en `.text`.
    • Pocas cadenas legibles: apenas texto ASCII o UTF-16 útil; ni rutas, ni claves de registro, ni URLs, porque están dentro del blob comprimido.
    • Identificación por firma: herramientas como Detect It Easy (DiE), PEiD (histórico) o el módulo de detección de packers de PEStudio comparan patrones de bytes del entry point con una base de firmas conocidas.

    La entropía alta no es una acusación

    Instaladores legítimos (NSIS, Inno Setup), muchos binarios .NET, ejecutables con grandes recursos multimedia y binarios firmados con secciones comprimidas dan entropías altas sin ser maliciosos. La entropía sirve para priorizar y para sospechar de empaquetado, no para emitir un veredicto: se combina siempre con la tabla de imports, los nombres de sección y el entry point.

    # Comprobacion rapida de empaquetado. Solo lee el fichero, no lo ejecuta.
    import pefile, math
     
    def entropia(datos):
        if not datos:
            return 0.0
        frec = [0] * 256
        for b in datos:
            frec[b] += 1
        e = 0.0
        for c in frec:
            if c:
                p = c / len(datos)
                e -= p * math.log2(p)
        return e
     
    pe = pefile.PE('muestra.bin')
    for s in pe.sections:
        nombre = s.Name.rstrip(b'\x00').decode(errors='replace')
        print(f'{nombre:9s} vsize={s.Misc_VirtualSize:#8x} raw={s.SizeOfRawData:#8x} entropia={entropia(s.get_data()):.2f}')
     
    n_imports = sum(len(d.imports) for d in getattr(pe, 'DIRECTORY_ENTRY_IMPORT', []))
    print('funciones importadas:', n_imports)

    4. Desempaquetado estático: el caso UPX

    El desempaquetado estático consiste en revertir la transformación sin ejecutar el binario, aplicando el algoritmo inverso al blob comprimido. Solo es viable cuando el formato del packer está documentado o es simétrico. UPX es el ejemplo canónico: el propio proyecto distribuye la opción de descompresión.

    # 1. Confirmar que el fichero esta empaquetado con UPX y que la cabecera esta intacta
    upx -t muestra.exe        # 'testing' -> [OK] si el formato UPX es valido
    upx -l muestra.exe        # 'list' -> muestra ratio y tamanos comprimido/original
     
    # 2. Descomprimir a un fichero NUEVO, sin tocar el original
    upx -d muestra.exe -o muestra_unpacked.exe
     
    # 3. Verificar el resultado: ahora deberia tener imports completos y menos entropia
    upx -t muestra_unpacked.exe   # ya NO deberia reconocerlo como UPX

    Si `upx -d` responde con un error del tipo «not packed by UPX» o «header corrupted» pese a que DiE identifica el binario como UPX, casi siempre es porque el actor ha alterado la cabecera UPX o los nombres de sección después de empaquetar. El algoritmo sigue siendo UPX, pero la herramienta oficial se niega. Opciones a alto nivel: reconstruir a mano los campos de la cabecera UPX comparándolos con los de un binario UPX sano de la misma versión, o —más habitual— pasar directamente al desempaquetado dinámico, que no depende de esos metadatos.

    SituaciónVía recomendada
    UPX estándar, upx -t da [OK]upx -d: segundos, sin ejecutar nada
    UPX con cabecera manipuladaDinámico, o reparación manual de la cabecera si el volumen lo justifica
    Instalador SFX (NSIS, Inno, 7z)Extractor dedicado (7-Zip, innoextract) o volcado del directorio temporal
    Protector comercial (Themida, VMProtect)Dinámico con herramientas específicas; a veces solo análisis en sandbox
    Packer a medida desconocidoDinámico: identificar el salto al OEP y volcar memoria

    5. La idea del desempaquetado dinámico

    Cuando no hay desempaquetador conocido, la estrategia es dejar que el propio stub haga el trabajo y capturar el resultado. El binario se ejecuta de forma controlada —en una máquina virtual aislada, sin red, con un depurador o un motor de instrumentación— y se le permite descomprimir el programa original en memoria. El objetivo es identificar el instante en que el stub termina y salta al OEP, y en ese punto volcar (dump) la imagen del proceso desde memoria a un fichero.

    A alto nivel, las técnicas para localizar ese instante son de dos tipos. Las manuales ponen un punto de interrupción en el momento en que el flujo pasa de la sección del stub a la sección donde aparece el código descomprimido (un cambio de sección con permisos de ejecución, o una escritura seguida de un salto a esa misma zona). Las automáticas usan herramientas genéricas de unpacking que monitorizan la ejecución y detectan el patrón «escribir memoria ejecutable y luego saltar a ella», hacen el volcado y reconstruyen la tabla de importaciones.

    Pieza del procesoQué resuelveHerramientas habituales (análisis)
    Ejecución controladaDejar que el stub descomprima sin dañar el hostVM aislada sin red, snapshots
    Detección del OEPSaber cuándo el código real ya está en memoriaDepurador (x64dbg) con breakpoints de sección; unpackers automáticos
    Volcado de memoriaExtraer la imagen ya descomprimidaPlugins de dump del depurador, volcado de secciones del proceso
    Reconstrucción de imports (IAT)Que el binario volcado vuelva a enlazar con las DLLScylla, ImpREC (histórico)
    Arreglo del PECabeceras y alineaciones coherentes para que cargueEditores de PE, LIEF

    El resultado —un dump con la IAT reconstruida— no siempre vuelve a ejecutarse, pero eso da igual: lo que se busca es un fichero que el desensamblador pueda leer entero, con sus cadenas, sus llamadas a API y su lógica a la vista. A partir de ahí el análisis continúa como con cualquier binario no empaquetado.

    Ejecutar para desempaquetar es ejecutar malware

    El desempaquetado dinámico implica correr la muestra. Hazlo solo en una máquina virtual dedicada, con instantánea previa, sin acceso a la red o con red simulada, sin carpetas compartidas con el host y sin credenciales reales dentro. Restaura la instantánea al terminar.

    6. Anti-unpacking y cuándo parar

    Los protectores serios y muchos crypters a medida incorporan anti-unpacking: mecanismos para que el binario se comporte de forma distinta —o no se desempaquete— cuando detecta que lo están analizando. A grandes rasgos:

    • Anti-debug: comprobaciones de si hay un depurador presente (flags del proceso, tiempos de ejecución anómalos, trampas con excepciones) que abortan o desvían la descompresión.
    • Anti-VM y anti-sandbox: el stub busca artefactos de virtualización o de entornos de análisis y, si los encuentra, no despliega el payload real.
    • Descompresión por partes (stolen bytes, code stripping): el código original nunca está entero en memoria a la vez; se reconstruye a trozos y se vuelve a borrar, de modo que un único volcado no basta.
    • Virtualización de código: en lugar de descomprimir instrucciones x86, el protector las traduce a un bytecode propio que ejecuta una máquina virtual embebida. No hay un OEP clásico al que saltar; «desempaquetar» aquí significa escribir un desensamblador para esa VM, un trabajo de semanas.

    Por eso una decisión importante del triaje es cuándo dejar de desempaquetar. Si el objetivo es clasificar la muestra, extraer indicadores de compromiso (IOC) y entender su comportamiento, casi siempre sale más a cuenta ejecutarla en una sandbox —automatizada, con captura de llamadas al sistema, tráfico de red y ficheros creados— que invertir días en vencer un VMProtect. El desempaquetado completo se reserva para cuando hace falta el código exacto: atribución, firma específica, o comprender un algoritmo concreto (cifrado de un ransomware, protocolo de un C2).

    Orden de trabajo razonable ante una muestra empaquetada

    Triaje estático: hash, tipo, identificación de packer con DiE, entropía por sección, imports y cadenas · Si es UPX estándar: upx -d y seguir con el binario limpio · Si no: sandbox primero para obtener comportamiento e IOC rápidos · Solo si se necesita el código real: desempaquetado dinámico en VM aislada, volcado y reconstrucción de la IAT · Si hay virtualización de código: valorar si el coste compensa o basta con el análisis dinámico

    7. Herramientas de referencia

    HerramientaTipoPara qué
    Detect It Easy (DiE)GUI/CLIIdentificar compilador, linker y packer; gráfica de entropía por zonas
    UPXCLIComprimir y descomprimir el formato UPX (upx -t, -l, -d)
    PEStudioGUI, WindowsMarca indicadores de empaquetado y cruza imports con listas de APIs de riesgo
    x64dbgDepurador, WindowsDesempaquetado dinámico manual: breakpoints de sección, seguimiento hasta el OEP
    ScyllaGUI, WindowsReconstrucción de la tabla de importaciones tras el volcado
    pefile / LIEFLibreríasAutomatizar el triaje estático y reparar cabeceras del PE volcado
    Sandbox (CAPE, Cuckoo, comercial)Entorno automatizadoComportamiento e IOC sin desempaquetar a mano; muchas hacen unpacking automático

    Marco legal y de seguridad

    Analiza solo binarios propios, retos públicos (crackmes, CTF) o muestras de malware dentro de un laboratorio aislado y sin salida a la red; nunca en tu equipo habitual · El desempaquetado dinámico ejecuta la muestra: máquina virtual dedicada, instantánea previa y posterior, sin carpetas compartidas ni credenciales reales · La ingeniería inversa de software de terceros está acotada en la UE a fines concretos (interoperabilidad, corrección de errores, seguridad) y con matices según el país y la licencia del producto; eludir la protección técnica de un programa para piratearlo o distribuir cracks es ilícito · En España, usar estas técnicas contra sistemas ajenos encaja en los artículos 197 bis, 197 ter y 264 del Código Penal, además de la normativa de propiedad intelectual · Si al analizar una muestra encuentras datos de una víctima real o indicios de un incidente en curso, documenta y deriva a INCIBE-CERT o a las fuerzas y cuerpos de seguridad; no lo difundas por tu cuenta

    Referencias

    «Practical Malware Analysis» (Sikorski y Honig, No Starch Press) — capítulo dedicado a packers y unpacking · Documentación oficial de UPX (upx.github.io) — formato y opciones de línea de comandos · Detect It Easy (github.com/horsicq/DIE-engine) — firmas de packers y protectores · OALabs y el canal de MalwareAnalysisForHedgehogs — vídeos de desempaquetado manual con x64dbg y Scylla · Documentación de CAPE Sandbox — extracción de configuración y unpacking automático

    Conclusión

    Un binario empaquetado no es más complejo: es el mismo programa envuelto en una capa que hay que retirar antes de poder analizarlo. Esa capa combina compresión o cifrado con un stub que reconstruye el código original en memoria y salta al OEP, y su huella —entropía alta, imports mínimos, secciones raras, entry point desplazado— se detecta en el triaje estático sin ejecutar nada.

    Deshacer el empaquetado va de menos a más esfuerzo: upx -d resuelve el caso estándar en segundos; cuando no hay desempaquetador conocido, se deja que el stub trabaje en una VM aislada y se vuelca la memoria en el salto al OEP, reconstruyendo después la tabla de importaciones. Y ante protectores con virtualización de código, lo sensato suele ser una sandbox que dé comportamiento e indicadores sin pelear semanas contra la máquina virtual del protector.

    unfantasmaenelsistema.com | Seguridad, sistemas y todo lo que no debería funcionar (pero funciona)

    Resumen de privacidad

    Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.