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。

ReadProcessMemory -缓冲区大小影响函数的正确性

别猜了。使用VirtualQueryEx()来查找内存在进程中的映射位置以及块的大小。