这里有一个有趣的问题:ReadProcessMemory - 缓冲区大小影响功能的正确性
我使用ReadProcessMemory(从C#中)写一个简单的调试程序。我需要通过目标进程的整个内存空间来查找某些字节串(FWIW,我使用Boyer-Moore来节省时间,这非常酷)。
为此,我使用ReadProcessMemory来复制大块内存,在我的程序中遍历它,然后继续到下一个块(是的,我还考虑了值可能跨越的情况两块之间的边界)。
但是,ReadProcessMemory根据要被复制到的缓冲区的大小返回不同的值。对于我的调查,我在calc.exe上使用了ReadProcessMemory(Windows 7 x64)。我得到了一致的结果:
这里是我的NativeMethods的P/Invoke签名:
[DllImport("Kernel32.dll", CallingConvention=CallingConvention.Winapi, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean ReadProcessMemory(IntPtr process, void* baseAddress, void* destBuffer, IntPtr size, out IntPtr bytesRead);
这里是我使用它的代码:
public IntPtr[] Search(Byte[] needle) {
OpenProcess();
List<IntPtr> ret = new List<IntPtr>();
Int32 iterations = (int)((MaxAddr32bit + 1)/BlockSize);
IntPtr sizeOfBlock = new IntPtr(BlockSize);
IntPtr bytesRead;
byte* buffer = (byte*)Marshal.AllocHGlobal(sizeOfBlock);
for(int i=0;i<iterations;i++) {
void* blockAddr = (void*)(i * BlockSize);
bool ok = NativeMethods.ReadProcessMemory(_process, blockAddr, buffer, sizeOfBlock, out bytesRead);
if(bytesRead.ToInt64() > 0) {
switch(needle.Length) {
case 1: Search8 (buffer, sizeOfBlock, ret, needle[0]); break;
case 2: Search16(buffer, sizeOfBlock, ret, needle[0], needle[1]); break;
case 4: Search32(buffer, sizeOfBlock, ret, needle[0], needle[1], needle[2], needle[3]); break;
case 8: Search64(buffer, sizeOfBlock, ret, needle[0], needle[1], needle[2], needle[3], needle[4], needle[5], needle[6], needle[7]); break;
}
}
}
Marshal.FreeHGlobal(new IntPtr(buffer));
CloseProcess();
return ret.ToArray();
}
BlockSize
是一个常数,我已经一直在变化并获得不同的结果。
当BlockSize
是大于2小于或等于65536功率(I测试的64,512,1024,2048,4096,8192,16384,32768,65536),然后调用ReadProcessMemory失败,直到blockAddr
值是0x10000(65536),此时ReadProcessMemory返回TRUE并报告非零bytesRead值。
然而,当BlockSize
是20480(20 * 2048,又名20KB,这不是二的幂),则该函数仅当blockAddr
是0x14000(81920)返回TRUE,这是奇怪的,因为32768和65536嵌段大小大于20480,但在blockAddr为0x10000时返回。
当我使用更大的块大小(包括128KB和1024KB)时,blockAddr值甚至更高,128KB是0x60000,1MB是0x600000。
很明显,我必须将程序限制为64KB大小的内存块,以免无法读取进程内存的所有内存,这意味着我的程序将不再正确,但为什么应该使用简单的缓冲区大小影响程序的正确性?所有的Windows都在做一个简单的内存拷贝。
FWIW,我正在运行Windows 7 x64。我的程序是用AnyCPU编译的C#,因此它运行的是x64。我所针对的程序是C:\ Windows \ calc.exe,它也是x64。