1

我目前正在开发一个小爱好项目,通过 VB.NET 在我的 G15 键盘上的游戏中显示健康信息。

当我通过 API 调用使用 ReadProcessMemory 时,它一直返回零。MSDN 文档让我使用 Marshal.GetLastWin32Error() 调用来找出问题所在,它返回 1400:INVALID WINDOW HANDLE。

我现在对函数的第一个参数是否需要窗口句柄或进程 ID 感到困惑。无论如何,我都尝试过使用 FindWindow 并在应用程序运行时对进程 ID 进行硬编码(从任务管理器中获取)。

我尝试了三种不同的游戏,Urban Terror、Grand Theft Auto: SA 和 windows 的 3D pinball,从一个名为 Cheat Engine 的应用程序中获取内存地址;他们似乎都失败了。

这是我用来执行此操作的代码:

API调用:

Private Declare Function ReadProcessMemory Lib "kernel32" ( _
ByVal hProcess As Integer, _
ByVal lpBaseAddress As Integer, _
ByRef lpBuffer As Single, _
ByVal nSize As Integer, _
ByRef lpNumberOfBytesWritten As Integer _
) As Integer

方法:

Dim address As Integer
address = &HA90C62&
Dim valueinmemory As Integer

Dim proc As Process = Process.GetCurrentProcess
For Each proc In Process.GetProcesses
    If proc.MainWindowTitle = "3D Pinball for Windows - Space Cadet" Then
        If ReadProcessMemory(proc.Handle.ToInt32, address, valueinmemory, 4, 0) = 0 Then
            MsgBox("aww")
        Else
            MsgBox(CStr(valueinmemory))
        End If
    End If
Next

Dim lastError As Integer
lastError = Marshal.GetLastWin32Error()
MessageBox.Show(CStr(lastError))

有人可以向我解释为什么它不起作用吗?提前致谢。

4

3 回答 3

3

首先,您的方法签名是错误的, Single=Float 而原始参数是 LPBUF 类型。

使用此方法签名:

<DllImport("kernel32.dll", SetLastError=true)> _
Public Shared Function ReadProcessMemory( _
ByVal hProcess As IntPtr, _
ByVal lpBaseAddress As IntPtr, _
<Out()>ByVal lpBuffer() As Byte, _
ByVal dwSize as Integer, _
ByRef lpNumberOfBytesRead as Integer
) As Boolean
End Function

其次,我相信 hProcess 句柄需要一个由 OpenProcess 函数打开的句柄,而不是窗口句柄。

于 2008-12-06T22:49:55.073 回答
1

谢谢你,arul,我已经解决了我的问题。

Dim address As Integer
address = &HA90C62&
Dim floatvalueinmemory() As Byte

Dim proc As Process = Process.GetCurrentProcess
For Each proc In Process.GetProcesses
    If proc.MainWindowTitle = "3D Pinball for Windows - Space Cadet" Then
        Dim winhandle As IntPtr = OpenProcess(PROCESS_ACCESS.PROCESS_VM_READ, True, proc.Id)

        If ReadProcessMemory(winhandle, address, floatvalueinmemory, 4, 0) = 0 Then
            Dim lastError As Integer
            lastError = Marshal.GetLastWin32Error()
            MessageBox.Show(CStr(lastError))
            MsgBox("aww")
        Else
            MsgBox("woo")
        End If

        CloseHandle(winhandle)
    End If
Next

现在它认为句柄有效并尝试读取进程内存,但我收到错误消息 299:ReadProcessMemory 或 WriteProcessMemory 请求的一部分已完成。

有没有人对我应该如何着手解决这个问题有任何想法?

于 2008-12-06T23:46:28.377 回答
1

消息 299:只有部分 ReadProcessMemory 或 WriteProcessMemory 请求完成意味着我试图读取的内存受到保护。

感谢您的所有帮助,我将把 arul 的答案标记为答案。

于 2008-12-08T23:02:01.770 回答