DexPatcher: Patch APKs Android usando Java

Você provavelmente já viu ou instalou aplicativos modificados, seja um discador corrigido para sua resolução ou uma versão personalizada do WhatsApp com recursos adicionais. Mas como os desenvolvedores fazem isso? Na maioria das vezes, o código fonte dos aplicativos nem está disponível; então, como tudo isso funciona? Vamos ver isso primeiro, depois daremos uma olhada em uma nova ferramenta que visa facilitar o processo e, finalmente, compará-la com a popular estrutura Xposed para ver como elas diferem.

Você deve ter ouvido falar sobre como os APKs geralmente são modificados - os desenvolvedores se conectam à matriz, começam a ver tudo em Smali e ganham a capacidade de modificar as coisas usando o poder da Fonte. Uma ligação telefônica é suficiente para liberá-los assim que estiver pronto, quando eles estão prontos para compartilhar os novos APKs brilhantes.

Mais a sério ... Vamos começar do começo. Se você não está familiarizado com a modificação de aplicativos Android, pode estar se perguntando o que é smali. Os desenvolvedores geralmente usam a linguagem de programação Java para codificar aplicativos Android. Um programa (o compilador) "converte" esse código para outro formato adequado ao seu dispositivo, resultando em arquivos .dex contidos no pacote de aplicativos (ou APK).

Nesse ponto, você não poderá mais acessar o código-fonte original (a menos que você seja o desenvolvedor ou o aplicativo seja de código aberto). No entanto, o que você tem é o APK, pois é o que está instalado no seu dispositivo. A partir dele, você pode obter os arquivos dex (geralmente classes.dex) e tentar convertê-lo de volta para um formato que você possa entender. É aí que entra o smali, como uma tradução mais legível, mas fiel. Você pode dar um passo adiante e traduzi-lo de volta para Java, embora esse processo não seja fiel o suficiente - você obterá um resultado compreensível, mas as chances são de que não será possível traduzi-lo ao contrário novamente, como alguns detalhes será perdido ao longo do caminho. Em outras palavras, qualquer modificação que você possa fazer será inútil, pois você não poderá transformá-lo novamente em um APK para instalá-lo no seu dispositivo ... pelo menos não sem muito esforço.

smali / baksmali é na verdade um montador / dissimulador para o formato dex - é o que significa literalmente em islandês. No entanto, geralmente nos referimos ao formato que o smali entende quando dizemos 'Smali' (pense nele como instruções que definem todos os pequenos detalhes, mesmo que nem todos sejam necessários para os humanos - portanto, é mais detalhado que o Java). Observe também que a explicação acima é um pouco simplificada, mas deve ser uma analogia próxima e ao mesmo tempo fácil de entender.

O que um desenvolvedor precisaria fazer para modificar um aplicativo (sem acesso à fonte), então? O processo é mais ou menos o seguinte:

  1. Obtenha o APK (da Web ou do dispositivo).
  2. Use algo como apktool para descompilar o APK para Smali. (o apktool utiliza smali / baksmali, mas facilita muito a decompilação e a reconstrução de APKs, além de cuidar da decodificação de recursos, como arquivos XML.)
  3. Extraia o classes.dex do APK e use o dex2jar e, finalmente, um descompilador Java para obter o código Java (incompleto, geralmente quebrado, mas principalmente compreensível). (Isso é opcional, mas pode ser útil, pois Smali é muito mais difícil de entender.)
  4. Identifique o que modificar.
  5. Na verdade, modifique-o editando o código Smali diretamente.
  6. Como alternativa, escreva a modificação em Java, compile-a, descompile-a novamente no Smali e copie o código Smali resultante.
  7. Quando tudo terminar, use o apktool novamente para reconstruir o APK.
  8. Assine o APK (para verificar a identificação do autor; todos os pacotes devem ser assinados) e, finalmente, instale-o.

Escrever código Smali é bastante difícil e propenso a erros. Alterações menores podem ser feitas no Smali, mas adicionar novos recursos a ele é mais desafiador. Além disso, você não terá erros no tempo de compilação, portanto, mesmo erros de digitação podem ser detectados apenas em tempo de execução. A expansão e o compartilhamento de patches Smali também podem ser problemáticos, pois os diffs tendem a ser muito específicos a uma versão específica do APK. Embora existam algumas ferramentas para facilitar partes do processo explicado acima (o Virtuous Ten Studio vem à mente), ainda pode ser cansativo.

O DexPatcher do membro sênior Lanchon visa corrigir esses problemas, simplificando o processo e permitindo que os desenvolvedores evitem completamente lidar com a Smali. Em vez disso, os desenvolvedores podem escrever patches apenas em Java e fazer com que o DexPatcher lide com todo o resto.

Isso tem a principal vantagem de ter arquivos de correção facilmente legíveis e gerenciáveis. A correção de APKs também se torna mais conveniente em geral. Veremos um exemplo completo de como usar o DexPatcher daqui a pouco, mas aqui está uma rápida visão geral do que ele oferece primeiro:

  • Código aberto.
  • Plataforma cruzada: deve ser executado no Linux, Mac e Windows.
  • Arquivos de correção: as modificações feitas estão contidas nos arquivos de correção Java que você pode compartilhar independentemente.
  • Java: não é Smali.

