Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
simplify — Máquina virtual de Android y desofuscador | Kitploit
Herramientas/GitHubGitHub/calebfenton/simplify
Seguridad AndroidAnálisis Dinámico (Sandboxing)Ingeniería InversaAnálisis de MalwareAnálisis de Binarios
GitHubcalebfenton/simplify

simplify

Máquina virtual de Android y desofuscador

Ver Repositorio
4.7k45523hace 5 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Simplify

Build Status Coverage Status Coverity Scan Build Status

Desofuscador Genérico de Android

Simplify ejecuta virtualmente una aplicación para entender su comportamiento y luego intenta optimizar el código para que se comporte de manera idéntica pero sea más fácil de entender para un humano. Cada tipo de optimización es simple y genérico, por lo que no importa qué tipo específico de ofuscación se utilice.

Antes y Después

El código de la izquierda es una descompilación de una aplicación ofuscada, y el código de la derecha ha sido desofuscado.

Muchas llamadas a métodos, sin significado claro Vaya, tanta literalidad, mucho significado

Resumen

Hay tres partes en el proyecto: smalivm, simplify y la aplicación demo.

  1. smalivm: Proporciona una caja de arena de máquina virtual para ejecutar métodos Dalvik. Después de ejecutar un método, devuelve un gráfico que contiene todos los valores posibles de registros y clases para cada ruta de ejecución. Funciona incluso si algunos valores son desconocidos, como E/S de archivos y red. Por ejemplo, cualquier condicional if o switch con un valor desconocido hace que se tomen ambas ramas.
  2. simplify: Analiza los gráficos de ejecución de smalivm y aplica optimizaciones como propagación de constantes, eliminación de código muerto, desreflexión y algunas optimizaciones de mirilla. Son bastante simples, pero cuando se aplican juntas repetidamente, descifran cadenas, eliminan la reflexión y simplifican enormemente el código. No renombra métodos ni clases.
  3. demoapp: Contiene ejemplos simples y muy comentados para usar smalivm en tu propio proyecto. Si estás construyendo algo que necesita ejecutar código Dalvik, échale un vistazo.

Uso

root@kitploit:~
usage: java -jar simplify.jar <input> [options]
deobfuscates a dalvik executable
 -et,--exclude-types <pattern>   Exclude classes and methods which include REGEX, eg: "com/android", applied after include-types
 -h,--help                       Display this message
 -ie,--ignore-errors             Ignore errors while executing and optimizing methods. This may lead to unexpected behavior.
    --include-support            Attempt to execute and optimize classes in Android support library packages, default: false
 -it,--include-types <pattern>   Limit execution to classes and methods which include REGEX, eg: ";->targetMethod\("
    --max-address-visits <N>     Give up executing a method after visiting the same address N times, limits loops, default: 10000
    --max-call-depth <N>         Do not call methods after reaching a call depth of N, limits recursion and long method chains, default: 50
    --max-execution-time <N>     Give up executing a method after N seconds, default: 300
    --max-method-visits <N>      Give up executing a method after executing N instructions in that method, default: 1000000
    --max-passes <N>             Do not run optimizers on a method more than N times, default: 100
 -o,--output <file>              Output simplified input to FILE
    --output-api-level <LEVEL>   Set output DEX API compatibility to LEVEL, default: 15
 -q,--quiet                      Be quiet
    --remove-weak                Remove code even if there are weak side effects, default: true
 -v,--verbose <LEVEL>            Set verbosity to LEVEL, default: 0

Construcción

La construcción requiere que esté instalado el Java Development Kit 8 (JDK).

Debido a que este proyecto contiene submódulos para frameworks de Android, clone con --recursive:

root@kitploit:~
git clone --recursive https://github.com/CalebFenton/simplify.git

O actualice los submódulos en cualquier momento con:

root@kitploit:~
git submodule update --init --recursive

Luego, para construir un único jar que contenga todas las dependencias:

