これは、文書を要約ので、侵害は、私に連絡してください場所を持っている必要があり、学ぶに開示されているので、杭州総会前任者のドキュメントを学ぶための主要オペレーティングシステムである、あなたに感謝します
.................................................. .................................................. .................................................. .................................................. ...................
問題:
クライアントサイトのマシンは、偶然またはダブルフリーの問題、CPUはおそらく、腕、MIPS、x86アーキテクチャなど、例外ログをキャプチャするためにどのような良い方法によって起こる週に一度かミスので、アプリケーションを実行しますか?
難易度ポイント:
1. R&D環境は、多くの場合、このような問題でも、顧客のサイトや他の非電流アプリケーションの開発環境を解決するために、GDB +コアダンプ技術を使用して、異常な使用が困難であり、操作するためのいくつかの困難があります
2.異なるアーキテクチャ(arm32、arm64、MIPS、x86の)、CライブラリとGDBの異なるバージョン、大きなスタックトレースバック異なる効果。PC Ubuntuのシステムテスト、glibcの2.15は、世代のアプリケーションは、このテストは他のアーキテクチャのCPU上で機能しない、自由、ダイレクト印刷スタックトレース情報を倍増します。セクションのテストarm64アーキテクチャのCPU、アプリケーションオフストリップへのGDBは、スタックトレースバックすることはできません、PC Ubuntuのシステムのテストは、この問題はありません。
原理バックトラックスタック
プッシュ動作を行う場合、LRとFPレジスタの値がスタックに格納されており、機能は、スタックの最上位にスタックポイントレジスタFPように、本実施形態は、第2のシート束の関数メモリアドレス(ローカル関数の変数)です。レジスタ・スタック機能に記憶されたデータLR抽出スタックバック、第1のアドレスレジスタポイントFP、FPとは、LRリターンアドレス値FPの値の関数である場合、スタックアドレスにスタックの関数であります
1.スタックポインタR13(SP)は:各例外モードは、独自の独立したR 13を有し、それは通常、異常なパターン、非異常パターン(ユーザモードとシステムモード)の5種類を言うことである専用小数点例外モードスタック、あります、
独自の独立したスタック、異なるインデックス付きでスタックポインタを持っています。例外モードARMしたがって、プログラムは、汎用レジスタ、戻りスタックとスタック上に置くことができる場合には、様々なモードでプログラム状態の整合性を確保 2.接続レジスタR14(LR):各モードR14の下に二つの特別な機能を持つグループ、独自のバージョンがある (1 サブルーチンの戻りアドレスを保存するために)。BLまたはBLXを使用している場合,,自動的R14でのリターンアドレスにジャンプ命令、サブルーチンをコピーしてR14がPC達成するために戻るには (2 例外が発生した場合、例外モードがR14異常リターンアドレスを保存するために)、R14スタックとしてネストされた割り込みを処理することができます。 3、プログラムカウンタR15(PC):PCを読み取り、書き込みが制限されています。ときに
制限時間が読み取られる超えない、読み出し値が指示プラス8バイトのアドレスである、ARM命令は常にワード境界で整列するので、「ビットので、[ 1:0 ]は常に00です。
PCまたはストレージSTMを使用する場合、STR、他のオフセット値、8または12が存在してもよいです
Unwind_frame機能:フレーム - > PC = *(unsigned long型*)(FP + 8)機能命令アドレス、現在の関数の、すなわちリターンアドレスを計算します。フレーム - > FP = *(unsigned long型*)(FP)は、スタックアドレスのスタックに基づいて計算されます
> TEST_B() - - > test_a()、test_a()関数は、カーネルが自動的にdo_page_fault実行する構造の(......、構造体pt_regsは* REGS)機能、REGS、エラーが発生したバーストと仮定アプリケーション機能実行処理はtest_c()であります - > PCが0x400538、regs-> REGS [29]である場合、()関数の命令アドレスをtest_aミスが発生され、FPレジスタです。カーネルスタックセグメントの誤用バックを達成するためにどのように?
アプリケーション・スタック・セグメントへ:(ポリシーエラーバック)
do_page_fault機能、バックミスのアプリケーション・スタックは、図に示すコードを実装するunwind_frame機能、増加user_unwind_frame機能を模倣。test_a関数の戻りアドレスを解析すると仮定して、スタックをバックトラックした後(TEST_B関数で)0x400550は、バックスタックスタックtest_a関数からTEST_B関数の戻りアドレスを検索し続ける(test_c関数で)0x400588であります
このカーネルdo_page_fault、スタックをバックトラックアプリケーションセグメント・エラー、次のように印刷処理が実行される: ユーザスレッドのbackstraceの PC1:0x400538 PC2:0x400550 PC3:0x400588
関数呼び出しを知ることができ、分解プロセスがtest_c後() - > TEST_B() - > test_a()。この方法はまた、最適化するのに続けることができます:do_page_faultや機能、アプリケーションのスタックトレースバック処理は、実行可能なELFファイルの情報を読んで、アドレスが配置されている命令の関数の名前を分析し、プリントアウト。特にELFファイルのセクションのデータ部には、原則ELF実行可能プログラムファイルデータ配信を使用するには、この必要性
読むエルフカーネル「の.symtab」と、データの「.strtab」セクションで、実行可能ファイルに、あなたは(test_cファイルを分析することができます)、TEST_B()、test_a()関数名の3つの文字列、関数最初のアドレスを実行し、機能命令はバイト。データなど
機能命令アドレスの機能最初の命令アドレスの関数名の末尾 test_c 0x400518 0x400518 + は0x27 TEST_B 0x400545 0x400545 + 0x35の
ユーザスレッドbackstrace [ < 0x400538 >] test_a + 0x20の / は0x27 [ < 0x400550 >] TEST_B + 0x0Bの / 0x35の [ < 0x400588 >] test_c + 0x08の / の0x20
分析例
する#include <stdio.hに> する#include <STDLIB.H> CHAR BUF [ 5 ]。 INT test_a() { のprintf(" %sの\ n " 、__func__)。 memcpy(BUF、" 12345677 "、7 )。 リターン0 ; } int型TEST_B() { のprintf(" %sの\ n " 、__func__)。 memset(BUF、0、はsizeof (BUF))。 test_a(); リターン0 ; } INT { test_c() printf(" %sの\ n " 、__func__)。 睡眠(1 )。 TEST_B(); リターン 0 ; } int型のmain() { のprintf(" %sの\ n " 、__func__)。 test_c(); リターン 0 ; }
例では、実証試験プログラムの実行可能コードの使用が他のライブラリ関数のmemcpyされ、本実施形態では、libc.soにCライブラリ関数です。
使用されるライブラリ関数の名前を含む「.Dynstr」セクションの実行可能ファイルは、データの「.dynsym」セクションは、一の構造体elf64_sym構造、構造に使用されるライブラリ関数に対応する各あります。以下のように発現ライブラリ機能情報部2は一個です。
ibc.so「.dynstr」セクションのライブラリファイルがCライブラリ関数ライブラリ名のすべてが含まれ、「.dynsym」セクションは、各々がCライブラリ関数ライブラリ構造に対応する構造体elf64_symのデータ構造であります
libc.so構造の構造体elf64_symにおけるライブラリ関数の「.dynsym」セクションで、st_valueは元のライブラリ関数は、最初のアドレスは、st_size命令はライブラリ関数であるバイトです。なぜ、元の最初のアドレスはありますか?実行可能プログラムは、Cライブラリ関数を呼び出すため、Cライブラリ関数は、次に、一度リダイレクトアプリケーションスペース実行可能プログラムにマッピングされ、最後に命令コードCライブラリ関数を実行します
。1 ".PLT" sectionTopアセンブリコード 2 0000000000400480 <PLT @のmemcpy> : 3 ............ .. 4。 400 484:f944fa11 LDR X17、[X16、#2544 ] 5。 400 488:追加9127c210 X16、X16、#0x9f0 6。 40048c: d61f0220 BR X17
。1 コードアセンブラtest_A機能 2 0000000000400650 <test_A> : 3。 400650:a9bf7bfd STP X29、X30、[SP、# - 16 ]! 4 400 654 :MOV 910003fd X29、SP 5 ..................... 。6 400 660:BL 97ffffa0 4004e0 <PLTプットを@> 7。 .................. 8。 400 678:97ffff82 BL 400480 <PLTのmemcpy @>
アセンブリコード、実行のmemcpy関数としてTest_a関数は、実際のmemcpy @ PLT関数の「.PLT」セクションを実行することです。関数は、コードコンパイルされるのmemcpy @ PLT、LDRのX17、[X16、#2544] X17レジスタに格納されたアドレスデータを削除し、メモリアドレス0x410a38のライブラリ関数算出された実際の操作アドレス「.got.plt」セクションのmemcpy。ある右、上で示したように、保存し、memcpyのBR X17にジャンプするメモリセル0x7f91db5a40オレンジX17のデータは、実際のライブラリ関数の先頭アドレス、機能実行コードであります
どのように使用するには:
現時点ではそのような値として、Cライブラリでのクラッシュは、0x7f91db5a60 PCであるとき、私たちは、あなたがどのように知っているように、ライブラリ関数で0x7f91db5a60を知ることができるように、最初と最後のアドレスで実行libc.soがすべてのライブラリの関数を知っている可能性がある場合Cライブラリスタックバックアップ。
具体的な方法:
- クラッシュへのmemcpyは、例えば、構造体のmemcpyライブラリ関数elf64_sym構造を見つけるために、ファイルのセクションlibc.so「.dynsym」から、元の構造のst_valueはメンバーは、ライブラリ関数のmemcpyの最初のアドレスであります
- ランタイムライブラリ関数の最初のアドレスを見つけるために実行可能プログラム「.got.plt」セクションからmemcpyの最初のアドレスを実行し、memcpyのマイナス元のアドレスはDXという名前の、最初のアドレスと、元のランタイムライブラリ関数の最初のアドレスとの間の第1の差であります
- Libc.soすべてのライブラリ関数elf64_sym構造は、第一のアドレスの各元のライブラリ関数を知っている構造体から分離され、先頭アドレス+ dxがランタイムライブラリ関数がアドレスを終了知っst_size合わせ各ライブラリ関数の先頭アドレスの元の実行、あります。そして、ファイルlibc.so「.dynstr」セクションからは、それぞれのライブラリ関数の名前を知っています。したがって、各ライブラリ関数の最初の実行、アドレスの最後に、関数の名前のアドレスを知っている、それはスタックトレースのための条件を持っています
二重の無料アプリケーション:
ダブルフリーCライブラリは、現在のプロセスにSIGABRT信号を送る次に、異常を検出し、その後、カーネル空間を入力され、do_send_specificに信号を送信する機能を実行します。この関数では、それは二重フリーアプリケーションフロースタックバックトレースは、以下のために、カーネル空間PC、LR、FP他のレジスタtask_pt_regs(電流)、及びこれらのバックトレースの原理を使用するに入る前に、異常取得処理、SIGABRT信号を検出デモンストレーションであります効果。
デモンストレーション効果
test_aアプリケーション機能は、二回の無料ライブラリ関数を呼び出した後、カーネルの印刷:
[<0x7f91dxxxx>]レイズ()0x38 / 0x78と [ <0x7f91dxxxx>]アボート()0x1b0 / 0x308 [ < 0x000400538 >] test_a()0x6c / 0xA4の [ < 0x000400550 >] TEST_B()の0x20 / 0x458 [ < 0x000400588 >] test_c ()の0x20 / 0x64