El blindaje de aplicaciones no está diseñado para ser inquebrantable. Está diseñado para que una evasión sea lo bastante difícil como para exigir a un atacante experto con las habilidades, las herramientas y el tiempo adecuados.
Esa premisa está empezando a cambiar. Los modelos de IA pueden ayudar a atacantes con menos experiencia a entender código protegido y a manejar las herramientas necesarias para intentar una evasión.
Esta semana analizamos cuánto puede reducir la IA el coste de eludir el blindaje de aplicaciones.
También en este número: crates de Rust envenenados, explotación rápida de un fallo crítico de GitLab, una vulnerabilidad de MLflow explotada activamente, fallos de Copilot Personal, scripts generados por IA que sondean PLC de Siemens, angr para el análisis de binarios y más.
En este número
🌡️ Nivel de amenaza: Alerta alta
⚡ Noticias: Cinco historias de seguridad para ponerse al día
🔎 Análisis a fondo: El coste cada vez menor de eludir el blindaje de aplicaciones
🎣 ¿Es phishing?
🔬 Investigación técnica: Cómo eludir el blindaje de cinco aplicaciones bancarias en producción.
🛠️ Herramienta de la semana: angr
👤 Persona de la semana: Connor Tumbleson
📅 Evento de la semana: Defcamp 2026
📚 Libro de la semana: MacOS and iOS Internals
😅 El meme
❓ Una pregunta antes de despedirnos
Vamos al grano.
Antes de entrar en las historias de esta semana, este es el estado del nivel de amenaza.
🌡️Nivel de amenaza
⚡ Noticias
Bastaron 86 minutos para envenenar una compilación de Rust
El equipo de Rust indicó que probablemente se comprometieron el equipo o las credenciales de un mantenedor después de que aparecieran en crates.io versiones maliciosas de arrayref, internment y append-only-vec. La versión envenenada de arrayref incorporaba proc-macro1, cuyo script de compilación descargaba malware durante la compilación. Rust retiró las versiones tras entre 86 y 107 minutos; RustSec registró 2,285 descargas de arrayref 0.3.10. Inspeccione cachés y lockfiles, aísle los runners de compilación y rote las credenciales expuestas durante las compilaciones afectadas.
La explotación de GitLab llegó a los pocos días de su divulgación
CVE-2026-19478, un fallo crítico de inyección de código en GraphQL, permite a atacantes sin autenticar modificar o eliminar proyectos públicos y datos de usuarios en instancias de GitLab autogestionadas vulnerables. GitLab publicó versiones con el parche el 17 de agosto; watchTowr informó después de explotación contra sus honeypots y dijo que reprodujo el problema en cuestión de minutos. GitLab.com y Dedicated ya estaban parcheados. Actualice de inmediato los despliegues autogestionados, y después busque en los registros solicitudes @gl_introduced y revise los repositorios públicos afectados.
La plataforma de IA que está delante de los metadatos de su nube está siendo explotada
El catálogo KEV de CISA incluye ahora CVE-2026-64849, un fallo crítico de SSRF sin autenticación en MLflow. Abusando de redirecciones de webhooks o de DNS rebinding, los atacantes pueden hacer que el servidor solicite endpoints internos o de metadatos de la nube y devuelva la respuesta, con lo que podrían exponerse credenciales de la nube. Las versiones de MLflow anteriores a la 3.15.0 están afectadas y la explotación está confirmada. Actualice a la 3.15.0 o posterior, elimine la exposición pública, inspeccione la actividad de los webhooks y rote los secretos accesibles desde el host de MLflow.
Un solo enlace de Copilot podría convertir las aplicaciones conectadas en una vía de exfiltración
Varonis divulgó tres fallos en Copilot Personal, entre ellos CVE-2026-24301, que podrían permitir que un único enlace manipulado ejecute automáticamente un prompt, consulte aplicaciones ya autorizadas y exfiltre los resultados a través de la función de obtención de URL de Copilot. Una ruta de resumen independiente podía envenenar la memoria persistente. El informe abarcaba el servicio para consumidores y no estableció el mismo comportamiento en Microsoft 365 Copilot. Microsoft corrigió los problemas el 18 de agosto, sin explotación observada. Audite los conectores, minimice el alcance de OAuth y examine con atención los enlaces de los asistentes de IA.
Scripts de explotación generados por IA están sondeando las máquinas que hay detrás de los procesos físicos
Agencias de EE. UU. advirtieron de una amenaza activa contra los PLC Siemens S7 y entornos industriales más amplios. Los actores usan escáneres de internet para encontrar controladores expuestos y después despliegan scripts de Python generados por IA basados en las bibliotecas snap7 para leer o escribir la memoria, la configuración y la lógica ladder de los PLC. El aviso no atribuyó la actividad y la describió principalmente como reconocimiento persistente y desarrollo de capacidades. Inventaríe los controladores, elimine la exposición directa a internet, segmente las redes OT, aplique parches al firmware y monitorice el tráfico S7comm anómalo.
🔎 Análisis a fondo
El coste cada vez menor de eludir el blindaje de aplicaciones
OWASP afirma que no se espera que el blindaje de aplicaciones sea inquebrantable. Está diseñado para que eludirlo sea costoso en tiempo, recursos y experiencia.
Pero ¿qué ocurre si se puede reducir ese coste?
En un estudio de ingeniería inversa de NDSS de 2026, los principiantes que usaron un LLM mejoraron en un 98% su capacidad de entender lo que hacían los programas compilados y alcanzaron el mismo nivel de comprensión que los expertos que trabajaban sin él.
Sistemas de investigación como EnIGMA pueden dar a los modelos acceso directo a herramientas de seguridad y a programas en ejecución, lo que les permite probar acciones, observar los resultados y decidir qué intentar a continuación.
Esto demuestra que los modelos de IA están influyendo directamente en el coste de eludir un blindaje.
Así que la pregunta es:
¿Cuánto pueden reducir los modelos de IA el coste de eludir el blindaje de aplicaciones?
El proceso tradicional para eludir el blindaje de aplicaciones
Eludir un blindaje puede dividirse en dos grandes etapas:
Aplicar ingeniería inversa a la aplicación para identificar y entender sus protecciones.
Convertir ese conocimiento en una evasión funcional, adaptando el enfoque hasta desactivar las protecciones.
El estudio de 2018 Honey, I Shrunk Your App Security muestra ambas etapas en la práctica.
Primero, los investigadores aplicaron ingeniería inversa manualmente a la versión de Promon Shield que estaban probando. Estudiaron cómo se añadía a las aplicaciones, cómo funcionaban sus protecciones y cómo podían desactivarse.
Después convirtieron esos hallazgos en Nomorp, una herramienta que automatizaba la evasión en las aplicaciones afectadas.
Promon cambió Shield más tarde, así que Nomorp no fue una evasión permanente.
Pero el caso demuestra con claridad el proceso tradicional: primero entender una protección concreta y luego usar ese conocimiento para eludirla.
Tradicionalmente, esa primera etapa exigía a un ingeniero inverso experimentado interpretar el código, relacionarlo con el comportamiento de la aplicación y determinar qué importaba.
Es esta barrera de experiencia la que ahora empieza a reducirse.
La barrera de experiencia cada vez menor en la ingeniería inversa
El mismo estudio de NDSS de 2026, Decompiling the Synergy, comparó a 24 principiantes y 24 expertos en dos tareas controladas de ingeniería inversa.
Con la ayuda de un LLM:
Los principiantes mejoraron en aproximadamente un 98% su capacidad de entender lo que hacían los programas compilados.
Rindieron al mismo nivel que los expertos que trabajaban sin ayuda.
Los expertos obtuvieron ganancias mucho menores, con solo una mejora limitada en su comprensión en comparación con los principiantes.
En estas tareas, la brecha de experiencia se redujo considerablemente.
Esto importa porque eludir un blindaje empieza por entender la aplicación protegida.
El estudio no probó aplicaciones móviles blindadas, pero muestra que una parte importante de la ingeniería inversa, entender el código compilado, puede requerir bastante menos experiencia.
Sin embargo, entender el código no desactiva una protección. La siguiente cuestión es si esta ventaja también puede ayudar a convertir ese conocimiento en una evasión funcional.
De entender una protección a intentar eludirla
Una vez que un atacante entiende una protección, aún necesita encontrar la manera de esquivarla. Prueba una posible evasión, observa cómo reacciona la aplicación y la ajusta hasta desactivar la protección.
Por ejemplo, una aplicación puede detectar un dispositivo con root y bloquear el acceso. El atacante podría intentar evitar que esa comprobación informe de que el dispositivo tiene root. Si la aplicación sigue bloqueando el acceso, debe averiguar por qué, cambiar la evasión y probarla de nuevo.
Los agentes de IA lograron una evasión funcional del blindaje en una aplicación bancaria real.
Una evaluación de cinco aplicaciones bancarias en producción utilizó agentes de IA para identificar sus protecciones de blindaje e intentar eludirlas.
Una aplicación tenía tres protecciones activas: una comprobación de root y Frida al inicio, una comprobación de integridad que cubría su código nativo y un detector de hooks de Java.
Los agentes modificaron las tres. Evitaron que la comprobación de inicio cerrara la aplicación, actualizaron el valor de integridad tras cambiar el código nativo y modificaron el detector de hooks para que dejara de informar de la instrumentación.
Después, la aplicación mantuvo una sesión autenticada durante más de un minuto, se movió por varias pantallas y superó comprobaciones de integridad repetidas en segundo plano. Un artefacto de Frida siguió visible mientras la aplicación continuaba en ejecución.
Los agentes rindieron bien cuando las herramientas necesarias estaban disponibles y el resultado podía observarse con claridad.
Identificaron varias protecciones conectadas, cambiaron código en distintas partes de la aplicación y comprobaron si esos cambios se sostenían mientras la aplicación estaba en ejecución. También adaptaron un cambio a otro actualizando el valor de integridad tras modificar el código protegido.
La IA seguía necesitando ayuda humana durante la evasión.
Cuando a los agentes les faltaba una herramienta necesaria, una persona tenía que proporcionársela. También a veces malinterpretaban la tarea y seguían iterando en la dirección equivocada hasta que un humano los reorientaba.
Seguir el camino equivocado puede aumentar rápidamente el coste.
En un experimento de Elastic Security Labs independiente, una canalización de ingeniería inversa impulsada por IA resolvió la primera versión de un programa ofuscado en menos de 12 minutos por $2.56.
Después de que los investigadores eliminaran un atajo en el que se había apoyado el modelo, el siguiente intento tardó unos 46 minutos y costó $8.83, pero aun así fracasó.
Esto muestra por qué la guía humana fue importante durante la evasión de la aplicación bancaria. Sin corrección, un agente puede seguir gastando más tiempo y recursos en un enfoque que no produce resultados.
Los agentes podían llevar a cabo gran parte del análisis, la modificación y las pruebas. Eran menos fiables cuando les faltaba la herramienta adecuada o cuando debían reconocer que su enfoque era erróneo.
Entonces, ¿cuánto se ha reducido el coste de una evasión?
La IA ha reducido la experiencia y el esfuerzo manual que hay detrás de una evasión, pero esos ahorros dependen de que el agente encuentre el camino correcto.
La reducción medida más clara aparece en la ingeniería inversa. En el estudio de NDSS, los principiantes asistidos por un LLM mejoraron su tasa de comprensión en aproximadamente un 98% y igualaron a los expertos que trabajaban sin ayuda.
Eso no significa que el coste total de la evasión cayera un 98%. Muestra que una parte importante del coste, la experiencia necesaria para entender el código compilado, se redujo drásticamente en esas tareas.
La evaluación de la aplicación bancaria mostró que esta reducción puede continuar hasta la propia evasión. Los agentes realizaron gran parte del análisis, la modificación y las pruebas necesarias para derrotar tres protecciones conectadas. Los humanos aportaron las herramientas que faltaban, reorientaron las iteraciones fallidas y verificaron el resultado final.
Cuando el camino correcto es más difícil de encontrar, el coste vuelve a subir.
Como vimos en el experimento de Elastic Security Labs, un modelo completó la primera versión de un reto de código ofuscado en menos de 12 minutos por $2.56. Después de que los investigadores eliminaran el atajo que había usado, otro intento tardó unos 46 minutos y costó $8.83, pero aun así fracasó.
Por tanto, el intento fallido tardó 3.8 veces más y costó 3.4 veces más sin producir un resultado. Aunque se trataba de un experimento de ingeniería inversa y no de una evasión de blindaje, mide la misma limitación observada durante la evaluación de la aplicación bancaria: un agente puede seguir gastando tiempo y recursos en la dirección equivocada hasta que una persona interviene.
Para los equipos que dependen del blindaje como control, el riesgo residual ha cambiado.
Una evasión ya no requiere que un experto realice cada paso manualmente. Los costes restantes se concentran cada vez más en el acceso a herramientas, la corrección de la dirección de los agentes y la verificación del resultado. A medida que los agentes mejoren, es probable que esos límites se debiliten.
🎣 ¿Es phishing?
Dificultad: media
Llega un perfil de conexión firmado digitalmente para una prueba rutinaria de AWS. ¿Haría clic en Connect?
🔬 Investigación técnica
Cómo eludir el blindaje de cinco aplicaciones bancarias en producción.
El blindaje de aplicaciones móviles es una protección compilada en la propia aplicación. Se vende como RASP, anti-tamper, anti-hooking, detección de root, detección de jailbreak o protección en tiempo de ejecución, y la promesa es la misma en todos los casos: si la aplicación se encuentra en un teléfono con root, dentro de un emulador, bajo Frida, conectada a un depurador o reempaquetada, debe darse cuenta y responder.
Esa promesa tiene dos mitades, y fallan de forma independiente.
La detección consiste en decidir que algo va mal. La aplicación de la respuesta consiste en hacer algo al respecto.
Un producto puede detectar el root a la perfección y no proteger nada si la aplicación ignora la respuesta, canaliza todas las respuestas por una única rama débil o confía en una entrada que controla el atacante.
Evaluamos cinco aplicaciones bancarias en producción en Android e iOS, que ejecutaban cuatro productos comerciales de blindaje distintos. La detección fue consistentemente buena. La aplicación de la respuesta fue, de forma consistente, donde todo se rompió.
El primer síntoma: un fallo diseñado para no revelar nada
El escaneo instaló la primera aplicación en un dispositivo de prueba y la lanzó. Cinco segundos después, el proceso había desaparecido. Sin diálogo, sin error, nada en los registros.
El informe del fallo:
signal 11 (SIGSEGV), fault addr 0x0
x0=0xdef040f0 x1=0x738416ae x4=0x2319d258 x5=0xbd7d47fb
x6..x30=0 sp=0 pc=0
tid: Thread-7x
La señal 11 es SIGSEGV, un fallo de segmentación: el proceso accedió a la memoria de una forma que el kernel rechazó. Esa parte es normal. El volcado de registros, no.
En ARM64, pc es el contador de programa, la dirección de la instrucción que se está ejecutando. sp es el puntero de pila, que ancla la pila de llamadas. x0 a x30 son los registros de propósito general, que contienen argumentos, valores de retorno y variables locales. En un fallo genuino esos valores se conservan, y por eso un informe de fallo es útil: el contador de programa señala la instrucción que falla y el puntero de pila permite a un depurador retroceder por los llamadores.
Aquí todos ellos son cero. No hay instrucción fallida que examinar ni pila que desenrollar. El único fotograma del backtrace dice #00 pc 0x0 <unknown>.
Algo borró deliberadamente el conjunto de registros antes de dejar morir el proceso. El hilo que figura en el informe, Thread-7x, es un worker genérico sin relación con la decisión. Y 0xdef040f0 no es un puntero plausible en esta plataforma; se comporta como un marcador dejado por el código de protección.
Este es un patrón habitual en aplicaciones reforzadas. En lugar de anunciar el veredicto, la aplicación destruye la evidencia forense al salir, de modo que el analista no sabe qué comprobación se activó ni dónde reside.

