简体   繁体   English

Golang 根据进程句柄和偏移量计算另一个进程内存的地址

[英]Golang Calculate address of another process memory based on process handle and offset

I need to read value from memory of another process with given process name/id, pointer and offset and output it to the user in realtime, I already found another question and successfully implemented logic to read and convert float values from given address of process memory, but since address is changing every time I rejoin the game, I need to calculate it.我需要从具有给定进程名称/id、指针和偏移量的另一个进程的内存中读取值并将其实时输出给用户,我已经找到了另一个问题并成功实现了从进程内存的给定地址读取和转换浮点值的逻辑,但由于每次重新加入游戏时地址都会改变,我需要计算它。 I have found pointer and process offset using cheat engine:我使用作弊引擎找到了指针和进程偏移:

在此处输入图像描述

From what I understood reading theory, final address needs to be calculated using this algorithm:根据我对阅读理论的理解,最终地址需要使用以下算法计算:

  1. Calculate base address (1DC45993300) using constant offset (+02518790)使用常量偏移量 (+02518790) 计算基地址 (1DC45993300)
  2. Take this address and add pointer value to it取这个地址并向它添加指针值
  3. Repeat 2 step with every pointer value from bottom (5E0) to top (2E4)对从底部 (5E0) 到顶部 (2E4) 的每个指针值重复 2 步
  4. This is the final address that you can use to retreive data这是您可以用来检索数据的最终地址

I have no problem with steps 2, 3 and 4: I can sum hex numbers and read process memory at address, but I don't know how to use offset to calculate the first address, how to do this in Go?我对步骤 2、3 和 4 没有任何问题:我可以对十六进制数求和并在地址处 读取进程内存,但我不知道如何使用偏移量来计算第一个地址,如何在 Go 中做到这一点? I'm trying to do this on Windows 10我正在尝试在 Windows 10 上执行此操作

Update: I tried code from this question but it returns incorrect base address.更新:我尝试了这个问题的代码,但它返回了不正确的基地址。 I get 7ff611530000 while actual base address in cheat engine is 1A009A6AB70我得到 7ff611530000 而作弊引擎中的实际基地址是 1A009A6AB70

Update 2: It may be hard to understand what am I trying to do, so I added another picture.更新 2:可能很难理解我想要做什么,所以我添加了另一张图片。 I need to find how to make this "plus" operation and how to find address in red square (green can be calculated, purple are constants)我需要找到如何进行这个“加号”操作以及如何在红色方块中找到地址(绿色可以计算,紫色是常数)

在此处输入图像描述

In order to find address and read value of another process, you must calculate it, based on offsets and base address of process.为了找到另一个进程的地址和读取值,您必须根据进程的偏移量和基地址来计算它。 Cheat engine shows reading address value operation as [hex + hex] -> address in pointer editor.作弊引擎将读取地址值操作显示为 [hex + hex] -> 在指针编辑器中的地址。 So everytime you see [address + offset] -> next address, it means sum address and offset as hex (16) and read value at this address in process memory.因此,每次您看到 [address + offset] -> next address 时,都表示将地址和偏移量求和为十六进制 (16),并在进程内存中读取此地址的值。 Retrieved value is the next address, which you should use to get the following one.检索到的值是下一个地址,您应该使用它来获取下一个地址。 Repeat this until you get to the last offset, then just sum address and offset without reading value.重复此操作,直到到达最后一个偏移量,然后将地址和偏移量相加而不读取值。 The resulted address is where the value stored.结果地址是存储值的位置。

How to find base address?如何找到基地址? Although it may seem to be constant in Cheat Engine (if you put 0 instead of 02518790, you'll get the same address each time you restart process), it's just a virtual address, don't use it.虽然它在 Cheat Engine 中可能看起来是恒定的(如果你输入 0 而不是 02518790,那么每次重启进程都会得到相同的地址),但它只是一个虚拟地址,不要使用它。 Instead, use winapi to iterate through all modules of the specified process using EnumProcessModules.相反,使用 winapi 使用 EnumProcessModules 遍历指定进程的所有模块。 You can find PID by searching in running apps by window's title.您可以通过按窗口标题在正在运行的应用程序中搜索来找到 PID。 Compare module's filename with GetModuleFilenameExW.将模块的文件名与 GetModuleFilenameExW 进行比较。 When you found the module with constant filename ("UE4Game-Win64-Shipping.exe" in your case), use GetModuleInformation to retrieve LpBaseOfDll.当您找到具有常量文件名的模块(在您的情况下为“UE4Game-Win64-Shipping.exe”)时,使用 GetModuleInformation 检索 LpBaseOfDll。 Not EntryPoint, which is not base address.不是入口点,它不是基地址。

Now that you have LpBaseOfDll, add constant offset to it (02518790) and read value at resulted address.现在您已经有了 LpBaseOfDll,向它添加常量偏移量 (02518790) 并在结果地址处读取值。 This is your starting address that you should use to run the loop and add offsets.这是您应该用来运行循环和添加偏移量的起始地址。 So the "plus operation" labelled on image is sum of LpBaseOfDll and offset.所以图像上标记的“加号操作”是 LpBaseOfDll 和偏移量的总和。 In fact, Cheat Engine accepts just executable name without offset, try putting "kernel32.dll" into address field :)事实上,作弊引擎只接受不带偏移量的可执行文件名,尝试将“kernel32.dll”放入地址字段:)

To interact with virtual memory, you must use windows native api (kernel32.dll).要与虚拟内存交互,必须使用 windows 原生 api (kernel32.dll)。 As in any other language, Go has a wrapper for winapi.与任何其他语言一样,Go 有一个 winapi 包装器。 You can choose between classic hardcoded "golang.org/x/sys/windows", modern and experimental "github.com/Andoryuuta/kiwi", but I would recommend you to use "github.com/0xrawsec/golang-win32/win32/kernel32".您可以在经典硬编码“golang.org/x/sys/windows”、现代和实验性“github.com/Andoryuuta/kiwi”之间进行选择,但我建议您使用“github.com/0xrawsec/golang-win32/win32” /内核32”。

The code below demonstrates how to get base address.下面的代码演示了如何获取基地址。 I published GitHub gist with full code that can find process ID by name and read float32 values.我发布了带有完整代码的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 // put PID here, you can find it in Cheat Engine process list
    baseAddress, _ := memoryReadInit(pid)
    fmt.Println("Base address is", baseAddress)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM