τTau SolutionsOfuscación

Packers y protectores

referencia técnica · Revisado el 12 de agosto de 2026

1. Alcance de este documento, antes de nada

Este documento explica el modelo de funcionamiento de un packer y las huellas que permiten identificarlo. No explica cómo extraer el payload, ni cómo volcar el DEX descifrado de memoria, ni cómo instrumentar el cargador. Esa línea —identificar sí, neutralizar no— es la que separa este documento de un manual de desempaquetado, y la sección 9 explica el razonamiento económico y legal que hay detrás en vez de dejarlo como una prohibición sin argumento.

La consecuencia práctica: aquí hay nombres de fichero, nombres de clase, cadenas y estructuras que sirven para contestar la pregunta «¿qué me he encontrado?». Buena parte de la literatura académica que se cita describe además cómo desempaquetar; de esos trabajos se ha extraído únicamente el modelo y las huellas.

2. Qué es un packer y por qué existe

Un ofuscador (Ofuscadores comerciales) transforma el código para que sea difícil de leer. Un packer hace algo distinto y más radical: quita el código del APK. Lo cifra, lo guarda como datos, y pone en su lugar un classes.dex mínimo cuyo único trabajo es descifrarlo y cargarlo en tiempo de ejecución.

Duan et al. lo enuncian de forma compacta: «una aplicación Android empaquetada suele empaquetar su código Java, y también su código nativo, dentro de ficheros de recurso binarios. Normalmente mantiene además un componente Java ficticio, que actúa únicamente como despachador para lanzar el procedimiento de desempaquetado».

Existe por dos motivos que conviene separar. El legítimo: proteger propiedad intelectual —la lógica de un juego, un algoritmo de recomendación, un DRM— frente a la copia y el reempaquetado. El otro: el malware lo usa para evadir el análisis estático de los antivirus, y de hecho lo usa mucho más que las aplicaciones legítimas (sección 6).

Para el analista, la diferencia con un ofuscador es cualitativa. Con un ofuscador queda código que decompilar, aunque sea horrible. Con un packer, el decompilador abre el APK y encuentra doscientas clases de infraestructura. Todo lo que le interesa está en un fichero de assets/ que es ruido.

3. El modelo común

Casi todos los packers implementan la misma arquitectura, con variaciones en el cifrado, en el momento de la carga y en el nivel de granularidad.

APK empaquetado
┌──────────────────────────────────────────────────────────────────┐
│ AndroidManifest.xml                                              │
│   <application android:name="com.qihoo.util.StubApplication"/>   │ ①
├──────────────────────────────────────────────────────────────────┤
│ classes.dex     ← el STUB. Pocas clases, ninguna de la app real  │ ②
├──────────────────────────────────────────────────────────────────┤
│ assets/ijiami.dat  ·  assets/classes0.jar  ·  assets/sealed1.dex │ ③
│   ← el DEX real, cifrado                                         │
├──────────────────────────────────────────────────────────────────┤
│ lib/arm64-v8a/libjiagu.so  ·  libDexHelper.so  ·  libshella.so   │ ④
│   ← el descifrador y el cargador, en nativo                      │
└──────────────────────────────────────────────────────────────────┘

Y su secuencia de arranque:

  Zygote crea el proceso
        │
        ▼
  ① Instancia la clase declarada en android:name  ─── la del packer, no la de la app
        │
        ▼
  ② Application.attachBaseContext(Context)        ─── el gancho: se ejecuta ANTES de onCreate
        │
        ├──► System.loadLibrary("jiagu")          ─── ④ carga el descifrador nativo
        │           │
        │           ├──► lee ③, descifra el DEX real
        │           └──► lo entrega al runtime
        │
        ├──► DexClassLoader / InMemoryDexClassLoader
        │    o manipulación directa de estructuras de ART
        │
        └──► por reflexión, sustituye el ClassLoader del proceso
             y restaura la Application original de la app
        │
        ▼
  ③ A partir de aquí la aplicación se ejecuta como si nada

3.1 El gancho: attachBaseContext

Es el detalle técnico que hace posible todo lo demás, y merece su propia explicación porque es donde converge toda la literatura.

Application hereda de ContextWrapper un método protected void attachBaseContext(Context base), disponible desde el nivel de API 1. La documentación de Application da la otra mitad: «puedes proporcionar tu propia implementación creando una subclase y especificando el nombre completamente cualificado de esa subclase como atributo android:name en la etiqueta <application> de tu AndroidManifest.xml. La clase Applicationse instancia antes que cualquier otra clase cuando se crea el proceso de tu aplicación/paquete».

