2011-04-11 108 views
2

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

回答

1

不要猜測在這。使用VirtualQueryEx()來找出內存在進程中的映射位置以及塊的大小。