Todos los registros de propósito general están a cero y el backtrace es un único fotograma desconocido.
Qué vigilan realmente estos productos
La primera tarea es un inventario: ¿qué comprueba esto?
El análisis estático encontró unas treinta funciones detectoras nativas, todas registradas en una única clase de Java al cargarse.
Ese detalle importa más de lo que parece. Las aplicaciones Android acceden al código nativo en C o C++ a través de JNI, la Java Native Interface. Una biblioteca nativa puede exponer una función a Java de dos maneras. Puede exportar un símbolo con un nombre decorado como Java_com_example_Foo_bar, visible para cualquiera que ejecute nm sobre la biblioteca. O puede llamar a RegisterNatives durante JNI_OnLoad y enlazar los métodos dinámicamente en tiempo de ejecución.
Esta biblioteca usa la segunda vía, así que ninguno de los nombres de los detectores aparece como símbolo exportado. Hay que leer la tabla de registro u observar el proceso en tiempo de ejecución para encontrarlos:
JNI_OnLoad @ 0x424264
checkHooks @ 0x424e50 scans the process memory map
checkForFridaAgent @ 0x424c38
isSuExists @ 0x424940
isFoundMagisk @ 0x425a90
isFoundDangerousProps @ 0x424810
isPermissiveSelinux @ 0x4248e8
getNativeSignature @ 0x42ca00 hashes the signing certificate
Hay cuatro categorías representadas, y cada una responde a una pregunta distinta.
La detección de root busca indicios de que el dispositivo concede privilegios elevados: binarios su en disco, artefactos de Magisk, rutas del sistema con permiso de escritura, SELinux permisivo, paquetes gestores de root. El root importa porque permite a un atacante leer el almacenamiento privado de la aplicación, conectarse al proceso y modificar su tiempo de ejecución.
La detección de hooking busca frameworks que reescriben el comportamiento de las funciones en tiempo de ejecución: Frida, Xposed, LSPosed, Zygisk, Substrate, SandHook, Taichi, VirtualXposed. Un hook puede cambiar el valor de retorno de una función sin tocar el APK en disco, que es precisamente como se derrotan las comprobaciones de seguridad del lado del cliente.
checkHooks lee /proc/self/maps. En Linux y Android, ese archivo enumera todas las regiones de memoria mapeadas en el proceso actual, con sus permisos y el archivo que las respalda. Si allí aparece una biblioteca ajena o una región ejecutable anónima, la aplicación puede inferir que está siendo instrumentada.
La verificación de firma es getNativeSignature, que calcula el hash del certificado de firma de la aplicación en tiempo de ejecución. Android exige que todo APK esté firmado. Un atacante que modifica y reempaqueta una aplicación debe volver a firmarla, normalmente con otra clave, de modo que comparar el certificado en tiempo de ejecución con un hash esperado detecta el reempaquetado ingenuo.
La detección de propiedades peligrosas lee las propiedades del sistema Android, que son pares clave-valor que el sistema operativo usa para publicar la configuración de la compilación y del dispositivo: ro.build.tags, ro.debuggable, ro.secure, ro.hardware, ro.product.model. Las imágenes de emulador y las compilaciones de ingeniería dejan ahí valores reconocibles.
Por debajo de este producto de pago hay otros tres controles de proveedores no relacionados: una segunda comprobación de root de una biblioteca de código abierto gratuita, una tercera dentro del propio código Dart compilado de la aplicación y telemetría de un cuarto. El manifiesto incluso declara entradas <queries> para que el gestor de paquetes responda a preguntas sobre los paquetes su, Magisk y KingRoot.
Cuatro controles independientes en una misma aplicación, cuatro opiniones independientes sobre el mismo dispositivo. Eso importa al final.
Esta no es una implementación superficial. La debilidad no es la falta de detección. Es aquello en lo que la aplicación confía y lo que hace con la respuesta.
Por qué leer la comprobación no funciona
Entre el analista y esta lógica hay tres capas, y las tres cumplen su cometido.
El nivel de Java es un señuelo. La aplicación incluye 4,129 blobs cifrados donde deberían estar los cuerpos de los métodos, que se descifran y ejecutan solo al arrancar. Las clases que importan, incluida la actividad principal, no están en el archivo de forma legible. Un descompilador muestra la estructura y algunos puntos de llamada, no el comportamiento.
La biblioteca nativa está empaquetada. Cifrada en reposo, con un único símbolo exportado y con el contenido real existiendo solo en memoria tras el arranque. Una biblioteca tiene un nombre de archivo aleatorio y un nombre de exportación aleatorio:
libGHDSDFIUPOIFDLS8DSFN23LK.so
export: _3Wbwdz5QepMbJNn8CiW3HwFivKZsZoNvu
Así que el escaneo volcó la biblioteca descifrada desde el proceso en ejecución y volvió a mirar. Las comprobaciones seguían sin aparecer.
Las comprobaciones se generan en tiempo de ejecución. El código descifrado emite 69 llamadas al sistema. Una llamada al sistema en ARM64 es una instrucción svc, con el número de llamada en el registro x8, de modo que un desensamblador normalmente puede leer qué función del kernel se solicita. En 64 de estos puntos el número es una constante. En los otros cinco, la aplicación lo calcula mientras se ejecuta, lo que hace invisibles esos cinco al análisis estático.
Una de las cinco se resuelve en mmap solicitando una sola página con PROT_READ | PROT_WRITE | PROT_EXEC. Lo hace aproximadamente cada 85 milisegundos. Escribe código en la página, lo ejecuta y lo descarta.
La memoria escribible y ejecutable a la vez es inusual por diseño. Los sistemas modernos mantienen separados ambos permisos, porque la memoria en la que se puede escribir y luego ejecutar es lo que hace posible la inyección de código. Los empaquetadores y protectores la usan de todos modos, precisamente para esto: emitir comprobaciones que nunca existen como código estable en una dirección estable.
Las cadenas se construyen, no se almacenan. Buscar qemu, goldfish o emulator en la biblioteca completamente descifrada no devuelve ningún resultado. La aplicación ensambla esas cadenas carácter a carácter en la pila, de modo que nunca existen como texto contiguo que se pueda buscar con grep.
Los nombres de métodos son caracteres Unicode parecidos. Una segunda aplicación, protegida por un producto distinto, juega al mismo juego en Java. El descompilador muestra m13674; el nombre real en tiempo de ejecución es ˎ, una letra modificadora Unicode. Muestra m13676; el nombre real es Ι, una iota mayúscula griega que se muestra igual que una i mayúscula latina.
Un hook escrito contra el nombre del descompilador simplemente nunca se activa. Sin error, sin fallo, y es fácil confundir ese silencio con una protección más fuerte de lo que es. Resolver los métodos por su firma de tipos en lugar de por su nombre evita el problema, que es como los hooks más adelante en este artículo funcionan al primer intento.
Medir la aplicación desde fuera
Cuando el código está hecho para ser ilegible, deje de leerlo y obsérvelo.
El escaneo conectó una traza a nivel de kernel, que observa desde fuera del proceso y no deja nada dentro que detectar, y luego registró todos los archivos que la aplicación abrió durante el arranque:
opens ~150 property files, three times each
reads /proc/self/maps three times
reads /proc/self/status, /proc/self/comm, /sys/fs/selinux/context
opens the virtual device files: 0 times
opens any su or root path: 0 times
Para quienes no hayan pasado tiempo en /proc: es un sistema de archivos virtual que el kernel genera bajo demanda, y /proc/self es la vista que el proceso que llama tiene de sí mismo. maps enumera las regiones de memoria mapeadas. status contiene metadatos del proceso, entre ellos TracerPid, el id de proceso de cualquier cosa que esté trazando a este. comm es el nombre del proceso. /sys/fs/selinux/context informa del contexto de seguridad de SELinux bajo el que se ejecuta el proceso.
El resultado lo replanteó todo. Casi todo el mundo supone que esta clase de comprobación busca su en disco y nodos de dispositivo de emulador. Esta no abre ninguno, ni una sola vez. La decisión de arranque se basa en los valores de las propiedades, en el mapa de memoria del propio proceso y en su estado de trazado. Dos de esos tres son escribibles por un usuario con privilegios.
El análisis estático produjo una lista de comprobaciones que podrían importar. La traza mostró cuáles se ejecutan realmente.
La puerta de las propiedades cae con una escritura en un archivo
Android publica las propiedades del sistema a través de una región de memoria compartida expuesta como archivos bajo /dev/__properties__/. Las bibliotecas las leen mediante __system_property_get; los valores se mantienen en memoria y, en un dispositivo con root, pueden escribirse en su sitio antes de que arranque la aplicación. La puerta no realiza ninguna comprobación de integridad ni de autenticidad sobre lo que lee allí.
Antes de la escritura:
signal 11 (SIGSEGV), fault addr 0x0
x0=0xdef040f0, pc=0, sp=0
crash report: GENERATED
Después:
no crash report
process alive
UI drawn
native libraries loaded

