vb 2008 WriteProcessMemory() 返回 0

发布于 2024-11-07 12:56:33 字数 2056 浏览 0 评论 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&)

hello
i'm using vb 2008 here is part of my code:

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&)

But, the WriteProcessMemory() returns 0, and value don't change

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&)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如何视而不见 2024-11-14 12:56:33

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

所需的具体错误检查因功能而异。 (像这样的不一致正是 .NET 使用异常的原因。)检查文档至关重要。

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

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

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

当然,有趣的部分是我们被告知必须调用 GetLastError 函数才能确定函数失败的原因。其中一部分是正确的。 调用GetLastError 当您编写非托管 C++ 代码时。在.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++语法中用星号*表示),这意味着在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()),因为它指定要写入的数据到地址空间。

When you're calling Windows API functions, you have to implement the error-checking code yourself. They won't throw exceptions when something goes wrong like the standard .NET Framework functions.

The specific error checks required vary depending on the function. (Inconsistency like this is precisely why .NET uses exceptions instead.) Checking the documentation is essential.

WriteProcessMemory works in a way that is fairly common. The return value is a BOOL (an integer that the Win32 libraries treat as a Boolean, where 0 = FALSE and 1 = TRUE). If the function fails, the return value is 0 (FALSE). If it's successful, the return value is 1 (TRUE):

If the function succeeds, the return value is nonzero.

If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError. The function fails if the requested write operation crosses into an area of the process that is inaccessible.

The interesting part there, of course, is that we're told that we must call the GetLastError function in order to determine why the function failed. Part of that is true. You only call GetLastError when you're writing unmanaged C++ code. In .NET, you need to do something else. There are two steps:

  1. Mark the P/Invoke signature with SetLastError = True, which causes the CLR to automatically call GetLastError and save its value.
  2. Call Marshal.GetLastWin32Error to retrieve that value.

So, to debug it, you'll need to re-write your code like this (using the standard P/Invoke syntax, rather than the more limited Declare keyword that is unique to 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

Once you know the error code, you can look it up in the list of System Error Codes to see what it means.


Turns out the error is number 299, ERROR_PARTIAL_COPY, which the documentation says just means:

Only part of a ReadProcessMemory or WriteProcessMemory request was completed.

Hmm, not very helpful... I was hoping you'd get something better. C'est la vie.

You're going to have to have a little bit of additional knowledge to solve that problem. A hint is given, once again, in the documentation. Any time it says that a parameter is a "pointer" (indicated in C++ syntax with an asterisk *), that means that in VB.NET, it needs to be passed as a reference, rather than as a value. To specify that something is passed as a reference, use the ByRef keyword. To pass by value, of course, you specify the default ByVal keyword.

Additionally, note that when the documentation says something is a handle or an address, you should declare it in VB.NET as an IntPtr type, rather than as an integer. IntPtr is special because its size changes, depending on whether the underlying operating system is 32-bit or 64-bit (unlike an integer, which is a fixed size, no matter what platform you're running on). Even though this is not causing your immediate problem, it will cause compatibility problems when you compile the code for 64-bit.

So it turns out that your declaration is actually wrong. Redeclare it like this:

<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

You might also consider that the third parameter (lpBuffer) should be an array of bytes (Byte()), because it specifies the data to be written to the address space.

雪化雨蝶 2024-11-14 12:56:33

文档指出:

如果函数失败,则返回
值为 0(零)。为了得到延长
错误信息,调用GetLastError。
如果请求,该功能将失败
写操作跨入一个区域
无法访问的进程。

我建议您按照它的说明进行操作,找出失败的原因。

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

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

The documentation states:

If the function fails, the return
value is 0 (zero). To get extended
error information, call GetLastError.
The function fails if the requested
write operation crosses into an area
of the process that is inaccessible.

I recommend you do what it says to find out why this has failed.

Having made that point, it seems likely that the cause of the failure is that the address 2000, which you are attempting to write to, is not a valid address in that process.

The lpBuffer parameter is a pointer and you are passing the integer value 2000 as that parameter. This is therefore interpreted and being a memory address. I suspect you actually intended to pass the address of data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文