为了查找另一个进程的地址并读取其值,您必须根据进程的偏移量和基地址进行计算。Cheat Engine将读取地址值操作显示为 [hex + hex] -> 地址在指针编辑器中。因此,每次看到 [address + offset] -> 下一个地址时,它意味着将地址和偏移量作为十六进制(16)相加,并在进程内存中的该地址处读取值。检索到的值是下一个地址,您应该使用它来获取以下一个地址。重复此过程,直到到达最后一个偏移量,然后只需将地址和偏移量相加而不读取值。结果的地址就是存储值的位置。
如何找到基地址?虽然在 Cheat Engine 中它可能看起来是常数(如果您将 0 替换为 02518790,则每次重新启动进程时都会得到相同的地址),但它只是一个虚拟地址,请勿使用它。相反,使用 winapi 使用 EnumProcessModules 迭代指定进程的所有模块。您可以通过窗口标题搜索正在运行的应用程序以查找 PID。将模块的文件名与 GetModuleFilenameExW 进行比较。当您找到带有恒定文件名(在您的情况下为“UE4Game-Win64-Shipping.exe”)的模块时,请使用 GetModuleInformation 检索 LpBaseOfDll。而不是 EntryPoint,EntryPoint 不是基地址。
现在,您已经拥有LpBaseOfDll,请向其添加常量偏移量(02518790),并读取结果地址处的值。这是您应该用于运行循环和添加偏移量的起始地址。因此,图像标记为“加法操作”的是LpBaseOfDll和偏移量的总和。实际上,Cheat Engine只接受可执行文件名而不是偏移量,尝试将“kernel32.dll”放入地址字段中即可:)
要与虚拟内存交互,您必须使用Windows本机API(kernel32.dll)。与任何其他语言一样,Go具有winapi的包装器。您可以在传统的硬编码“golang.org/x/sys/windows”,现代和实验性的“github.com/Andoryuuta/kiwi”之间进行选择,但我建议您使用“github.com/0xrawsec/golang-win32/win32/kernel32”。
下面的代码演示了如何获取基地址。我发布了一个
GitHub gist,其中包含可以通过名称查找进程ID并读取float32值的完整代码。
package main
import (
"fmt"
"path/filepath"
"github.com/0xrawsec/golang-win32/win32"
kernel32 "github.com/0xrawsec/golang-win32/win32/kernel32"
windows "golang.org/x/sys/windows"
)
func memoryReadInit(pid uint32) (int64, bool) {
win32handle, _ := kernel32.OpenProcess(0x0010 | windows.PROCESS_VM_READ | windows.PROCESS_QUERY_INFORMATION, win32.BOOL(0), win32.DWORD(pid))
moduleHandles, _ := kernel32.EnumProcessModules(win32handle)
for _, moduleHandle := range moduleHandles {
s, _ := kernel32.GetModuleFilenameExW(win32handle, moduleHandle)
targetModuleFilename := "UE4Game-Win64-Shipping.exe"
if(filepath.Base(s) == targetModuleFilename) {
info, _ := kernel32.GetModuleInformation(win32handle, moduleHandle)
return int64(info.LpBaseOfDll), true
}
}
return 0, false
}
func main() {
var pid uint32 = 0x38E4
baseAddress, _ := memoryReadInit(pid)
fmt.Println("Base address is", baseAddress)
}