私は、プログラムのある時点で実行されるいくつかのコードのアセンブリコードを持っています。 メモリ内のコードのアドレスがわかりません。gdb内の特定のオペコードで命令をブレーク
現在の命令が入力された命令と一致するときにgdbを中断させることはできますか?例えば
私は、GDBは、この命令に到達するたびに分割するgdbをしたい:
leaq 0x000008eb(%rip),%rax
私は、プログラムのある時点で実行されるいくつかのコードのアセンブリコードを持っています。 メモリ内のコードのアドレスがわかりません。gdb内の特定のオペコードで命令をブレーク
現在の命令が入力された命令と一致するときにgdbを中断させることはできますか?例えば
私は、GDBは、この命令に到達するたびに分割するgdbをしたい:
leaq 0x000008eb(%rip),%rax
いいえ、これが不可能であり、また、実装するのは非常に非効率的だろう。
デバッガの通常のブレークポイントの2種類のサポート:
int 3
/0xcc
)に置き換えます。現在の命令のオペコードを一致させると、ハードウェアブレークポイントを挿入するためのCPUサポートが必要になるか、ソフトウェアブレークポイントを使用するためにデバッガがアドレスを知る必要があります。
理論上、デバッガは命令のバイトシーケンスをメモリ全体で検索するだけで、命令またはデータの途中でバイトシーケンスが発生する可能性があるため、誤検出が発生する可能性があります。
アセンブリ命令は可変長であるため、任意のアドレスにジャンプしたり、コード自体を修正したりすることができます。メモリ領域全体を逆アセンブルして特定の命令を見つけるのも簡単ではありません。
基本的に、任意のアセンブリコードで確実に命令を見つける唯一の方法は、命令レベルでシングルステッピングすることです。これは非常に高価なものになります。すべての命令を一歩一歩実行すれば、今日のハードウェアではprintf()
などの些細な図書館の呼び出しでも数分かかることがあります。
ハードウェアのサポートがないため、効率的に実行することは不可能です。
しかし、あなたが本当にそれをしたい場合は、この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
*ハードウェアのサポートがないので効率的に行うことは不可能です。* - 関数名を壊すハードウェアサポートはありませんが、GDBはそれをやる。 – jww
@jww厳密に言えばあなたは正しいとは言えますが、GDBはもちろんテキストセクション全体を解析して、すべてのオペコードにソフトウェアブレークポイントを設定することができます。これはPythonで簡単に行うことができます。それとも、私がやっているようなシングルステップができます。しかし、それはいくつかの関数を見つけてそこにブレークポイントを置くためにシンボルテーブルを調べるよりもはるかに時間がかかるでしょう。また、1つの関数名に対して数千のオペコードが存在するため、以前にブレークポイントを設定しても実行が遅くなります。 –
@jwwまた、プロセッサがすでにオペコードを解析しているので、ハードウェアサポートが可能であるため、これは言及する価値があると思います。しかし、ハードウェアサポート関数のブレークポイントには、ELF解析プロセッサが必要です:-) –
* - 私はこれについてはよく分かりません。純粋な実装は、実行時に各ニーモニックを比較する文字列のように非効率的な場合があります。しかし、ロシアの雇用者が示唆したことをGDBに要請するのは合理的だと思われる。私の場合は、 'CPUID'の呼び出しを打ち切りたいと思います。たった4〜5回の呼び出ししかないので、GDBのように、雇用されたロシア語が私には完璧だと思ったので、時間を無駄にする必要はありません。 – jww