5

iOSタグを入れましたが、Core i7 MacBook Pro(x86-64ですよね?)のシミュレーターで動かしているので、大したことないと思います。

現在、Flurry の動画広告のクラッシュをデバッグしています。Objective-C の例外にブレークポイントを設定しています。ブレークポイントに到達すると、私はobjc_msgSend. コールスタックには、Flurry と iOS のプライベート メソッドが混在しており、公開されているものも、私が書いたものもありません。スタック フレームregister readから 呼び出すと、次のように出力されます。objc_msgSend

(lldb) register read
General Purpose Registers:
       eax = 0x1ac082d0
       ebx = 0x009600b5  "spaceWillDismiss:interstitial:"
       ecx = 0x03e2cddb  "makeKeyAndVisible"
       edx = 0x0000003f
       edi = 0x0097c6f3  "removeWindow"
       esi = 0x00781e65  App`-[FlurryAdViewController removeWindow] + 12
       ebp = 0xbfffd608
       esp = 0xbfffd5e8
        ss = 0x00000023
    eflags = 0x00010202  App`-[FeedTableCell setupVisibleCommentAndLike] + 1778 at FeedTableCell.m:424
       eip = 0x049bd09b  libobjc.A.dylib`objc_msgSend + 15
        cs = 0x0000001b
        ds = 0x00000023
        es = 0x00000023
        fs = 0x00000000
        gs = 0x0000000f

この出力についていくつか質問があります。

  • $ebx にはクラッシュの原因となったセレクターが含まれており、$edi は最後に実行されたメソッドであると想定しました。そうですか?
  • $eip はクラッシュした場所です。それは通常そうですか?
  • $eflags は、私が知る限り、このクラッシュとは何の関係もないインスタンス メソッドを参照しています。それは何ですか?
  • これらのレジスタからこじ開けることができる他の情報はありますか?
4

1 に答える 1

1

iOS/Objective-C フレーム レイアウトについて具体的に話すことはできないため、EBX と EDI に関するご質問にはお答えできません。しかし、EIP と EFLAGS に関してはお手伝いできますし、ESP/EBP とセレクター レジスターに関する一般的なヒントを提供することもできます。(ちなみに、シミュレーターは 32 ビットの x86 環境をシミュレートしています。レジスターの長さが 32 ビットであるため、それがわかります。)

EIP は命令ポインタレジスタで、プログラム カウンタとも呼ばれ、現在実行中のマシン命令のアドレスが含まれています。したがって、プログラムがクラッシュした場所、またはより一般的には、プログラムがブレークポイントに達したり、コアをダンプしたりしたときの場所を示します。

EIP は保存され、関数呼び出しを実装するために復元されます (マシン コード レベルで -- インライン化により、高レベル言語呼び出しが実際の呼び出しを実行しない可能性があります)。メモリが安全でない言語では、スタック バッファ オーバーフローが命令ポインタの保存された値を上書きし、リターン命令が間違った場所に戻る可能性があります。運が良ければ、上書きされた値は次のメモリ フェッチで segfault をトリガーしますが、EIP の値は任意であり、問​​題のデバッグには役に立ちません。運が悪ければ、攻撃者が有用なコードを指すように新しい EIP を作成したため、多くの環境では「スタック Cookie」または「カナリア」を使用して、保存/上書きされた EIP を復元する前にこれらの上書きを検出します。この場合、EIP 値は使える。

EFLAGSはメモリ アドレスではなく、間違いなく汎用レジスタではありません。EFLAGS の各ビットは、さまざまな命令によって設定またはテストできるフラグです。最も重要なフラグはキャリー、ゼロ、および符号フラグで、算術命令によって設定され、条件分岐に使用されます。デバッガーはそれをメモリ アドレスと誤って解釈し、最も近い関数として表示していますが、実際にはクラッシュとは関係ありません。(これ+ 1778は景品です。これは、EFLAGS が関数に 1778 バイトを指すことを意味しますが、関数が実際に 1778 バイトの長さになる可能性は低いです。)

ESP はスタック ポインターであり、EBP は (通常) フレーム ポインター (ベース ポインターとも呼ばれます) です。これらのレジスタは、コール スタック上の現在のフレームをバインドします。通常、デバッガーは、これらのポインターに基づいて、スタック変数の値と現在の呼び出しスタックを表示できます。破損した場合は、スタックを手動で検査して EBP を回復し、コール スタックを手動で巻き戻すことができる場合があります。コードはフレーム ポインタなしでコンパイルできることに注意してください (フレーム ポインタの省略)。これにより、EBP を他の用途に解放できます。汎用レジスタがほとんどないため、これは x86 では一般的です。

SS、CS、DS、ES、FS、および GS は、セグメンテーションを実装するためにページングが行われる前の悪い時代に使用されたセグメント セレクターを保持します。現在、FS と GS は、プロセスとスレッドの状態ブロックのためにオペレーティング システムで一般的に使用されています。これらは、x86-64 に引き継がれた唯一のセレクター レジスタでした。セレクタ レジスタは、通常、デバッグには役立ちません。

于 2014-10-06T14:26:58.787 に答える