vb 2008 WriteProcessMemory () возвращает 0 - PullRequest
1 голос
/ 14 мая 2011

привет, я использую vb 2008, вот часть моего кода:

Private Declare Function WriteProcessMemory Lib "kernel32" Alias "WriteProcessMemory" ( _
      ByVal hProcess As Integer, _
      ByVal lpBaseAddress As Integer, _
      ByVal lpBuffer As Integer, _
      ByVal nSize As Integer, _
      ByVal lpNumberOfBytesWritten As Integer _
   ) As Integer

    Dim proc() As Process = Process.GetProcessesByName("process")
    If proc.Length = 0 Then Console.WriteLine("Process Not Found") : Exit Sub
    Dim p = proc(0)
    Dim pH As Integer = OpenProcess(PROCESS_ALL_ACCESS, 0, p.Id)
    Dim address As Integer
    address = &H98544
    Dim memory As IntPtr
    Call ReadProcessMemory(pH, address, memory, 4, 0)
    Console.WriteLine(memory.ToString)
    Dim data As Integer = 2000
    Call WriteProcessMemory(pH, address, data, Len(data), 0&)

Но WriteProcessMemory () возвращает 0, и значение не меняется

РЕШЕНИЕ:

<DllImport("kernel32", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function WriteProcessMemory( _
                                      ByVal hProcess As IntPtr, _
                                      ByVal lpBaseAddress As IntPtr, _
                                      ByVal lpBuffer As Byte(), _
                                      ByVal nSize As UInt32, _
                                      ByRef lpNumberOfBytesWritten As UInt32 _
                                      ) As Boolean
End Function

        Dim proc() As Process = Process.GetProcessesByName("process")
        If proc.Length = 0 Then Console.WriteLine("Process Not Found") : Exit Sub
        Dim p = proc(0)
        Dim pH As Integer = OpenProcess(PROCESS_ALL_ACCESS, 0, p.Id)
        Dim address As Integer
        address = &H98544
        Dim memory As IntPtr
        Call ReadProcessMemory(pH, address, memory, 4, 0)
        Console.WriteLine(memory.ToString)
        Dim data() As Byte = BitConverter.GetBytes(2000)
        Call WriteProcessMemory(pH, address, data, 4, 0&)

Ответы [ 2 ]

2 голосов
/ 14 мая 2011

Когда вы вызываете функции Windows API, вы должны самостоятельно реализовать код проверки ошибок. Они не будут генерировать исключения, если что-то пойдет не так, как стандартные функции .NET Framework.

Требуемая проверка ошибок зависит от функции. (Такое несоответствие именно поэтому .NET использует вместо этого исключения.) Проверка документации необходима.

WriteProcessMemory работает таким образом, что довольно распространено. Возвращаемым значением является BOOL (целое число, которое библиотеки Win32 рассматривают как логическое значение, где 0 = FALSE и 1 = TRUE). Если функция завершается ошибкой, возвращаемое значение равно 0 (ЛОЖЬ). В случае успеха возвращаемое значение равно 1 (ИСТИНА):

Если функция завершается успешно, возвращаемое значение отлично от нуля.

Если функция завершается ошибкой, возвращаемое значение равно 0 (ноль). Чтобы получить расширенную информацию об ошибке, позвоните GetLastError. Функция завершается ошибкой, если запрошенная операция записи пересекает область недоступного процесса.

Интересно, конечно, что нам говорят, что мы должны вызвать функцию GetLastError, чтобы определить , почему функция не сработала. Частично это правда. Вы только звоните GetLastError, когда пишете неуправляемый код C ++ . В .NET вам нужно сделать что-то еще. Есть два шага:

  1. Пометьте подпись P / Invoke с помощью SetLastError = True, что заставляет CLR автоматически вызывать GetLastError и сохранять его значение.
  2. Позвоните Marshal.GetLastWin32Error, чтобы получить это значение.

Итак, для его отладки вам нужно переписать ваш код следующим образом (используя стандартный синтаксис P / Invoke, а не более ограниченное ключевое слово Declare, уникальное для VB.NET):

<DllImport("kernel32", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function WriteProcessMemory(
                                           ByVal hProcess As Integer, _
                                           ByVal lpBaseAddress As Integer, _
                                           ByVal lpBuffer As Integer, _
                                           ByVal nSize As Integer, _
                                           ByVal lpNumberOfBytesWritten As Integer _
                                          ) As Integer
End Function

Dim proc() As Process = Process.GetProcessesByName("process")
If proc.Length = 0 Then Console.WriteLine("Process Not Found") : Exit Sub
Dim p = proc(0)
Dim pH As Integer = OpenProcess(PROCESS_ALL_ACCESS, 0, p.Id)
Dim address As Integer
address = &H98544
Dim memory As IntPtr
Call ReadProcessMemory(pH, address, memory, 4, 0)
Console.WriteLine(memory.ToString)
Dim data As Integer = 2000
If WriteProcessMemory(pH, address, data, Len(data), 0&) = 0 Then
   ' The function failed, so find out what the error was
   MessageBox.Show("WriteProcessMemory failed with error " & Marshal.GetLastWin32Error)
End If

Как только вы узнаете код ошибки, вы можете найти его в списке кодов системных ошибок , чтобы увидеть, что он означает.


Оказывается, ошибка номер 299, ERROR_PARTIAL_COPY, что в документации просто означает:

Была выполнена только часть запроса ReadProcessMemory или WriteProcessMemory.

Хм, не очень полезно ... Я надеялся, что вы получите что-то лучше. C'est la vie .

Вам понадобится немного дополнительных знаний, чтобы решить эту проблему. Намек дается, еще раз, в документации. Каждый раз, когда он говорит, что параметр является «указателем» (указывается в синтаксисе C ++ звездочкой *), это означает, что в VB.NET его необходимо передать как ссылку , а не как значение. Чтобы указать, что что-то передается в качестве ссылки, используйте ключевое слово ByRef. Конечно, для передачи по значению вы указываете ключевое слово по умолчанию ByVal.

Кроме того, обратите внимание, что когда в документации говорится, что что-то является handle или address , вы должны объявить это в VB.NET как IntPtr type , а не как целое число. IntPtr особенный, потому что его размер изменяется в зависимости от того, является ли базовая операционная система 32-битной или 64-битной (в отличие от целого числа, которое является фиксированным размером, независимо от того, на какой платформе вы работаете). Даже если это не вызывает ваших непосредственных проблем, это будет вызывать проблемы совместимости, когда вы компилируете код для 64-бит.

Так что получается, что ваше заявление на самом деле неверно. Переписать это так:

<DllImport("kernel32", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function WriteProcessMemory(
                                           ByVal hProcess As IntPtr, _
                                           ByVal lpBaseAddress As IntPtr, _
                                           ByVal lpBuffer As Integer, _
                                           ByVal nSize As Integer, _
                                           ByRef lpNumberOfBytesWritten As Integer _
                                          ) As Integer
End Function

Можно также учитывать, что третий параметр (lpBuffer) должен быть массивом байтов (Byte()), поскольку он указывает данные, которые должны быть записаны в адресное пространство.

1 голос
/ 14 мая 2011

Документация гласит:

В случае сбоя функции возвращаемое значение равно 0 (нулю).Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.Функция завершается ошибкой, если запрошенная операция записи пересекает область недоступного процесса.

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

ИмеяС этой точки зрения вполне вероятно, что причиной сбоя является то, что адрес 2000, на который вы пытаетесь записать, не является допустимым адресом в этом процессе.

Параметр lpBuffer является указателеми вы передаете целочисленное значение 2000 в качестве этого параметра.Поэтому это интерпретируется и является адресом памяти.Я подозреваю, что вы на самом деле намеревались передать адрес data.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...