DexPatcher: parchea APK de Android usando Java

DexPatcher permite a los desarrolladores parchear APK usando Java. Esto tiene varias ventajas y utilizar DexPatcher es mucho más fácil que el enfoque clásico de Smali.

Probablemente hayas visto o instalado aplicaciones modificadas, ya sea un marcador parcheado para tu resolución o una versión personalizada de WhatsApp con funciones adicionales. ¿Cómo hacen eso los desarrolladores? Muchas veces, el código fuente de las aplicaciones ni siquiera está disponible, entonces, ¿cómo funciona todo? Primero veremos eso, luego veremos una nueva herramienta que tiene como objetivo hacer el proceso mucho más fácil y, finalmente, la compararemos con el popular marco Xposed para ver en qué se diferencian.

Es posible que haya oído hablar de cómo se suelen modificar los APK: los desarrolladores se conectan ellos mismos al Matrix, comience a ver todo en Smali y obtenga la capacidad de modificar cosas usando el poder del Fuente. Una llamada telefónica es suficiente para sacarlos una vez hecho esto, momento en el cual están listos para compartir los nuevos y brillantes APK.

Más en serio… Empecemos por el principio. Si no está familiarizado con la modificación de aplicaciones de Android, es posible que se pregunte qué es smali. Los desarrolladores suelen utilizar el lenguaje de programación Java para codificar aplicaciones de Android. Luego, un programa (el compilador) "traduce" ese código a otro formato adecuado para su dispositivo, lo que da como resultado archivos .dex contenidos dentro del paquete de la aplicación (o APK).

En ese momento, ya no podrás acceder al código fuente original (a menos que seas el desarrollador o que la aplicación sea de código abierto). Sin embargo, lo que sí tienes es el APK, ya que es el que está instalado en tu dispositivo. Desde allí, puede obtener los archivos dex (generalmente clases.dex) y luego intentar traducirlos a un formato que pueda comprender. Ahí es donde entra en juego smali, una traducción más legible pero fiel. Puedes ir un paso más allá y volver a traducirlo a Java, aunque ese proceso no es lo suficientemente fiel: obtendrás un Resultado comprensible, pero es probable que no puedas volver a traducirlo al revés ya que se perderán algunos detalles. por el camino. Es decir, cualquier modificación que hagas será en vano ya que no podrás volver a convertirlo en APK para instalarlo en tu dispositivo… al menos no sin mucho esfuerzo.

smali/baksmali es en realidad un ensamblador/disimulador del formato dex; eso es lo que significa literalmente en islandés. Sin embargo, normalmente nos referimos al formato que entiende Smalli cuando decimos 'Smali' (considérelo como instrucciones definir cada pequeño detalle, incluso si los humanos no lo necesitamos todo; por lo tanto, es más detallado que Java). También tenga en cuenta que la explicación anterior está un poco simplificada, pero debería ser una analogía cercana y al mismo tiempo ser fácil de entender.

Entonces, ¿qué debería hacer un desarrollador para modificar una aplicación (sin acceso a la fuente)? El proceso es más o menos el siguiente:

  1. Obtener el APK (desde la web o desde el dispositivo).
  2. Usa algo como herramienta apk para descompilar el APK en Smali. (herramienta apk hace uso de smali/baksmali, pero hace que sea mucho más fácil descompilar y reconstruir APK, y también se encarga de decodificar recursos como archivos XML).
  3. Extraiga classs.dex del APK, luego use dex2jar y finalmente un descompilador de Java para obtener código Java (incompleto, a menudo roto, pero en su mayoría comprensible). (Esto es opcional, pero puede resultar útil ya que Smali es mucho más difícil de entender).
  4. Identificar qué modificar.
  5. Modifíquelo editando el código Smali directamente.
  6. Alternativamente, escriba la modificación en Java, compílela, descompílela nuevamente en Smali y luego copie el código Smali resultante.
  7. Una vez que todo haya terminado, use herramienta apk nuevamente para reconstruir el APK.
  8. Firme el APK (para verificar la identidad del autor; todos los paquetes deben estar firmados) y finalmente instalarlo.

Escribir código Smali es bastante difícil y propenso a errores. Se pueden realizar cambios más pequeños en Smali, pero agregar nuevas funciones es más desafiante. Además, no tendrá ningún error en tiempo de compilación, por lo que incluso los errores tipográficos solo podrán detectarse en tiempo de ejecución. Ampliar y compartir parches Smali también puede resultar problemático, ya que las diferencias tienden a ser muy específicas de una versión de APK en particular. Aunque existen algunas herramientas para facilitar partes del proceso explicado anteriormente (Estudio Virtuoso Diez me viene a la mente), todavía puede resultar aburrido.

DexPatcher por miembro senior de XDA Lanchón tiene como objetivo solucionar estos problemas, simplificando el proceso y permitiendo a los desarrolladores evitar por completo el trato con Smali. En cambio, los desarrolladores pueden escribir parches solo en Java y hacer que DexPatcher se encargue de todo lo demás.

Esto tiene la principal ventaja de tener archivos de parches fáciles de leer y administrar. Parchar APK también resulta más conveniente en general. Veremos un ejemplo completo sobre cómo usar DexPatcher en un momento, pero aquí hay una descripción general rápida de lo que ofrece primero:

  • Fuente abierta.
  • Multiplataforma: debería ejecutarse en Linux, Mac y Windows.
  • Archivos de parche: las modificaciones que realice están contenidas en archivos de parche de Java que puede compartir de forma independiente.
  • Java: no es Smalli.

También obtiene la ventaja de la verificación de errores en tiempo de compilación, por lo que los errores aparecen temprano en el ciclo de desarrollo. El Java compilado proporciona su verificación habitual del tiempo de compilación (con acceso a los símbolos APK originales) y DexPatcher aplica Compatibilidad de fuente y parche al parchear, proporcionando información útil y dando advertencias cuando parece que estás haciendo algo. legal pero sospechoso.

Además de eso, DexPatcher viene con un conjunto de guiones de ayuda (sólo están disponibles en Linux, aunque también se pueden migrar a otras plataformas). Estos se encargan de configurar el espacio de trabajo, extraer las clases y recursos del APK de destino, descompilar las clases en Java (el Descompilador CFR Java se usa para este último), y finalmente compilar y firmar el APK parcheado una vez que haya terminado.

Echemos un vistazo a un ejemplo (en Linux):

Instalar los scripts de DexPatcher

$# Make a directory where we can test stuff out and enter it. 

$ mkdir xda-test

$cd xda-test

$ git clone https://github.com/Lanchon/DexPatcher-scripts.git dexpatcher # Clone the DexPatcher helper scripts repo.

$cd dexpatcher

$ chmod +x dxp-* # Not necessary, but for clarity: we need to make sure the files we'll call later are executable.

Configurar los scripts de DexPatcher

Abierto dxp.config en su editor de texto favorito y asegúrese de cambiar las variables necesarias para adaptarlas a su sistema. Solo necesita cambiar la siguiente línea para que apunte a la ubicación de instalación de su SDK de Android:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher elegirá automáticamente la versión de plataforma más alta disponible. Además, también puede modificar otras opciones de configuración para que utilice sus propias versiones de algunas herramientas en lugar de las predeterminadas incluidas).

Para facilitar el acceso, podemos agregar el despachador directorio a nuestro CAMINO, o incluso vincular simbólicamente los diferentes dxp-* scripts a una ubicación que ya está en su CAMINO, como ~/contenedor:

export PATH=$PWD:$PATH

Modificar una aplicación

Para este ejemplo, usaremos una aplicación simple y de código abierto. Por supuesto, en este caso particular sería posible parchear el código fuente directamente, ¡pero eso no es nada divertido!

Tomaremos la aplicación "Get ID" de basil2style, una aplicación que te muestra algunos detalles sobre tu dispositivo. Nuestro objetivo es modificar el botón "Copiar" para el "ID del dispositivo" y hacer que comparta este ID:

  • Primero, descarguemos el APK que vamos a modificar: Obtener identificación.
  • Descompila la aplicación.
  • Crea la clave de firma que luego usaremos para firmar el APK.

También podemos hacerlo todo a través del shell, usando los scripts auxiliares:

$cd dexpatcher # Go to our working directory. 

$ curl -O https://f-droid.org/repo/makeinfo.com.getid_1.apk # Download the APK.

$ dxp-setup-for-apk makeinfo.com.getid_1.apk # Unpack and decompile the APK.

$cd makeinfo.com.getid_1 # Go to the newly created directory where everything is unpacked/decompiled to.

$ dxp-create-keystore # Create the APK signing key. Press 6 times (or fill out the info), then "yes".

Notarás algunos directorios diferentes allí:

  • descodificar: encontrará los recursos y Smali aquí, tal como lo decodifica herramienta apk.
  • src: Directorio vacío. Aquí es donde colocaremos nuestros archivos de parche.
  • src-cfr: aquí es donde cfr descompiló la aplicación (junto con los errores). Un buen lugar para buscar y decidir qué cambiar (es posible que también necesite recursos y sus ID del directorio de decodificación anterior, pero no para este ejemplo en particular).
  • código de nodo src-cfr: igual que el anterior, pero que contiene solo resguardos vacíos (sin código, solo esqueletos). Puede utilizar estos archivos como base para su parche, como veremos en un momento.

Como mencionamos antes, queremos cambiar el botón "Copiar" del ID del dispositivo para compartir el texto del ID. Si miramos el código fuente, notaremos que el botón Copiar ID del dispositivo (copia_dispositivo) al hacer clic El evento es manejado por una clase anónima en src-cfr/makeinfo/com/getid/MainActivity.java. Si bien podríamos modificarlo aquí, generalmente es mejor encontrar una forma alternativa de hacerlo ya que las clases anónimas tienen nombres numéricos (Nombre de clase principal $ algún número, p.ej. Actividad principal$3) que podría cambiar de forma impredecible entre versiones.

