Fazer um bom laboratório para testes de segurança em aplicações android pode ser uma tarefa difícil. Muitas vezes, uma aplicação vai precisar que muitos passos sejam executados antes de você realmente poder testar a aplicação, isso é muito comum em aplicações reais. Vamos chamar essas barreiras de ‘pré-testes’ durante esse texto.
Você também pode ouvir a versão em áudio desse blogpost:
Pensando em uma aplicação de celular como uma parte do código que você coloca na mão do cliente, nós começamos a ver por que é tão importante que a aplicação tenha esses tipos de proteção.
Uma única aplicação pode ter várias etapas de pré-teste, então o que temos que fazer pode variar muito de aplicação para aplicação. Qual é o público-alvo da aplicação? Esse aplicativo faz algum tipo de transação financeira? Com que tecnologia ele foi feito? Essas são algumas perguntas que podem ajudar a prever quais pré-testes você pode encontrar em uma aplicação. Aqui eu vou falar de algumas partes básicas que são mais comuns de se encontrar em vários tipos de apps.
Para deixar as coisas mais interessantes, eu baixei alguns aplicativos para ver quais tipos de barreiras eles tem implementados. Nesse texto eu vou mostrar alguns pré-testes que eu encontrei olhando 30 apps que foram desenvolvidos nessas tecnologias:

Falando um pouco sobre eles, a maioria eram de bancos ou apps com relações financeiras e alguns eram lojas, mas todos eles estavam disponíveis na Play Store brasileira.
Ofuscação
Falando sobre barreiras em aplicações android, uma que com certeza você vai ver muitas vezes é a ofuscação. O tipo de ofuscação pode variar de app para app, as variáveis e métodos podem ter seus nomes trocados para letras, partes inúteis podem ser adicionadas ao código, só para fazer a análise estática ficar mais complicada e o APK também pode tentar parar uma ferramenta que tente descompila-lo.

Dos 21 aplicativos nativos que eu encontrei, 14 tinham algum tipo de ofuscação. Só estou falando de apps nativos porque quando uma aplicação é desenvolvida de uma forma não nativa, outros arquivos ficam tão interessantes quanto os arquivos do Java, adicionando outros desafios para essa etapa da engenharia reversa.
A maioria das partes da ofuscação está mais relacionada com o processo de compilação do que com o código escrito pelo desenvolvedor em si, então não temos muito controle sobre essa etapa. A famosa ferramenta de descompilação jadx oferece uma ajuda para aplicações que tenham uma ofuscação que troca o nome dos métodos e variáveis.
Aqui nós temos um pedaço de código sem ofuscação:
.png)
E essa é uma parte do código depois dela ser ofuscada:
.png)
Usando a flag de –deobf, nós podemos dizer qual o mínimo de caracteres que o app poderá ter nas variáveis, classes e métodos. Então todas as vezes que o jadx encontrar um nome com menos caracteres que o indicado, ela irá substituir por um que seja mais fácil de identificar, tornando o processo de análise estática um pouco mais fácil.
.png)
Anti root
Agora olhando para outras técnicas que podemos encontrar, nós temos o anti root. Na relação de aplicativos com anti root, 9 deles tinham algum tipo de segurança e 2 conseguiam ser burladas com scripts simples.

