(これは、Adam Rosenfieldsソリューションが適用できないことを前提としています。これ、または同様のアプローチが、おそらくそれを解決するためのより良い方法です。)
%gsレジスタをエミュレートする方法については説明していませんが、プログラムに関する特別な知識がない限り、一般的にすべての使用法にパッチを適用するのは難しいでしょう。一般的なケース)パッチで変更できます。もちろん、%es =%gsのようなものを使用している場合は、比較的簡単なはずです。
これが何らかの形で機能するようにできると仮定すると、戦略はELFファイルの実行可能セクションをスキャンし、GSレジスタを使用または変更する命令にパッチを適用することです。それは少なくとも次の指示です:
- GSセグメントオーバーライドプレフィックスを持つすべての命令(
65
分岐命令を想定します。この場合、プレフィックスは他の何かを示します)
push gs
(0F A8
)
pop gs
(0F A9
)
mov r/m16, gs
(8C /r
)
mov gs, r/m16
(8E /r
)
mov gs, r/m64
(REX.W 8E /r
)(64ビットモードをサポートしている場合)
そして、セグメントレジスタを許可する他の命令(私はそれ以上ではないと思いますが、100%確信はありません)。
これはすべて、インテル®64およびIA-32アーキテクチャーソフトウェア開発者マニュアルの結合ボリューム2Aおよび2B:命令セットリファレンス、AZからのものです。命令の接頭辞が他の接頭辞である場合とそうでない場合があることに注意してください。したがって、バイトシーケンスを盲目的に検索するのではなく、ライブラリを使用して命令のデコードを行う必要があります。
上記の手順のいくつかは、比較的簡単に変換call my_patch
または類似する必要がありますが、2バイトに収まり、一般的に機能するものを見つけるのに苦労する可能性があります。int XX
(CD XX
)は、割り込みベクトルを設定できる場合は良い候補かもしれませんが、現在使用している方法よりも高速になるかどうかはわかりません。もちろん、パッチが適用された命令を記録し、(ハンドラーが受け取る)リターンアドレスに応じて割り込みハンドラー(またはその他)の反応を変える必要があります。
-128..127バイト以内にスペースが見つかった場合は、トランポリンをセットアップし、JMP rel8
(EB cb
)を使用してトランポリン(通常は別のJMP
、ただし今回はターゲットアドレス用のスペースがあります)にジャンプして、命令を処理できる場合があります。エミュレーションを行い、パッチを適用した%gsの使用法に従って命令に戻ります。
最後に、トラップアンドエミュレートコードを実行したままにして、思いもよらなかった可能性のあるケース(たとえば、自己変更コードや挿入コード)をキャッチすることをお勧めします。このようにして、未処理のケースをログに記録し、ソリューションに追加することもできます。