まず、これが重複しているように見えますが、他の質問を調べても解決策が見つからなかったので、聞いてください.
相対仮想アドレスを動的メモリアドレス、つまり複数レベルのポインターの読み取りに変換する機能があります (以下を参照)。すべてのアクセス権を持つリモート プロセスへの有効なハンドル、プロセスのベース アドレス (4194304 または 0x400000) へのポインター、rva (29128148 または 0x1BC75D4)、およびオフセット ({ 20, 48, 12 } 、{ 0x14、0x30、0xC })。ベースアドレスを rva に追加する行は、正しい 33322452 または 0x1FC75D4 を返します (チートエンジンで検証済み)。ループの最初の反復では、前述のアドレスで RPM() を呼び出し、BitConverter.ToInt32() への呼び出しは -134118400 または正しい 0xF8018400 を返します。dynamicMemoryAddress の新しい値は、そのアドレスと、-134118380 または 0xF8018414 の値を持つ IntPtr を生成する最初のオフセット (0x14) を追加することによって設定されます。
ただし、RPM() が 2 回目の繰り返しで新しい dynamicMemoryAddress (0xF8018414) の値で呼び出されると、関数は失敗ステータスを返します。GetLastError() を呼び出すと、998 または ERROR_NOACCESS (メモリ位置への無効なアクセス) が返されます。Cheat Engine で 0xF8018414 を参照すると、正しい値があり、ページの保護値が PAGE_READ_WRITE であるため、十分なアクセス権があるように見えても、最初の呼び出しが成功するのに 2 番目の呼び出しが失敗する理由がわかりません。
デバッグの目的で、RPM() への呼び出しの直前に VirtualQueryEx() への呼び出しを挿入しました。最初の反復は成功し、MemoryBasicInformation 構造体は正しく設定され、2 回目の反復では構造体は完全に空になります。
私はこの問題で 2 日間立ち往生しており、機知に富んでいます。どんな助けも大歓迎です。私は x64 Windows 7 で実行していますが、関連するプロセスはすべて x86 です。
private static IntPtr ConvertRVAToDMA(RemoteProcess rProcess, IntPtr baseAddress, IntPtr relativeVirtualAddress, Int32[] offsets)
{
Process.EnterDebugMode();
byte[] buffer = new byte[Marshal.SizeOf(new IntPtr())];
int tmpNewBaseAddress;
IntPtr bytesRead = new IntPtr();
IntPtr dynamicMemoryAddress = new IntPtr(baseAddress.ToInt32() + relativeVirtualAddress.ToInt32());
try
{
for (int i = 0; i < (offsets.Length); i++)
{
if (!WinApis.ReadProcessMemory(rProcess.Handle, dynamicMemoryAddress, buffer, Marshal.SizeOf(new IntPtr()), out bytesRead))
{
dynamicMemoryAddress = IntPtr.Zero;
break;
}
tmpNewBaseAddress = BitConverter.ToInt32(buffer, 0);
if (tmpNewBaseAddress == 0)
{
dynamicMemoryAddress = IntPtr.Zero;
break;
}
dynamicMemoryAddress = IntPtr.Add((IntPtr)tmpNewBaseAddress, offsets[i]);
}
}
catch (Exception ex)
{
dynamicMemoryAddress = IntPtr.Zero;
}
Process.LeaveDebugMode();
return dynamicMemoryAddress;
}