读写阳光
大约 3 分钟game-plugin
创建项目
地址类
头文件
头文件 Addr.h 的源码:
#pragma once
#ifndef ADDR_H
#define ADDR_H
#include <iostream>
#include <Windows.h>
using namespace std;
class Addr
{
private:
UINT_PTR addr;
Addr* child;
public:
Addr(UINT_PTR a);
void setAddr(UINT_PTR a);
UINT_PTR getAddr();
void setChild(Addr* a);
Addr* getChild();
string toString();
};
#endif
类源码文件
类源码文件 Addr.cpp 的源码
#include "Addr.h"
#include<sstream>
using namespace std;
// 构造函数
Addr::Addr(UINT_PTR a):addr(a) {}
void Addr::setAddr(UINT_PTR a) {
addr = addr;
}
UINT_PTR Addr::getAddr() {
return addr;
}
void Addr::setChild(Addr* a) {
child = a;
}
Addr* Addr::getChild() {
return child;
}
string Addr::toString() {
return "addr:"+std::to_string(addr);
}
入口文件
项目入口类文件的全部源码:
#include <iostream>
#include <Windows.h>
#include <string>
#include "Addr.h"
using namespace std;
#pragma region 读取阳光相关的全局变量
HWND gameWindowHwnd = 0;// 游戏窗口句柄
DWORD pid, tid;// 游戏 pid,tid.十进制数字
HANDLE processHandle = 0;// 游戏进程句柄
// 下面的基址和偏移是180天翼云盘家庭共享目录下:教程与资料 > 郁金香2021 > 用到的工具 > 用到的游戏和工具 下的 “GMEPlantsVsZombie练习用”
// 中的数据,已经验证正确
UINT_PTR BASE_ADDR = 0x006A9EC0;
UINT_PTR OFFSET01 = 0x768;
UINT_PTR OFFSET02 = 0x5560;
UINT_PTR directAddr = 0;// 阳光的直接地址
#pragma endregion
unsigned int sunVal = 0;// 阳光值
Addr* addrTree = NULL;// 递归结构内存地址
void showMenu()
{
cout << "************************" << endl;
cout << "***** 1. 获取进程句柄 *****" << endl;
cout << "***** 2. 读取阳光数据 *****" << endl;
cout << "***** 3. 写入阳光5K *****" << endl;
cout << "***** 0. 退出系统 *****" << endl;
cout << "请输入要操作的编号:" << endl;
}
void printl(string msg) {
cout << msg << endl;
}
#pragma region 读取阳光
// 初始化基址和偏移对象,递归属性对象,读取阳光值时通过递归算法应用该基址+偏移的数据结构
void initAddr() {
addrTree = new Addr(BASE_ADDR);
Addr* offset1P = new Addr(OFFSET01);
Addr* offset2P = new Addr(OFFSET02);
offset1P->setChild(offset2P);
addrTree->setChild(offset1P);
//cout << "已初始化基址和偏移,十进制基址是:" << baseAddrP->toString() << endl;
}
// 读取指定内存地址的4字节数据
unsigned int read(UINT_PTR addr) {
// 使用进程句柄读取游戏数据
unsigned int readBuff = 0;
ReadProcessMemory(processHandle, (LPCVOID)addr, &readBuff, 4, 0);
//printf("从地址:%d(十进制),%X(十六进制) 读取到的4字节数据的\r\n16进制,10进制,无符号数据依次是:%X,%d,%u\r\n", addr, addr, readBuff, readBuff, readBuff);// 如果读取过程出错使用 GetLastError() 获取并处理
return readBuff;
}
// 获取游戏进程句柄
int getProcessHandler() {
if (processHandle > 0) {
printf("已经获取进程句柄是:%d", processHandle);
return 1;
}
// 获取窗口句柄
gameWindowHwnd = FindWindowA("MainWindow", "植物大战僵尸中文版");
printf("游戏窗口句柄:%p\r\n", gameWindowHwnd);
// 使用窗口句柄获取 pid,tid
tid = GetWindowThreadProcessId(gameWindowHwnd, &pid);
printf("十进制:\r\ntid=%d,pid=%d\r\n", tid, pid, pid);
printf("十六进制:\r\ntid=%X,pid=%X\r\n", tid, pid, pid);
// 使用 pid 获取进程句柄
processHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
printf("游戏进程句柄:%d\r\n", processHandle);
// 初始化基址对象
initAddr();
return 1;
}
// 递归读取内存数据
void recursionAddr(Addr* addr) {
unsigned int addrVal = addr->getAddr();
Addr* child = addr->getChild();
directAddr = sunVal + addrVal;
sunVal = read(directAddr);
if (child != NULL) recursionAddr(child);
}
// 执行读取阳光
void getSunNum() {
//read(read(read(BASE_ADDR) + OFFSET01) + OFFSET02);
if (processHandle == 0) getProcessHandler();// 先获取进程句柄再获取数据
sunVal = 0;
recursionAddr(addrTree);
cout << "阳光:" << sunVal << endl;
}
void writeSunVal() {
if (directAddr == 0) getSunNum();// 先读取一次阳光并获得阳光的直接地址
int newValue = 5000;
WriteProcessMemory(processHandle, (PBYTE*)directAddr, &newValue, sizeof(newValue), 0);
}
#pragma endregion
int main()
{
int select = 0;
while (true)
{
showMenu();
cin >> select;
system("cls");
switch (select)
{
case 1:
getProcessHandler();
break;
case 2:
getSunNum();
break;
case 3:
writeSunVal();
break;
case 0:
printl("欢迎再来!");
system("pause");
return 0;
default:
cout << "请输入0-4进行操作!" << endl;
break;
}
cout << endl << endl << endl;
}
system("pause");
return 0;
}