Duan et al. lo señalan como el punto canónico: «AttachBaseContext() es la función que los packers suelen sobrescribir para realizar estas tareas, ya que el framework la llama incluso antes que OnCreate() y tiene el momento ideal para el preprocesado».

DexHunter añade el matiz que explica una huella concreta: las clases envoltorio com.bangcle.protect.ApplicationWrapper y com.shell.SuperApplication «solo aparecen si el fichero dex original tenía una clase Application». Es decir, el packer sustituye la Application del desarrollador y, si existía, la reintroduce después. Un manifiesto que declare una Application con un nombre de paquete que no tiene nada que ver con el de la aplicación es la señal más barata que existe.

3.2 Las tres vías de carga

Vía API Qué implica
DexClassLoader Nivel 3 «Carga clases de ficheros .jar y .apk que contengan una entrada classes.dex. Se puede usar para ejecutar código no instalado como parte de una aplicación». Deja el DEX descifrado en disco
InMemoryDexClassLoader Nivel 26 «Carga clases desde un buffer que contiene un fichero DEX. Se puede usar para ejecutar código que no se ha escrito en el sistema de ficheros local»
Manipulación directa de ART El nativo modifica las estructuras internas del runtime. La más difícil de observar

Corrección frecuente: DexClassLoader no está obsoleta. Lo que está obsoleto es su parámetro optimizedDirectory, que «está deprecado y no tiene efecto desde el nivel de API 26». La clase sigue documentada y sin aviso de deprecación, con la advertencia de siempre: «No caches clases optimizadas en almacenamiento externo. El almacenamiento externo no proporciona los controles de acceso necesarios para proteger tu aplicación frente a ataques de inyección de código».

Los constructores de InMemoryDexClassLoader llegaron en tres oleadas, y el dato sirve para acotar la edad de un packer: el de un solo ByteBuffer en API 26, el de array de buffers en API 27, y el que además acepta librarySearchPath en API 29.

La tercera vía, la manipulación de estructuras, la documentan los trabajos de desempaquetado. Happer describe que «los packers enganchan ClassLinker::LoadMethod para modificar los objetos ArtMethod», y DexHunter que se «modifican estructuras de datos clave en memoria, como DexHeader, ClassDef y ArtMethod». Las funciones nativas del runtime que aparecen citadas son openDexFileNative(), openDexFile_bytearray() y DexFile::<init>.

3.3 Tres niveles de sofisticación

La literatura describe tres regímenes claramente distintos. Los ordinales son una construcción editorial de este documento; ⚠️ sin verificar: no se ha encontrado ninguna fuente que use la etiqueta «primera / segunda / tercera generación» de forma literal, así que cada nivel se ancla a la fuente que lo describe.

Nivel 1 — liberación completa. Todo el DEX original se descifra de una vez antes de que el flujo de control llegue a él. AppSpear lo llama full-code releasing: «descifra el fichero DEX cifrado entero antes de que el flujo de control llegue a él». Parema lo formula como regla: «los mecanismos tradicionales de empaquetado de aplicaciones siguen una regla de escribir-y-luego-ejecutar».

Nivel 2 — descifrado incremental y por capas. AppSpear: «incremental code releasing, que descifra selectivamente solo la porción de código que se ejecuta realmente, y puede volver a cifrarla después de ejecutarla». El packer de Baidu, según el mismo trabajo, usa «cifrado en dos capas». Duan et al. lo miden: «estrategia de desempaquetado multicapa… capa a capa durante la ejecución», con Bangcle en 9 capas, ijiami en 4, Qihoo en 4 y Tencent en 40.

Nivel 3 — virtualización y traslado a nativo. Parema: «los packers de Android más recientes adoptan protecciones basadas en máquina virtual que nunca liberan el DCode… traducen el DCode a otro tipo de bytecode personalizado, denominado PCode, e incrustan una máquina virtual personalizada (P-VM)». Happer describe la variante complementaria: «JNI Transformation… los packers pueden usar código nativo para reimplementar métodos seleccionados de la aplicación».

Ese tercer nivel es la razón de que el desempaquetado genérico haya dejado de ser un problema resoluble de una vez: no hay ningún momento en el que el DEX original exista.

4. Las familias

Origen, mercado y qué las distingue. El estado de cada sitio web se ha comprobado directamente el 12 de agosto de 2026 y se declara, porque buena parte de este ecosistema es chino y sus sitios entran y salen.

