2012-12-25 4 views
5

私は、プログラムのある時点で実行されるいくつかのコードのアセンブリコードを持っています。 メモリ内のコードのアドレスがわかりません。gdb内の特定のオペコードで命令をブレーク

現在の命令が入力された命令と一致するときにgdbを中断させることはできますか?例えば

私は、GDBは、この命令に到達するたびに分割するgdbをしたい:

leaq  0x000008eb(%rip),%rax 

答えて

2

いいえ、これが不可能であり、また、実装するのは非常に非効率的だろう。

デバッガの通常のブレークポイントの2種類のサポート:

  • をハードウェアがをブレークポイント:メモリ内のいくつかの場所が変更されたように、デバッガは、いくつかのイベントが発生したときに特別な例外割り込みを上げるためにCPUを要求します。
  • ソフトウェアブレークポイント:デバッガはブレークポイントのアドレスのオペコードを特別な "トラップ"命令(x86アーキテクチャではint 3/0xcc)に置き換えます。

現在の命令のオペコードを一致させると、ハードウェアブレークポイントを挿入するためのCPUサポートが必要になるか、ソフトウェアブレークポイントを使用するためにデバッガがアドレスを知る必要があります。

理論上、デバッガは命令のバイトシーケンスをメモリ全体で検索するだけで、命令またはデータの途中でバイトシーケンスが発生する可能性があるため、誤検出が発生する可能性があります。

アセンブリ命令は可変長であるため、任意のアドレスにジャンプしたり、コード自体を修正したりすることができます。メモリ領域全体を逆アセンブルして特定の命令を見つけるのも簡単ではありません。

基本的に、任意のアセンブリコードで確実に命令を見つける唯一の方法は、命令レベルでシングルステッピングすることです。これは非常に高価なものになります。すべての命令を一歩一歩実行すれば、今日のハードウェアではprintf()などの些細な図書館の呼び出しでも数分かかることがあります。

+0

* - 私はこれについてはよく分かりません。純粋な実装は、実行時に各ニーモニックを比較する文字列のように非効率的な場合があります。しかし、ロシアの雇用者が示唆したことをGDBに要請するのは合理的だと思われる。私の場合は、 'CPUID'の呼び出しを打ち切りたいと思います。たった4〜5回の呼び出ししかないので、GDBのように、雇用されたロシア語が私には完璧だと思ったので、時間を無駄にする必要はありません。 – jww

2

I don't know the address of the code in memory.

あなたはそのアドレスを見つけることを妨げる原因は何ですか? objdump -dを実行し、目的の命令を見つけ、そのアドレスを書き留めます。問題が解決しました? (これは共有ライブラリにも同様に拡張されています)

+1

これはQuickLookプラグインなので、どのように読み込まれて呼び出されるのか分かりません。 – Tyilo

+0

GDBがこれをやってしまうのを防ぐには? – jww

6

ハードウェアのサポートがないため、効率的に実行することは不可能です。

しかし、あなたが本当にそれをしたい場合は、このPythonコマンドは、出発点としての役割を果たすことができます。

class ContinueI(gdb.Command): 
    """ 
Continue until instruction with given opcode. 

    ci OPCODE 

Example: 

    ci callq 
    ci mov 
""" 
    def __init__(self): 
     super().__init__(
      'ci', 
      gdb.COMMAND_BREAKPOINTS, 
      gdb.COMPLETE_NONE, 
      False 
     ) 
    def invoke(self, arg, from_tty): 
     if arg == '': 
      gdb.write('Argument missing.\n') 
     else: 
      thread = gdb.inferiors()[0].threads()[0] 
      while thread.is_valid(): 
       gdb.execute('si', to_string=True) 
       frame = gdb.selected_frame() 
       arch = frame.architecture() 
       pc = gdb.selected_frame().pc() 
       instruction = arch.disassemble(pc)[0]['asm'] 
       if instruction.startswith(arg + ' '): 
        gdb.write(instruction + '\n') 
        break 
ContinueI() 

だけでそれをソース:

source gdb.py 

として次のコマンドを使用します。

breaki mov 
breaki callq 

あなたは与えられたオペコードで実行された第1の命令のままになります。

TODO:これはあなたの他のブレークポイントを無視します。

syscallの特定の一般的なケースでは、あなたがcatch syscallを使用することができます「...そして、また、実装するのは非常に非効率的だろう」* https://reverseengineering.stackexchange.com/questions/6835/setting-a-breakpoint-at-system-call

+0

*ハードウェアのサポートがないので効率的に行うことは不可能です。* - 関数名を壊すハードウェアサポートはありませんが、GDBはそれをやる。 – jww

+0

@jww厳密に言えばあなたは正しいとは言えますが、GDBはもちろんテキストセクション全体を解析して、すべてのオペコードにソフトウェアブレークポイントを設定することができます。これはPythonで簡単に行うことができます。それとも、私がやっているようなシングルステップができます。しかし、それはいくつかの関数を見つけてそこにブレークポイントを置くためにシンボルテーブルを調べるよりもはるかに時間がかかるでしょう。また、1つの関数名に対して数千のオペコードが存在するため、以前にブレークポイントを設定しても実行が遅くなります。 –

+0

@jwwまた、プロセッサがすでにオペコードを解析しているので、ハードウェアサポートが可能であるため、これは言及する価値があると思います。しかし、ハードウェアサポート関数のブレークポイントには、ELF解析プロセッサが必要です:-) –

関連する問題