En su lugar, registraremos nuestra propia clase para el evento modificando el Actividad principal clase. Primero, copiemos la versión "esqueleto" de src-cfr-nocode/makeinfo/com/getid/MainActivity.java a src/makeinfo/com/getid/MainActivity.java (recuerda eso src es donde vivirá nuestro parche). (También puedes copiar la versión con el código completo si lo prefieres, esto es pura cuestión de gustos.)

Ahora podemos editarlo de la siguiente manera:

  • Agregue la importación necesaria para la anotación DexPatcher:
importlanchon.dexpatcher.annotation.*;
  • Agregue una etiqueta para indicar que estamos editando la clase. También configuramos la acción predeterminada para los miembros de la clase de parche en IGNORAR, lo que significa que nuestro código hará referencia a los miembros durante la compilación de Java, pero DexPatcher los ignorará.
@DexEdit(defaultAction=DexAction.IGNORE)

publicclassMainActivity

// The reference to ActionBarActivity will be satisfied by symbols

// extracted from the app when we build the patch.

extendsActionBarActivity{

  • Además, agregue cuerpos vacíos al constructor y enCrear método, así como todos los demás métodos que planeamos usar (recuerde que serán ignorados cuando nuestro parche se aplique realmente; simplemente los estamos agregando para poder consultarlos aquí si es necesario). También puedes simplemente agregar el nativo palabra clave en su lugar.
  • Ya podemos crear el parche en este punto, si tienes curiosidad:
    $ dxp-make # Output: `patched.apk`.
    Bastante simple, ¿verdad? Sin embargo, sigamos adelante: todavía no hemos terminado.
  • editemos enCrear ahora a plantearnos lo propio OnClickListener para que podamos compartir el ID del dispositivo en lugar de copiarlo al portapapeles:
    // Rename the target method so that we can still call it (the original)// if needed.@DexEdit(target="onCreate")protectedvoidsource_onCreate(Bundlevar1){}// Add our new custom method.@Override@DexAddprotectedvoidonCreate(Bundlevar1){// Call the original method:source_onCreate(var1);// Replace the text and handler:device_copy.setText("Share");device_copy.setOnClickListener(newDeviceCopyOnClick());}// Note that we don't use an anonymous class to avoid nameclashing with// MainActivity$1, which already exists.// We also could've defined a nested MainActivity.Patch class and used// an anonymous class in MainActivity.Patch.onCreate(), and then called// MainActivity.Patch.onCreate() from MainActivity.onCreate().@DexAddclassDeviceCopyOnClickimplementsView.OnClickListener{@OverridepublicvoidonClick(Viewobject){if(MainActivity.this.val){Intentintent=newIntent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra(Intent.EXTRA_SUBJECT,"Device ID");intent.putExtra(Intent.EXTRA_TEXT,device.getText().toString());startActivity(Intent.createChooser(intent,"Share Device ID"));}else{Toast.makeText(MainActivity.this.getApplicationContext(),"Nothing to Share",0).show();}}}
  • ¡Parece que ya hemos terminado! El parche completo debería verse así este. Ahora podemos construir el APK parcheado e instalarlo:
    $ dxp-make$ adb install patched.apk
  • Echemos un vistazo al resultado:

(¡Gracias a Lanchon por ayudar con el código de muestra!)

Xposed es inmensamente popular y por una buena razón: hace que crear, compartir e instalar mods sea mucho más sencillo tanto para los desarrolladores como para los usuarios. Existen algunas diferencias entre DexPatcher y Xposed que pueden hacer que algunos prefieran uno sobre el otro:

  1. Xposed hace su magia conectando métodos en tiempo de ejecución y permitiendo a los desarrolladores hacer algo antes, después o en lugar de cualquier método. DexPatcher, por otro lado, modifica todo antes del tiempo de ejecución y produce un APK modificado e independiente. -- todavía es posible ejecutar código antes, después o en lugar de los métodos, y en realidad tienes algo extra libertad.
  2. Producir un APK independiente significa que no depende de ningún marco externo. Esto también significa que no se requiere root para modificar las aplicaciones del usuario.
  3. Dado que creó un nuevo APK con DexPatcher, se firmará de manera diferente. Esto significa que los usuarios no pueden recibir actualizaciones oficiales del autor original y puede causar algunos problemas con aplicaciones como Google Apps si se verifican las firmas.
  4. El código fuente de ambos módulos y parches DexPatcher se puede distribuir y modificar fácilmente. También comparten muchas similitudes si te familiarizas un poco con cada uno.

Ya hemos hablado suficiente sobre DexPatcher. Es tu turno de intentarlo ahora, así que dirígete al Hilo del foro de DexPatcher ¡Para empezar de inmediato!