Los cierres dejan de producirse. Sin parche del APK, sin hook, sin ninguna modificación de la aplicación.
Eso no hace inútiles las comprobaciones de propiedades. Las hace no autoritativas. Si un atacante con root puede reescribir el valor, la aplicación necesita corroboración entre señales independientes, o una aplicación de la respuesta que no se derrumbe cuando una señal cambia.
Por qué importa el archivo de índice
Esto es más delicado de lo que parece, y el modo de fallo merece conocerse.
Ese directorio contiene dos estructuras distintas: los registros prop_info que almacenan cada propiedad y un índice serializado aparte que se usa para resolver el nombre de una propiedad hasta su registro. Toda búsqueda por nombre pasa por el índice. Una búsqueda y sustitución a ciegas en los archivos lo corrompe.
El daño luego se oculta a sí mismo. La enumeración de propiedades recorre directamente los registros y sigue funcionando, devolviendo unas 460 entradas, mientras que pedir cualquier propiedad concreta por nombre no devuelve nada. Todas las bibliotecas que leen una propiedad al arrancar fallan, de maneras que parecen no tener relación con lo que acaba de hacer.
Por eso el escaneo identifica los registros genuinos por su forma antes de escribir, y luego verifica su propio trabajo en lugar de fiarse de él:
properties : 465 (was 465)
sdk : '31'
giveaways : 0
El recuento de propiedades no cambia, una búsqueda conocida sigue resolviéndose, los indicios delatores han desaparecido. Solo entonces lanza la aplicación. Una evasión que funciona destrozando el entorno no es una evasión.
La detección de Frida es en realidad detección de temporización
Frida es el kit estándar de instrumentación dinámica para este trabajo. Inyecta un agente en un proceso en ejecución y permite hacer hook de métodos de Java, funciones nativas y llamadas al sistema.
Contra estas aplicaciones muere de inmediato. Un depurador, sin duda más invasivo, funciona todo el tiempo que se quiera.
debugger attaches 1.9s after launch -> ran 120 seconds, no complaint
Frida attaches 1.0s after launch -> killed
Frida launches together with the app -> killed
La aplicación lee /proc/self/status una sola vez, al principio. Una línea de ese archivo es TracerPid, que vale 0 cuando nada está trazando el proceso y, en caso contrario, contiene el id de proceso del trazador. Los depuradores usan ptrace, así que lo establecen. La inyección de Frida también usa ptrace brevemente, para secuestrar un hilo y hacer que cargue el agente.
La comprobación se ejecuta una sola vez, al cabo de aproximadamente un segundo. Lo confirmamos de la manera aburrida: conectar un depurador, reanudar y luego no hacer absolutamente nada durante 100 segundos. Sin veredicto, aplicación viva. Que lo observen no es el desencadenante.
El problema de Frida es su entrada. La inyección deja dos marcas en esa ventana de arranque: TracerPid establecido durante unos cientos de milisegundos y un mapeo ejecutable ajeno en /proc/self/maps, desde donde se cargó el agente a partir de un archivo anónimo. El veredicto se dispara antes de que el script del agente imprima su primera línea:
{"c":7,"v":1,"p":{"id":107,"name":"Hooking Detected"}}
Hay quien intenta renombrar los hilos y los puertos de Frida para esquivarlo. No cambia nada, porque el nombre nunca fue lo que se detectaba.
Así que la pregunta que se hace la aplicación no es «¿es esto Frida?». Se parece más a «¿hubo algo que me trazara o modificara durante esta ventana?». Es un control distinto con consecuencias distintas: cuando una comprobación se ejecuta una sola vez en un momento conocido, la temporización se convierte en superficie de ataque. Se puede llegar antes, llegar después o lanzar el proceso suspendido y estar en posición antes de que la aplicación ejecute su primera instrucción. El escaneo adopta la última opción, que es como llega a comprobaciones que un attach normal nunca podría ver.
Una segunda aplicación llega a la misma conclusión por otra vía. Trazada desde su primera instrucción, toda la decisión son las últimas cuatro cosas que hace:
openat(".../split_config.arm64_v8a.apk")
readlinkat("/proc/self/fd/60", ".../split_config.arm64_v8a.apk")
openat("/proc/self/status")
--- SIGBUS {si_code=BUS_ADRALN, si_addr=0x8f19c0bf} ---
+++ killed by SIGBUS +++
SIGBUS con BUS_ADRALN es un fallo de alineación: una carga o un almacenamiento en una dirección que la CPU no acepta para ese ancho de acceso. No es un fallo accidental común en ARM64, y la dirección que falla es idéntica en cada ejecución. La aplicación lee su estado de trazado y luego ejecuta deliberadamente un acceso desalineado para matarse a sí misma.
Un entero decide ocho lugares
La segunda aplicación Android expone el argumento central mejor que cualquier otra del conjunto.
Su protección es seria. Cadenas de detección cifradas dentro de la biblioteca nativa, nombres de clase cifrados en el nivel de Java, nombres de métodos que son caracteres Unicode parecidos y llamadas al sistema emitidas como instrucciones svc en línea en lugar de a través de libc, de modo que hacer hook del wrapper estándar syscall() no captura absolutamente nada.
Todo eso converge en un único método de Java. Se le pasa un entero aleatorio. En un dispositivo limpio devuelve el mismo entero.
Todos los puntos de aplicación de la respuesta de la aplicación comprueban ese único valor:
j/ma.java:480 if (rd.m13674(ctx, nextInt) != nextInt)
j/ma.java:551 if (rd.m13674(ctx, nextInt2) != nextInt2)
bk/a.java:844 m9379 = rd.m13674(ctx, nextInt) == nextInt ? -91 : 808;
bk/a.java:911 if (rd.m13674(ctx, nextInt2) == nextInt2)
ca/ma.java:2298 if (rd.m13674(ctx, r0) == r0)
ca/b.java:1331 if (rd.m13674(ctx, r0) == r0)
ca/a.java:816 if (rd.m13674(ctx, r0) == r0)
y/b.java:192,228 rd.m13674(ctx, SecureRandom.nextInt())

