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

huangapple go评论106阅读模式
英文:

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

问题

我需要从另一个进程的内存中读取值,并根据给定的进程名称/ID、指针和偏移量将其实时输出给用户。我已经找到了另一个问题,并成功实现了从给定进程内存地址读取和转换浮点值的逻辑,但由于地址在我重新加入游戏时会发生变化,我需要计算它。我已经使用作弊引擎找到了指针和进程偏移量:

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

根据我理解的理论,需要使用以下算法来计算最终地址:

  1. 使用常量偏移量(+02518790)计算基地址(1DC45993300)
  2. 将该地址与指针值相加
  3. 从底部(5E0)到顶部(2E4)依次重复第2步
  4. 这就是您可以用来检索数据的最终地址

对于步骤2、3和4,我没有问题:我可以求和十六进制数并且可以在地址处读取进程内存,但我不知道如何使用偏移量来计算第一个地址,在Go中应该如何做到这一点?我正在尝试在Windows 10上实现这个。

更新: 我尝试了这个问题中的代码,但返回的基地址不正确。我得到的是7ff611530000,而作弊引擎中的实际基地址是1A009A6AB70。

更新2: 可能很难理解我要做什么,所以我添加了另一张图片。我需要找到如何进行这个“加法”操作以及如何找到红色方框中的地址(绿色可以计算,紫色是常量)。

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

英文:

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. I have found pointer and process offset using cheat engine:

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

From what I understood reading theory, final address needs to be calculated using this algorithm:

  1. Calculate base address (1DC45993300) using constant offset (+02518790)
  2. Take this address and add pointer value to it
  3. Repeat 2 step with every pointer value from bottom (5E0) to top (2E4)
  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? I'm trying to do this on 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

Update 2: It may be hard to understand what am I trying to do, so I added another picture. 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)

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

答案1

得分: 1

为了找到另一个进程的地址并读取值,你必须根据进程的偏移量和基地址进行计算。作弊引擎将读取地址值的操作显示为 [十六进制 + 十六进制] -> 指针编辑器中的地址。所以每当你看到 [地址 + 偏移量] -> 下一个地址,它意味着将地址和偏移量作为十六进制相加,并在进程内存中的该地址处读取值。获取的值是下一个地址,你应该使用它来获取下一个地址。重复此过程,直到达到最后一个偏移量,然后只需将地址和偏移量相加而不读取值。结果得到的地址就是值存储的位置。

如何找到基地址?虽然在作弊引擎中它可能看起来是固定的(如果你将 0 替换为 02518790,每次重新启动进程时都会得到相同的地址),但它只是一个虚拟地址,不要使用它。相反,使用 winapi 使用 EnumProcessModules 迭代指定进程的所有模块。你可以通过窗口标题在运行的应用程序中搜索 PID。将模块的文件名与 GetModuleFilenameExW 进行比较。当你找到具有恒定文件名的模块(在你的情况下是 "UE4Game-Win64-Shipping.exe")时,使用 GetModuleInformation 检索 LpBaseOfDll。而不是 EntryPoint,EntryPoint 不是基地址。

现在你有了 LpBaseOfDll,将常量偏移量添加到它上面(02518790),并读取结果地址处的值。这是你应该用来运行循环并添加偏移量的起始地址。因此,图像上标记为 "加法操作" 的部分是 LpBaseOfDll 和偏移量的和。实际上,作弊引擎只接受可执行文件名而不接受偏移量,尝试将 "kernel32.dll" 放入地址字段中 根据进程句柄和偏移量,使用Golang计算另一个进程内存的地址。

要与虚拟内存交互,你必须使用 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 // put PID here, you can find it in Cheat Engine process list
	baseAddress, _ := memoryReadInit(pid)
	fmt.Println("Base address is", baseAddress)
}
英文:

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. 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. 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. Instead, use winapi to iterate through all modules of the specified process using EnumProcessModules. You can find PID by searching in running apps by window's title. Compare module's filename with GetModuleFilenameExW. When you found the module with constant filename ("UE4Game-Win64-Shipping.exe" in your case), use GetModuleInformation to retrieve 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. 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. In fact, Cheat Engine accepts just executable name without offset, try putting "kernel32.dll" into address field 根据进程句柄和偏移量,使用Golang计算另一个进程内存的地址。

To interact with virtual memory, you must use windows native api (kernel32.dll). As in any other language, Go has a wrapper for 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".

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.

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

huangapple
  • 本文由 发表于 2022年4月2日 18:16:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/71716646.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定