MASTG-TECH-0036: Análise Baseada em Emulação

O emulador Android é baseado no QEMU, um emulador de máquina genérico e de código aberto. O QEMU emula uma CPU convidada traduzindo as instruções do convidado em tempo real em instruções que o processador host pode entender. Cada bloco básico de instruções do convidado é desmontado e traduzido em uma representação intermediária chamada Tiny Code Generator (TCG). O bloco TCG é compilado em um bloco de instruções do host, armazenado em um cache de código e executado. Após a execução do bloco básico, o QEMU repete o processo para o próximo bloco de instruções do convidado (ou carrega o bloco já traduzido do cache). Todo o processo é chamado de tradução binária dinâmica.

Como o emulador Android é um fork do QEMU, ele vem com todos os recursos do QEMU, incluindo funcionalidades de monitoramento, depuração e rastreamento. Parâmetros específicos do QEMU podem ser passados para o emulador com o flag de linha de comando -qemu. Você pode usar os recursos de rastreamento incorporados do QEMU para registrar as instruções executadas e os valores de registros virtuais. Iniciar o QEMU com o flag de linha de comando -d fará com que ele despeje os blocos de código do convidado, micro operações ou instruções do host que estão sendo executadas. Com o flag -d_asm, o QEMU registra todos os blocos básicos de código do convidado à medida que entram na função de tradução do QEMU. O seguinte comando registra todos os blocos traduzidos em um arquivo:

emulator -show-kernel -avd Nexus_4_API_19 -snapshot default-boot -no-snapshot-save -qemu -d in_asm,cpu 2>/tmp/qemu.log

Infelizmente, é impossível gerar um rastreamento completo de instruções do convidado com o QEMU, pois os blocos de código são gravados no log apenas no momento em que são traduzidos, não quando são recuperados do cache. Por exemplo, se um bloco for executado repetidamente em um loop, apenas a primeira iteração será impressa no log. Não há como desativar o caching de TB no QEMU (além de modificar o código fonte). No entanto, a funcionalidade é suficiente para tarefas básicas, como reconstruir a desmontagem de um algoritmo criptográfico executado nativamente.