MASTG-TECH-0032: Rastreamento de Execução
Além de ser útil para depuração, a ferramenta de linha de comando jdb oferece funcionalidade básica de rastreamento de execução. Para rastrear um aplicativo desde o início, você pode pausar o app com o recurso "Aguardar Depurador" do Android ou um comando kill -STOP e anexar o jdb para definir um ponto de interrupção de método diferido em qualquer método de inicialização. Quando o ponto de interrupção for atingido, ative o rastreamento de métodos com o comando trace go methods e retome a execução. O jdb irá despejar todas as entradas e saídas de métodos a partir desse ponto.
$ adb forward tcp:7777 jdwp:7288
$ { echo "suspend"; cat; } | jdb -attach localhost:7777
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
> All threads suspended.
> stop in com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>()
Deferring breakpoint com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>().
It will be set after the class is loaded.
> resume
All threads resumed.M
Set deferred breakpoint com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>()
Breakpoint hit: "thread=main", com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>(), line=44 bci=0
main[1] trace go methods
main[1] resume
Method entered: All threads resumed.
O Dalvik Debug Monitor Server (DDMS) é uma ferramenta GUI incluída no Android Studio. Pode não parecer muito, mas seu rastreador de métodos Java é uma das ferramentas mais impressionantes que você pode ter em seu arsenal, sendo indispensável para analisar bytecode ofuscado.
No entanto, o DDMS pode ser um pouco confuso; ele pode ser iniciado de várias maneiras, e diferentes visualizadores de rastreamento serão abertos dependendo de como um método foi rastreado. Existe uma ferramenta autônoma chamada "Traceview" e também um visualizador integrado no Android Studio, ambos oferecendo diferentes formas de navegar pelo rastreamento. Geralmente você usará o visualizador integrado do Android Studio, que fornece uma linha do tempo hierárquica zoomável de todas as chamadas de método. Porém, a ferramenta autônoma também é útil, pois possui um painel de perfil que mostra o tempo gasto em cada método, juntamente com os pais e filhos de cada método.
Para gravar um rastreamento de execução no Android Studio, abra a guia Android na parte inferior da interface gráfica. Selecione o processo alvo na lista e clique no pequeno botão cronômetro à esquerda. Isso inicia a gravação. Quando terminar, clique no mesmo botão para parar a gravação. A visualização de rastreamento integrada será aberta e mostrará o rastreamento gravado. Você pode rolar e dar zoom na linha do tempo com o mouse ou trackpad.
Rastreamentos de execução também podem ser gravados no Android Device Monitor autônomo. O Device Monitor pode ser iniciado dentro do Android Studio (Ferramentas -> Android -> Android Device Monitor) ou a partir do shell com o comando ddms.
Para iniciar a gravação de informações de rastreamento, selecione o processo alvo na guia Dispositivos e clique em Iniciar Criação de Perfil de Método. Clique no botão parar para interromper a gravação, após o que a ferramenta Traceview será aberta e mostrará o rastreamento gravado. Clicar em qualquer um dos métodos no painel de perfil destaca o método selecionado no painel da linha do tempo.
O DDMS também oferece um conveniente botão de despejo de heap que despejará o heap Java de um processo em um arquivo .hprof. O guia do usuário do Android Studio contém mais informações sobre o Traceview.
Rastreamento de Chamadas de Sistema¶
Descendo um nível na hierarquia do sistema operacional, chegamos a funções privilegiadas que exigem os poderes do kernel do Linux. Essas funções estão disponíveis para processos normais por meio da interface de chamadas de sistema. Instrumentar e interceptar chamadas para o kernel é um método eficaz para ter uma ideia geral do que um processo de usuário está fazendo e, muitas vezes, a maneira mais eficiente de desativar defesas de violação de baixo nível.
O Strace é um utilitário padrão do Linux que não vem incluído no Android por padrão, mas pode ser facilmente compilado a partir do código-fonte via Android NDK. Ele monitora a interação entre processos e o kernel, sendo uma maneira muito conveniente de monitorar chamadas de sistema. No entanto, há uma desvantagem: como o strace depende da chamada de sistema ptrace para anexar ao processo alvo, uma vez que as medidas anti-depuração se tornam ativas, ele para de funcionar.
Se o recurso "Aguardar depurador" em Configurações > Opções de desenvolvedor estiver indisponível, você pode usar um script de shell para iniciar o processo e anexar imediatamente o strace (não é uma solução elegante, mas funciona):
while true; do pid=$(pgrep 'target_process' | head -1); if [[ -n "$pid" ]]; then strace -s 2000 - e "!read" -ff -p "$pid"; break; fi; done
Ftrace¶
O Ftrace é um utilitário de rastreamento integrado diretamente no kernel do Linux. Em um dispositivo com root, o ftrace pode rastrear chamadas de sistema do kernel de forma mais transparente do que o strace (o strace depende da chamada de sistema ptrace para anexar ao processo alvo).
Convenientemente, o kernel padrão do Android tanto no Lollipop quanto no Marshmallow inclui funcionalidade ftrace. O recurso pode ser ativado com o seguinte comando:
echo 1 > /proc/sys/kernel/ftrace_enabled
O diretório /sys/kernel/debug/tracing contém todos os arquivos de controle e saída relacionados ao ftrace. Os seguintes arquivos são encontrados neste diretório:
- available_tracers: Este arquivo lista os rastreadores disponíveis compilados no kernel.
- current_tracer: Este arquivo define ou exibe o rastreador atual.
- tracing_on: Escreva "1" neste arquivo para permitir/iniciar a atualização do buffer circular. Escrever "0" impedirá gravações adicionais no buffer circular.
KProbes¶
A interface KProbes fornece uma maneira ainda mais poderosa de instrumentar o kernel: permite inserir sondas em (quase) quaisquer endereços de código dentro da memória do kernel. O KProbes insere uma instrução de ponto de interrupção no endereço especificado. Quando o ponto de interrupção é atingido, o controle passa para o sistema KProbes, que então executa as funções de manipulador definidas pelo usuário e a instrução original. Além de serem excelentes para rastreamento de funções, os KProbes podem implementar funcionalidades tipo rootkit, como ocultação de arquivos.
Jprobes e Kretprobes são outros tipos de sondas baseados em KProbes que permitem o hooking de entradas e saídas de funções.
O kernel padrão do Android vem sem suporte a módulos carregáveis, o que é um problema porque os Kprobes são geralmente implantados como módulos do kernel. A proteção rigorosa de memória com a qual o kernel do Android é compilado é outra questão, pois impede a modificação de algumas partes da memória do Kernel. O método de hooking de chamadas de sistema do Elfmaster causa um pânico no Kernel no Lollipop e Marshmallow padrão porque a sys_call_table não é gravável. No entanto, você pode usar KProbes em um sandbox compilando seu próprio Kernel mais permissivo (mais sobre isso depois).