首先,我知道这看起来像是重复但是我查看了其他问题并且找不到解决方案所以请听我说。
我有一个函数将相对虚拟地址转换为动态内存地址,即读取多级指针(如下所示)。我用具有所有访问权限的远程进程的有效句柄调用该函数,指向进程基址(4194304或0x400000),rva(29128148或0x1BC75D4)和偏移量({20,48,12}}的指针,{0x14,0x30,0xC})。将基址添加到rva的行返回33322452或0x1FC75D4,这是正确的(通过作弊引擎验证)。循环的第一次迭代使用上述地址调用RPM(),并且对BitConverter.ToInt32()的调用返回-134118400或0xF8018400,这也是正确的。 dynamicMemoryAddress的新值是通过添加该地址和第一个偏移量(0x14)来设置的,该偏移量为IntPtr,其值为-134118380或0xF8018414。
但是,当在第二次迭代中使用dynamicMemoryAddress的新值(0xF8018414)调用RPM()时,该函数将返回失败状态。对GetLastError()的调用返回998或ERROR_NOACCESS(对内存位置的无效访问)。在Cheat Engine中我浏览到0xF8018414并且它具有正确的值并且页面Protect值是PAGE_READ_WRITE所以我无法理解为什么第一次调用成功但第二次调用失败,即使我似乎有足够的访问权限。
出于调试目的,我在调用RPM()之前立即插入了对VirtualQueryEx()的调用,第一次迭代成功并且MemoryBasicInformation结构被正确填充,在第二次迭代时结构完全为空。
我已经被困在这个问题上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;
}