Familia Vendedor / origen Estado del sitio Qué la distingue
Jiagu / 加固保 Qihoo 360 (Beijing, China), plataforma «360 Tianyu» jiagu.360.cn responde, pero es una SPA vacía sin contenido legible El packer chino más extendido. Su .so incluye una función señuelo llamada youAreFooled
Bangcle Bangcle (China) bangcle.com devuelve HTTP 500 Uno de los más antiguos. 9 capas de descifrado según Duan et al.
SecNeo SecNeo (China) secneo.com NXDOMAIN Tres variantes (A, B, C) distinguibles por su biblioteca nativa
Tencent Legu / 乐固 Tencent (China) ❌ portal de producto inaccesible El más agresivo por capas: 40 según Duan et al. Assets con nombres deliberadamente confusos (0OO00l111l1l)
Virbox Protector Beijing Shendun Technology (Pekín, China) shell.virbox.com Cubre nativo, Java, .NET, Python, ARM Linux. Ofrece shell y virtualización
DexProtector Licel dexprotector.com, licelus.com «Cifra de forma segura cadenas, clases enteras, assets y recursos». Motor InvokeDynamic. Falsifica la cabecera ELF de sus bibliotecas
Ijiami / 爱加密 Beijing Zhiyou Wang'an (Pekín, China) ⚠️ ijiami.cn sí, www.ijiami.cn no resuelve Declara «tecnología de endurecimiento de sexta generación» y «más de un millón de apps»
Baidu Baidu (China) apkprotect.baidu.com Declara «6W+ apps endurecidas» y cobertura de AAB
AppSealing Rebautizado como DoveRunner ⚠️ redirige; doverunner.com devuelve 403 Producto AppSecurity. Marca sus assets con un directorio propio
Promon Shield Promon AS, Oslo, Noruega, fundada en 2005 por Tom Lysemose promon.io «RASP, anti-tamper, anti-repackaging y protección de código de primer nivel, todo integrado en profundidad post-compilación»
DexGuard Guardsquare, Lovaina, Bélgica Cifra clases selectivamente. Ver la nota de abajo
Alibaba / Aliyun Alibaba (China) ❌ producto retirado o movido: 404 y NXDOMAIN Su huella (libmobisec.so) sigue en las reglas de APKiD
APKProtect / Naga Varias generaciones con huellas muy distintas
KiwiSec KiwiSec Bibliotecas libkiwi*

Sobre DexGuard en modo packing. Guardsquare declara cifrado de clases, pero no usa la palabra packing en ninguna de sus páginas consultadas, y la evidencia del Netflix del corpus va en contra de tratarlo como packer: su classes.dex contiene 8.920 clases reales y decompilables, con androidx y com.google.android.gms legibles (Ofuscadores comerciales, sección 3.1). Lo que sí tiene son ocho ficheros cifrados en la raíz. Es cifrado selectivo de clases, la transformación 2.3 de ese documento, no sustitución del DEX por un stub. ⚠️ sin verificar: que DexGuard tenga además un modo de packing completo; no se ha encontrado documentación del fabricante que lo describa.

5. Huellas de detección

Esta es la sección central. Todo lo que sigue está transcrito de las reglas YARA de APKiD 3.1.0, leídas en crudo del repositorio, salvo lo marcado como procedente de otra fuente. APKiD es la mejor documentación de huellas que existe: 297 reglas, de las cuales 132 con etiqueta packer y 75 con etiqueta protector, bajo licencia dual GPL-3.0 y comercial.

5.1 Por familia