Você também obtém a vantagem da verificação de erros em tempo de construção, para que os erros apareçam no início do ciclo de desenvolvimento. O Java compilado fornece a verificação usual do tempo de compilação (com acesso aos símbolos APK originais) e o DexPatcher reforça a compatibilidade da fonte e do patch ao aplicar patches, fornecendo informações úteis e dando avisos quando você parece estar fazendo algo legal, mas suspeito.

Além disso, o DexPatcher vem com um conjunto de scripts auxiliares (disponíveis apenas no Linux, embora também possam ser portados para outras plataformas). Eles cuidam da configuração da área de trabalho, da extração das classes e dos recursos do APK de destino, da decompilação das classes para Java (o descompilador de CFR Java é usado para o último) e, finalmente, da criação e assinatura do APK corrigido assim que você terminar.

Vamos dar uma olhada em um exemplo (no Linux):

Instale os scripts do DexPatcher

 $ # Crie um diretório onde possamos testar as coisas e inseri-lo. $ mkdir xda-test $ cd xda-test $ git clone //github.com/Lanchon/DexPatcher-scripts.git dexpatcher # Clona o repositório de scripts auxiliares do DexPatcher. $ cd dexpatcher $ chmod + x dxp- * # Não é necessário, mas para maior clareza: precisamos garantir que os arquivos que chamaremos mais tarde sejam executáveis. 

Configurar os scripts do DexPatcher

Abra o dxp.config no seu editor de texto favorito e altere as variáveis ​​necessárias para se adequar ao seu sistema. Você só precisa alterar a seguinte linha para apontar para o local de instalação do SDK do Android:

 dxp_android_sdk_dir = (~ / android / sdk) 

(O DexPatcher escolherá automaticamente a versão de plataforma mais alta disponível. Além disso, você também pode modificar outras opções de configuração para que ele use suas próprias versões de algumas ferramentas, em vez dos padrões incluídos.)

Para facilitar o acesso, podemos adicionar o diretório dexpatcher ao nosso PATH ou até mesmo vincular os diferentes scripts dxp- * a um local que já esteja no seu PATH, como ~ / bin:

 exportar PATH = $ PWD: $ PATH 

Modificar um aplicativo

Neste exemplo, usaremos um aplicativo simples e de código aberto. Obviamente, a correção direta do código-fonte seria possível nesse caso específico, mas isso não é nada divertido!

Usaremos o aplicativo "Get ID" do basil2style, um aplicativo que mostra alguns detalhes sobre o seu dispositivo. Nosso objetivo é modificar o botão "Copiar" para o "ID do dispositivo" e fazer com que ele compartilhe esse ID:

  • Primeiro, vamos baixar o APK que vamos modificar: Obter ID.
  • Descompile o aplicativo.
  • Crie a chave de assinatura que usaremos mais tarde para assinar o APK.

Também podemos fazer tudo isso através do shell, usando os scripts auxiliares:

 $ cd dexpatcher # Vá para o nosso diretório de trabalho. $ curl -O //f-droid.org/repo/makeinfo.com.getid_1.apk # Faça o download do APK. $ dxp-setup-for-apk makeinfo.com.getid_1.apk # Descompacte e descompile o APK. $ cd makeinfo.com.getid_1 # Vá para o diretório recém-criado onde tudo é descompactado / descompilado. $ dxp-create-keystore # Crie a chave de assinatura do APK. Pressione 6 vezes (ou preencha as informações) e, em seguida, "sim". 

Você notará alguns diretórios diferentes:

  • decodificar : você encontrará os recursos e o Smali aqui, conforme decodificado pelo apktool.
  • src : Diretório vazio. É aqui que colocaremos nossos arquivos de correção.
  • src-cfr : é aqui que o cfr descompila o aplicativo (junto com os erros). Um bom local para procurar e decidir o que alterar (você também pode precisar de recursos e seus IDs no diretório de decodificação acima, mas não neste exemplo em particular).
  • src-cfr-nodecode : o mesmo que acima, mas contendo apenas stubs vazios (sem código, apenas esqueletos). Você pode usar esses arquivos como base para o seu patch, como veremos a seguir.

Como mencionamos anteriormente, queremos alterar o botão "Copiar" da ID do dispositivo para compartilhar o texto da ID. Se analisarmos o código-fonte, perceberemos que o evento onClick do botão Cópia de ID do dispositivo (device_copy) é tratado pela classe anônima em src-cfr / makeinfo / com / getid / MainActivity.java. Embora possamos modificá-lo aqui, geralmente é melhor encontrar uma maneira alternativa de fazê-lo, pois as classes anônimas têm nomes numéricos (MainClassName $ SomeNumber, por exemplo, MainActivity $ 3) que podem mudar imprevisivelmente entre as versões.

