vb 2008 WriteProcessMemory()返回0

你好我使用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&) 

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

具体的错误检查要求根据功能的不同而不同。 (像这样的不一致正是为什么.NET使用异常来代替。)检查文档是至关重要的。

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

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

如果函数失败,则返回值为0(零)。 要获得扩展错误信息,请调用GetLastError 。 如果请求的写入操作进入不可访问的进程区域,则该函数将失败。

当然有趣的部分是,我们被告知必须调用GetLastError函数来确定函数失败的原因。 其中的一部分是事实。 当您编写非托管C ++代码时,您调用GetLastError 。 在.NET中,你需要做别的事情。 有两个步骤:

  1. SetLastError = True标记P / Invoke签名,这会导致CLR自动调用GetLastError并保存其值。
  2. 调用Marshal.GetLastWin32Error来检索该值。

因此,要调试它,需要像这样重写代码(使用标准的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 

一旦知道错误代码,您可以在系统错误代码列表中查看它的含义。


原来的错误是数字299, ERROR_PARTIAL_COPY ,文档说只是意味着:

只有ReadProcessMemory或WriteProcessMemory请求的一部分已经完成。

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

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

此外,请注意,当文档说什么是句柄地址时 ,您应该在VB.NET中将其声明为IntPtr类型 ,而不是整数。 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() ),因为它指定了要写入地址空间的数据。

该文件指出:

如果函数失败,则返回值为0(零)。 要获得扩展错误信息,请调用GetLastError。 如果请求的写入操作进入不可访问的进程区域,则该函数将失败。

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

说完这一点之后,看起来可能是因为你试图写入的地址2000在这个过程中不是一个有效的地址。

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