赞
踩
在按键精灵篇使用取色和模拟按钮,已经实现了对一个游戏自动吃血脚本,但是也留下了一些不足,本篇博客将从读取游戏内存的方式去实现对一个游戏的自动加血
本篇记录了使用 Cheat Engine寻找到血量内存地址,使用C#语言循环读取血量内存,监测血量变化,然后模拟按键按键,来达到精准补血的操作
具体步骤为:
Cheat Engine 也就是大名鼎鼎的CE修改器,功能非常强大,界面如下
打开CE载入游戏进程,搜索血量值1223,会出现一很多搜索结果,然后脱下自己的装备(脱下装备会导致血量值变换)发现自己血量变成942,然后在搜索942,还是有很多搜索结果,这时在穿上装备,如此往复,直到搜索结果变得很少,然后切换一下地图,可以然后观察一下CE那个和血量保持一致的就是要找的血量存储地址,但是这个地址还不能拿来直接用,因为这个地址是一个动态地址,关闭游戏重开一下就没有用了,因此还要去找到人物的基址
关于找基址有两种方法,一种是一层一层向上查,另一种是指针扫描,这里就用一层一层向上找的方法把,因为很简单
然后去ce搜 03501758
要勾上十六进制
绿色就要找的基址了, 可以看到血量的地址是由 [neuz.exe+4E99D8] + 820个偏移得到
这样基址就找到了
可以在ce中手动添加一下基址,然后填入对应的偏移值,就知道是否正确了,如果是正确的即使退出游戏,重新运行也会是正确的数据,到这里CE部分就已经完成了
这里使用C#来读取游戏的数据,当然大多数外怪程序都是用易语言编写的,其实使用什么语言来编写应该都是可以的,重要的是知道流程和方法就行,想想刚才在CE手动添加基址的过程,其实就是一个程序读取另一个程序数据的过程,只需要把对应的操作还原成代码就可以了
使用 Process.GetProcessesByName() 去查询进程Id
// 进程名称
string processName = "Neuz";
// 查找进程,如果多开就会有多个
Process[] arrayProcess = Process.GetProcessesByName(processName);
// 得到进程Id
mProcessId = arrayProcess[0].Id;
具体流程为:
先创建出一个内存空间
然后打开进程句柄
然后把该进程句柄下某个地址的数据,拷贝到刚刚创建出来的内存空间上
具体代码为:
// 创建一个内存空间 byte[] buffer = new byte[4]; // 获取刚刚创建的内存空间在内存中的地址 IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); // 最高权限获取进程句柄 IntPtr hProcess = WinAPI.OpenProcess(0x1F0FFF, false, processId); //将指定内存中的值读入内存空间 WinAPI.ReadProcessMemory(hProcess, (IntPtr)pAddreass, byteAddress, 4, IntPtr.Zero); //关闭操作 WinAPI.CloseHandle(hProcess); //从非托管内存中读取一个 32 位带符号整数。 还原成int数据 Marshal.ReadInt32(byteAddress);
因为这段代码会频繁用到,可以把它抽取成一个方法,方便调用
/// <summary> /// 读取一个int数据 /// </summary> /// <param name="pAddreass">要读取的地址</param> /// <param name="processId">要读取的进程Id</param> /// <returns></returns> public static int ReadMemoryValue(int pAddreass, int processId) { try { // 创建一个内存空间 byte[] buffer = new byte[4]; // 获取刚刚创建的内存空间在内存中的地址 IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); // 最高权限获取进程句柄 IntPtr hProcess = WinAPI.OpenProcess(0x1F0FFF, false, processId); //将指定内存中的值读入内存空间 WinAPI.ReadProcessMemory(hProcess, (IntPtr)pAddreass, byteAddress, 4, IntPtr.Zero); //关闭操作 WinAPI.CloseHandle(hProcess); //从非托管内存中读取一个 32 位带符号整数。 还原成int数据 return Marshal.ReadInt32(byteAddress); } catch { return 0; } }
这里根据 先读基址数据,先添加上血量的偏移就得到了血量的地址,在去读一下血量的地址,就得到了游戏中实时运行的血量了
// 因为这个游戏的入口地址是变化的,因此需要先去找到进程的入口
var baseaddress = mProcess.MainModule.BaseAddress.ToInt32();
// 得到基址的数据
address_user = WinAPI.ReadMemoryValue(baseaddress + offset_user, mProcessId);
// 得到血量数据
TotalHP = WinAPI.ReadMemoryValue(address_user + offset_hp, mProcessId);
搭一个界面,看看效果,这样就实现了读取血量数据了
只需要加一个定时器,循环读取,那么就能一直知道血量的变化
使用user32中的向进程发送消息的方法来模拟 键盘按下
[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern int PostMessage(IntPtr hWnd, int Msg, System.Windows.Forms.Keys wParam, int lParam);
模拟按一下 F1
// 按下f1
WinAPI.PostMessage(formHandler.MainWindowHandle, WM_KEYDOWN, Keys.F1, 0);
Thread.Sleep(60);
WinAPI.PostMessage(formHandler.MainWindowHandle, WM_KEYUP, Keys.F1, 0);
当血量减少后,就按一下
以上就是本篇博客讲述的内容了,本文简单的讲解了使用ce查找游戏数据,找基址,使用C#读取游戏内存地址的过程,还是有点复杂的,但是完成了也很有成就感!
根据进程名称获取进程Id
Process[] arrayProcess = Process.GetProcessesByName(processName);;
根据进程id获取进程句柄
Process process= Process.GetProcessById(mProcessId);
读取某个进程中某个地址的数据
// 创建一个内存空间 byte[] buffer = new byte[4]; // 获取刚刚创建的内存空间在内存中的地址 IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); // 最高权限获取进程句柄 IntPtr hProcess = WinAPI.OpenProcess(0x1F0FFF, false, processId); //将指定内存中的值读入内存空间 WinAPI.ReadProcessMemory(hProcess, (IntPtr)pAddreass, byteAddress, 4, IntPtr.Zero); //关闭操作 WinAPI.CloseHandle(hProcess); //从非托管内存中读取一个 32 位带符号整数。 还原成int数据 Marshal.ReadInt32(byteAddress);
向某个进程发送消息(模拟键盘)
WinAPI.PostMessage(formHandler.MainWindowHandle, WM_KEYDOWN, Keys.F1, 0);
Thread.Sleep(40);
WinAPI.PostMessage(formHandler.MainWindowHandle, WM_KEYUP, Keys.F1, 0);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。