這裏有一個有趣的問題: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。