MASTG-KNOW-0008: Informações de Depuração e Símbolos de Depuração
No Android, as bibliotecas nativas geralmente são desenvolvidas em C ou C++ com o NDK e compiladas em objetos compartilhados ELF com extensão .so, que residem no diretório lib/ do APK. Essas bibliotecas frequentemente expõem funcionalidades para serem usadas a partir do Dalvik através da Java Native Interface (JNI). Símbolos de depuração nesses binários fornecem detalhes como nomes de funções, nomes de variáveis e mapeamentos de arquivos fonte, que são úteis para engenharia reversa, depuração e análise de segurança.
Ao compilar e vincular programas, os símbolos representam funções ou variáveis. Em arquivos ELF (Executable and Linkable Format), os símbolos têm funções diferentes:
- Símbolos locais: Visíveis apenas dentro do arquivo onde são definidos. Usados internamente. Não acessíveis a partir de outros arquivos.
- Símbolos globais: Visíveis para outros arquivos. Usados para compartilhar funções ou variáveis entre diferentes arquivos de objeto.
- Símbolos fracos: Semelhantes aos símbolos globais, mas com prioridade menor. Um símbolo forte (não fraco) substitui um fraco se ambos existirem.
Em builds de produção, as informações de depuração devem ser stripped para reduzir o tamanho do binário e limitar a divulgação de informações. No entanto, builds de depuração ou internas podem reter símbolos tanto dentro do binário quanto em arquivos complementares separados.
A visibilidade de símbolos é frequentemente mal gerenciada, levando à exposição externa não intencional de símbolos e exigindo inspeção manual.
Tabelas de Símbolos e Seções DWARF¶
O formato ELF define quais seções devem ser usadas para armazenar informações de símbolos:
.symtab: A tabela de símbolos completa usada no momento da vinculação, frequentemente removida em binários de produção (dtagDT_SYMTAB)..dynsym: A tabela de símbolos dinâmica, usada para vinculação em tempo de execução. Está sempre presente em objetos compartilhados.
DWARF é o formato de depuração padrão usado em binários ELF (mas também é usado em outros sistemas baseados em UNIX, como para binários MACH-O no ecossistema Apple). As seções principais incluem:
.debug_info: Contém as principais informações de depuração, incluindo tipos, definições de funções e escopos..debug_line: Mapeia o código de máquina para números de linha do código fonte..debug_str: Armazena strings usadas pelas entradas DWARF..debug_loc,.debug_ranges,.debug_abbrev, etc.: Suportam metadados de depuração detalhados.
Além disso, algumas toolchains usam compressão zlib para dados DWARF a fim de reduzir o tamanho do binário (por exemplo, clang e gcc suportam isso usando a opção -gz). Essas seções são normalmente nomeadas com um prefixo .z (ex.: .zdebug_info, .zdebug_line, .zdebug_str, etc.) e contêm as mesmas informações que suas contrapartes não comprimidas. Algumas ferramentas de análise que não suportam isso podem relatar incorretamente o binário como stripped.
Para verificar a presença dessas seções em um binário, você pode usar objdump — iOS (com a opção -x) ou radare2 para Android (comando iS) e outras ferramentas como readelf.
Por exemplo, usando radare2:
[0x0003e360]> iS~debug,symtab,SYMTAB
23 0x000c418c 0x60 0x00000000 0x60 ---- 0x0 PROGBITS .debug_aranges
24 0x000c41ec 0x14d85c 0x00000000 0x14d85c ---- 0x0 PROGBITS .debug_info
25 0x00211a48 0xa14f 0x00000000 0xa14f ---- 0x0 PROGBITS .debug_abbrev
26 0x0021bb97 0x5d6a3 0x00000000 0x5d6a3 ---- 0x0 PROGBITS .debug_line
27 0x0027923a 0x7c26a 0x00000000 0x7c26a ---- 0x30 PROGBITS .debug_str
28 0x002f54a4 0x172883 0x00000000 0x172883 ---- 0x0 PROGBITS .debug_loc
29 0x00467d27 0x20 0x00000000 0x20 ---- 0x0 PROGBITS .debug_macinfo
30 0x00467d47 0x602d0 0x00000000 0x602d0 ---- 0x0 PROGBITS .debug_ranges
32 0x004c8018 0x27510 0x00000000 0x27510 ---- 0x0 SYMTAB .symtab
IMPORTANTE: A presença dessas seções não indica necessariamente que o binário não foi stripped. Algumas toolchains podem reter essas seções mesmo em binários stripped, mas muitas vezes elas estão vazias ou contêm informações mínimas. No final, o que importa é se os símbolos em si ainda estão presentes. Consulte Obtendo Informações de Depuração e Símbolos para mais detalhes sobre como extrair e analisar símbolos de depuração.
Arquivos Externos de Símbolos de Depuração¶
A documentação do Android Developers explica que as bibliotecas nativas em builds de release são stripped por padrão. Para habilitar relatórios de crash nativo simbolizados, você deve gerar um arquivo separado de símbolos de depuração — normalmente localizado em <variant>/native-debug-symbols.zip — e enviá-lo para o Google Play Console. Este arquivo ZIP contém arquivos .so não stripped completos com informações de depuração DWARF incorporadas. Os dados DWARF não são divididos em arquivos separados (como .dwo), mas permanecem dentro de cada .so.
Este processo de simbolização é análogo ao envio de um arquivo
mapping.txtpara desofuscar stack traces para código Java/Kotlin ofuscado com ProGuard ou R8.
Em contraste, o iOS usa uma abordagem semelhante em espírito ao split DWARF, familiar das toolchains do Linux. De acordo com a documentação do Apple Developer, habilitar a opção DWARF with dSYM File no Xcode gera arquivos separados de símbolos de depuração (.dSYM) para builds de release. Estes podem ser enviados para os servidores de símbolos da Apple para simbolização de relatórios de crash.