El entero aleatorio no es decoración. Es un nonce, y existe para detener el ataque más perezoso. Si el método simplemente devolviera true o 0 en un dispositivo limpio, un atacante le haría un hook para que devolviera esa constante siempre. Pasar un valor aleatorio nuevo en cada llamada y exigir que se devuelva hace que una devolución constante falle, porque la respuesta esperada cambia cada vez.
Aquí no sirve de nada. Un atacante que puede hacer hook del método puede devolver el argumento que recibió, y la comparación pasa en todos los puntos.
Tres hooks, resueltos por firma de tipos en lugar de por nombre porque los nombres son Unicode:
{"type":"hooked","method":"m13674","sig":"int(android.content.Context,int)"}
{"type":"hooked","method":"m13676","sig":"boolean(java.lang.Exception)"}
{"type":"hooked","method":"m13677","sig":"int(android.content.Context,int,int)"}
{"type":"alive","pid":6285,"ping":1} ... {"type":"alive","pid":6285,"ping":18}

Dos minutos de ejecución, un proceso estable, sin fallos, y la ruta de manipulación nunca se activa.
El fallo es arquitectónico, no criptográfico. El nivel nativo calculó un veredicto correcto. La aplicación confió después en ese veredicto como un único entero mutable situado en la parte menos protegida del programa.
Cómo demostrar de verdad una evasión del pinning
El certificate pinning significa que la aplicación no depende únicamente del almacén de confianza del sistema operativo. También comprueba que el certificado del servidor, o la clave pública que contiene, coincida con un valor incluido en la aplicación. Bien hecho, resiste a que un atacante instale su propia CA raíz en el dispositivo.
Pero el pinning es código de la aplicación, así que hacer hook o parchear la comparación lo derrota.
La mayoría de los informes lo demuestran de forma débil: el hook se cargó, el proxy mostró tráfico, la aplicación no falló. Eso es coherente con una evasión, pero también con otras explicaciones.
En su lugar, el escaneo realizó un experimento controlado contra el verificador de certificados de la propia aplicación, construido mediante el constructor de la propia aplicación y cargado con la lista de pines de la propia aplicación. El mismo certificado las dos veces, el mismo objeto, los mismos pines. La única variable era si los hooks estaban activos.
Una ejecución rechaza, la otra acepta, y todo lo demás permaneció inalterado. Ese es el estándar al que conviene aspirar: no «la herramienta dijo que funcionó», sino «la decisión protegida cambió en condiciones controladas». Tampoco necesitó proxy ni tráfico capturado, porque la prueba acciona directamente el código de pinning en lugar de esperar a que la aplicación establezca una conexión.
En iOS, nadie comprueba el recibo
La aplicación de iOS incluye una puerta de jailbreak, dos implementaciones independientes de pinning en dos lenguajes distintos, un framework de protección de 35 MB y varios SDK de terceros.
Nunca comprueba si su propio código ha sido modificado.
La autoverificación en iOS consiste en preguntar al sistema por la firma de su propio código, mediante API como SecStaticCodeCheckValidity o la llamada al sistema csops, o calcular el hash de sus propias páginas __TEXT y compararlo con un valor esperado. El escaneo buscó en los siete binarios relacionados con la protección todas las formas estándar de esto:
main binary 36.8 MB self-check: NONE
Flutter framework 19.6 MB self-check: NONE
protection framework 35.0 MB self-check: NONE
attribution SDK 0.6 MB self-check: NONE
jailbreak detection 0.07 MB self-check: NONE
fingerprinting SDK 0.9 MB self-check: NONE
monitoring agent 5.9 MB self-check: NONE
Un símbolo ausente prueba poco en un binario ofuscado, ya que los símbolos pueden eliminarse y las llamadas pueden hacerse por número de llamada al sistema en bruto. Por eso no se detuvo ahí. Desensambló el framework de protección y revisó los 1,761 puntos en los que ese framework emite directamente una llamada al sistema. Ninguno consulta la firma del código.
Ese framework puede detectar un depurador activo y una inyección activa. No puede darse cuenta de que sus propios bytes han cambiado.
Así que se cambiaron los bytes. Tres parches, cada uno de unas pocas instrucciones:
Jailbreak check
sub sp, sp, #0x40 -> mov w0, #0 ; ret
Flutter TLS pinning
ldrb w0, [sp, #8] -> mov w0, #1
bic w8, w0, w0, asr#31 -> mov w8, #1
Payment SDK pinning, four places
mov w1, #2 -> mov w1, #1
En la convención de llamadas de ARM64, w0 son los 32 bits bajos de x0, el registro en el que una función devuelve su valor. mov w0, #0 seguido de ret es una función completa que devuelve cero, lo que en Objective-C es NO. Así, los ocho bytes que sustituyen al prólogo de la comprobación de jailbreak convierten toda la función en «no tiene jailbreak», y nada de lo que viene después se ejecuta.
Los parches de pinning funcionan igual, un nivel más abajo, forzando que el callback que informa de una decisión de confianza informe de éxito.
El tercer parche es el interesante. En lugar de forzar a la aplicación a aceptar un certificado inválido, cambió los cuatro puntos en los que la aplicación rechaza uno. Esos puntos pasaban 2 al gestor del desafío, que significa cancelar la conexión. Ahora pasan 1, que significa recurrir a la evaluación normal del sistema. El único punto que realmente acepta un certificado bueno se dejó intacto.
La aplicación deja de rechazar sin que nunca se le diga que acepte, lo que mantiene su comportamiento verosímil en lugar de evidentemente roto.
Los tres parches sobrevivieron al reempaquetado y a la nueva firma sin reacción alguna de nada en el bundle. Que es exactamente lo que cabría esperar de una aplicación que nunca comprueba su propio recibo.
El blindaje no es autorización
Una aplicación del conjunto no tenía ninguna brecha de blindaje digna de mención y, aun así, una vulnerabilidad crítica.
Una Activity es un punto de entrada en una aplicación Android, más o menos una pantalla. Por defecto es privada de la aplicación. Marcarla como exported=”true” permite que otras aplicaciones la lancen. Añadir la categoría BROWSABLE a su filtro de intents permite que un navegador web la lance siguiendo un enlace con el esquema personalizado de la aplicación.
Esta actividad estaba exportada, era accesible desde el navegador y no realizaba ninguna comprobación de autenticación, sesión ni llamador antes de escribir en el repositorio de transacciones.
Con todos los datos de la aplicación borrados, de modo que nadie había iniciado sesión, bastó una línea de JavaScript:
<script>
window.location.href = "app://quickpay?payee=BrowserAttacker&amount=200.00";
</script>
El navegador lanzó la pantalla. La lista de transacciones contenía después seis entradas, donde la línea base tenía cinco, con el beneficiario y el importe del atacante.
Ningún producto de blindaje lo habría detectado, porque nada en el dispositivo era sospechoso. El blindaje eleva el coste de atacar un teléfono comprometido. No hace nada ante la falta de autorización en uno limpio, y no sustituye las comprobaciones del lado del servidor sobre la propia transacción.
El patrón, en todas las aplicaciones
La tecnología de detección no fue trivial en ningún caso. Código nativo empaquetado, código generado en memoria nueva varias veces por segundo, llamadas al sistema hechas por debajo de libc, cadenas que nunca existen como texto, registro dinámico de JNI, escaneo del mapa de memoria, hash de firmas, nombres de métodos que son letras griegas haciéndose pasar por latinas y fallos diseñados para no enseñarle nada.
Los fallos estaban todos una capa más adentro:
valores de propiedades de confianza que un atacante con privilegios puede reescribir
una única ventana de arranque que lo decide todo
ocho puntos de aplicación de la respuesta que leen un único entero mutable
código de iOS parcheado sin ninguna autoverificación que lo advierta
una aplicación que detectó el root correctamente y no aplicó nada
Y el hallazgo más contundente no fue una evasión en absoluto. Una de estas aplicaciones se instaló en un teléfono con root corriente, sin parches, sin hooks y sin ediciones de propiedades. Fue directa a su pantalla de inicio de sesión y se quedó allí. El blindaje detectó el root y lo informó correctamente. La aplicación siguió adelante, porque nadie estaba escuchando.
Un detector responde: ¿qué vemos? Un control responde: ¿qué hacemos y puede el atacante cambiar esa decisión? Muchos despliegues son fuertes en lo primero y débiles en lo segundo.
Tres pruebas que conviene hacer en su propia aplicación
Confirme la respuesta, no la detección. No pregunte si la aplicación puede detectar el root. Póngala en un teléfono con root y observe. ¿Se cierra, restringe los flujos sensibles, bloquea la autenticación o solo registra y continúa? Si continúa, ha comprado telemetría, no un control.
Cuente los puntos de aplicación de la respuesta. Rastree cómo llega el veredicto al comportamiento. ¿Hay un único método que lo decide todo? ¿Un único booleano o entero que lleva toda la respuesta? ¿Puede un hook cambiarlo? ¿La aplicación de la respuesta ocurre junto a la acción sensible o solo una vez al arrancar?
Verifique la integridad de su propio código, sobre todo en iOS. ¿La aplicación consulta su propia firma de código o calcula el hash de sus propias páginas de texto? ¿Detecta el reempaquetado y la nueva firma? ¿Verifica el propio framework de protección? ¿Falla en modo cerrado? Sin eso, cualquier otra protección está a una instrucción de ser anulada y nada en el bundle lo notará.
Cómo se realizó la evaluación
El blindaje móvil es fácil de juzgar mal. Que una herramienta se cargue no es una prueba. Que un fallo desaparezca no siempre es una prueba. Que un proxy muestre tráfico no es prueba de una evasión del pinning. El método importa tanto como el resultado.
Línea base antes de la evasión. Cada aplicación se lanzó primero en un dispositivo limpio, sin root y sin nada conectado. ¿Se ejecuta? ¿Muere? Si muere, ¿qué se activa primero? Esa respuesta nombra el blindaje más externo y se convierte en la referencia de toda afirmación posterior. Sin ella no se puede distinguir una protección de un error.
Mapee ambas capas. La inspección de paquetes, la descompilación y el desensamblado produjeron el inventario de detectores y los desplazamientos citados arriba, los ocho puntos de aplicación de la respuesta y el método que hay detrás, los puntos de parcheo de iOS y la lógica de validación de certificados.
Ajuste el estado del dispositivo a la pregunta. Dispositivos limpios para las líneas base, dispositivos con root para el trabajo de root y propiedades, dispositivos con interceptación de tráfico para el pinning, lanzamiento suspendido para las comprobaciones que se activan antes de que un attach normal pudiera verlas, y compilaciones parcheadas y vueltas a firmar para las pruebas de manipulación en iOS. Un solo estado del dispositivo no puede responder a todas las preguntas.
Cambie una sola variable cada vez. La misma aplicación antes y después de la escritura de la propiedad. El mismo certificado antes y después de los hooks de pinning. El mismo proceso con attach temprano frente a tardío. El mismo binario de iOS antes y después del parcheo.
Exija un efecto de seguridad observable. Un hallazgo solo contaba cuando cambiaba un resultado relevante para la seguridad: la aplicación seguía viva donde antes había terminado, la interfaz llegaba a un estado protegido, la decisión sobre el certificado cambiaba, el repositorio aceptaba entradas sin autenticar o la compilación parcheada se ejecutaba sin ser detectada. El tiempo transcurrido nunca es un criterio de éxito, porque «sobrevivió treinta segundos» es una esperanza, no una observación.

Todos los criterios que se fijó la evaluación y lo que devolvió realmente cada uno.
🛠️ Herramienta de la semana
Explorar los posibles comportamientos de un programa exige probar cada entrada por separado.
No siempre.
angr usa la ejecución simbólica para representar muchas entradas posibles a la vez y determinar qué condiciones llevan a distintas rutas del programa.
angr es un framework de análisis de binarios de código abierto para examinar software compilado, incluso cuando no se dispone de su código fuente.
Piense en él como:
un desensamblador + un simulador de ejecución + un solucionador de restricciones en Python.
¿Qué puede hacer?
angr ofrece a los investigadores de seguridad un conjunto de herramientas para analizar binarios. Puede:
Recuperar funciones y mapear cómo se conectan
Desensamblar y descompilar código
Simular la ejecución de programas
Rastrear datos por la memoria y los registros
Analizar qué partes del código influyen en un resultado
Determinar las condiciones necesarias para llegar a un punto concreto
Generar entradas que cumplan esas condiciones
Cómo funciona la ejecución simbólica
Una ejecución normal de un programa usa valores fijos. Si la entrada es 10, el programa sigue las decisiones que produce ese valor.
La ejecución simbólica sustituye la entrada fija por un valor desconocido. Cuando el programa llega a una decisión, angr registra la condición de cada resultado posible.
Por ejemplo, una rama puede exigir que la entrada tenga más de ocho caracteres, mientras que otra exige que comience con un valor específico. angr reúne estas condiciones y usa un solucionador para encontrar una entrada que las cumpla.
De código sospechoso a una prueba reproducible
Imagine a un investigador que examina un analizador de archivos de código cerrado.
Encuentra una función sospechosa, pero solo se alcanza cuando varios campos del archivo contienen valores precisos.
Con angr, el investigador puede:
Cargar el binario.
Localizar la función que quiere investigar.
Representar el contenido relevante del archivo como valores desconocidos.
Explorar las condiciones que llevan a la función.
Generar un archivo que cumpla esas condiciones.
El archivo resultante puede probarse después en un entorno controlado para confirmar el comportamiento.
Personalizar el análisis
angr está construido como un conjunto de bibliotecas de Python en lugar de como un escáner fijo.
Los investigadores pueden decidir dónde empieza el análisis, qué datos deben tratarse como desconocidos y qué parte del programa quieren examinar.
También pueden simplificar funciones complejas o modelar interacciones con bibliotecas y con el sistema operativo. Esto hace que angr se adapte a distintos binarios y preguntas de investigación.
Dónde tiene dificultades
Un programa puede crear más rutas posibles en cada decisión. En binarios grandes, ese número puede crecer rápidamente y ralentizar el análisis.
El software también puede depender de archivos, redes, servicios del sistema operativo o hardware que angr no puede reproducir automáticamente. Los investigadores suelen tener que acotar el alcance y modelar las partes que faltan.
Lo que no reemplaza
angr no es un escáner automático de vulnerabilidades.
Funciona mejor junto a desensambladores, depuradores, fuzzers e investigadores capaces de interpretar los resultados. Esas herramientas ayudan a revelar y probar el programa, mientras que angr ofrece una forma programable de investigar sus posibles comportamientos.
angr ayuda a los investigadores a pasar de inspeccionar un binario a probar lo que realmente puede hacer.
👏 Persona de la semana
Connor Tumbleson
Esta semana destacamos a Connor Tumbleson , mantenedor desde hace mucho tiempo de Apktool.
Connor mantiene Apktool desde 2011 y lo ha mantenido compatible a medida que evolucionaban Android y sus herramientas de compilación. Ha gestionado versiones, corregido problemas de compatibilidad y ayudado a llevar el proyecto hasta Apktool 3, una gran modernización publicada en 2026.
Apktool permite a los investigadores decodificar aplicaciones Android en una estructura de proyecto legible, inspeccionar sus recursos y su código Smali, y reconstruirlas tras hacer cambios. Se ha convertido en una herramienta esencial de la ingeniería inversa de Android y de las pruebas de seguridad móvil.
Por mantener y modernizar durante 15 años una de las herramientas de código abierto más utilizadas de la seguridad de Android, Connor Tumbleson es nuestra Persona de la semana.
📅 Evento de la semana
DefCamp 2026
Si prefiere la investigación técnica de seguridad combinada con retos prácticos, vale la pena seguir DefCamp 2026.
Ya en su 16.ª edición, DefCamp reúne en Bucarest a miles de profesionales de la seguridad, investigadores y estudiantes. La conferencia cuenta con más de 90 ponentes en charlas técnicas, paneles y demostraciones en vivo, además de competiciones en su Hacking Village.
El programa abarca seguridad ofensiva y defensiva, amenazas de IA, cadenas de suministro de software, seguridad en la nube, ransomware, inteligencia de amenazas y criptografía. Talleres prácticos independientes se celebran del 16 al 18 de noviembre, antes de la conferencia principal.
📍 Palacio del Parlamento, Bucarest, Rumanía
📅 19 y 20 de noviembre de 2026
📚 Libro de la semana
MacOS and iOS Internals
¿Qué ocurre realmente bajo la interfaz de un iPhone o un Mac?
En la serie de tres volúmenes MacOS and iOS Internals, Jonathan Levin examina los sistemas operativos de Apple desde dentro. Los libros avanzan desde componentes del modo usuario como los procesos, Mach-O, XPC y launchd hasta el kernel XNU, los sistemas de archivos y mecanismos de seguridad como la firma de código y el sandboxing.
Es una referencia técnica exhaustiva para investigadores de seguridad, ingenieros inversos y desarrolladores que quieren entender macOS e iOS por debajo de la capa de aplicación.
😅 El meme
Si los agentes de IA necesitan menos ayuda experta para eludir el blindaje de aplicaciones, ¿qué debe hacer de forma distinta el blindaje para que la evasión siga siendo costosa para los atacantes?
The Breach Brief, Equipo de Ostorlab











