Android

20 jun, 2016

Breve panorama sobre a segurança para aplicativos nativos Android – Parte 02

Publicidade

Na parte 01 dessa série, vimos que toda instalação do Java e do Android já possuem ferramentas para facilitar a engenharia reversa de código compilado. Porém, como podemos usar isso para testar a segurança do nosso aplicativo?

Vamos pensar em um fluxo imaginário com o que vimos até agora:

  • Preciso pegar um APK que eu baixei da loja (Google Play);
  • Preciso acessar o “classes.dex” que há dentro deste pacote;
  • Preciso executar o hexdump nele para convertê-lo em bytecode Java;
  • Preciso executar o javap no resultado para converter em source code Java;
  • Faço alguma alteração neste arquivo e executo o javac (compilador) nele;
  • Executamos o dx para recriar o “classes.dex”;
  • Executamos o aapt para regerar o apk final.

Espero que com o que vimos até agora, o leitor já veja como isso tudo é possível. Porém, faltam alguns passos importantes aí no meio do caminho…

Em primeiro lugar, todo pacote é assinado e alinhado. Isso quer dizer que antes de você subir um APK para a loja, você precisa assiná-lo com uma chave. Assim, os recursos dentro do APK ficam criptografados de acordo com a sua chave. Vamos ver isso em um APK real? Claro!

Escolha um aplicativo instalado no seu device e vamos tentar achar onde esse “mardito” APK fica. Para isso, vamos abrir um “shell” no nosso device:

  • Habilite o modo de desenvolvedor no seu device;
  • Vá até a pasta “platform-tools” dentro da SDK do Android;
  • Execute: adb -d shell.

Pronto! Estamos dentro de um shell do nosso device. Lembre-se de que o Android é baseado em Linux, portanto, muitos comandos de shell de Linux funcionam nele.

Agora queremos listar todos os pacotes instalados no nosso device. Para isso executamos o comando:

pm list packages

Estamos usando um utilitário de linha de comando do Android que é um grande conhecido nosso: o Package Manager. Dentro do shell do Android podemos passar comandos para ele usando o binário pm.

Ao executar o comando acima, vemos uma lista gigante de pacotes. Vamos escolher um. No meu caso, será o aplicativo sample da nossa biblioteca de padrões brasileiros no Android, chamada de Canarinho. Poderíamos escolher qualquer pacote que baixamos do Google Play ou instalamos localmente. O pacote da aplicação neste caso é br.com.concretesolutions.canarinho.sample.

Agora vamos descobrir o caminho do APK desta aplicação instalada no device. Para isso, basta executar:

pm path br.com.concretesolutions.canarinho.sample

Outro comando do Package Manager para mostrar um caminho do arquivo dentro do device. Por exemplo:

/data/app/br.com.concretesolutions.canarinho.sample-2/base.apk

Agora, só precisamos puxar este arquivo do aparelho. Para isso, vamos sair do shell digitando ‘exit’ (ou apertando CTRL + D). De fora do shell do aparelho, mas ainda em um shell da nossa máquina, vamos usar o adb novamente para pegar o arquivo. Basta digitar:

adb -d pull /data/app/br.com.concretesolutions.canarinho.sample-2/base.apk

Lembre-se que o caminho para o arquivo a gente verificou anteriormente. Estou usando meu exemplo aqui do aplicativo de sample do Canarinho. Use o caminho do aplicativo que você escolheu.

Pronto! Sem root e sem ferramentas externas além do kit de desenvolvimento do próprio Android, nós conseguimos baixar um arquivo de aplicativo baixado da loja (ou instalado localmente).

Agora temos o arquivo que queremos ‘fuçar’ (termo técnico para analisar). Vamos começar do mais simples e ver o que temos. Primeiro, eu já disse que todo arquivo ‘.apk’ é simplesmente um arquivo zip que segue uma certa organização dos arquivos. Vamos ver isso: criem um diretório para nossos testes e coloquem o APK lá dentro. Pode ser qualquer diretório. Apenas não queremos sujar o diretório em que o APK está atualmente, pois ao processar os comandos abaixo vamos desempacotar diversos arquivos que compõem o APK.

Dentro deste diretório de teste, vamos desempacotar o APK. Executem:

unzip base.apk

Agora temos o APK desempacotado no nosso diretório de testes. Algo como a figura abaixo:

Captura-de-tela-de-2016-04-26-18-34-30

Ao olhar o resultado pela primeira vez, vimos que já temos logo de cara o AndroidManifest.xml! Será que conseguimos pegar o conteúdo dele já? Tentemos, irmãos!

cat AndroidManifest.xml

Obs: se não está em uma plataforma Unix, tente abrir o arquivo com um editor de texto qualquer.

O resultado é quase tudo em binário =( Estava fácil demais para conseguirmos…

Mas nem tudo está perdido. Mesmo antes de tentarmos algumas ferramentas mais avançadas de “hackers”, vemos que com um simples cat algumas informações sobre o build do binário já estão disponíveis. No meu caso, já consigo ver a versão do app entre outras coisas.

Tudo bem… Vamos em frente que logo, logo esse manifesto estará lindo e transparentemente traduzido para nós.

Nos outros arquivos temos:

  • classes.dex: o conjunto de todas as classes do aplicativo (incluindo suas dependências);
  • META-INF: diretório para metadados de binários JAVA (e que não deveria ser usado por aplicações Android);
  • res: os resources (XMLs assinados) do aplicativo;
  • resources.arsc: todos os recursos indexados e compilados.

Ou seja, parece que temos todos os arquivos para começarmos nossa engenharia reversa; mas todos estão ou assinados ou não acessíveis para nós.

No entanto, até esse momento só usamos as ferramentas padrões de uma instalação da JDK e do Android SDK. Precisamos de ferramentas mais pesadas para continuar. Vejamos uma hoje apenas para apetecer nossos leitores.

Apktool é, sem sombra de dúvida, a ferramenta mais fundamental para quem quer começar a estudar engenharia reversa. Basicamente, ela nos dará tudo o que queríamos até agora: reverter a assinatura dos arquivos e nos dar quase tudo de mão aberta.

Para usá-la, baixe o jar no site e execute o seguinte comando:

java -jar apktool_2.1.0.jar d base.apk

Neste caso, estou usando a versão 2.1.0 do Apktool para descompilar (opção “d”) um APK chamado base.apk. Por padrão, ele coloca o resultado em uma pasta com o mesmo nome do APK (no meu caso: “base”).

Parece mágica, mas vamos olhar o AndroidManifest dentro deste diretório “base”:

cat base/AndroidManifest.xml

Agora sim! Temos um manifesto legível! Não tivemos quase nenhum esforço e já revertemos o manifesto. Pense em quantas aplicações colocam dados em um manifesto… Todos estes dados estão acessíveis agora para nós.

Neste ponto, é importante lembrar do “Uncle Ben”:

spiderman-and-voltaire

Traduzindo: nosso intuito com esta série é mostrar como a segurança do Android funciona e exemplificar ferramentas de análise comumente usadas para testar a segurança de nossos aplicativos.

Traduzindo mais diretamente: não usem essas ferramentas com intuitos maléficos.

E por enquanto, é só. Testem este fluxo em aplicativos da loja que vocês já tenham publicado e vejam como é interessante começar nesse mundo de engenharia reversa.

Dúvidas ou sugestões? Deixem seus comentários!