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

Issue

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:

enter image description here

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)

enter image description here

Solution

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 🙂

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

Answered By – Dmitriy

Answer Checked By – Dawn Plyler (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.