Em vez disso, registraremos nossa própria classe para o evento modificando a classe MainActivity. Primeiro, vamos copiar a versão "esqueleto" de src-cfr-nocode / makeinfo / com / getid / MainActivity.java para src / makeinfo / com / getid / MainActivity.java (lembre-se de que o src é onde o nosso patch ficará). (Você também pode copiar a versão com o código completo, se preferir, isso é apenas uma questão de gosto.)

Agora podemos editá-lo da seguinte maneira:

  • Adicione a importação necessária para a anotação DexPatcher:
 import lanchon.dexpatcher.annotation. *; 
  • Adicione uma tag para indicar que estamos editando a turma. Também definimos a ação padrão para membros da classe de patch como IGNORE, o que significa que os membros devem ser referenciados por nosso código durante a compilação Java, mas serão ignorados pelo DexPatcher.
 @DexEdit (defaultAction = DexAction. IGNORE) classe pública MainActivity // A referência a ActionBarActivity será atendida por símbolos // extraídos do aplicativo quando criamos o patch. estende ActionBarActivity { 
  • Além disso, adicione corpos vazios ao método construtor e onCreate, bem como a todos os outros métodos que planejamos usar (lembre-se de que eles serão ignorados quando o patch for realmente aplicado - estamos apenas adicionando-os para que possamos consultá-los aqui) se precisarmos). Você também pode adicionar a palavra-chave nativa.
  • Já podemos criar o patch neste momento, se você estiver curioso:
     $ dxp-make # Saída: `patched.apk`. 

    Muito simples, certo? Mas vamos continuar - ainda não terminamos.

  • Vamos editar o onCreate agora para definir o OnClickListener próprio para que possamos compartilhar o ID do dispositivo em vez de copiá-lo para a área de transferência:
     // Renomeie o método de destino para que ainda possamos chamá-lo (o original) // se necessário. @DexEdit (target = "onCreate") void source_onCreate protegido (Bundle var1) {} // Adicione nosso novo método personalizado. @Override @DexAdd void protegido onCreate (Bundle var1) {// Chame o método original: source_onCreate (var1); // Substitua o texto e o manipulador: device_copy. setText ("Compartilhar"); device_copy. setOnClickListener (novo DeviceCopyOnClick ()); } // Observe que não usamos uma classe anônima para evitar a troca de nomes com // MainActivity $ 1, que já existe. // Também poderíamos ter definido uma classe MainActivity.Patch aninhada e usado // uma classe anônima em MainActivity.Patch.onCreate () e, em seguida, chamado // MainActivity.Patch.onCreate () de MainActivity.onCreate (). A classe @DexAdd DeviceCopyOnClick implementa View. OnClickListener {@Override public void onClick (Exibir objeto) {if (MainActivity. This. Val) {Intenção intenção = nova Intenção (intenção. ACTION_SEND); intenção. setType ("texto / sem formatação"); intenção. putExtra (Intenção. EXTRA_SUBJECT, "ID do dispositivo"); intenção. putExtra (Intenção. EXTRA_TEXT, dispositivo. getText (). toString ()); startActivity (Intenção. createChooser (intenção, "Compartilhar ID do Dispositivo")); } else {Torrada. makeText (MainActivity. this. getApplicationContext (), "Nada para compartilhar", 0). mostrar (); }}} 
  • Parece que terminamos agora! O patch completo deve ficar assim. Agora podemos criar o APK corrigido e instalá-lo:
     Instalação do $ dxp-make $ adb patched.apk 
  • Vamos dar uma olhada no resultado:

(Obrigado a Lanchon por ajudar com o código de exemplo!)

O Xposed é imensamente popular, e por uma boa razão - torna a construção, o compartilhamento e a instalação de mods muito mais simples para desenvolvedores e usuários. Existem algumas diferenças entre o DexPatcher e o Xposed que podem fazer com que alguns prefiram um sobre o outro:

  1. O Xposed faz sua mágica conectando métodos em tempo de execução e permitindo que os desenvolvedores façam algo antes, depois ou qualquer método. O DexPatcher, por outro lado, modifica tudo antes do tempo de execução e produz um APK independente, modificado - executando o código antes, depois ou depois dos métodos ainda é possível, e você realmente tem uma liberdade extra.
  2. Produzir um APK independente significa que ele não depende de nenhuma estrutura externa. Isso também significa que a raiz não é necessária para modificar os aplicativos do usuário.
  3. Como você criou um novo APK com o DexPatcher, ele será assinado de forma diferente. Isso significa que os usuários não podem receber atualizações oficiais do autor original e podem causar alguns problemas com aplicativos como o Google Apps se as assinaturas estiverem marcadas.
  4. O código fonte dos patches dos módulos e do DexPatcher pode ser facilmente distribuído e modificado. Eles também compartilham muitas semelhanças se você se familiarizar um pouco com cada um.

Já conversamos bastante sobre o DexPatcher. Agora é sua vez de tentar, então vá até o Tópico do fórum do DexPatcher para começar imediatamente!