9

私は現在、別の位置に移動されたコードが変数とクラスポインターを読み取る、32ビットのコード置換スキームを使用しています。x86_64は絶対アドレス指定をサポートしていないため、コードの新しい位置にある変数の正しいアドレスを取得するのに問題があります。詳細な問題は、相対アドレス指定がリップであるため、命令ポインタアドレスがコンパイル時とは異なることです。

それで、x86_64で絶対アドレス指定を使用する方法、または命令ポインタ相対ではなく変数のアドレスを取得する別の方法はありますか?

次のようなものleaq variable(%%rax), %%rbxも役立ちます。命令ポインタに依存したくないだけです。

4

2 に答える 2

7

x86_64のラージコードモデルを使用してみてください。gccでは、これは-mcmodel=largeで選択できます。コンパイラは、コードとデータの両方に64ビットの絶対アドレス指定を使用します。

-fno-picを追加して、位置に依存しないコードの生成を禁止することもできます。

編集:-mcmodel = largeを使用して小さなテストアプリを作成しましたが、結果のバイナリには次のようなシーケンスが含まれています

400b81:       48 b9 f0 30 60 00 00    movabs $0x6030f0,%rcx
400b88:       00 00 00 
400b8b:       49 b9 d0 09 40 00 00    movabs $0x4009d0,%r9
400b92:       00 00 00 
400b95:       48 8b 39                mov    (%rcx),%rdi
400b98:       41 ff d1                callq  *%r9

これは、絶対64ビット即時(この場合はアドレス)の負荷と、それに続く間接呼び出しまたは間接負荷です。命令シーケンス

moveabs $variable, %rbx
addq %rax, %rbx

これは「leaqoffset64bit(%rax)、%rbx」(存在しない)と同等ですが、フラグの変更などのいくつかの副作用があります。

于 2011-11-02T12:24:50.310 に答える
2

あなたが求めていることは実行可能ですが、それほど簡単ではありません。

これを行う1つの方法は、命令内のコードの移動を補正することです。RIP相対アドレス指定を使用するすべての命令(ModRM05h、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レジスタにフラグを設定して、すべての命令の実行の最後にRFLAGSCPUにsingle-stepデバッグ割り込みを生成させることによって、命令の境界を見つけることもできます。デバッグ例外ハンドラーはそれらをキャッチし、次の命令のRIPの値を記録する必要があります。これはWindowsで実行できると思いStructured Exception Handling (SEH)ます(デバッグ割り込みで試したことはありません)。Linuxについてはよくわかりません。これを機能させるには、すべてのコード、すべての命令を実行する必要があります。

ところで、64ビットモードには絶対アドレス指定があります。たとえば、0A0hから0A3hまでのオペコードを使用したアキュムレータ命令との間のMOVを参照してください。

于 2011-11-02T12:24:34.870 に答える