Ofuscadores comerciales
Antes conviene leer «Formato DEX», «R8 y ProGuard»
1. Qué es y por qué existe
R8 renombra («R8 y ProGuard»). Un ofuscador comercial hace eso y
además cifra, aplana, inserta ruido y esconde llamadas, y en algunos casos vende junto a
ello comprobaciones de integridad en ejecución. La diferencia práctica para quien analiza es
que con R8 el código decompilado es correcto y feo, y con un ofuscador comercial el
decompilador puede directamente no producir código válido.
Este documento cataloga las transformaciones —que es la parte reutilizable, porque los productos van y vienen pero el repertorio es finito—, describe los cuatro productos relevantes y publica una tabla de huellas. Es el complemento de «Packers y protectores», que trata el caso en el que ya no hay código que decompilar porque viaja cifrado.
Alcance. Se documenta qué transformación aplica cada producto y cómo se identifica. No se documenta cómo revertir ninguna, ni cómo neutralizar las comprobaciones de integridad que algunos añaden. La «sección 2.2 · Cifrado de cadenas» se acerca a la frontera al tratar el cifrado de cadenas y se queda del lado de la identificación; el tratamiento del descifrado como análisis estático para leer código está en «Deofuscación → §6 · Descifrado de cadenas».
Todas las cifras y listas de esta página vienen de la fuente del propio fabricante o de un estudio publicado, y las huellas concretas vienen de las reglas YARA de APKiD o de medición directa sobre el «muestrario». Lo que no se ha podido verificar va marcado.
Versiones de referencia: APKiD 3.1.0 y su rama master, R8 9.2.4-dev y aapt2 de
build-tools 37.0.0, Allatori 9.9 y la ficha de DexGuard de 2024, consultadas en agosto y
septiembre de 2026.
2. Catálogo de transformaciones
Once transformaciones cubren prácticamente todo lo que se encuentra. Para cada una: qué hace, qué le hace al decompilador y qué huella deja.
2.1 Renombrado de identificadores
Lo que hace R8. Clases, campos, métodos y paquetes pasan a a, b, c. La variante
agresiva mueve además todas las clases a un solo paquete —Netflix tiene 17.329 clases en
un paquete llamado o— o al paquete raíz.
Efecto: el decompilador produce código correcto. El lector pierde toda la semántica de los nombres, que es la mitad de la comprensión. Huella: mediana de longitud de identificador de 1 a 3 («R8 y ProGuard → §10 · Medición propia: la fracción de identificadores cortos»). Paquete raíz poblado.
Dos refinamientos que distinguen al producto de pago:
- Sobrecarga por nombre (name overloading): reutilizar el mismo nombre para métodos con
firmas distintas y para campos de tipos distintos. Es legal en el
DEX, donde unmethod_idllevaclass_idx,proto_idxyname_idx, pero convierte el índice en ambiguo para quien busca por nombre. - Alfabetos hostiles. El estudio de Wermke et al. lo documenta: «Allatori y DexGuard
construyen sobre el alfabeto de ofuscación de nombres de ProGuard y añaden palabras
reservadas de Windows (
AUX,NUL)». Dong et al. observaron en malware nombres con caracteres Unicode (È,ô) y secuencias confusas (llllllll,oO00O0oo). La gramática deSimpleNamedelDEXes mucho más permisiva que la de Java («Formato DEX → §7 · Descriptores de tipo y shorty»), así que un ofuscador puede emitir nombres que ningún decompilador a Java puede reproducir como código compilable.
Ese último punto explica una huella muy concreta de APKiD (3.1.0, igual en master): las reglas dexguard_b y
dexguard_d buscan literalmente clases llamadas AUX, CON e IF en cualquier
combinación de mayúsculas, y la de Lo/ —Lo/AUX;, Lo/CON;— la marca como específica de
DexGuard porque otros ofuscadores usan esos nombres pero no dentro de un paquete o.
2.2 Cifrado de cadenas
Las constantes de texto se sustituyen por datos cifrados más una llamada a un descifrador que se ejecuta al vuelo. Es la transformación más rentable para el que ofusca, porque las cadenas literales son la principal vía de orientación de quien lee código ajeno: nombres de endpoints, claves de preferencias, mensajes de error, nombres de clases usados por reflexión.
Efecto: el decompilador produce b(c("Èk9@sg^W0~aa ÿ")) en vez de "Wrong Password" —el
ejemplo es de la propia documentación de Zelix—. La búsqueda por texto deja de funcionar.
Huella: un string_ids lleno de secuencias no imprimibles o de longitud uniforme, y uno o
pocos métodos estáticos invocados desde cientos de sitios con argumentos constantes
distintos.
El límite lo declara el propio fabricante. Zelix: «el cifrado de cadenas de Zelix KlassMaster no es, ni puede ser, fundamentalmente irreversible». Wermke et al. lo dicen igual: «hay que llegar a un compromiso entre la fuerza del cifrado y el impacto en rendimiento de descifrar. El descifrador tiene que estar dentro del programa, lo que hace el cifrado inadecuado para ocultar información sensible».
2.3 Cifrado de clases
El bytecode de clases enteras se guarda cifrado y se descifra y carga en ejecución. Es la frontera con el packing: cuando se aplica a todo el código, ya es un packer («Packers y protectores»); aplicado selectivamente a unas pocas clases, es una transformación más del ofuscador.
Efecto: esas clases sencillamente no están en el DEX. El decompilador no las ve.
Huella: ficheros de datos opacos y de alta entropía en assets/ o en la raíz del APK
con nombres cortos, y un class_defs_size menor de lo que sugiere el tamaño del APK.
2.4 Aplanamiento y ofuscación del flujo de control
Se reestructuran los if/while/for en formas que no tienen equivalente directo en Java:
un despachador con un switch sobre una variable de estado, saltos cruzados, predicados
opacos cuyo valor es constante pero indecidible localmente.
Efecto: Zelix lo describe con precisión: «normalmente fuerza a los decompiladores a
insertar una serie de etiquetas y sentencias goto ilegales en el código fuente que
producen» y «a veces el código fuente se ofusca aún más por los errores del decompilador».
Es decir: la salida ni siquiera compila.
Huella: densidad anómala de goto/goto/16/goto/32 y de packed-switch/sparse-switch
(«Bytecode Dalvik»); métodos con un solo bucle enorme y
un switch sobre un registro que se reasigna en cada rama.
2.5 Inserción de código muerto y basura
Instrucciones y ramas que nunca se ejecutan, o que se ejecutan y no hacen nada.
Efecto: infla el volumen a leer y despista al análisis automático.
Huella: nop en cantidad, aritmética sin consumidor, ramas cuya condición es constante.
Obfuscapk implementa tres de estas de forma pura y documentada: Nop («inserta código
basura; Nop inserta instrucciones aleatorias de no-operación»), ArithmeticBranch
(«inserta cómputos aritméticos e instrucciones de salto como código basura») y Goto
(«inserta una instrucción goto que apunta al final del método»).
2.6 Indirección por reflexión
Una llamada directa objeto.metodo(x) se sustituye por
Class.forName(s1).getMethod(s2, …).invoke(objeto, x), casi siempre con s1 y s2
cifrados («sección 2.2 · Cifrado de cadenas»).
Efecto: el grafo de llamadas se rompe. Dong et al. lo explican bien: «la reflexión es una
buena opción para ocultar comportamientos del programa porque puede transferir el control a
una función determinada de forma implícita, algo que las herramientas de análisis estático
del estado del arte no manejan bien».
Huella: proporción elevada de Ljava/lang/reflect/Method;.invoke y Class.forName sobre
el total de invocaciones. Zelix la vende como Reference Obfuscation: «permite ofuscar las
referencias a campos o métodos sustituyéndolas por llamadas a la Reflection API o por
invokedynamic», y además «cifra los nombres de los campos, métodos y clases a los que se
accede por esa vía».
Dato de escala, de Dong et al. sobre 114.560 aplicaciones: de 121.262 llamadas reflexivas observadas, 116.595 (96,2 %) tenían objetivo resoluble. Y su conclusión sobre prevalencia es menos alarmante de lo que suele decirse: «las proporciones de uso de reflexión en aplicaciones benignas y en malware son similares» y «la mayoría de los casos de reflexión se usan para invocar funciones ocultas o para dar soporte a compatibilidad hacia atrás».
2.7 Ofuscación aritmética
Expresiones aritméticas y lógicas simples se sustituyen por otras equivalentes pero enrevesadas (aritmética booleana mixta, identidades algebraicas). Guardsquare lo vende literalmente como protección de fórmulas: «DexGuard protege las fórmulas propietarias transformando expresiones aritméticas y lógicas simples en código difícil de analizar».
Efecto: el decompilador produce código correcto e incomprensible.
Huella: densidad anómala de xor-int, and-int, shl-int y compañía. La regla
dexguard_c de APKiD, que busca un método con la firma a(IIZI[I[[I[I)V que contenga
xor-int/2addr («xor es bastante raro en código legítimo»), no detecta esto: su propio
comentario describe ese método como un método de descifrado en tiempo de ejecución, es decir,
el descifrador del cifrado de cadenas de la «sección 2.2 · Cifrado de cadenas».
2.8 Ocultación de llamadas a la API
Caso particular de 2.6 dirigido a las llamadas que delatan. Guardsquare: «DexGuard añade reflexión para acceder a APIs sensibles, como las APIs estándar de Android para validación de firmas o para operaciones criptográficas».
Efecto: un análisis que busque PackageManager.getPackageInfo o javax.crypto no
encuentra nada.
Huella: ausencia sospechosa de llamadas a APIs que los permisos del manifiesto implican.
Obfuscapk tiene una transformación específica, AdvancedReflection, descrita como «usa
reflexión para invocar APIs peligrosas del framework de Android».
2.9 Ofuscación de recursos
Dos cosas distintas que se confunden:
- Nombres de entrada en
resources.arsc: el nombre simbólico (activity_main) se colapsa o se sustituye. - Rutas de fichero dentro del
APK:res/layout/activity_main.xmlpasa ares/a/b.xmlo ares/raw/AW.xml.
Lo notable es que hay una vía oficial de Google para esto, en aapt2 optimize:
Opción de aapt2 optimize |
Qué hace (texto de la propia herramienta) |
|---|---|
--collapse-resource-names |
«Colapsa los nombres de recurso a un único valor en el key string pool. Se pueden exceptuar recursos con la directiva no_collapse» |
--shorten-resource-paths |
«Acorta las rutas de los recursos dentro del APK. Se pueden exceptuar con no_path_shorten» |
--save-obfuscation-map <f> |
«Ruta donde volcar el mapa de rutas/nombres originales a ofuscados» |
Ese último fichero es el mapping.txt de los recursos, y es lo que hace que esta
transformación sea determinísticamente reversible si se tiene el mapa y prácticamente
irreversible si no. Ver «Deofuscación → §4 · Determinista 2 — renombrado de recursos».
Huella: medida directamente sobre el muestrario, hay tres firmas distintas y bien separadas:
Firma en aapt2 dump resources |
Qué es | Visto en |
|---|---|---|
anim/0_resource_name_obfuscated |
aapt2 --collapse-resource-names. La cadena aparece una sola vez en el resources.arsc, porque todas las entradas apuntan al mismo índice del key string pool |
Snapchat (22.890 entradas) |
anim/(name removed) |
Mismo mecanismo, cadena centinela distinta: es RESOURCE_NAME_REMOVED de Redex, el optimizador de Meta, no de aapt2. También una sola aparición en el fichero |
WhatsApp (54.797 entradas) |
anim/2130771970 |
El nombre se sustituye por el propio resource ID en decimal (0x7f010002). Hay tantas cadenas distintas como entradas |
Netflix, con DexGuard |
La cadena 0_resource_name_obfuscated está dentro del binario de aapt2 37.0.0 de esta
máquina, junto a no_collapse y a los descriptores protobuf aapt.pb.CollapsedNamesMap: es
un artefacto oficial, no de un ofuscador de terceros. (name removed), en cambio, no aparece
en ese binario: es la constante RESOURCE_NAME_REMOVED de libredex/RedexResources.h.
2.10 Virtualización
La forma más fuerte. El cuerpo del método se traduce a un bytecode propio y se sustituye por una llamada a un intérprete de ese bytecode incluido en la aplicación. Guardsquare: «la virtualización de código transforma las implementaciones de los métodos en instrucciones para máquinas virtuales generadas aleatoriamente».
Efecto: no hay nada que decompilar. El analista tiene que reconstruir primero la máquina
virtual y luego su juego de instrucciones, que es distinto en cada build.
Huella: métodos enormes con un switch gigante sobre un array de bytes, y un array de
datos que no es texto ni recurso.
2.11 Endurecimiento del código nativo
Mover lógica a .so y proteger ese .so. Guardsquare: «DexGuard endurece las bibliotecas
nativas frente a la ingeniería inversa y la manipulación, incluida la interfaz entre las
bibliotecas nativas y el código de la aplicación». Se trata en
«Anti-análisis y hardening → §7 · Lógica movida a nativo».
3. DexGuard (Guardsquare)
El hermano de pago de ProGuard, del mismo fabricante. Nació en 2012, dos años antes de que
se fundara Guardsquare. Sede en Lovaina, Bélgica. Licencia comercial sin precio público;
el estudio de Wermke et al. lo registra en su tabla comparativa como «On request», frente a
los 290 $ de Allatori y los 800 $ de DexProtector.
Lo que dice de sí mismo su ficha de producto de 2024, verbatim y agrupado por el eje de este documento:
| Categoría | Técnicas declaradas |
|---|---|
| Ofuscación estática | Name obfuscation (clases, campos, métodos, bibliotecas nativas, y también nombres de recursos, ficheros de recursos, ficheros de assets y atributos XML de recursos), control flow obfuscation, arithmetic obfuscation, call hiding, removal of Android logging code |
| Cifrado | Data encryption: «cifra cadenas sensibles… También cifra clases, ficheros de assets, ficheros de recursos y bibliotecas nativas» |
| Virtualización | Code virtualization |
| Nativo | Native code obfuscation |
| RASP | Certificate checks, debugger and emulator checks, root detection, hook detection, tamper detection, malware protection |
Y la frase que explica por qué se lo encuentra uno tan a menudo: «DexGuard es compatible hacia atrás con ProGuard. Eso hace fácil la migración: puedes reutilizar tu configuración de ProGuard e implementar las capas adicionales de protección de DexGuard». Cubre además aplicaciones multiplataforma —Unity, Cordova, Ionic, Flutter, React Native— y declara «más de 900 clientes en todo el mundo».
Sobre si DexGuard hace packing en el sentido de
«Packers y protectores»: Guardsquare usa la palabra, aunque no en
su ficha de 2024. Al presentar DexGuard 8.1, el 30 de noviembre de 2017, anunció el
«Code packing», que además de cifrar clases concretas permite
«encrypt all combined bytecode as an additional layer of protection»; y en 2019 describía el
cifrado de clases como «class encryption (and by extension, packing)». Guardsquare ha
anunciado, pues, las dos cosas: cifrado de clases concretas, que es la transformación 2.3,
y cifrado de todo el bytecode. Se lo cataloga a veces como «un packer comercial», pero la
evidencia del muestrario que sigue muestra que Netflix no usa la segunda: su classes.dex
contiene código real decompilable, no un stub.
3.1 La evidencia real en el Netflix del muestrario
com.netflix.mediaclient.sai.zip, base.apk, 21,9 MB, versionName 8.76.0 build 7 50451.
Todo lo que sigue está medido directamente, no inferido de una regla de detección.
Cadenas y clases que nombran al producto, encontradas recorriendo string_ids y
class_defs de los cinco classes*.dex:
DEX |
Cadena |
|---|---|
classes.dex |
DEXGUARD, Dexguard |
classes2.dex, classes5.dex |
Lcom/netflix/mediaclient/dexguard/impl/DexguardImpl$DexguardModule; |
classes3.dex |
Lcom/netflix/mediaclient/service/player/streamingplayback/exosessionplayer/DexguardInitializerError; |
classes3.dex |
Ignore dexguard error |
classes3.dex |
SPY-37220 - dexguard unable to decrypt ASE |
Las dos últimas son las más elocuentes: son mensajes de manejo de errores del propio
Netflix ante fallos del descifrado de DexGuard, con hasta un identificador de incidencia
interno. El producto está integrado como un módulo de inyección de dependencias
(DexguardModule) del propio código de la aplicación.
Repaquetado agresivo. El manifiesto declara android:name="o.KY" como clase
Application. De las 43.838 clases definidas en los cinco DEX, 17.329 están en un
paquete llamado o —el 39,5 %—, mientras que el resto conserva su paquete real
(com/netflix/…, androidx/…, com/google/android/gms/…, 1.337 paquetes distintos).
Es decir: DexGuard mueve el código propio a un paquete de una letra y deja las bibliotecas de
terceros donde estaban.
Cifrado de clases y de assets. En la raíz del APK, no en assets/, hay ocho
ficheros con nombres de dos caracteres:
a- 9.329 bytes b'java/lang/Integer' + 9.312 bytes de alta entropía
b- 1.153 java/lang/Integer + …
c- 9.893 java/lang/Integer + …
d- 46.969 java/lang/Integer + …
e- 9.900 java/io/Serializable + …
f- 45.460 java/io/Serializable + …
g- 14.012 java/io/Serializable + …
h- 69.996 java/io/Serializable + …
Cada uno empieza por un descriptor de tipo Java en ASCII plano y sigue con datos opacos. Hay
además un assets/e de 205.861 bytes sin cabecera reconocible y un assets/volicense_av1.dat
de 135 bytes que tampoco es texto.
Ofuscación de recursos, completa. De las 4.656 entradas bajo res/, 4.655 están en
res/raw/ con nombres de una a dos letras (A.xml, AW.xml, BA.xml…), y la restante en
res/xml/. La estructura por tipo de recurso ha desaparecido del ZIP. Y en el
resources.arsc, el nombre de cada entrada es su propio resource ID en decimal:
type anim id=01 entryCount=54
resource 0x7f010002 anim/2130771970
() (file) res/raw/f.xml type=XML
0x7f010002 = 2.130.771.970. Es una firma distinta de la de aapt2 («sección 2.9 · Ofuscación de recursos») y por sí
sola distingue a DexGuard de una aplicación optimizada con las herramientas de Google.
Lo que DexGuard se llevó por delante. No hay ni un META-INF/*.kotlin_module en el
APK, cuando aplicaciones ofuscadas con R8 a secas conservan decenas («sección 8.5 · Lo que sobrevive por descuido»). No hay
marcador ~~R8 en ningún DEX; solo un ~~D8{"compilation-mode":"release","version":"1.6.68"}
residual de alguna dependencia.
Y lo que no. La mediana de longitud de identificador del primer DEX de Netflix es
10, con solo un 22,0 % de identificadores de tres caracteres o menos. Sus primeras clases
son Landroid/support/v4/media/MediaBrowserCompat$ConnectionCallback;, legibles. El paquete
com/netflix/mediaclient/graphql/models/type/ conserva nombres como ArtworkAlignment y
ArtworkFallbackStrategy. DexGuard está configurado selectivamente: repaquetado y
cifrado sobre una parte del código, no sobre todo.
4. Allatori
De Smardec Inc. Versión 9.9, publicada el 1 de septiembre de 2026. Ofuscador de bytecode Java
con soporte explícito de Android: se engancha en build.gradle con un doLast tras la
compilación Java y antes de generar el DEX. Eso lo sitúa en un punto distinto de la
cadena que R8, y explica que sus efectos y los de R8 se acumulen.
Su lista de características, verbatim: Name Obfuscation, Flow Obfuscation, Debug Info Obfuscation, String Encryption, 100% Protection Against Popular Decompilers, Optimizing, Watermarking, Incremental Obfuscation, Stack Trace Utility, Build Tool Interface, J2ME Obfuscation, Android Obfuscation.
Dos cosas que no tiene ningún otro de esta lista:
- Marca de agua (watermarking): «cualquier cadena que se incruste en los
jarde la aplicación. Puede ser el copyright, el nombre del cliente, el nombre de la empresa o cualquier otra información que identifique unívocamente el build». Es decir, Allatori añade información identificatoria a propósito, al contrario que el resto. - Caducidad (expiry): «se usa para poner fecha de caducidad a la aplicación. Las
comprobaciones de caducidad se insertan en muchos métodos, no solo en
main».
Su cifrado de cadenas tiene cuatro niveles (enable por defecto —solo cadenas seguras—,
disable, maximum —todos los literales—, maximum-with-warnings) y dos tipos, fast y
strong. El renombrado se configura por separado para paquetes, clases, métodos, campos y
variables locales, con esquemas de nombres que incluyen carácter único, alfabético,
numérico y palabras reservadas.
Licencias: 290 $ por desarrollador individual, 3.750 $ site, 4.850 $ business, y gratuito para proyectos educativos y no comerciales.
Huella: la regla allatori_demo de APKiD busca la cadena ALLATORIxDEMO en el DEX, que
la versión de evaluación incrusta. Un build de pago no la lleva.
5. Zelix KlassMaster
De Zelix Pty Ltd, Australia. Se autodenomina «el primer ofuscador Java de segunda generación de verdad, de uso intensivo». Sus cinco funciones son Name Obfuscation, Flow Obfuscation, String Encryption, Reference Obfuscation y Trim.
Es el más útil de los cuatro como documentación, porque explica sus propios mecanismos con precisión inusual. Ya se le ha citado en las secciones «2.2», «2.4» y «2.6». Dos detalles adicionales:
- Las variables locales no se renombran, se eliminan: «los nombres originales de las
variables locales se han quitado». Es la misma operación que borrar el
debug_info_itemdelDEX(«Formato DEX → §12 · debug_info_item»), y es irreversible por construcción. - Method Parameter Changes: añade parámetros extra a los métodos —su ejemplo muestra un
longde más— para reforzar la ofuscación por referencia.
Trim es su reductor: «reduce el tamaño de la aplicación eliminando las clases, campos y
métodos sin usar y los atributos de bytecode innecesarios», con análisis de las llamadas a la
Reflection API que podrían ocultar usos legítimos. Es el equivalente del shrinking de R8.
Es un ofuscador de bytecode Java, no de DEX. Su propia página lo define así: «un
ofuscador Java cambia el bytecode Java», y en efecto nunca menciona DEX: habla de
.class y, como mucho, del APK resultante.
Lo que sí menciona es Android, y con detalle. El FAQ oficial tiene dos entradas dedicadas: la
Q5 —«Zelix KlassMaster supports Google Android by obfuscating the Java class files before they
are converted into an APK file»— y la Q40, «What settings do I use for Android Apps?», con un
ZKM Script completo: classpath al android.jar, exclusiones para Activity, Application,
Service, BroadcastReceiver, ContentProvider, los constructores de android.view.View,
Parcelable$Creator CREATOR, *.R$* y @JavascriptInterface, más preverify=false y
keepBalancedLocks=true para el verificador de ART.
La vía existe, pero con un límite que el propio FAQ señala: desde Android Studio 3.6 ya no se
puede usar ProGuard, así que Zelix no sirve como sustituto directo suyo. Lo que sigue
funcionando es lo de siempre, y por eso se lo encuentra uno en aplicaciones Android: cualquier
ofuscador de .class opera antes de D8.
Precios: 585 $ estándar, 290 $ para organizaciones de hasta dos personas, 2.195 $ site.
6. obfuscapk
Obfuscapk es lo contrario de los tres anteriores: académico, de código abierto (licencia
MIT) y de caja negra —opera sobre el APK ya construido, sin código fuente—. Publicado
por Simone Aonzo, Gabriel Claudiu Georgiu, Luca Verderame y Alessio Merlo en SoftwareX
vol. 11 (2020), art. 100403. El repositorio está archivado en GitHub, en solo lectura;
su último push es del 27 de julio de 2024.
Vale la pena por dos motivos. Uno, su catálogo está documentado y es reproducible, lo que lo convierte en el banco de pruebas natural para un deofuscador. Dos, la separación en categorías es una taxonomía útil por sí misma. Sus 21 transformaciones:
| Categoría | Transformaciones |
|---|---|
| Trivial | NewAlignment, NewSignature, Rebuild |
| Rename | ClassRename (incluido el manifiesto), FieldRename, MethodRename |
| Encryption | AssetEncryption, ConstStringEncryption, LibEncryption, ResStringEncryption |
| Code | AdvancedReflection, ArithmeticBranch, CallIndirection, DebugRemoval, Goto, MethodOverload, Nop, Reflection, Reorder |
| Resource | RandomManifest |
| Other | VirusTotal |
CallIndirection («añade métodos envoltorio que invocan a los originales, modificando el
flujo de control»), MethodOverload («explota la sobrecarga de Java creando métodos void
nuevos con nombres idénticos») y Reorder («cambia el orden de los bloques básicos y
reorganiza el código con instrucciones goto») son buenos ejemplos de transformaciones que
un evaluador puede aplicar y medir.
Depende de apktool, apksigner, zipalign y Java.
Las 21 transformaciones de la tabla están verificadas contra el código, no contra el
README: el repositorio declara exactamente veintiún plugins, uno por fichero
.obfuscator, y los nombres coinciden uno a uno con los de arriba.
git clone --depth 1 https://github.com/ClaudiuGeorgiu/Obfuscapk.git
find Obfuscapk/src -name '*.obfuscator' | wc -l
21
⚠️ no ejecutado localmente: obfuscapk no arranca en la máquina de referencia, y no por
falta de dependencias externas —apktool 3.0.3, apksigner, zipalign y Java 21 sí están—
sino porque su gestor de plugins, Yapsy 1.12.2, importa el módulo imp, retirado de la
biblioteca estándar en Python 3.12:
File ".../yapsy/PluginManager.py", line 134, in <module>
import imp
ModuleNotFoundError: No module named 'imp'
Hacerlo funcionar exige un intérprete anterior a 3.12 o el contenedor Docker que publica el proyecto. Es un dato sobre su mantenimiento tan informativo como su catálogo: la herramienta de referencia académica para evaluar deofuscadores no corre en un Python actual sin preparar el entorno aparte.
7. Tabla de huellas
Reunida a partir de las reglas YARA de APKiD (etiqueta v3.1.0; las reglas citadas son
iguales en master, que añade dexprotector_b para libdexprotector*.so y amplía
dexprotector_alice con libalice.so), de la
documentación de cada fabricante y de la medición directa sobre el muestrario. Las huellas de
APKiD se citan verbatim de los ficheros de reglas.
| Transformación | Cómo se ve en el binario | Herramientas que la aplican |
|---|---|---|
| Renombrado | Mediana de longitud de identificador 1–3; paquete raíz o de una letra poblado | R8, DexGuard, Allatori, Zelix, obfuscapk |
| Renombrado hostil | Clases AUX, CON, IF (reglas dexguard_b, dexguard_d); nombres con Unicode no ASCII |
DexGuard, Allatori |
| Cifrado de cadenas | string_ids con secuencias no imprimibles; descifrador estático invocado desde cientos de sitios; en DexGuard, método a(IIZI[I[[I[I)V con xor-int/2addr (regla dexguard_c) |
DexGuard, Allatori, Zelix, DexProtector, obfuscapk |
| Cifrado de clases/assets | Ficheros opacos de alta entropía con nombre corto en la raíz o en assets/ |
DexGuard (a-…h- en Netflix), DexProtector (assets/classes.dex.dat, assets/dp.mp3) |
| Flujo de control | Densidad anómala de goto y switch; salida del decompilador que no compila |
DexGuard, Allatori, Zelix, obfuscapk (Goto, Reorder) |
| Código muerto | nop en masa, aritmética sin consumidor |
obfuscapk (Nop, ArithmeticBranch) |
| Reflexión | Proporción alta de Class.forName + Method.invoke con argumentos cifrados |
DexGuard (call hiding), Zelix (Reference Obfuscation), obfuscapk |
| Aritmética | Densidad anómala de xor-int, and-int, shl-int |
DexGuard |
| Recursos, nombres | 0_resource_name_obfuscated (una sola vez en el pool) · (name removed) (ídem) · <resourceID en decimal> |
aapt2 --collapse-resource-names · Redex · DexGuard |
| Recursos, rutas | res/a/b.xml, res/0.xml planos · todo bajo res/raw/XX.xml |
aapt2 --shorten-resource-paths · DexGuard |
| Marca de agua | Cadena ALLATORIxDEMO (regla allatori_demo) |
Allatori (versión demo) |
| Runtime DexGuard | guardsquare/dexguard/runtime/, Ldexguard/util/TamperDetector; (dexguard_c), Ldexguard/util/TamperDetection; (dexguard_d), Ldexguard/util/CertificateChecker;, com/guardsquare/dexguard/ (reglas dexguard_c, dexguard_d) |
DexGuard |
| Nativo DexGuard | libdgrt.so, símbolo Java_com_guardsquare_dexguard_runtime_detection_HookDetector (reglas dexguard_native, dexguard_native_a) |
DexGuard 9.x |
| ELF falsificado | Cabecera 7f 45 4c 46 … 44 50 4c 46 — \x7fELF seguido de DPLF (regla dexprotector) |
DexProtector |
| Arxan / Digital.ai | Paquetes L(aaaaaa|bbbbbb|…)/[a-z]{6} y Lcom/arxan/guardit; fichero guardit4j.fin en la raíz |
Arxan / Digital.ai |
| Gemalto | lib/<abi>/libmedl.so |
Gemalto |
Nota metodológica sobre APKiD: es una herramienta de identificación por firma, con las limitaciones que eso implica. Está bajo licencia dual GPL-3.0 y comercial; la firman Caleb Fenton y Tim Strazzere, y el mayor contribuidor por número de commits es hoy Eduardo Novella.
Su versión 3.1.0 trae 291 reglas en las cuatro etiquetas que interesan aquí. Contado sobre
el árbol de reglas de la etiqueta v3.1.0 del repositorio, el 13 de agosto de 2026:
git clone --depth 1 --branch v3.1.0 https://github.com/rednaga/APKiD.git
grep -rhoE '^\s*rule\s+\w+\s*:\s*[a-z_ ]+' APKiD/apkid/rules --include='*.yara' \
| sed 's/.*: *//' | tr ' ' '\n' | grep -v '^$' | sort | uniq -c | sort -rn | head -6
136 packer
72 protector
69 obfuscator
28 anti_vm
19 internal
14 compiler
136 + 72 + 69 + 14 = 291. Las cifras que circulan son algo distintas —el propio proyecto habla de un total mayor— porque el recuento depende de cómo se cuenten las reglas con más de una etiqueta; la diferencia no cambia ninguna conclusión.
Un apunte de evolución que sí importa: la rama master posterior a
v3.1.0 añade 1.281 reglas con etiqueta tracker, una categoría que la versión publicada
no tiene. La cifra se repite el 25 de septiembre de 2026, con v3.1.0 aún como última versión
publicada y el último commit de master del 2 de septiembre. APKiD está creciendo hacia la identificación de SDK de seguimiento.
7.1 Lo que APKiD encuentra, y lo que no
Ejecutado con la versión 3.1.0 sobre 81 APK —los 58 standalone más los 23 base.apk
extraídos de los contenedores— y sus 387 entradas contando cada classes*.dex:
| Etiqueta | Aciertos |
|---|---|
packer |
0 |
protector |
0 |
dropper |
0 |
obfuscator |
7 |
manipulator: Resources Confusion |
64 |
Los siete obfuscator son «unreadable field names» y «unreadable method names» sobre tres
juegos —Candy Crush, Coin Master y My Talking Tom—, y describen el síntoma, no el producto.
Cero packers confirma de forma independiente lo que la «sección 6.3 de Packers y protectores · El muestrario: cero packers» midió con lectores propios. Dos métodos distintos, el mismo resultado: el fenómeno no está en este muestrario.
Y ahora las dos limitaciones, que valen más que la lista.
APKiD no identifica a DexGuard en la única aplicación del muestrario protegida con
DexGuard. Sobre el base.apk de Netflix, sus cinco DEX devuelven compiler: r8 y varias
anti_vm, y ninguna regla de DexGuard dispara, pese a que todas llevan la etiqueta
obfuscator. Que Netflix usa DexGuard está fuera de
duda: sus propios DEX contienen Lcom/netflix/mediaclient/dexguard/impl/DexguardImpl;,
DexguardModule y cadenas de registro como SPY-37220 - dexguard unable to decrypt ASE. La
huella que delata al producto no es una firma del ofuscador: es el código de integración que
Netflix escribió y no ofuscó. Un detector por firma no puede ver eso.
Y «Resources Confusion» dispara sobre 54 de los 58 APK de F-Droid. La regla es de una
línea:
strings:
$res = /res\/[^\/]+\.xml/
condition:
is_apk and #res > 10
Es decir: más de diez ficheros XML colgando directamente de res/, sin subdirectorio de
calificador. Eso era la huella de AndResGuard cuando se escribió la regla, y hoy es lo que
produce aapt2 --shorten-resource-paths, la optimización de tamaño que AGP aplica desde la
4.2 mediante OptimizeResourcesTask a toda variante no depurable, salvo que se desactive
con android.enableResourceOptimizations=false. La opción está marcada como obsoleta con
retirada anunciada para AGP 9.0, pero la rama principal de AGP la sigue aceptando en
septiembre de 2026, con la misma condición. No depende de shrinkResources ni de
minifyEnabled, y de ahí que la lleven también aplicaciones sin encoger nada: Termux declara
shrinkResources false y tiene 362 entradas res/*.xml planas. Medido:
unzip -Z1 app.pachli_50.apk | grep -cE '^res/[^/]+\.xml$'
unzip -Z1 app.pachli_50.apk | grep -E '^res/[^/]+\.xml$' | head -3
873
res/--.xml
res/-0.xml
res/-1.xml
873 en Pachli y 362 en Termux, dos aplicaciones libres compiladas desde fuente y sin protección de ninguna clase. Los cuatro que no disparan son los que quedan por debajo del umbral o vienen de compilaciones antiguas: Mindustry tiene 3 y GnuCash, ninguno.
La conclusión no es que la regla esté mal escrita: es que la cadena de compilación de
Android adoptó una transformación que antes distinguía a un protector, y la regla no se ha
movido con ella. Es el modo de fallo característico de la identificación por firma, y la razón
por la que las etiquetas packer y protector de APKiD se pueden leer casi como un veredicto
mientras que manipulator, anti_vm y anti_debug exigen mirar el contexto.
Y un resultado negativo que importa: ninguna de las huellas de packer del catálogo de
APKiD aparece en el muestrario. Buscadas por nombre de fichero y por contenido de los 323
classes*.dex de las 86 aplicaciones, no hay libjiagu, ni libsecexe, ni libDexHelper,
ni libshell*.so, ni assets/ijiami.dat, ni pairip. Ver
«Packers y protectores → §6.3 · El muestrario: cero packers».
8. Qué NO se puede ofuscar
Esta sección es la más importante para quien construye herramientas, porque describe el suelo: lo que sigue siendo legible pase lo que pase, y sobre lo que se apoya todo el análisis de una aplicación protegida.
8.1 La superficie declarada en el manifiesto
Los android:name de activity, service, receiver y provider tienen que corresponder
a clases que el framework pueda instanciar por nombre. Se pueden renombrar de forma
coherente —reescribiendo el manifiesto con el nombre nuevo, que es lo que hace DexGuard en
Netflix, cuya Application es o.KY— pero no pueden desaparecer ni dejar de corresponder.
R8 no los renombra: conserva siempre los componentes del manifiesto
(«R8 y ProGuard → §5.3 · Qué se conserva siempre, y qué rompe»), así que un android:name ofuscado ya es
señal de algo más que R8. Consecuencia: el manifiesto siempre da la lista exacta de puntos de entrada,
y por tanto el conjunto de clases desde las que arranca cualquier análisis.
Lo mismo vale para los intent-filter, los permisos, los meta-data y los provider
autorities: son contrato con el sistema y con otras aplicaciones.
La formulación académica más precisa que se ha encontrado es de Wermke et al.: «las clases que necesitan ser accesibles desde un contexto externo… las clases que extienden clases nativas de Android como activities, services o content providers deberían quedar sin ofuscar en la mayoría de los casos para que la biblioteca o el sistema puedan invocar sus callbacks».
Lo documenta la página oficial «Use rules to troubleshoot optimization» (actualizada el 19 de
mayo de 2026): entre los orígenes de lo que R8 conserva cita las «rules generated by AAPT
(Android Asset Packaging Tool)», y su ejemplo de -whyareyoukeeping muestra una MainActivity
conservada por una regla de …/aapt_proguard_file/release/processReleaseResources/aapt_rules.txt.
Las reglas las genera, pues, AAPT2, no AGP. La misma página avisa de que esas reglas
«are not present when optimized resource shrinking is enabled», que es lo normal desde AGP 9.0
con isShrinkResources = true: entonces es el propio R8 quien lee el manifiesto
(«R8 y ProGuard → §5.1 · Los ficheros y su procedencia»). En los dos casos, los componentes del
manifiesto son entry points del grafo de R8.
8.2 Los puntos de entrada del framework
Todo método que el framework llama por nombre a través de una interfaz o de una superclase
conserva ese nombre: onCreate, onBind, onReceive, run, compare, test. No es una
concesión del ofuscador, es que el nombre está en la superclase, que vive fuera de la
aplicación. Renombrar el método de la subclase rompería el override.
De ahí que la métrica de la «sección 10 de R8 y ProGuard · Medición propia: la fracción de identificadores cortos» nunca llegue al 100 %: incluso en la aplicación más ofuscada del muestrario queda un 8 % de métodos con nombre largo, y son estos.
Las reglas por defecto de AGP amplían ese suelo de forma bien documentada
(«R8 y ProGuard → §5.2 · Las reglas que AGP empaqueta de verdad»): sobreviven con su nombre los set*/get*
de las subclases de View, los values()/valueOf() de los enum, el campo CREATOR de
todo Parcelable y los métodos anotados con @JavascriptInterface.
8.3 Las llamadas a la API de Android
android.*, java.* y javax.* no son parte de la aplicación: son referencias externas
resueltas en tiempo de carga. Aparecen en type_ids y method_ids con su nombre real,
siempre. Ocultarlas exige la indirección por reflexión de la «sección 2.6 · Indirección por reflexión», que cambia el
problema —hay que resolver la cadena— pero no lo elimina, y que además deja su propia huella.
El manual de ProGuard lo enuncia de forma literal para el modelo que R8 hereda: «Program
classes are processed, while library classes always remain unchanged» (Troubleshooting,
v7.10.0), y las bibliotecas que se pasan con -libraryjars «will not be included in the output
jars». Reproducido con el R8 de build-tools 37.0.0 (9.2.4-dev) sobre dos clases de prueba: la
propia pasa de com.ejemplo.Cifrador a com.ejemplo.a, y sus métodos a a y b, mientras
Landroid/util/Log;.d, Ljavax/crypto/Cipher;.getInstance y Ljava/lang/StringBuilder;.append
siguen en method_ids con su nombre. Y la indirección de la «sección 2.6 · Indirección por reflexión» es justo lo que anuncia
Guardsquare: DexGuard «hides standard library method calls by replacing them with reflections
calls».
androidx.* no entra en ese grupo: no está en el framework (el android.jar de la
plataforma solo trae unas anotaciones), viaja dentro del DEX de la aplicación y R8 lo
renombra como al resto del código, salvo lo que conserven sus consumer rules.
8.4 Los métodos nativos
La regla estándar que AGP incluye por defecto es explícita:
-keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; }
con la justificación de Guardsquare: «conservar sus nombres y los de sus clases, para que se
puedan seguir enlazando con la biblioteca nativa». La documentación de JNI de Android da la
alternativa: registrar los métodos dinámicamente con RegisterNatives() desde JNI_OnLoad(),
en cuyo caso «el único símbolo que normalmente hay que exportar es JNI_OnLoad()». Un
ofuscador serio usa esa segunda vía, y entonces el nombre del método Java sí se puede
renombrar — pero la correspondencia sigue existiendo dentro de JNI_OnLoad, en el binario
nativo.
8.5 Lo que sobrevive por descuido
Cosas que no son estructuralmente irrenombrables pero que en la práctica nadie renombra:
META-INF/*.kotlin_module. Conservan el nombre del módulo Gradle. En Shazam, con un 70 % de identificadores cortos, siguen ahíAMSKit_release.kotlin_moduleyapp_googleRelease.kotlin_module; en Reddit,account_impl.kotlin_module,awards_public.kotlin_module,deeplinkdispatch_release.kotlin_module. Es el organigrama del proyecto, intacto. DexGuard sí los elimina: Netflix no tiene ninguno.META-INF/*.versiony*.properties. Netflix lleva 98 ficherosandroidx.<artefacto>.versiony 30play-services-*.propertiesen la raíz, cada uno con el nombre y la versión de una dependencia. Es unSBOMcompleto entregado gratis.- Los mensajes de error y de telemetría propios.
SPY-37220 - dexguard unable to decrypt ASEno debería estar ahí. - Los nombres de recursos referenciados desde el manifiesto, que tienen que resolverse.
Ese suelo es lo que hace posible el análisis pese a todo, y es la base de las heurísticas de «Deofuscación → §5 · Heurístico — inferencia de nombres sin mapping.txt».
9. Cuánta ofuscación hay realmente
Dos estudios grandes, con cifras que conviene no confundir.
Wermke et al., ACSAC 2018, «A Large Scale Investigation of Obfuscation Use in Google Play», sobre 1.762.868 aplicaciones gratuitas de Google Play:
- «solo el 24,92 % de las aplicaciones están ofuscadas por el desarrollador».
- «Aproximadamente el 25 % de las aplicaciones están ofuscadas, pero ese número sube al 50 % para las más populares, con más de 10 millones de descargas».
- Pero el detector encontró el patrón de renombrado de la familia ProGuard en 1.137.228 (64,51 %). La diferencia con el 24,92 % es la clave: «un gran porcentaje de aplicaciones no fueron ofuscadas intencionadamente por el desarrollador original, sino que incluían bibliotecas de terceros que usaban ofuscación».
- «ProGuard es, con diferencia, la herramienta de ofuscación más popular para Android».
- Y un resultado sobre el factor humano: «el 78 % falló al usar ProGuard correctamente en un escenario más complejo y realista».
Dong et al., SecureComm 2018, «Understanding Android Obfuscation Techniques», sobre 114.560 aplicaciones (26.614 de Google Play, 65.666 de mercados chinos, 22.280 de malware), recogidas entre 2016 y 2017:
| Técnica | Google Play | Mercados de terceros | Malware |
|---|---|---|---|
| Renombrado de identificadores | 57,0 % | 73,0 % | 63,5 % |
| Cifrado de cadenas | 0,0 % | 0,1 % | 5,3 % |
La segunda fila es el dato que más contradice la intuición: el cifrado de cadenas es prácticamente inexistente en aplicaciones legítimas. La explicación que dan los autores es económica: «el cifrado de cadenas no es una característica habitual de los ofuscadores de estantería (ProGuard). Los ofuscadores que ofrecen cifrado de cadenas son caros (DexGuard, DexProtector)».
Consecuencia para quien construye herramientas: un descifrador de cadenas sirve para
analizar malware y aplicaciones de alto valor, no para el catálogo general. Y el
renombrado, que sí es masivo, es exactamente el problema que mapping.txt resuelve cuando
está y que hay que inferir cuando no («Deofuscación»).
Los datos del muestrario son coherentes con esos rangos. De las 22 aplicaciones comerciales
medidas en detalle en «R8 y ProGuard → §10.2 · El resultado, y por qué el umbral de dos caracteres es el instrumento equivocado», 16 tienen
renombrado de identificadores —15 con mediana de longitud de 1 a 3, más Netflix— y 6 no
lo tienen —Telegram, Clash Royale, Coin Master, Signal, LinkedIn Learning y Candy Crush, con
medianas de 8 a 17—, aunque varias de estas últimas sí pasaron por R8 con shrinking. Netflix
da mediana 10 porque esa métrica solo lee classes.dex; en el conjunto de sus cinco DEX,
17.329 clases están renombradas en el paquete o («sección 3.1 · La evidencia real en el Netflix del muestrario»). Y
solo una, Netflix, tiene cifrado de cadenas y de clases. Aplicar un ofuscador comercial
es la excepción, no la norma.
Fuentes
- DexGuard factsheet 2024 (Guardsquare) — «https://www.guardsquare.com/hubfs/Website/Resources/Fact sheets/factsheet-DexGuard-2024.pdf» Consultado el 12 de agosto de 2026. De aquí sale íntegra la tabla de técnicas declaradas de la «sección 3 · DexGuard (Guardsquare)», las citas de las secciones «2.1», «2.7», «2.8», «2.10» y «2.11», y la compatibilidad hacia atrás con ProGuard.
- DexGuard (página de producto) — https://www.guardsquare.com/dexguard Consultado el 12 de agosto de 2026. De aquí sale que no hay precio público y el enfoque de capas superpuestas y polimorfismo de la «sección 3 · DexGuard (Guardsquare)».
- ProGuard manual — Configuration examples — https://www.guardsquare.com/manual/configuration/examples Consultado el 12 de agosto de 2026. De aquí sale la regla estándar de métodos nativos y su justificación («sección 8.4 · Los métodos nativos»).
- Allatori — Features / Docs / Price — http://www.allatori.com/features.html,
http://www.allatori.com/doc.html, http://www.allatori.com/price.html
Consultados el 12 de agosto de 2026. De aquí salen la lista de características, el
watermarking, el expiry, los niveles de cifrado de cadenas, la integración en Gradle
antes del
DEXy los precios de la «sección 4 · Allatori». - Zelix KlassMaster — Features y subpáginas —
https://www.zelix.com/klassmaster/features.html y las páginas
featuresNameObfuscation.html,featuresFlowObfuscation.html,featuresStringEncryption.html,featuresReferenceObfuscation.html,featuresTrim.htmlConsultadas el 12 de agosto de 2026. De aquí salen las citas de las secciones «2.2», «2.4», «2.6» y toda la «sección 5 · Zelix KlassMaster», incluida la admisión de que su cifrado de cadenas no es irreversible. - Obfuscapk — https://github.com/ClaudiuGeorgiu/Obfuscapk Consultado el 12 de agosto de 2026. De aquí sale la lista completa de 21 transformaciones con sus descripciones («sección 6 · obfuscapk») y la cita del paper de SoftwareX. ⚠️ https://www.sciencedirect.com/science/article/pii/S2352711020300108 devolvió HTTP 403; la referencia bibliográfica procede del README del repositorio.
- Wermke, Huaman, Acar, Reaves, Traynor, Fahl — «A Large Scale Investigation of
Obfuscation Use in Google Play», ACSAC 2018 — https://arxiv.org/pdf/1801.02742
Consultado el 12 de agosto de 2026. De aquí salen las cifras de la «sección 9 · Cuánta ofuscación hay realmente», la nota
sobre
AUX/NULde la «sección 2.1 · Renombrado de identificadores», la tabla de licencias citada en la «sección 3 · DexGuard (Guardsquare)» y la formulación sobre lo que no puede ofuscarse de la «sección 8.1 · La superficie declarada en el manifiesto». ⚠️ https://dl.acm.org/doi/10.1145/3274694.3274726 devolvió HTTP 403; se ha usado la versión de arXiv. - Dong, Li, Diao, Liu, Liu, Li, Xu, Chen, Wang, Zhang — «Understanding Android Obfuscation Techniques: A Large-Scale Investigation in the Wild», SecureComm 2018 — https://diaowenrui.github.io/paper/securecomm18-dong.pdf Consultado el 12 de agosto de 2026. De aquí salen las dos tablas de prevalencia de la «sección 9 · Cuánta ofuscación hay realmente», las citas sobre reflexión de la «sección 2.6 · Indirección por reflexión» y la observación sobre alfabetos de renombrado de la «sección 2.1 · Renombrado de identificadores».
- APKiD — reglas YARA — https://github.com/rednaga/APKiD, ficheros
apkid/rules/apk/obfuscators.yara,apk/packers.yara,dex/obfuscators.yara,dex/packers.yara,elf/obfuscators.yara,elf/packers.yara, leídos en crudo desderaw.githubusercontent.com/rednaga/APKiD/master/Consultados el 12 de agosto de 2026. De aquí salen todas las huellas de la tabla de la «sección 7 · Tabla de huellas» marcadas con nombre de regla, y los datos del proyecto (versión 3.1.0, licencia dual, autoría, recuento de reglas). aapt2 optimize --help, build-tools 37.0.0 — ejecutado el 12 de agosto de 2026. De aquí salen--collapse-resource-names,--shorten-resource-paths,--save-obfuscation-mapy las directivasno_collapse/no_path_shortende la «sección 2.9 · Ofuscación de recursos».- JNI tips — https://developer.android.com/training/articles/perf-jni
Consultado el 12 de agosto de 2026. De aquí sale
RegisterNatives()desdeJNI_OnLoad()y la advertencia sobre keep rules de la «sección 8.4 · Los métodos nativos». ClaudiuGeorgiu/Obfuscapk— https://github.com/ClaudiuGeorgiu/Obfuscapk Clonado y ejecutado el 13 de agosto de 2026. De aquí sale el recuento de 21 ficheros.obfuscatorque verifica la tabla de la «sección 6 · obfuscapk», y el fallo de arranque con Python 3.12.rednaga/APKiD, etiquetav3.1.0— https://github.com/rednaga/APKiD Clonado el 13 de agosto de 2026. De aquí salen el recuento de reglas por etiqueta de la «sección 7 · Tabla de huellas» y el texto literal de la reglaResources Confusion.- APKiD 3.1.0 ejecutado localmente — sobre los 58 APK standalone del muestrario y los 23
base.apkextraídos de sus contenedores, el 13 de agosto de 2026. De aquí sale la tabla de aciertos de la «sección 7.1 · Lo que APKiD encuentra, y lo que no» y la ausencia de detección de DexGuard en Netflix. - Redex —
libredex/RedexResources.h— https://github.com/facebook/redex/blob/main/libredex/RedexResources.h Consultado el 25 de septiembre de 2026. De aquí sale la constanteRESOURCE_NAME_REMOVEDcon el valor(name removed), que no aparece en el binario deaapt237.0.0 («sección 2.9 · Ofuscación de recursos»). rednaga/APKiD,apkid/rules/dex/obfuscators.yara— https://github.com/rednaga/APKiD/blob/v3.1.0/apkid/rules/dex/obfuscators.yara Consultado el 25 de septiembre de 2026. De aquí salen el comentario de la regladexguard_c(«runtime decryption method») y la etiquetaobfuscatorde las reglasdexguard_*, iguales env3.1.0y enmaster(secciones «2.7», «7» y «7.1»).- Allatori — Changelog — http://www.allatori.com/changelog.html Consultado el 25 de septiembre de 2026. De aquí sale la versión 9.9, del 1 de septiembre de 2026 («sección 4 · Allatori»).
- API de GitHub,
repos/ClaudiuGeorgiu/Obfuscapk— https://api.github.com/repos/ClaudiuGeorgiu/Obfuscapk Consultado el 25 de septiembre de 2026. De aquí salen"archived": truey el último push, del 27 de julio de 2024 («sección 6 · obfuscapk»). android.jardeplatforms/android-36y R8 9.2.4-dev de build-tools 37, ejecutados localmente —unzip -l android.jaryjava -cp build-tools/37.0.0/lib/d8.jar com.android.tools.r8.R8Consultado el 25 de septiembre de 2026. De aquí sale queandroid.jarsolo traeandroidx/annotation/y que una claseandroidx.*que entra como código del programa sale renombrada (androidx.demo.Ayudante -> a) («sección 8.3 · Las llamadas a la API de Android»). Con la misma versión deR8, dos clases de prueba en las que la propia pasa acom.ejemplo.ayandroid.util.Log,javax.crypto.CipheryStringBuilderconservan su nombre enmethod_ids(«sección 8.3 · Las llamadas a la API de Android»).rednaga/APKiD, comparación dev3.1.0conmaster— https://raw.githubusercontent.com/rednaga/APKiD/v3.1.0/apkid/rules/ y https://raw.githubusercontent.com/rednaga/APKiD/master/apkid/rules/, más https://api.github.com/repos/rednaga/APKiD/releases/latest Consultado el 25 de septiembre de 2026. De aquí sale quedex/obfuscators.yarayapk/obfuscators.yarason idénticos en las dos, quemasterañadedexprotector_by amplíadexprotector_aliceenelf/obfuscators.yara, quev3.1.0(9 de abril de 2026) sigue siendo la última versión publicada y el recuento de 1.281 reglastrackerenmaster(secciones «2.1» y «7»).- Android Gradle plugin, rama
mirror-goog-studio-main— https://android.googlesource.com/platform/tools/base/+/refs/heads/mirror-goog-studio-main/build-system/gradle-core/src/main/java/com/android/build/gradle/, ficherosoptions/BooleanOption.kt,internal/TaskManager.kteinternal/tasks/OptimizeResourcesTask.ktConsultado el 25 de septiembre de 2026. De aquí sale queENABLE_RESOURCE_OPTIMIZATIONSsigue existiendo con valortrueyFeatureStage.SoftlyEnforced(VERSION_9_0), y queOptimizeResourcesTask, con--shorten-resource-paths, se registra para toda variante no depurable que no sea de test («sección 7.1 · Lo que APKiD encuentra, y lo que no»). - DexGuard 8.1 released (Guardsquare) — https://www.guardsquare.com/blog/dexguard-81-released Consultado el 25 de septiembre de 2026. Entrada del 30 de noviembre de 2017. De aquí sale el «Code packing» y el cifrado de todo el bytecode («sección 3 · DexGuard (Guardsquare)»).
- DexGuard introduces code virtualization for Android apps (Guardsquare) — https://www.guardsquare.com/blog/dexguard-introduces-code-virtualization-android Consultado el 25 de septiembre de 2026. Entrada del 19 de enero de 2019. De aquí salen «class encryption (and by extension, packing)» («sección 3 · DexGuard (Guardsquare)») y la sustitución de llamadas a la biblioteca estándar por reflexión («sección 8.3 · Las llamadas a la API de Android»).
- Use rules to troubleshoot optimization —
https://developer.android.com/topic/performance/app-optimization/troubleshooting-rules
Consultado el 25 de septiembre de 2026 (actualizada el 19 de mayo de 2026). De aquí salen
las reglas generadas por
AAPT, el ejemplo conaapt_rules.txty el aviso sobre la reducción optimizada de recursos («sección 8.1 · La superficie declarada en el manifiesto»). - ProGuard manual, etiqueta
v7.10.0— https://github.com/Guardsquare/proguard/tree/v7.10.0/docs/md/manual, ficherostroubleshooting/troubleshooting.mdyconfiguration/usage.mdConsultado el 25 de septiembre de 2026. De aquí salen «Program classes are processed, while library classes always remain unchanged» y lo que dice-libraryjars(«sección 8.3 · Las llamadas a la API de Android»).