あなたが求めていることは実行可能ですが、それほど簡単ではありません。
これを行う1つの方法は、命令内のコードの移動を補正することです。RIP相対アドレス指定を使用するすべての命令(ModRM
05h、0dh、15h、1dh、25h、2dh、35h、または3dhのバイト)を見つけて、disp32
移動量に応じてフィールドを調整する必要があります(したがって、移動は仮想アドレス空間では+/-2GBに制限されていますが、64ビットアドレス空間が4GBより大きい場合、これは保証されない可能性があります。
これらの命令を同等のものに置き換えることもできます。たとえば、次のように、すべての元の命令を複数に置き換えることができます。
; These replace the original instruction and occupy exactly as many bytes as the original instruction:
JMP Equivalent1
NOP
NOP
Equivalent1End:
; This is the code equivalent to the original instruction:
Equivalent1:
Equivalent subinstruction 1
Equivalent subinstruction 2
...
JMP Equivalent1End
どちらの方法でも、少なくともいくつかの基本的なx86逆アセンブリルーチンが必要になります。
前者はVirtualAlloc()
、元のコードのパッチが適用されたコピーを含むメモリがその元のコードの+/- 2GB以内であることを保証するために、Windows(またはLinuxでは同等のもの)での使用を必要とする場合があります。また、特定のアドレスでの割り当ては依然として失敗する可能性があります。
後者は、プリミティブな分解だけでなく、完全な命令のデコードと生成も必要とします。
回避すべき他の癖があるかもしれません。
TF
レジスタにフラグを設定して、すべての命令の実行の最後にRFLAGS
CPUにsingle-step
デバッグ割り込みを生成させることによって、命令の境界を見つけることもできます。デバッグ例外ハンドラーはそれらをキャッチし、次の命令のRIPの値を記録する必要があります。これはWindowsで実行できると思いStructured Exception Handling (SEH)
ます(デバッグ割り込みで試したことはありません)。Linuxについてはよくわかりません。これを機能させるには、すべてのコード、すべての命令を実行する必要があります。
ところで、64ビットモードには絶対アドレス指定があります。たとえば、0A0hから0A3hまでのオペコードを使用したアキュムレータ命令との間のMOVを参照してください。