2015-05-24 5 views
1

Я пытаюсь прочитать некоторую память из процесса на C#. Вот моя вспомогательная функция, чтобы получить адрес указателя из серии удалений, наряду с другими соответствующими функциями:переменная цикла (i) таинственно сбрасывается до 0 после каждого цикла при отладке в Visual Studio (работает, когда не отлаживается)

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern Int32 ReadProcessMemory(
     IntPtr hProcess, 
     IntPtr lpBaseAddress, 
     [In, Out] byte[] buffer, 
     UInt32 size, 
     out int lpNumberOfBytesRead); 

    public static bool ReadProcessMemoryHelper(
     IntPtr hProcess, 
     long lpBaseAddress, 
     [In, Out] byte[] buffer, 
     UInt32 size, 
     out int lpNumberOfBytesRead) 
    { 
     return ReadProcessMemory(
      hProcess, 
      new IntPtr(lpBaseAddress), 
      buffer, 
      size, 
      out lpNumberOfBytesRead) != 0; 
    } 
    public long Pointer(params int[] Offsets) 
    { 
     long pointerAddress = _baseAddr; 

     if (Offsets.Length > 1) 
     { 
      byte[] buff = new byte[4]; 
      for (int i = 0; i < Offsets.Length - 1; i++) 
      { 
       int bytesRead; 
       var cur = pointerAddress; 
       var offset = Offsets[i]; 
       var next = cur + offset; 
       Console.WriteLine("i = {0}", i); 
       Console.WriteLine("[{0}+{1}], {2}", cur.ToString("X"), offset.ToString("X"), next.ToString("X")); 

       if (0 == cur) 
       { 
        return 0; 
       } 

       var readProcess = ReadProcessMemoryHelper(
        _process.Handle, 
        next, 
        buff, 
        4, 
        out bytesRead); 
       if (readProcess) 
       { 
        pointerAddress = BitConverter.ToUInt32(buff, 0); 
       } 
       else 
       { 
        return 0; 
       } 
       Console.WriteLine("i = {0}", i); 
      } 
     } 

     return pointerAddress + Offsets[Offsets.Length - 1]; 
    } 

Загадочно, после того, как ReadProcessMemoryHelper называется, переменная цикла я становлюсь 0. Этого цикл завершается только потому, что в конце концов он не удается прочитать память из процесса, возвращая 0.

Вот пример вывода:

i = 0 
[170000+FB02F0], 11202F0 
i = 0 
i = 1 
[11469240+1C], 1146925C 
i = 0 
i = 1 
[12DCC690+1C], 12DCC6AC 
i = 0 
i = 1 
[114673A0+1C], 114673BC 
i = 0 
i = 1 
[10F2C830+1C], 10F2C84C 
i = 0 
i = 1 
[111561E0+1C], 111561FC 
i = 0 
i = 1 
[E972CAE+1C], E972CCA 
i = 0 
i = 1 
[1302736E+1C], 1302738A 
i = 0 
i = 1 
[3E49+1C], 3E65 

Возможно, еще более загадочным. Это ТОЛЬКО случается, когда отладчик подключен (расскажите о Heisenbug). Если я запускаю из командной строки, я получаю следующее (правильный) вывод:

i = 0 
[170000+FB02F0], 11202F0 
i = 0 
i = 1 
[11469240+1C], 1146925C 
i = 1 
i = 2 
[12DCC690+10], 12DCC6A0 
i = 2 
i = 3 
[113E4430+130], 113E4560 
i = 3 
i = 4 
[10F2CEF0+1C], 10F2CF0C 
i = 4 

Я понятия не имею, что могло бы делать это, и это сводит меня с ума.

+0

Ну, отладчик возился с потоками, чтобы установить точки останова. Вы пытались использовать старомодный вывод консоли для отслеживания? –

+0

Нет точек останова. Вывод представлен, как вы выразились, старомодным выходом консоли. Единственное различие между ними заключается в том, что один из них запускается через F5, а другой через ctrl-F5 из Visual Studio (отладчик подключен или отсутствует отладчик). –

+0

Любопытный и любопытный. Если я добавлю эту строку: var tmpBSVariable = 0xDEADBEEF; В первой строке цикла for эта переменная имеет значение 0 после вызова, и я обычно увеличивает/код работает, как ожидалось. Моя единственная теория заключается в том, что отладчик Visual Studio просто перегружен в VS2013 при взаимодействии с kernel.dll /, возможно, с другими родными компонентами и беспорядок со стеком в управляемом коде. –

ответ

5

Я собираюсь предположить, что ваш процесс в 64-разрядной версии. Если это так, то сигнатура interop неверна как размер последнего параметра, lpNumberOfBytesRead должен быть 64-битным, а не 32-битным.

BOOL WINAPI ReadProcessMemory(
    _In_ HANDLE hProcess, 
    _In_ LPCVOID lpBaseAddress, 
    _Out_ LPVOID lpBuffer, 
    _In_ SIZE_T nSize, 
    _Out_ SIZE_T *lpNumberOfBytesRead); 



#if defined(_WIN64) 
typedef unsigned __int64 ULONG_PTR; 
#else 
typedef unsigned long ULONG_PTR; 
#endif 

typedef ULONG_PTR SIZE_T; 

Вы можете себе представить, как это может привести к повреждению стека. Поскольку вы игнорируете параметр out anyways, вы можете использовать IntPtr в сигнатуре.

+0

Извините, что я не ответил вам ранее - процесс 64-разрядный (или, более конкретно, он скомпилирован как любой процессор, работающий на 64-битной машине). Смена int на IntPtr, похоже, сделала трюк. Спасибо что подметил это! Я все еще удивляюсь, что это проявляется как повреждение стека в управляемом коде, но вы правы, что нетрудно представить, что он мог это сделать. –

 Смежные вопросы

  • Нет связанных вопросов^_^