IDA を使用してアセンブリ コードを表示し、Android システムによって生成された Tombstone ファイルと組み合わせて、Android アプリ プログラムのクラッシュを分析します。

目次

1. IDA ツールの概要

2. 製品と問題のシナリオの説明

3. トゥームストーン ファイルを表示する

4. IDA を使用して .so ダイナミック ライブラリ ファイルを開き、アセンブリ コードのコンテキストを表示し、C++ ソース コード内でクラッシュしたコード行を見つけます。

4.1. IDA を使用して .so ダイナミック ライブラリ ファイルを開く

4.2. テキストビューテキストビューモードに切り替える

4.3. 関数に対する相対的なオフセットに従って、アセンブリ コード内の対応する位置を見つけ、近くのアセンブリ コンテキストを確認します。

4.4. アセンブリ コード コンテキストを通じて、対応する C++ ソース コードの場所を見つける

4.5. null ポインターを使用してクラスのメンバー関数を呼び出すと、関数呼び出し時にクラッシュするのはなぜですか?

5. 最後に


VC++共通機能開発まとめ(コラム記事一覧、購読歓迎、継続更新…)https://blog.csdn.net/chenlycly/article/details/124272585 C++ソフトウェア例外トラブルシューティング入門から習得までシリーズチュートリアル(コラム記事)リスト、購読へようこそ、更新し続けます...) https://blog.csdn.net/chenlycly/article/details/125529931エントリーからマスタリー事例集までの C++ ソフトウェア分析ツール (コラム記事は更新中...) https :/ /blog.csdn.net/chenlycly/article/details/131405795 C/C++ の基礎と上級 (コラム記事、継続的に更新されています...) https://blog.csdn.net/chenlycly/category_11931267.html       いつなのかを調査中ですソフトウェアに異常がある場合、問題の分析を支援するために、IDA 逆アセンブリ ツールを使用してバイナリ ファイルのアセンブリ コードを表示する必要がある場合があります。最近、IDA ツールを使用して Android システムのアプリ プログラムのクラッシュを確認しました。IDA を使用して .so ダイナミック ライブラリ ファイルを開いて、アセンブリ コード コンテキストと、自動生成された Tombstone ファイル内の情報を組み合わせて表示しました。 Android システム、ついにクラッシュの原因が判明しました。今日は、この問題の詳細な調査プロセスについて、参考または参考のためにお話します。

1. IDA ツールの概要

       IDA は、ベルギーの Hex-Rays Company によって製造された強力なインタラクティブな静的逆アセンブリ ツールです。バイナリ ファイルのアセンブリ コードを直接逆アセンブルすることができ、ソフトウェア リバース エンジニアリングおよびセキュリティ分析の分野で最高かつ最も強力な静的逆アセンブル ソフトウェアであり、多くのソフトウェア セキュリティ アナリストにとって不可欠なツールとなっています。Windows や Linux などの複数のプラットフォームをサポートし、Intel X84、X64、ARM、MIPS などの数十の CPU 命令セットをサポートします。IDA は、Windows プラットフォームで .dll ライブラリ ファイルを開くことをサポートするだけでなく、Linux プラットフォームで .so ライブラリ ファイルを開くこともサポートします。

IDA は、2005 年にベルギーで Hex-Rays を創立者兼 CEO として設立した才能あるロシアのプログラマー、llfak Guilfanov によって開発されました。

多くの人は、ロシアがソフトウェア分野で非常に強力で、才能のあるプログラマーが豊富な国であることを知らないかもしれません. たとえば、ここで話している最も強力な静的逆アセンブル ツール IDA はロシア人によって書かれました。人気の IDE 開発ツールIDEA、PyChram、WebStormの会社であるJetbrains は、 3 人の才能あるロシアのプログラマーによって設立されました。IT分野で広く使われているロードバランシングとリバースプロキシのオープンソースライブラリNginxと、ビッグデータの分野で有名なオープンソースライブラリClickHouseは、どちらもロシア人によって書かれています。

ロシア人は論理的思考が強く、偉大な数学者オイラーや元素周期表を発明した化学者メンデレーエフなど、ロシアには数学者や化学者がたくさんいます。

ファーウェイの自社開発データベースは GaussDB ( GaussDB )にちなんで名付けられ、ファーウェイのサーバーオペレーティングシステムは EulerOS ( EulerOS ) にちなんで名付けられました。偉人たちに敬意を表します!

2. 製品と問題のシナリオの説明

       この記事の問題は、組み込みハードウェア デバイスです。デバイスではAndroid システムが使用されており、アプリケーションがデバイス上で実行されています。アプリケーション プログラムの本体はJava で開発された Android アプリ プログラムであり、アプリ プログラムはC++ で実装された基盤となるビジネス モジュールを通じてリモート サーバーと通信します。

アプリ プログラムは、カプセル化された JNI インターフェイスを呼び出して、基になる C++ モジュールを操作します。この場合、基になる C++ モジュールでクラッシュが発生しました。クラッシュは基になる C++ モジュールで発生しましたが、基になる C++ モジュールはアプリ プログラムのプロセスでも実行されているため、アプリ プログラムのクラッシュに直接つながります。

       アプリプログラムがクラッシュすると、Android システムはそれを認識し、異常なクラッシュ情報を含むTombstone (トゥームストーン) ファイルを生成します。このファイルは、Linux システムで生成される CoreDump ファイルに似ています。ソフトウェアの異常なクラッシュを分析するとき、私たちは分析します。これらのファイルです。

       まずトゥームストーン ファイルを開き、異常クラッシュの特定の例外タイプとクラッシュ時の関数呼び出しスタックを確認しましたが、トゥームストーン ファイルを通じてわかるのは、どの関数でクラッシュが発生したかだけです。関数内のコードは次のとおりです。比較的長いため、クラッシュが発生した場所、どの行を特定することは不可能です。

       そのため、IDA を使用して関数呼び出しスタックに表示されている .so モジュール ファイルを開いてアセンブリ コードを表示し、クラッシュしたアセンブリ コード付近のコンテキストを確認し、最後にクラッシュした C++ ソース コードの行を見つけます。

3. トゥームストーン ファイルを表示する

       組み込みデバイスからクラッシュが発生したときに Android システムによって自動的に生成された Tombstone ファイルを取得し、ファイルを開くと、次の情報が表示されます。

まず第一に、現在のクラッシュの理由は次のとおりです。ヌル ポインター逆参照、ヌル ポインター参照、つまり、プログラム内でヌル ポインターを使用するとクラッシュが発生しますその直後、クラッシュが発生したときの関数呼び出しスタックを確認したところ、libxxservice_hddll.so ダイナミック ライブラリの CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp 関数でクラッシュが発生していることがわかりました。特定の関数名はコール スタックで確認でき、.so ダイナミック ライブラリ ファイルに関数シンボルがあることがわかります。ただし、特定のコード行番号は表示されず、関数 CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp に対する相対的なオフセットのみが表示されます。

#00 pc 0000000000075200 /xxxkyui/lib64/ libxxservice_hddll.so (CXXXServiceHMpHandler:: OnTextImageCreateBannerInfoRsp (mtmsg::CMtMsg*, unsigned int, unsigned int)+ 1048 ) (BuildId: d6e3064a3e1a03d9bea3c) 4496e78cb4942d187d1)

CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp 関数のコードは比較的長いため、コードのどの行でクラッシュが発生したかを特定できません。

もちろん、問題が避けられない場合、または再現が簡単な場合は、関数で使用されているすべてのポインターの値を出力する印刷を追加することができ、クラッシュ後にログを確認して確認することができます。ただし、一部の問題は再現が難しいため、いくつかの分析方法を習得する必要があります。

       特定の関数名と関数に対する相対オフセット (最初のアドレス) は関数呼び出しスタックから確認できるため、IDA 逆アセンブリ ツールを使用して、関数が配置されているモジュール libxxservice_hddll.so のアセンブリ コード コンテキストを表示できます。問題の特定を支援します。

4. IDA を使用して .so ダイナミック ライブラリ ファイルを開き、アセンブリ コードのコンテキストを表示し、C++ ソース コード内でクラッシュしたコード行を見つけます。

4.1. IDA を使用して .so ダイナミック ライブラリ ファイルを開く

       当社の組み込みハードウェアデバイスで使用されている Android システムは、メイン制御 CPU が ARM アーキテクチャに基づいており、プログラムのコードも ARM プラットフォームの環境でコンパイルされており、IDA 逆アセンブル ツールは ARM プラットフォームをサポートしているため、 IDA を直接使用してプログラムを開きます。バイナリはアセンブリ コードを表示します。

       Windows システム上で IDA を直接起動すると、次のウィンドウが表示されます。

「新規」ボタンをクリックして新しいファイルを逆アセンブルすると、メイン IDA ウィンドウがポップアップ表示されます。次に、libxxservice_hddll.so ファイルを IDA メイン ウィンドウに直接ドラッグして開くと、次のように 64 ビット IDA でファイルを開くように求められます。

libxxservice_hddll.so ダイナミック ライブラリは 64 ビット プログラムであるため、64 ビット IDA を使用して開きます。

先ほど 32 ビット IDA を開きました。

       したがって、デスクトップのショートカットからインストール パスを見つけ、そのパスで IDA の 64 バージョンを起動し、次に libxxservice_hddll.so を IDA メイン ウィンドウにドラッグし、次に示すようにバイナリ ファイルを開く形式を選択するためにポップアップします。

IDA はバイナリ ファイルの種類を自動的に認識し、デフォルトのファイル形式で開きます。

4.2. テキストビューテキストビューモードに切り替える

        バイナリ ファイルを開くと、デフォルトでグラフィック ビュー ビュー モードが表示されます。

 右クリックするには、次のように、ポップアップ右クリック メニューの [テキスト ビュー] メニュー項目をクリックしてテキスト モード ページに切り替えます。

4.3. 関数に対する相対的なオフセットに従って、アセンブリ コード内の対応する位置を見つけ、近くのアセンブリ コンテキストを確認します。

        まず、IDA によって表示されるアセンブリ コード内で CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp 関数が存在する場所を見つける必要があります。メニュー バーで [ジャンプ] -> [関数にジャンプ] をクリックして、次のウィンドウを開きます。

ウィンドウの下部にある [検索] ボタンをクリックし、ポップアップ ウィンドウに関数名 OnTextImageCreateBannerInfoRsp を入力します。

次に、「OK」ボタンをクリックし、関数リストで関数を検索し、それをダブルクリックして、以下に示すように関数のアセンブリ コードに直接ジャンプします。

Tombstone ファイルに表示される相対関数のオフセットによれば、この関数の関数アドレス (関数の最初のアドレス) は 0x0000000000074DE8 であることがわかります。

#00 pc 0000000000075200 /xxxkyui/lib64/ libxxservice_hddll.so (CXXXServiceHMpHandler:: OnTextImageCreateBannerInfoRsp (mtmsg::CMtMsg*, unsigned int, unsigned int)+ 1048 ) (BuildId: d6e3064a3e1a03d9bea3c) 4496e78cb4942d187d1)

新しいアドレスを計算します。

0x0000000000074DE8 + 0x418 (10 進数の 1048 に相当) =   0x0000000000075200

次に、IDA でアドレス 0x00000000000075200 を検索して、アセンブリ コードの対応する行を見つけます。具体的な方法は、アセンブリ コード ウィンドウ内でマウスをクリックし (ウィンドウにフォーカスを置きます)、ショートカット キー g を押すと、[アドレスへジャンプ] ウィンドウが表示され、上で計算したアドレス 0x0000000000075200 を入力します。

「OK」をクリックすると、以下に示すように、対応する行にジャンプします。

4.4. アセンブリ コード コンテキストを通じて、対応する C++ ソース コードの場所を見つける

       X86プラットフォームのアセンブリコードは見慣れていますが、ARMアーキテクチャのアセンブリコードは見慣れておらず、アセンブリ命令の名前にしても、レジスタの名前にしても、大きな違いがあります。X86プラットフォームのアセンブリコードの方が読みやすい気がします。

       上記のアセンブリ コード内の場所は特定できましたが、C++ ソース コードのどの行がそのアセンブリ コードに対応するのでしょうか? さらに、Release でコンパイルすると、コンパイラは C++ コードを最適化します (一部の変数または関数呼び出しが最適化される場合があります)。その結果、アセンブリ コードと C++ コードの間に不整合が生じます。

       アセンブリ コードを C++ ソース コードと一致させるにはどうすればよいですか? アセンブリコードを一文ずつ噛み砕いていきたいでしょうか? アセンブリコードの文脈を強制的に読み取るには、ある程度のアセンブリスキルが必要であり、一般人には困難です。一般に、アセンブリ コンテキストの注釈情報を使用して、読み取りを支援します。この例では、注釈情報を使用して、すばやく読み取り、特定します。

一般に、アセンブリ コードのコンテキストを読み取るときは、一方ではアセンブリ コード内のコメントを使用し、他方ではアセンブリ コードを C++ ソース コードと比較します。

       アドレス 0x0000000000075200 に対応するアセンブリ コード行、コード行のすぐ下のコメントは定数値文字列のコメントです。

しかし、完全な文字列は表示されません。ここにはトリックがあります。マウスを変数の上に移動すると、以下に示すように、変数の完全な内容がトゥーチップの形式で表示されます。

この場所は偶然で、このような文字列がログに出力されるので、C++ ソース コードで CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp 関数を見つけ、関数内で「[CXXXServiceHMpHandler::OnTextImageCreateBannerInfoRsp] ディスパッチ」の出力を見つけます。確かにこの行の印刷は次のようになります。

そこで、アドレス 0x0000000000075200 に対応する C++ ソース コードの近似行を見つけたので、この例における null ポインタの問題は、上図の ptTip ポインタ、つまりポインタの値が null であるはずです。このポインタを使用して値インターフェイスを呼び出すとクラッシュが発生しました。

       IDA ツールの紹介と詳細な手順については、以前の記事を参照してください。

IDA 逆アセンブリ ツールの使用方法の詳細な説明https://blog.csdn.net/chenlycly/article/details/120635120 IDA を使用してアセンブリ コード コンテキストを表示し、C++ ソフトウェア例外のトラブルシューティングに役立てるhttps://blog.csdn.net /chenlycly/article/details/128942626逆アセンブリ ツール IDA を使用して異常なアセンブリ コードのコンテキストを表示し、C++ ソフトウェア例外の分析に役立てますhttps://blog.csdn.net/chenlycly/article/details/132158574

4.5. null ポインターを使用してクラスのメンバー関数を呼び出すと、関数呼び出し時にクラッシュするのはなぜですか?

       関数呼び出し時にクラッシュするのはなぜですか? 呼び出される関数が通常の関数 (非仮想関数) の場合、通常、関数呼び出しはクラッシュしませんが、関数内でクラスのメンバー変数にアクセスする場合、null ポインターを使用した呼び出しは呼び出された関数内でクラッシュします。通話機能がクラッシュします!

       呼び出された関数が 仮想関数 である可能性があります。仮想関数の呼び出しでは、仮想関数のアドレスが 2 次アドレス指定 (仮想関数コード セグメント アドレス、ここでは必要です) を通じて仮想関数テーブル内で見つかる必要があります。コード セグメント アドレスとデータ セグメント アドレスを区別するため)、セカンダリ アドレッシングのプロセスで、メモリにアクセスするためのメモリ アドレスとしてヌル ポインタが使用されます。これにより、メモリ アクセス違反が引き起こされ、クラッシュが発生します。

       別のケースでは、大きなスタック メモリを占有するローカル変数が呼び出された関数で定義されており(ローカル変数を定義するために大規模な定義を持つ構造体を使用するなど)、現在のスレッドのスタック オーバーフロー(占有されているスタック スペース)現在のスレッドは、スレッドの作成時に割り当てられるスタック領域の上限に達します)。この種のスレッド スタック オーバーフローのシナリオでは、関数が呼び出された場所でクラッシュする可能性があり、プロジェクト内でこの種の問題が発生しました。

5. 最後に

       この記事では、Tombstone ファイルと IDA 逆アセンブリ ツールを組み合わせて、クラッシュの完全なプロセスを迅速に特定する方法について詳しく説明し、皆様に参考と参考になれば幸いです。さらに、この質問では、IDA 逆アセンブリ ツールの使用方法について詳しく説明します。

おすすめ

転載: blog.csdn.net/chenlycly/article/details/132283582
おすすめ