vb 2008 WriteProcessMemory()返回0

时间:2011-05-14 10:59:42

标签: .net windows vb.net winapi process

您好 我正在使用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,值不会改变

SOLUTION:

<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 个答案:

答案 0 :(得分:2)

当您调用Windows API函数时,您必须自己实现错误检查代码。当标准.NET Framework函数出现问题时,它们不会抛出异常。

所需的特定错误检查因功能而异。 (像这样的不一致正是.NET使用异常的原因。)检查文档是必不可少的。

WriteProcessMemory的工作方式是相当普通。返回值是BOOL(Win32库视为布尔值的整数,其中0 = FALSE,1 = TRUE)。如果函数失败,则返回值为0(FALSE)。如果成功,则返回值为1(TRUE):

  

如果函数成功,则返回值为非零值。

     

如果函数失败,则返回值为0(零)。要获取扩展错误信息,请致电GetLastError。如果请求的写入操作跨越了无法访问的进程区域,则该函数将失败。

当然,有趣的部分是我们被告知我们必须调用GetLastError函数来确定为什么函数失败。部分原因是正确的。 You only call GetLastError when you're writing unmanaged C++ code。在.NET中,您需要执行其他操作。有两个步骤:

  1. 使用SetLastError = True标记P / Invoke签名,这会导致CLR自动调用GetLastError并保存其值。
  2. 致电Marshal.GetLastWin32Error以检索该值。
  3. 因此,要调试它,您需要重新编写这样的代码(使用标准的P / Invoke语法,而不是VB.NET独有的更有限的Declare关键字):

    <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
    

    了解错误代码后,您可以在list of System Error Codes中查找错误代码,了解其含义。


    原来错误是编号299,ERROR_PARTIAL_COPY,文档说明的意思是:

      

    只完成了ReadProcessMemory或WriteProcessMemory请求的一部分。

    嗯,不是很有帮助......我希望你能得到更好的东西。 C'est la vie

    你将需要一些额外的知识来解决这个问题。在文档中再次给出了提示。任何时候它说参数是“指针”(用C ++语法用星号*表示),这意味着在VB.NET中,它需要作为<强>参考,而不是作为一个值。要指定将某些内容作为参考传递,请使用ByRef关键字。当然,要传递值,请指定默认的ByVal关键字。

    另外,请注意,当文档说某些内容是句柄地址时,您应该在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 :(得分:1)

documentation州:

  

如果函数失败,则返回   值为0(零)。扩展   错误信息,调用GetLastError。   如果请求,该函数将失败   写操作跨越一个区域   无法进入的过程。

我建议你按照说法去找出失败的原因。

说到这一点之后,失败的原因似乎是您尝试写入的地址2000不是该过程中的有效地址。

lpBuffer参数是一个指针,您将整数值2000作为该参数传递。因此,这被解释并且是存储器地址。我怀疑你确实打算传递data的地址。