什么?go也可以修改游戏内存?

众所周知,go是一款天生多线程的语言,一般用来作为服务端开发,但是并不代表它只能作为服务端开发,我们还可以用来开发一些桌面端小工具。

今天我们将使用windows经典游戏《扫雷》,来作为我们的修改对象,通过go去修改扫雷游戏运行时内存里面的数值。

首先,我们运行扫雷

好的,游戏成功启动,我们打开著名的CE修改器(Cheat Engine)

然后找到扫雷这个进程,并打开它

成功打开之后我们查看现在的“雷数”,可以看到,现在是40个雷,我们选择扫描类型精确数值,然后输入40,然后点击首次扫描

找到一些地址

此时我们先不着急,我们切换点击扫雷左上角的“游戏”按钮,然后切换初级,此时“雷数”变为了10,我们把数值改成10,然后点击再次扫描

此时我们精确到3个基址

我们可以通过鼠标右键点击扫雷,然后标记雷区,这时我们发现第一个基址发生了变化,变成了9,于是我们就找到了这个雷数的基址

我们双击第一个地址,然后下方出现的16进制的地址也就是我们最终需要修改的基址 0x01005194 (注:0x是用来表示16进制的)

我们发现通过CE可以直接去进行修改,但是这样会造成我们每次都需要打开CE去进行扫描数值,比较麻烦,怎么办呢,这就到我们的第二步,打开我们的golang进行编码

1.添加自动获取pid的方法,这样就不用每次都手动选择程序的pid了

func getPID(name string) (pid int) {
  // 查找指定名称的进程ID
  cmd := exec.Command("tasklist", "/NH", "/FI", "IMAGENAME eq "+name)
  output, err := cmd.Output()
  if err != nil {
    fmt.Println("command error:", err)
    return
  }
  lines := strings.Split(string(output), "\r\n")
  for _, line := range lines {
    if strings.TrimSpace(line) == "" {
      continue
    }
    fields := strings.Fields(line)
    pid, err = strconv.Atoi(fields[1])
    if err == nil {
      fmt.Println("pid 获取成功", pid)
      return
    }
  }
  return
}


 

2.完整代码实现

package main

import (
  "fmt"
  "golang.org/x/sys/windows"
  "os/exec"
  "strconv"
  "strings"
  "unsafe"
)

const (
  AppName  = "winmine.exe"       // 应用名称
  Addr     = uintptr(0x01005194) // 需要修改的基址
  NewValue = 66                  // 新的值
)

func main() {
  pid := getPID(AppName)
  // 打开进程,获取进程句柄 windows.PROCESS_ALL_ACCESS = 0x000F0000|0x00100000|0xFFF
  handle, err := windows.OpenProcess(0x000F0000|0x00100000|0xFFF, false, uint32(pid))
  if err != nil {
    fmt.Println("OpenProcess error:", err)
    return
  }
  defer windows.CloseHandle(handle)

  // 读取进程内存中的值
  var value int32
  var nread uintptr
  err = windows.ReadProcessMemory(handle, Addr, (*byte)(unsafe.Pointer(&value)), 4, &nread)
  if err != nil {
    fmt.Println("read process memory error:", err)
    return
  }
  fmt.Println("原始值:", value)
  value = int32(NewValue) // 需要写入的值
  var nwrite uintptr
  err = windows.WriteProcessMemory(handle, Addr, (*byte)(unsafe.Pointer(&value)), 4, &nwrite)
  if err != nil {
    fmt.Println("write process memory error:", err)
    return
  }
  fmt.Println("修改后的值:", value)
}

func getPID(name string) (pid int) {
  // 查找指定名称的进程ID
  cmd := exec.Command("tasklist", "/NH", "/FI", "IMAGENAME eq "+name)
  output, err := cmd.Output()
  if err != nil {
    fmt.Println("command error:", err)
    return
  }
  lines := strings.Split(string(output), "\r\n")
  for _, line := range lines {
    if strings.TrimSpace(line) == "" {
      continue
    }
    fields := strings.Fields(line)
    pid, err = strconv.Atoi(fields[1])
    if err == nil {
      fmt.Println("pid 获取成功", pid)
      return
    }
  }
  return
}

上述代码通过应用名自动去查找pid,然后打开对应的句柄,去修改我们找到的基址的数值,上面代码只是一个示例,实际应用可以添加GUI,可以去动态的输入我们需要修改的数值

最终的运行结果如下

本文/资源仅供学习交流,请勿用于任何违法用途

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清欢大魔王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值