あなたは最も重要な部分を見逃しました、これは32ビットまたは64ビットのコードですか?いずれにせよ、コードプロジェクトには、両方をカバーする優れたランダウンとライブラリがあります。
この「昔ながらの」ことをしたいのなら、それは非常に簡単に行うことができます。
まず、フックする関数の仮想アドレスを見つける必要があります(ASLRのため、同じ場所にあることに依存しないでください)。これは通常、関数のRVA+モジュールベースロードアドレスを使用して行われます。エクスポート、エクスポートされた関数には、を使用できますGetProcAddress
。
そこから、タイプフックは何を達成したいかによって異なります。あなたの場合、2つの方法があります。
- ターゲット関数のプロローグで関数にジャンプ/呼び出しをパッチします
- フックしたい関数にすべての呼び出しサイトにパッチを適用し、関数にリダイレクトします
1つ目は単純ですが、一般にインラインアセンブリが必要になるため(/HOTPATCH
バイナリをフックしている場合やスタブしたい場合を除く)、2つ目ははるかにクリーンですが、デバッガーで少し作業が必要です。
ジャンプする関数は、フックしている関数と同じパラメーターと呼び出し規約(ABI)を持っている必要があります。この関数では、渡されたパラメーターのキャプチャ、操作、呼び出しのフィルター処理などを行うことができます。
どちらの場合も、Windowsでパッチを適用するためのアセンブリを作成する方法が必要です。これWriteProcessMemory
は、最初の呼び出しポートです(注:これを行うにはRWX権限が必要であるため、を呼び出しますVirtualProtect
)。これは、作成する小さなユーティリティ関数です。 32ビットの相対呼び出しまたはジャンプ(として渡されたオペコードに応じてeType
)
#pragma pack(1)
struct patch_t
{
BYTE nPatchType;
DWORD dwAddress;
};
#pragma pack()
BOOL ApplyPatch(BYTE eType, DWORD dwAddress, const void* pTarget)
{
DWORD dwOldValue, dwTemp;
patch_t pWrite =
{
eType,
(DWORD)pTarget - (dwAddress + sizeof(DWORD) + sizeof(BYTE))
};
VirtualProtect((LPVOID)dwAddress,sizeof(DWORD),PAGE_EXECUTE_READWRITE,&dwOldValue);
BOOL bSuccess = WriteProcessMemory(GetCurrentProcess(),(LPVOID)dwAddress,&pWrite,sizeof(pWrite),NULL);
VirtualProtect((LPVOID)dwAddress,sizeof(DWORD),dwOldValue,&dwTemp);
return bSuccess;
}
この関数は方法2でうまく機能しますが、方法1では、元の関数に戻る前にパッチが上書きしたコードを復元するために、中間アセンブリトランポリンにジャンプする必要があります。これは非常に面倒です。既存のテスト済みライブラリを使用するだけです。
その音から、方法1を使用してパッチを適用すると、パッチを適用した関数を実行する必要がないように見えるため、ターゲット関数のプロローグをジャンプして、必要な処理を実行できます。
(HWブレークポイントを使用する3番目の方法がありますが、これは非常に脆弱であり、4つのHWブレークポイントに制限されているため問題になる可能性があります)。