Fluxo de Inicialização do Aplicativo
A criação de um processo de aplicativo no Android inicia no processo Zygote, culminando na execução do método ActivityThread.main(). Este ponto de entrada configura o loop de mensagens principal e inicializa o ambiente da aplicação.
// Criar instância do ActivityThread
ActivityThread instance = new ActivityThread();
instance.attach(false);
// Iniciar o loop de mensagens
Looper.loop();
}
</div>O método `handleBindApplication` é invocado quando o sistema vincula os dados da aplicação. Neste ponto, ocorre a inicialização do `Application`, incluindo a chamada aos métodos `attachBaseContext` e `onCreate`. Ferramentas de proteção frequentemente substituem a classe `Application` para inserir lógica de desempacotamento nesses métodos.
Princípio de Empacotamento e Fluxo de Execução
----------------------------------------------
O empacotamento envolve criptografar os DEX e injetar código de desempacotamento na classe `Application`. Durante a execução, o shell descriptografa os DEX na memória, carrega-os via um `ClassLoader` customizado e utiliza reflexão para corrigir variáveis críticas, especialmente o `ClassLoader` da aplicação.
Para contramedidas contra despejo de memória, shells avançados implementam desempacotamento por instruções, descriptografando métodos apenas durante a execução. Esta técnica dificulta a obtenção do DEX completo.
Ferramentas de Desempacotamento em ART e Limitações
---------------------------------------------------
Técnicas existentes incluem despejo durante a compilação `dex2oat`, interceptação de estruturas `DexFile` na memória, e hooking de funções de carregamento. No entanto, muitas destas abordagens falham contra shells que empregam desempacotamento por instruções.
A proposta ativa de métodos, como implementada no FUPK3 para Dalvik, engana o shell executando métodos de forma controlada, forçando a descriptografia. Com a transição para ART, surgiu a necessidade de uma solução equivalente.
Princípio e Implementação do FART
---------------------------------
O FART opera em três etapas principais:
1. Despejo completo do DEX a partir da estrutura `DexFile` na memória.
2. Invocação ativa de métodos para despejar seus `CodeItem`s.
3. Reparo dos métodos extraídos utilizando os dados coletados.
### 1. Despejo da Estrutura DexFile
O ponto de coleta é dentro de `ActivityThread.performLaunchActivity`, após a inicialização completa do `Application`. Obtém-se o `ClassLoader` final e inicia uma nova thread para operações demoradas.
<div class="code-block">```
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// ... código existente ...
ClassLoader cl = r.packageInfo.getClassLoader();
final ClassLoader appClassLoader = mInitialApplication.getClassLoader();
new Thread(() -> {
dumpDexFilesViaReflection(appClassLoader);
}).start();
// ... continuação ...
}
int fd = open(convertJString(env, path), O_WRONLY | O_CREAT, 0666);
write(fd, data, size);
close(fd);
}
}
</div>### 2. Invocação Ativa de Métodos
A invocação ativa é inspirada no mecanismo JNI. Modifica-se `ArtMethod::Invoke` para detectar chamadas artificiais (através de um marcador, como `Thread*` nulo) e despejar o `CodeItem` do método.
<div class="code-block">```
void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size,
JValue* result, const char* shorty) {
if (self == nullptr) { // Marcador de invocação ativa
dumpMethodCodeItem(this);
return;
}
// ... implementação original ...
}
void ArtMethod::invokeArtificially(ArtMethod* method) {
JValue unused_result;
uint32_t placeholder_args = 0;
method->Invoke(nullptr, &placeholder_args, 0, &unused_result, "V");
}
3. Reparo dos Métodos Extraídos
Um script Python recombina os CodeItems despejados com o arquivo DEX, corrigindo os métodos cujo código foi extraído pelo shell.
# Ler metadados dos CodeItems despejados
for method_code in read_code_items(output_dir):
method_id = locate_method(dex_data, method_code)
replace_code_item(dex_data, method_id, method_code.content)
with open(dex_path + '.repaired', 'wb') as f:
f.write(dex_data)
</div>Uso e Configuração
------------------
O proceso envolve criar um arquivo de configuração com o nome do pacote e o caminho de dados privados, instalá-lo no dispositivo, e iniciar a aplicação. O FART automaticamente despejará os DEX e `CodeItem`s durante a inicialização da `Activity` principal. Os arquivos resultantes são então combinados offline usando o script de reparo.
Imagens de sistema pré-configuradas são fornecidas para emuladores e dispositivos físicos (como Nexus 5) para facilitar testes.