MASTG-KNOW-0008 デバッグ情報とデバッグシンボル (Debugging Information and Debug Symbols)

Android では、ネイティブライブラリは通常、NDK を使用して C または C++ で開発され、.so 拡張子を持つ ELF 共有オブジェクトにコンパイルされ、APK の lib/ ディレクトリに格納します。これらのライブラリは、多くの場合、Java Native Interface (JNI) を通じて Dalvik から使用される機能を公開します。これらのバイナリ内の デバッグシンボル は、関数名、変数名、ソースファイルマッピングなどの詳細を提供し、リバースエンジニアリング、デバッグ、セキュリティ解析に役立ちます。

プログラムをコンパイルおよびリンクする際、シンボルは関数または変数を表します。ELF (Executable and Linkable Format) ファイルでは、シンボルは異なる役割を果たします。

  • ローカルシンボル: 定義されたファイル内でのみ視認できます。内部的に使用されます。他のファイルからはアクセスできません。

  • グローバルシンボル: 他のファイルから視認できます。異なるオブジェクトファイル間でファイルや変数を共有するために使用されます。

  • ウィークシンボル: グローバルシンボルと似ていますが優先度が低くなります。ストロング (非ウィーク) シンボルとウィークシンボルの両方が存在する場合、ストロングシンボルがウィークシンボルをオーバーライドします。

プロダクションビルドでは、バイナリサイズを削減し、情報開示を制限するために、デバッグ情報を削除する必要があります。しかし、デバッグビルドまたは内部ビルドはバイナリ内または別のコンパニオンファイルにシンボルを保持することがあります。

シンボルの可視性は誤って扱われることがよくあり、シンボルの意図しない外部公開につながり、手動検査を必要とします。

シンボルテーブルと DWARF セクション

ELF 形式は、シンボル情報を格納するためにどのセクションを使用する必要があるかを定義しています。

  • .symtab: リンク時に使用される完全なシンボルテーブル。プロダクションバイナリでは削除されることがよくあります (DT_SYMTAB dtag)。

  • .dynsym: ランタイムリンク時に使用される動的シンボルテーブル。共有オブジェクトには常に存在します。

DWARF は ELF バイナリで使用される標準デバッグ形式です (ただし、Apple エコシステムの MACH-O バイナリなど、他の UNIX ベースのシステムでも使用されています)。主なセクションは以下のとおりです。

  • .debug_info: 型、関数定義、スコープなど、主要なデバッグ情報を含みます。

  • .debug_line: マシンコードをソースコードの行番号にマップします。

  • .debug_str: DWARF エントリで使用される文字列を格納します。

  • .debug_loc, .debug_ranges, .debug_abbrev など: 詳細なデバッグメタデータをサポートします。

さらに、一部のツールチェーンは DWARF データのバイナリサイズを縮小するために zlib 圧縮 を使用します (たとえば clanggcc-gz オプションを使用してこれをサポートしています)。これらのセクションは一般的に .z プレフィックスを使用して名前付けされ (例: .zdebug_info, .zdebug_line, .zdebug_str など)、圧縮されていないセクションと同じ情報を含みます。これらをサポートしていない一部の解析ツールでは、削除されているものとしてバイナリを誤って報告されることがあります。

バイナリ内にこれらのセクションが存在するかどうかをチェックするには、objdump - iOS (-x オプションを使用)、radare2 for Android (iS コマンド)、readelf などのその他のツールを使用できます。

たとえば、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

重要: これらのセクションが存在するからといって、必ずしもバイナリが削除されていないことを示すわけではありません。一部のツールチェーンではストリップされたバイナリでもこれらのセクションを保持することがありますが、多くの場合、空であるか、最低限の情報のみ含みます。最終的に、重要なのは シンボル自体がまだ存在しているかどうか です。デバッグシンボルの抽出と解析方法の詳細については デバッグ情報とシンボルの取得 (Obtaining Debugging Information and Symbols) を参照してください。

外部デバッグシンボルファイル

Android 開発者ドキュメント では、リリースビルドのネイティブライブラリはデフォルトで削除されると説明しています。シンボル化されたネイティブクラッシュレポートを有効にするには、別途デバッグシンボルファイル (一般的に <variant>/native-debug-symbols.zip にあります) を生成し、Google Play Console にアップロードする必要があります。この ZIP アーカイブは DWARF デバッグ情報を埋め込まれた完全な 削除されていない .so ファイル を含みます。DWARF データは個別のファイル (.dwo など) に分割されず、各 .so 内に残ります。

このシンボル化プロセスは ProGuard または R8 で難読化された Java/Kotlin コードの スタックトレースの難読化解除 するために mapping.txt ファイルをアップロードすることに似ています。

対照的に、iOS は Linux ツールチェーンでおなじみの split DWARF精神的に似た アプローチを使用しています。Apple 開発者ドキュメント に従って、Xcode で DWARF with dSYM File オプションを有効にすると、リリースビルド用に個別のデバッグシンボルファイル (.dSYM) を生成します。これらはクラッシュレポートのシンボル化のために Apple のシンボルサーバーにアップロードできます。

Last updated

Was this helpful?