Familia assets/ y raíz lib/ Clases DEX y cadenas
Jiagu / Qihoo 360 assets/jiagu_data.bin, assets/sign.bin libjiagu.so, libjiagu_art.so, libapktoolplus_jiagu.so, libprotectClass.so En la .so: JIAGU_APP_NAME, JIAGU_SO_BASE_NAME, JIAGU_ENCRYPTED_DEX_NAME, JIAGU_HASH_FILE_NAME. Clase com.qihoo.util.StubApplication
Bangcle assets/bangcleplugin/container.dex, bangcleclasses.jar, bangcle_classes.jar, assets/secData0.jar libsecexe.so, libsecmain.so, libSecShell.so, libSecShell-x86.so com.shell.NativeApplication, com.bangcle.protect.ApplicationWrapper, com.shell.SuperApplication
SecNeo assets/classes0.jar libDexHelper.so, libDexHelper-x86.so; variante B libdexjni.so, variante C libdatajar.so
Tencent Legu assets/tosversion, assets/0OO00l111l1l, assets/0OO00oo01l1l, assets/o0oooOO0ooOo.dat; variante VMP assets/wsDal.jar, assets/WSSEC[A-D].jar libshell.so, libshella-<v>.so, libshellx-<v>.so, libmobisecy.so, libshell-superv*.<año>.so, libxgVipSecurity.so Lcom/tencent/StubShell/TxAppEntry;, Lcom/tencent/StubShell/a, com.tencent.StubShell.ProxyShell. Ruta /mix.dex
Virbox libv++.so, libv++_64.so, libsandhook.so, libsandhook-native.so En la ELF, la cadena Virbox Protector. Clase Lvirbox/StubApp;
DexProtector assets/classes.dex.dat, assets/classes<n>.dex.dat, assets/resources.dat, assets/dp.mp3, assets/dp.<abi>.so.dat libdexprotector.<algo>.so, libalice.so Cabecera ELF falsificada: \x7fELF seguido de DPLF en el offset 4
Ijiami assets/ijiami.dat, ijiami.ajm/ijiami3.ajm, assets/ijm_lib/, assets/IJMDal.Data assets/libijmDataEncryption.so Stub UPX modificado: la magia UPX! sustituida por AJM!
Baidu baiduprotect1.jar, assets/baiduprotect.jar libbaiduprotect.so com.baidu.protect.StubApplication
Alibaba libmobisec.so com.ali.mobisecenhance.StubApplication
AppSealing assets/appsealing.dex, assets/sealed1.dex, assets/AppSealing/* libcovault.so, libcovault-appsec.so Lcom/inka/appsealing/AppSealingApplication;, AppSealingLoader … v1.2.2, APPSEALING-CORE-VERSION_2.10.10
Promon Shield libshield.so o un nombre aleatorio lib[a-z]{10,12}.so Secciones ELF anómalas .ncc (código), .ncd (datos), .ncu
KiwiSec / Kiro assets/sbox libkiroro.so, libkiwicrash.so, libkiwi_dumper.so, libKwProtectSDK.so, libkadp.so, libwhite-box.so Lcom/kiwisec/crash/CrashUtils;, Lcom/kiwivm/security/StubApplication;
APKProtect assets/apkprotect.bin, assets/apkprotect/classes.dex.bin, apkprotect-build.properties, META-INF/APKPROTECT.RSA libapkprotect.so, libAPKProtect.so Ruta apkprotect.com/key.dat
Naga assets/maindata/fake_classes.dex libedog.so/libddog.so/libfdog.so/libvdog.so, libchaosvmp.so, libxloader.so
Otros stubs Lcom/manxi/shell/MXApplication; (Manxi), Lcom/merry/wapper/WapperApplication; (PangXie), Lcom/vdog/VDogApplication; (Crazy Dog), Lcom/inca/security/Proxy/JNISoxProxy; (AppGuard), Lcom/security/inner/stub000/x; (DingXiang), Lcom/nesun/stub/ZAP; (Nesun), Lweb/apache/sax/app; (Medusah AppSolid)

5.2 Huellas transversales, que valen para familias que aún no tienen regla

Las anteriores envejecen: cambian con cada versión del producto. Estas no.

El stub UPX modificado. Tres familias comprimen su biblioteca nativa con UPX y sustituyen la magia UPX! para que upx -d no la reconozca:

Sustituto Familia
SEC! Bangcle y SecNeo
\x03\x02\x01\x00 Bangcle y SecNeo, versiones nuevas
AJM! Ijiami

La regla busca el marcador dos veces: en los primeros 200 bytes y en los últimos 50 del fichero.

La secuencia de arranque en el bytecode. La regla apkguard_dex de APKiD no busca nombres: busca la forma del código del stub, con los opcodes anotados uno a uno.

invoke-super {v14, v15}, Landroid/app/Application;.attachBaseContext:(Landroid/content/Context;)V
invoke-virtual {v14},    …getClassLoader:()Ljava/lang/ClassLoader;
new-instance v4,         Ldalvik/system/DexClassLoader;
invoke-direct {…},       Ldalvik/system/DexClassLoader;.<init>:(String;String;String;ClassLoader;)V
invoke-virtual {v4, v9}, Ldalvik/system/DexClassLoader;.loadClass:(String;)Ljava/lang/Class;
const-string v10,        "attachBaseContext"
invoke-virtual {…},      Ljava/lang/Class;.getDeclaredMethod:(…)
invoke-virtual {…},      Ljava/lang/reflect/Method;.invoke:(…)

Ese patrón —attachBaseContextDexClassLoadergetDeclaredMethod("attachBaseContext")invokees el packer, con independencia de quién lo haya escrito. Es la huella más duradera que hay, y es genérica.

Anomalías estructurales del DEX. La regla jiagu_k de APKiD comprueba (dex.header.data_size + dex.header.data_offset) < dex.header.file_size: hay bytes en el fichero que la cabecera no declara. Es la clase de comprobación que solo se puede hacer leyendo el fichero por el map_list y no por la cabecera (Formato DEX, sección 5). En la misma línea: un class_defs_size de dos cifras en un APK de 30 MB, un assets/ con un fichero de varios megabytes de entropía uniforme, o un lib/ con una biblioteca cuyo nombre no aparece en ningún System.loadLibrary visible.

Cabeceras falsificadas. DexProtector escribe DPLF —presumiblemente «DexProtector Linkable Format»— justo después de \x7fELF en el offset 4, donde debería ir la clase y el endianness. El comentario de la propia regla incluye el volcado:

0x00000000  7f45 4c46 0101 0100 4450 4c46 0000 0000  .ELF....DPLF....  // armeabi-v7a
0x00000000  7f45 4c46 0201 0100 4450 4c46 00e0 0100  .ELF....DPLF....  // Aarch64

Nótese que los bytes 4 y 5 —clase y data encoding— sí son válidos; lo que se sobrescribe es el resto del EI_PAD.

5.3 Corroboración independiente

Las reglas de APKiD son firmas; conviene comprobar que describen algo real. El análisis de Romain Thomas sobre Legu (Quarkslab, 26 de noviembre de 2019) nombra los mismos cuatro assets: «el packer usa los primeros 16 bytes de assets/tosversion xoreados con una clave fija», y enumera «tosversion, 0OO00l111l1l, 0OO00oo01l1l, o0oooOO0ooOo.dat». Coinciden exactamente con la regla tencent_legu.

⚠️ En cambio los nombres de biblioteca de aquel sample —orange-super.2019.so, orangea-4.1.0.XY.sono coinciden con los libshell*.so de las reglas. Es el recordatorio de siempre: las huellas por nombre de fichero envejecen y varían entre versiones del mismo producto.

6. Prevalencia real

6.1 El 0,59 %

La cifra de referencia sobre cuántas aplicaciones de Google Play llevan packer detectable es un 0,59 %. Conviene arrastrarla siempre con su fuente y con sus tres avisos, porque hay otra cifra casi idéntica con la que se confunde.

La frase original, literal:

«Compare that to Google Play at 0.59% packed and 2.65% obfuscated, an order of magnitude lower on every measure.»

Eduardo Blázquez, «Practical Android Software Protection in the Wild» — An Appetizer, blog de Quarkslab, 4 de junio de 2026. El artículo acompaña al trabajo revisado por pares Blázquez, E. y Tapiador, J., «Practical Android Software Protection in the Wild», ACM Computing Surveys 58(2), art. 36, DOI 10.1145/3757735, pp. 36:1–36:32. El estudio analizó 2.450.338 APK (el 99 % de su conjunto de datos), de los cuales «96.169 aplicaciones (~4 %) usaban al menos un packer, ofuscador o protector: 50.664 con packers, 45.320 con ofuscadores y 185 con protectores». La detección se hizo con APKiD.

Tres avisos que hay que arrastrar con la cifra:

  1. ⚠️ El 0,59 % se ha leído en el blog del primer autor, no en el artículo revisado: dl.acm.org/doi/full/10.1145/3757735 devuelve HTTP 403 y no hay preprint abierto.
  2. ⚠️ El tamaño de la muestra concreta de Google Play detrás de ese 0,59 % no se ha podido confirmar: vive en tablas que el blog publica solo como imagen.
  3. El propio autor pone el límite, y hay que citarlo con la cifra: «como APKiD se apoya en reglas YARA para la detección, las técnicas anti-análisis no cubiertas por su conjunto de reglas pueden pasar desapercibidas, lo que potencialmente rebaja los resultados».

Y una trampa que hay que evitar activamente: AppSpear (RAID 2015) reporta un 0,58 % que se parece muchísimo y no es lo mismo —es sobre malware de 2013, otra población y otro año—. Confundirlos es fácil y el error se propaga.

6.2 Las otras mediciones

Fuente Población N Empaquetado
Blázquez y Tapiador, ACM CSUR 58(2) Google Play ⚠️ no confirmado 0,59 %
Mauthe, Kargén, Shahmehri, SANER 2021 Google Play 13.594 127 apps (0,93 %, aritmética propia: el artículo solo publica conteos)
Ruggia et al., AsiaCCS 2024 Google Play, más descargadas, abril de 2023 21.154 0 — «APKiD no pudo reconocer ningún packer ni protector»
Duan et al., NDSS 2018 Malware, 2010–2015 93.910 13,89 %
Ruggia et al., AsiaCCS 2024 Malware 11,4 %
Blázquez y Tapiador, ACM CSUR 58(2) Huawei AppGallery / Qihoo 360 / Baidu 43 % / 40 % / 25 %

La conclusión que sostienen las seis filas a la vez, y que es lo que de verdad importa:

  • En Google Play, el packer es una rareza estadística: por debajo del 1 % en las tres mediciones, y cero en la muestra de aplicaciones más descargadas.
  • En malware, es un orden de magnitud más frecuente: del 11 % al 14 %.
  • En los mercados chinos, es lo normal: del 25 % al 43 %.

6.3 El corpus: cero packers

Buscadas las huellas de la sección 5.1 en los 86 contenedores del corpus —por nombre de entrada del ZIP, en el base.apk y en cada split, y por contenido en los 323 ficheros classes*.dex— el resultado es ninguna coincidencia. No hay libjiagu, ni libsecexe, ni libDexHelper, ni libshell*.so, ni assets/ijiami.dat, ni libcovault, ni libv++, ni libdexprotector, ni libbaiduprotect, ni ninguna de las clases stub de la tabla.

Es coherente con el 0,59 %: con 86 aplicaciones, la mayoría de F-Droid y el resto del catálogo internacional de Play, la expectativa estadística de encontrar un packer es inferior a una. El corpus no está mal construido; es que el fenómeno no está ahí.

Consecuencia operativa: un detector de packers no se puede validar contra este corpus. Cualquier prueba será de no-regresión y de ausencia de falsos positivos, que sigue siendo valiosa —un detector que dispara sobre 86 aplicaciones limpias es peor que ninguno— pero no mide el recall.

7. Qué se puede seguir haciendo con una app empaquetada

Encontrarse un packer no deja al analista a ciegas. Deja intacto todo lo que el packer no puede tocar porque es contrato con el sistema (Ofuscadores comerciales, sección 8).

Sigue disponible:

Superficie Qué se saca
AndroidManifest.xml Nombre de paquete, versión, minSdk/targetSdk, permisos, componentes exportados, intent-filter, provider authorities, meta-data. El manifiesto no está cifrado, porque el sistema lo lee antes de ejecutar nada
resources.arsc y res/ Cadenas de interfaz en todos los idiomas, colores, layouts. Con frecuencia el packer no toca los recursos
Firma Certificado, cadena, esquemas v1–v4, lineage. Ver Esquemas de firma
lib/*.so Análisis del binario nativo. Aquí está el descifrador y, en los packers de nivel 3, también la lógica de la aplicación
Estructura del ZIP Orden de entradas, alineación, marcas de herramienta. Ver Contenedor ZIP
El propio stub Nombres de clase, cadenas, y la biblioteca que carga: identifica al packer y con frecuencia también a su versión
Comportamiento observable Tráfico de red, ficheros creados, permisos ejercidos. Análisis dinámico

Ya no está disponible: el código Java de la aplicación, su grafo de llamadas, sus cadenas literales, y todo análisis estático que dependa de ellos —detección de SDKs y trackers por clase, SBOM desde el DEX, cobertura de decompilación—.

La regla honesta para un informe: decir que la aplicación está empaquetada, decir por qué familia si se sabe, y declarar explícitamente qué análisis quedan invalidados. Un informe que dice «0 trackers detectados» sobre una aplicación empaquetada está mintiendo por omisión, y esa es exactamente la clase de fallo silencioso que un producto serio no puede permitirse.

8. Recetas de identificación

Ejecutables con lo que hay instalado, sin herramientas específicas.

CORPUS=~/corpus-apk
BT=~/Library/Android/sdk/build-tools/37.0.0
APP=$CORPUS/com.termux_1002.apk
Qué se busca Orden
Clase Application declarada $BT/aapt2 dump xmltree --file AndroidManifest.xml $APP | grep -A6 'E: application'
Bibliotecas nativas unzip -l $APP 'lib/*'
Assets sospechosos unzip -l $APP 'assets/*' | sort -k1 -n -r | head
Número de clases del primer DEX $BT/dexdump -f <(unzip -p $APP classes.dex) | grep class_defs_size
Cadenas del stub unzip -p $APP classes.dex | strings | grep -iE 'stubapp|shell|jiagu|secmain|dexhelper'
Entropía de un asset unzip -p $APP assets/X | xxd | head — datos cifrados no tienen estructura visible

Ejecutado sobre el Netflix del corpus, el volcado del manifiesto da android:name="o.KY", que no es una clase stub conocida sino el resultado del repaquetado de DexGuard: la comprobación de la sección 3.1 acierta al levantar la sospecha y el resto del análisis la descarta.

La herramienta de referencia es APKiD:

apkid -j app.apk

⚠️ no ejecutado localmente: APKiD no está instalado y no se instala nada en esta máquina. La sintaxis procede de su README; sus reglas se han leído directamente del repositorio y son la fuente de la sección 5.

9. Por qué desempaquetar está fuera del alcance

No es mojigatería, y conviene tener el argumento escrito.

Es un pozo sin fondo por diseño. El repaso de la sección 3.3 muestra la trayectoria: los packers pasaron de liberar todo el DEX de una vez a liberarlo por capas —hasta 40 en Tencent— y de ahí a no liberarlo nunca, traduciéndolo a un bytecode propio interpretado por una máquina virtual generada por build. Cada avance del desempaquetado genérico se responde con una capa más. Un desempaquetador es correcto contra la versión concreta del packer contra la que se probó, y deja de serlo con la siguiente. El coste de mantenimiento no converge.

El público es minúsculo. Los datos de la sección 6 son inequívocos: por debajo del 1 % en Google Play, cero en la muestra de las más descargadas, y ni una en las 86 aplicaciones del corpus. Dedicar el esfuerzo más caro de una herramienta de análisis al 0,59 % de los casos, y además a la parte que peor envejece, es una mala asignación aunque fuese gratis.

El riesgo legal es real y asimétrico. Extraer el payload de un protector comercial es una elusión de una medida técnica de protección, con tratamiento distinto en cada jurisdicción y, en varias, con excepciones para investigación en seguridad que no cubren la distribución de una herramienta de propósito general. Detectar e informar no tiene ese problema en ninguna parte: es leer un fichero y decir qué hay dentro.

Y hay una asimetría técnica a favor. La detección es barata —unos cuantos patrones sobre el ZIP y sobre el DEX—, estable —las huellas estructurales de la sección 5.2 llevan años sin cambiar—, verificable y publicable. Es, además, lo que el analista necesita el 100 % de las veces: saber a qué se enfrenta. Desempaquetar solo lo necesita a veces, y quien lo necesita de verdad tiene herramientas especializadas y un laboratorio.

La frontera resultante, en una frase: se identifica y se informa; no se extrae.

Fuentes

  1. APKiD — reglas YARA y datos del proyecto — https://github.com/rednaga/APKiD, ficheros apkid/rules/apk/packers.yara, apk/protectors.yara, dex/packers.yara, elf/packers.yara, elf/protectors.yara, apkid/__init__.py, README.md, LICENSE.COMMERCIAL, leídos en crudo desde raw.githubusercontent.com/rednaga/APKiD/master/ Consultados el 12 de agosto de 2026. De aquí sale íntegra la sección 5, y el recuento de reglas, la versión 3.1.0, la licencia dual y la autoría.
  2. Blázquez, E. — «Practical Android Software Protection in the Wild» — An Appetizer — https://blog.quarkslab.com/practical-android-software-protection-in-the-wild-an-appetizer.html Consultado el 12 de agosto de 2026 (publicado el 4 de junio de 2026). De aquí sale el 0,59 % de la sección 6.1, el tamaño del conjunto de datos, el reparto entre packers, ofuscadores y protectores, las cifras de los mercados chinos y el caveat sobre APKiD. Artículo revisado subyacente: Blázquez, E. y Tapiador, J., ACM Computing Surveys 58(2), art. 36, DOI 10.1145/3757735. ⚠️ dl.acm.org/doi/full/10.1145/3757735 devolvió HTTP 403.
  3. Duan, Zhang, Roy, Bianchi, Bao, Zhang, Wang, Xing — «Things You May Not Know About Android (Un)Packers: A Systematic Study based on Whole-System Emulation», NDSS 2018 — https://www.cs.ucr.edu/~heng/pubs/DroidUnpack_ndss18.pdf Consultado el 12 de agosto de 2026. De aquí salen la definición de packer de la sección 2, la cita canónica sobre attachBaseContext de la sección 3.1, el número de capas por familia de la sección 3.3 y el 13,89 % de malware de la sección 6.2. ⚠️ La URL ndss2018_01A-4_Duan_paper.pdf que circula está rota; la correcta en el sitio de NDSS es ndss2018_04A-4_Duan_paper.pdf.
  4. Zhang, Luo, Yin — «DexHunter: Toward Extracting Hidden Code from Packed Android Applications», ESORICS 2015 — https://www4.comp.polyu.edu.hk/~csxluo/DexHunter.pdf Consultado el 12 de agosto de 2026. De aquí salen la lista de clases Application stub por familia y la nota sobre ApplicationWrapper/SuperApplication de la sección 3.1, y los nombres de asset de la sección 5.1.
  5. Yang, Zhang, Wang, Zhu, Xue — «AppSpear: Bytecode Decrypting and DEX Reassembling for Packed Android Malware», RAID 2015 — https://link.springer.com/chapter/10.1007/978-3-319-26362-5_17 (DOI 10.1007/978-3-319-26362-5_17) Consultado el 12 de agosto de 2026. De aquí salen full-code releasing, incremental code releasing y el cifrado en dos capas de Baidu (sección 3.3), y el 0,58 % que la sección 6.1 advierte de no confundir. El PDF que circula en gosec.sjtu.edu.cn/publications/RAID2015Yang.pdf ya no existe (404 el 12 de agosto de 2026); se sustituye por la entrada editorial, que es estable.
  6. Xue, Luo et al. — «PackerGrind», «Happer», «Parema» — https://www4.comp.polyu.edu.hk/~csxluo/PackerGrind.pdf, https://www4.comp.polyu.edu.hk/~csxluo/Happer.pdf, https://www4.comp.polyu.edu.hk/~csxluo/Parema.pdf Consultados el 12 de agosto de 2026. De aquí salen el gancho de ClassLinker::LoadMethod y los ArtMethod de la sección 3.2, la JNI Transformation y la P-VM de la sección 3.3.
  7. Thomas, R. — «A Glimpse into Tencent's Legu Packer» — https://blog.quarkslab.com/a-glimpse-into-tencents-legu-packer.html Consultado el 12 de agosto de 2026 (publicado el 26 de noviembre de 2019). De aquí sale la corroboración independiente de la sección 5.3.
  8. DexClassLoader, InMemoryDexClassLoader, PathClassLoader, BaseDexClassLoader — https://developer.android.com/reference/dalvik/system/DexClassLoader, https://developer.android.com/reference/dalvik/system/InMemoryDexClassLoader Consultados el 12 de agosto de 2026. De aquí sale la tabla de vías de carga de la sección 3.2, los niveles de API de cada constructor y la corrección sobre la no deprecación de DexClassLoader.
  9. Application y ContextWrapper.attachBaseContext — https://developer.android.com/reference/android/app/Application, https://developer.android.com/reference/android/content/ContextWrapper Consultados el 12 de agosto de 2026. De aquí salen las dos citas de la sección 3.1 sobre android:name y sobre el momento de instanciación.
  10. Sitios de los fabricantesshell.virbox.com, dexprotector.com, licelus.com/products/dexprotector, promon.io/about-us, ijiami.cn, apkprotect.baidu.com, jiagu.360.cn, docs.doverunner.com, guardsquare.com/dexguard Consultados el 12 de agosto de 2026. De aquí sale la tabla de la sección 4, incluido el estado de cada sitio. Fallaron: bangcle.com (HTTP 500), secneo.com (NXDOMAIN), los portales de producto de Tencent (404 y reto anti-bot), senseshield.com (NXDOMAIN), jaq.alibaba.com (NXDOMAIN) y aliyun.com/product/security/mobilesecurity (404).
  11. Mauthe, Kargén, Shahmehri, SANER 2021 — https://www.ida.liu.se/~ulfka17/papers/SANER2021.pdf y Ruggia et al., AsiaCCS 2024 — https://s3.eurecom.fr/docs/asiaccs24_ruggia.pdf Consultados el 12 de agosto de 2026. De aquí salen las dos filas correspondientes de la tabla de la sección 6.2.
  12. Mediciones propias sobre el corpus — ejecutadas el 12 de agosto de 2026 sobre ~/corpus-apk con build-tools 37.0.0 y Python 3.12. De aquí sale la sección 6.3 —la búsqueda de las huellas de la sección 5.1 sobre los 86 contenedores y los 323 classes*.dex— y la comprobación del manifiesto de Netflix de las secciones 4 y 8.