root@kitploit:~
./gradlew fatjar

El jar de Simplify estará en simplify/build/libs/. Puede probar que funciona simplificando la aplicación de ejemplo ofuscada proporcionada. Así es como se ejecuta (puede que necesite cambiar simplify.jar):

root@kitploit:~
java -jar simplify/build/libs/simplify.jar -it "org/cf/obfuscated" -et "MainActivity" simplify/obfuscated-app.apk

Para entender qué se está desofuscando, consulte el README de la Aplicación Ofuscada.

Solución de Problemas

Si Simplify falla, pruebe estas recomendaciones, en orden:

  1. Apunte solo a unos pocos métodos o clases usando la opción -it.
  2. Si el fallo se debe a que se excedió el máximo de visitas, intente usar valores más altos para --max-address-visits, --max-call-depth y --max-method-visits.
  3. Pruebe con -v o -v 2 e informe el problema con los registros y un hash del DEX o APK.
  4. Intente de nuevo, pero no rompa el contacto visual. Simplify puede sentir el miedo.

Si construye en Windows y la construcción falla con un error similar a:

Could not find tools.jar. Please check that C:\Program Files\Java\jre1.8.0_151 contains a valid JDK installation.

Esto significa que Gradle no puede encontrar una ruta JDK adecuada. Asegúrese de que el JDK esté instalado, establezca la variable de entorno JAVA_HOME en su ruta JDK y asegúrese de cerrar y volver a abrir el símbolo del sistema que usa para construir.

Contribuir

No seas tímido. Creo que la ejecución virtual y la desofuscación son problemas fascinantes. Cualquiera que esté interesado es automáticamente genial y las contribuciones son bienvenidas, incluso si es solo para corregir un error tipográfico. No dudes en hacer preguntas en los issues y enviar pull requests.

Reportar Problemas

Incluya un enlace al APK o DEX y el comando completo que está utilizando. Esto hace que sea mucho más fácil reproducir (y por lo tanto corregir) su problema.

Si no puede compartir la muestra, por favor incluya el hash del archivo (SHA1, SHA256, etc).

Estrategias de Optimización

Propagación de Constantes

Si una operación coloca un valor de un tipo que puede convertirse en una constante como una cadena, número o booleano, esta optimización reemplazará esa operación con la constante. Por ejemplo:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
# Decrypts to: "Tell me of your homeworld, Usul."
move-result v0

En este ejemplo, una cadena cifrada se descifra y se coloca en v0. Dado que las cadenas son "constanteables", el move-result v0 puede reemplazarse con un const-string:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."

Eliminación de Código Muerto