Como o nome diz, anti root é quando a aplicação nota que está sendo executada em um dispositivo com root e adota um comportamento diferente por isso. O que a aplicação vai fazer depois disso também pode variar, exemplos comuns são simplesmente fechar, ou mover você para outra activity e te forçar a ficar lá.
O método utilizado para identificar quando ele está ou não em um dispositivo com root também pode variar, eu vou mostrar 3 técnicas comuns.
Procurar por arquivos
Uma forma comum, é procurando por arquivos específicos no dispositivo, como ‘/bin/su’, ‘su’ e outras formas. Aqui nós temos um exemplo básico de um famoso anti root.
.png)
Como podemos ver nessa parte do código, ela usa o método ‘File.exists’ com uma string que é fornecida. Anti root tem várias formas de ser burlado, as mais comuns atualmente são utilizando ferramentas que usam o frida como base ou os próprios scripts do frida para isso.
Olhando no Frida Codeshare, nós podemos encontrar esse script. Esse é um dos scripts mais famosos para bypass de detecção de root, ele basicamente olha uma série de métodos comumente utilizados, e tenta fazer um novo retorno para eles (por exemplo trocando os verdadeiros para falso), prevenindo que o app identifique que está sendo executado em um dispositivo com root.
Se nós olharmos esse script mais de perto vamos ver a parte que ele implementa um novo retorno para o método ‘File.exists’ que nós vimos no exemplo anterior.
.png)
Procurar por pacotes
Outra técnica que é comum de ver em detecções root é procurando por pacotes, um pacote é um app instalado no seu dispositivo. A forma é muito parecida com a que vimos antes, basicamente usando o método ‘getPackageManager’, uma falha nesse método indica que o pacote não está instalado.
.png)
O mesmo script que nós usamos para evitar a detecção no método ‘File.exists‘ também tem uma implementação para esse, como podemos ver aqui.
.png)
Tentando executar comandos
A última forma de detectar root que iremos ver aqui é utilizando o método ‘Runtime.getRuntime.exec’ para tentar executar um comando que precisa de um privilegio de super usuário. Da mesma forma que no ‘getPackageManager’, se o comando falhar, ele interpreta como o dispositivo não tivesse root.
.png)
O mesmo script do Frida pode funcionar nesse método, carregando várias chamadas do método exec, para garantir que será executado. Nós podemos ver umas das implementações completas aqui.
.png)
Esses são alguns exemplos do que você pode encontrar, provavelmente esse script não irá funcionar todas as vezes, é aí que você tem que parar e fazer um pouco de análise estática para tentar identificar quais os passos que essa aplicação está olhando que ainda não foi burlado. Depois disso, você mesmo pode fazer um script Frida ou adicionar a implementação em algum outro script.
Leia também: Desserialização Insegura em PHP: uma introdução
SSL Pinning
SSL Pinning é uma técnica muito mais comum, ela literalmente adiciona um certificado SSL na aplicação e tenta só funcionar da maneira correta em comunicações feitas utilizando aquele certificado, se você tentar colocar um proxy no caminho, como o certificado usado nas comunicações com o app irá mudar, ele vai parar de se comunicar e agir como se não tivesse internet.
A implementação do SSL Pinning também irá variar de tecnologia para tecnologia, muitas aplicações em Flutter podem utilizar métodos diferentes de validar certificados nas comunicações. A relação de apps com esse tipo de proteção foi:

Uma forma conhecida de implementar SSL Pinninng nos apps é utilizando o OKHTTP3, que possui uma classe chamada ‘CertificatePinner‘, e nesse classe têm um método ‘check’, que como você já deve ter imaginado, tem várias formas de ser burlado.
.png)
Aqui nós temos um script Frida que possui várias formas de bypassar SSL Pinning. Buscando sobrescrever as formas de check conhecidas, esse script pode facilmente driblar a implementação do OKHTTP3.
.png)
HTTPS Body Encoding

Uma técnica não tão comum é criptografar a parte do body das comunicações feitas nesse aplicativo. Para conseguir passar isso, você precisa olhar o app mais de perto, fazendo uma análise estática para entender o que está acontecendo nas comunicações.
Uma forma de começar é olhando algumas classes do pacote ‘javax.crypto’. As vezes um script conhecido pode ajudar nessa parte, como os scripts do Brida (Ele usa esse script feito pela FSecure) ou outros scripts no Codeshare.

Conclusão
Tenha em mente que esses são só alguns exemplos do que você pode encontrar olhando apps reais. Se você está olhando uma aplicação grande, você provavelmente precisará gastar mais tempo nas etapas de pré-teste. O importante é ver que olhar para uma aplicação mais de perto pode ser uma boa ideia, nunca sabemos quando vamos encontrar uma forma mais sofisticada de proteção.
Referências e boas leituras
- Ferramenta Jadx
- Frida script usado para anti root
- Frida script usado para SSLPinning
- Frida script usado para olhar criptografia
- Bom texto sobre interceptar trafego em apps flutter
- Bom texto sobre colocar proxy em applicações nom-proxy-aware
