ReadProcessMemory -缓冲区大小影响函数的正确性
本文关键字:函数 正确性 影响 缓冲区 ReadProcessMemory | 更新日期: 2023-09-27 17:49:58
这里有一个有趣的问题:
我正在使用ReadProcessMemory(从c#中)编写一个简单的调试程序。我需要通过目标进程的整个内存空间来找到某些字节串(哎呀,我使用Boyer-Moore来节省时间,这很酷)。
要做到这一点,我使用ReadProcessMemory来复制大块内存,在我的程序中迭代它,然后移动到下一个块(是的,我也考虑到一个值可能跨越两个块之间的边界的情况)。
然而,ReadProcessMemory返回不同的值取决于它被告知要复制到的缓冲区的大小。为了我的调查,我在calc.exe (Windows 7 x64)上使用了ReadProcessMemory。我得到了一致的结果:
这是我的native emethods 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
是小于或等于65536的2次幂时(我测试了64、512、1024、2048、4096、8192、16384、32768和65536),则调用ReadProcessMemory失败,直到blockAddr
的值为0x10000(65536),此时ReadProcessMemory返回TRUE并报告非零bytesRead值。
然而,当BlockSize
为20480(20*2048,即20KB,不是2的幂)时,该函数仅在blockAddr
为0x14000(81920)时返回TRUE,这很奇怪,因为32768和65536块大小大于20480,但当blockAddr为0x10000时返回。
当我使用更大的块大小(包括128KB和1024KB)时,blockAddr值甚至更高,128KB为0x60000, 1MB为0x600000。
显然,我必须限制我的程序到64kb大小的内存块的风险不能读取所有的进程的内存,这意味着我的程序将不再是正确的,但为什么一个简单的缓冲区大小影响程序的正确性?Windows所做的只是一个简单的内存拷贝。
哎呀,我用的是Windows 7 x64。我的程序是c#编译与AnyCPU,所以它运行为x64。我的目标程序是C:'Windows'calc.exe,也是x64。
别猜了。使用VirtualQueryEx()来查找内存在进程中的映射位置以及块的大小。