El código está muerto si eliminarlo no puede alterar el comportamiento de la aplicación. El caso más obvio es si el código es inalcanzable, p.ej. if (false) { // dead }). Si el código es alcanzable, puede considerarse muerto si no afecta ningún estado fuera del método, es decir, no tiene efecto secundario. Por ejemplo, el código puede no afectar el valor de retorno del método, alterar ninguna variable de clase o realizar ninguna E/S. Esto es difícil de determinar en el análisis estático. Afortunadamente, smalivm no tiene que ser inteligente. Simplemente ejecuta estúpidamente todo lo que puede y asume que hay efectos secundarios si no puede estar seguro. Considere el ejemplo de Propagación de Constantes:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."

En este código, el invoke-static ya no afecta el valor de retorno del método y supongamos que no hace nada extraño como escribir bytes en el sistema de archivos o en un socket de red, por lo que no tiene efectos secundarios. Simplemente puede eliminarse.

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
const-string v0, "Tell me of your homeworld, Usul."

Finalmente, el primer const-string asigna un valor a un registro, pero ese valor nunca se usa, es decir, la asignación está muerta. También puede eliminarse.

root@kitploit:~
const-string v0, "Tell me of your homeworld, Usul."

¡Hurra!

Desreflexión

Uno de los principales desafíos del análisis estático de Java es la reflexión. Simplemente no es posible conocer los argumentos de los métodos de reflexión sin realizar un análisis cuidadoso del flujo de datos. Hay formas inteligentes y astutas de hacer esto, pero smalivm lo hace simplemente ejecutando el código. Cuando encuentra una invocación de método reflejado como:

root@kitploit:~
invoke-virtual {v0, v1, v2}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;

Puede conocer los valores de v0, v1 y v2. Si está seguro de cuáles son los valores, puede reemplazar la llamada a Method.invoke() con una invocación de método real no reflejada. Lo mismo aplica para las búsquedas de campos y clases reflejadas.

Optimización de Mirilla

Para todo lo que no encaja claramente en una categoría particular, existen las optimizaciones de mirilla. Esto incluye eliminar operaciones check-cast inútiles, reemplazar llamadas a Ljava/lang/String;-><init> con const-string, y así sucesivamente.

Ejemplo de Desofuscación

Antes de la Optimización

root@kitploit:~
.method public static test1()I
    .locals 2

    new-instance v0, Ljava/lang/Integer;
    const/4 v1, 0x1
    invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V

    invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
    move-result v0

    return v0
.end method

Todo esto hace es v0 = 1.

Después de la Propagación de Constantes

root@kitploit:~
.method public static test1()I
    .locals 2

    new-instance v0, Ljava/lang/Integer;
    const/4 v1, 0x1
    invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V

    invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
    const/4 v0, 0x1

    return v0
.end method

El move-result v0 se reemplaza con const/4 v0, 0x1. Esto se debe a que solo hay un posible valor de retorno para intValue()I y el tipo de retorno puede convertirse en una constante. Los argumentos v0 y v1 son inequívocos y no cambian. Es decir, hay un consenso de valores para cada posible ruta de ejecución en intValue()I. Otros tipos de valores que pueden convertirse en constantes:

  • números - const/4, const/16, etc.
  • cadenas - const-string
  • clases - const-class

Después de la Eliminación de Código Muerto

root@kitploit:~
.method public static test1()I
    .locals 2

    const/4 v0, 0x1

    return v0
.end method

Debido a que el código anterior a const/4 v0, 0x1 no afecta el estado fuera del método (sin efectos secundarios), puede eliminarse sin cambiar el comportamiento. Si hubiera una llamada a método que escribiera algo en el sistema de archivos o la red, no podría eliminarse porque afecta el estado fuera del método. O si test()I tomara un argumento mutable, como un LinkedList, cualquier instrucción que lo accediera no podría considerarse muerta.

Otros ejemplos de código muerto:

  • asignaciones no referenciadas - asignar registros y no usarlos
  • instrucciones no alcanzadas / inalcanzables - if (false) { dead_code(); }

Licencia

Esta herramienta está disponible bajo una licencia dual: una comercial adecuada para proyectos de código cerrado y una licencia GPL que puede usarse en software de código abierto.

Dependiendo de sus necesidades, debe elegir una de ellas y seguir sus políticas. Un detalle de las políticas y acuerdos para cada tipo de licencia está disponible en los archivos LICENSE.COMMERCIAL y LICENSE.GPL.

Lectura Adicional

  • Ejecución Virtual Dalvik con SmaliVM
  • Guillot, Yoann, and Alexandre Gazet. "Automatic Binary Deobfuscation." Journal in Computer Virology 6.3 (2010): 261-76
  • Unicorn - El emulador de CPU definitivo
  • Babak Yadegari, Saumya Debray. "Symbolic Execution of Obfuscated Code"
  • Casos de éxito:
    • Carga dinámica de clases de Android con cifrado "AES/CFB/NoPadding". Echa un vistazo antes y después. Herramienta usada: #simplify. #Android #ofuscación #cifradodeclases #dex
    • Descifrando el cifrado de cadenas de malware
Descargar herramienta