• 植物大战僵尸杂交版破解C++实现


    前言

    最近出来的PVZ杂交版又掀起一波热潮,在各大短视频平台也有一席之地,借助工具Cheat Engine,写了个简单的植物大战僵尸杂交版破解程序,话不多说,我们来看如何实现的。
    工具:Cheat Engine、visual studio (MFC支持)、植物大战僵尸杂交版

    准备工作:基地址与偏移

    通过CE寻找基地址的工作可以参考其他人的博客:
    通过CE寻找游戏基址1
    通过CE寻找游戏基址2
    这里直接给出对应内容:【基址+偏移】
    阳光值:0x006A9EC0 + 0x00000768 + 0x00005560
    银币值:0x006A9EC0 + 0x0000082C + 0x00000208
    金币值:0x006A9EC0 + 0x0000082C + 0x0000020C
    钻石值:0x006A9EC0 + 0x0000082C + 0x00000210
    冷却值:0x006A9EC0 + 0x00000768 + 0x00000144 +{
    0x00000070, 0x000000C0, 0x00000110, 0x00000160,
    0x000001B0, 0x00000200, 0x00000250, 0x000002A0,
    0x000002F0, 0x00000340, 0x00000390, 0x000003E0,
    0x00000430, 0x00000480, 0x000004D0, 0x00000520
    对应卡牌栏目第几章卡牌,索引就是几,实际上卡牌不会超过14张,只要给出14个就行了,找到前几个偏移量之后可以按照规律往后推测。
    }

    UI界面设计和绑定

    项目模板

    使用MFC应用程序,选择基于对话框选项

    总览图

    UI设计图

    生成与实现

    1、依此双击按钮、单选框,studio会自动建立信号与函数的映射。
    2、Dlg.h中添加成员变量:

    public:
    UINT sunvalue;	//阳光
    UINT money_a;	//银币
    UINT money_b;	//金币
    UINT money_c;	//钻石
    int check1;		//锁定阳光	check 的状态
    int check2;		//无冷却	check 的状态
    

    3、Dlg.cpp中进行内容绑定:

    void CPVZCrackerDlg::DoDataExchange(CDataExchange* pDX){
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1, sunvalue);	//将edit1的内容与sunvalue绑定,以下同理
    	DDX_Text(pDX, IDC_EDIT2, money_a);	
    	DDX_Text(pDX, IDC_EDIT3, money_b);	
    	DDX_Text(pDX, IDC_EDIT4, money_c);	
    	DDX_Check(pDX, CHECK1, check1);
    	DDX_Check(pDX, CHECK2, check2);
    }
    

    4、如何让check选择时,实现阳光锁定和刷新冷却呢?
    可以在check勾选时,开启定时器,每隔0.5s进行模拟点击刷新事件来达到效果
    因此需要引入定时器模块,给出相关博客(主要参考2)
    MFC中如何使用定时器:1
    MFC中如何使用定时器:2
    创建出void XXXXXDlg::OnTimer(UINT_PTR nIDEvent)。
    当勾选状态时,打开计时器,未勾选状态时,关闭计时器即可

    5、经过上面的操作后,Dlg.h内容大致如下:

    
    // PVZCrackerDlg.h: 头文件
    //
    
    #pragma once
    
    // CPVZCrackerDlg 对话框
    class CPVZCrackerDlg : public CDialogEx
    {
    // 构造
    public:
    	CPVZCrackerDlg(CWnd* pParent = nullptr);	// 标准构造函数
    	UINT sunvalue;	//阳光
    	UINT money_a;	//银币
    	UINT money_b;	//金币
    	UINT money_c;	//钻石
    	int check1;		//锁定阳光	check 的状态
    	int check2;		//无冷却	check 的状态
    // 对话框数据
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_PVZCRACKER_DIALOG };
    #endif
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
    
    
    // 实现
    protected:
    	HICON m_hIcon;
    
    	// 生成的消息映射函数
    	virtual BOOL OnInitDialog();
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	DECLARE_MESSAGE_MAP()
    public:
    	afx_msg void OnBnClickedButton1();
    	afx_msg void OnBnClickedButton2();
    	afx_msg void OnBnClickedButton3();
    	afx_msg void OnBnClickedButton4();
    	afx_msg void OnBnClickedButton5();
    
    	afx_msg void OnBnClickedCheck1();
    	afx_msg void OnBnClickedCheck2();
    	afx_msg void OnTimer(UINT_PTR nIDEvent);
    
    	int TIM_X ;
    	afx_msg void OnClose();
    };
    
    

    信号处理

    1、阳光值更新:BTN1

    void CPVZCrackerDlg::OnBnClickedButton1(){
    	// 修改阳光
    	UpdateData(TRUE);	//先进行数据更新
    	HWND PVZ;			//获取窗口句柄
    	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");//这里需要对应游戏窗口名。
    	DWORD pid = 0;
    	GetWindowThreadProcessId(PVZ, &pid);	//获取进程id
    	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);//打开进程,获取所有权
    
    	SIZE_T ipread = 0;           //下面要用的参数,实际上往往忽略,但不写又不行
    
    	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
    	DWORD offset1 = 0x00000768;
    	DWORD offset2 = 0x00005560;
    	//[A]->B 表示将A地址里的值拿到B中,不加[]代表立即数下文同理,如有错误欢迎指正
    	//[base]->sunbase
    	DWORD sunbase = 0;
    	ReadProcessMemory(handle, LPCVOID(base), &sunbase, sizeof(DWORD), &ipread);
    
    	//[sunbase+offset1]->sunoffset1
    	DWORD sunoffset1 = 0;
    	ReadProcessMemory(handle, LPCVOID(sunbase + offset1), &sunoffset1, sizeof(DWORD), &ipread);
    
    	//sunvalue -> [sunoffset1+offset2]
    	DWORD svalue = sunvalue;
    	WriteProcessMemory(handle, LPVOID(sunoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
    }
    

    2、三种钱币值更新:BTN2-BTN4

    void CPVZCrackerDlg::OnBnClickedButton2(){
    	// TODO: 在此添加控件通知处理程序代码
    	// 修改银币
    	UpdateData(TRUE);
    	HWND PVZ;
    	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
    	DWORD pid = 0;
    	GetWindowThreadProcessId(PVZ, &pid);
    	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    	SIZE_T ipread = 0;           //下面要用的参数
    
    	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
    	DWORD offset1 = 0x0000082C;
    	DWORD offset2 = 0x00000208;
    
    	//[base]->moneybase
    	DWORD moneybase = 0;
    	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);
    
    	//[moneybase+offset1]->moneyoffset1
    	DWORD moneyoffset1 = 0;
    	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);
    
    	//money_a -> [moneyoffset1+offset2]
    	DWORD svalue = money_a;
    	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
    }
    
    void CPVZCrackerDlg::OnBnClickedButton3(){
    	// TODO: 在此添加控件通知处理程序代码
    	// 修改金币
    	UpdateData(TRUE);
    	HWND PVZ;
    	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
    	DWORD pid = 0;
    	GetWindowThreadProcessId(PVZ, &pid);
    	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    	SIZE_T ipread = 0;           //下面要用的参数
    
    	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
    	DWORD offset1 = 0x0000082C;
    	DWORD offset2 = 0x0000020C;
    
    	//[base]->moneybase
    	DWORD moneybase = 0;
    	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);
    
    	//[moneybase+offset1]->moneyoffset1
    	DWORD moneyoffset1 = 0;
    	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);
    
    	//money_b -> [moneyoffset1+offset2]
    	DWORD svalue = money_b;
    	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
    }
    
    
    
    void CPVZCrackerDlg::OnBnClickedButton4(){
    	// TODO: 在此添加控件通知处理程序代码
    	// 修改钻石
    	UpdateData(TRUE);
    	HWND PVZ;
    	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
    	DWORD pid = 0;
    	GetWindowThreadProcessId(PVZ, &pid);
    	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    	SIZE_T ipread = 0;           //下面要用的参数
    
    	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
    	DWORD offset1 = 0x0000082C;
    	DWORD offset2 = 0x00000210;
    
    	//[base]->moneybase
    	DWORD moneybase = 0;
    	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);
    
    	//[moneybase+offset1]->moneyoffset1
    	DWORD moneyoffset1 = 0;
    	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);
    
    	//money_a -> [moneyoffset1+offset2]
    	DWORD svalue = money_c;
    	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
    }
    

    3、冷却刷新:BTN5

    void CPVZCrackerDlg::OnBnClickedButton5(){
    	// 修改冷却
    	UpdateData(TRUE);
    	HWND PVZ;
    	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
    	DWORD pid = 0;
    	GetWindowThreadProcessId(PVZ, &pid);
    	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    	SIZE_T ipread = 0;           //下面要用的参数
    
    	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
    	DWORD offset1 = 0x00000768;
    	DWORD offset2 = 0x00000144;
    	DWORD offset3[16] = {
    		0x00000070, 0x000000C0, 0x00000110, 0x00000160,
    		0x000001B0, 0x00000200, 0x00000250, 0x000002A0,
    		0x000002F0, 0x00000340, 0x00000390, 0x000003E0,
    		0x00000430, 0x00000480, 0x000004D0, 0x00000520
    	};
    
    	//[base]->freshbase
    	DWORD freshbase = 0;
    	ReadProcessMemory(handle, LPCVOID(base), &freshbase, sizeof(DWORD), &ipread);
    
    	//[freshbase+offset1]->freshoffset1
    	DWORD freshoffset1 = 0;
    	ReadProcessMemory(handle, LPCVOID(freshbase + offset1), &freshoffset1, sizeof(DWORD), &ipread);
    
    	//[freshoffset1+offset2]->freshoffset2
    	DWORD freshoffset2 = 0;
    	ReadProcessMemory(handle, LPVOID(freshoffset1 + offset2), &freshoffset2, sizeof(DWORD), &ipread);
    
    	//1 ->[freshoffset2+offset3]
    	DWORD freshvalue = 1;	//1代表冷却完毕	其他代表正在冷却
    	for (int i = 0; i < 16; ++i)
    		WriteProcessMemory(handle, LPVOID(freshoffset2 + offset3[i]), &freshvalue, sizeof(DWORD), &ipread);
    }
    

    4、锁定阳光:check1

    void CPVZCrackerDlg::OnBnClickedCheck1(){
    	// TODO: 在此添加控件通知处理程序代码
    	CButton* pBtn = (CButton*)GetDlgItem(CHECK1);
    	int checked = pBtn->GetCheck();	//获取check状态
    	//实际上可以直接check1
    	switch (checked){
    	case 1: {
    		SetTimer(1, 500, NULL);	//设置500ms为周期的定时器,标签为1,并开启
    		break;
    	}
    	case 0: {
    		KillTimer(1);			//关闭标签为1的定时器
    		break;
    	}
    	default:
    		break;
    	}
    }
    

    5、无冷却:check2

    void CPVZCrackerDlg::OnBnClickedCheck2(){
    	// TODO: 在此添加控件通知处理程序代码
    	CButton* pBtn = (CButton*)GetDlgItem(CHECK2);
    	int checked = pBtn->GetCheck();
    
    	switch (checked) {
    	case 1: {
    		SetTimer(2, 500, NULL);
    		break;
    	}
    	case 0: {
    		KillTimer(2);
    		break;
    	}
    	default:
    		break;
    	}
    }
    

    6、OnTimer()和OnClose()处理函数

    void CPVZCrackerDlg::OnTimer(UINT_PTR nIDEvent)
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	switch (nIDEvent){
    	case 1: OnBnClickedButton1(); break;
    	case 2: OnBnClickedButton5(); break;
    	default:
    		break;
    	}
    	CDialogEx::OnTimer(nIDEvent);
    }
    
    
    void CPVZCrackerDlg::OnClose()
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	KillTimer(1);
    	KillTimer(2);
    	CDialogEx::OnClose();
    }
    

    7、其余未描述部分参考

    
    // PVZCrackerDlg.cpp: 实现文件
    #include "pch.h"
    #include "framework.h"
    #include "PVZCracker.h"
    #include "PVZCrackerDlg.h"
    #include "afxdialogex.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    // CPVZCrackerDlg 对话框
    CPVZCrackerDlg::CPVZCrackerDlg(CWnd* pParent /*=nullptr*/)
    	: CDialogEx(IDD_PVZCRACKER_DIALOG, pParent){
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    	check1 = 0;
    	check2 = 0;
    	sunvalue = 5000;
    	money_a = 10000;
    	money_b = 10000;
    	money_c = 10000;
    	TIM_X = 0;
    }
    
    void CPVZCrackerDlg::DoDataExchange(CDataExchange* pDX){
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1, sunvalue);	//将edit1的内容与sunvalue绑定,以下同理
    	DDX_Text(pDX, IDC_EDIT2, money_a);	
    	DDX_Text(pDX, IDC_EDIT3, money_b);	
    	DDX_Text(pDX, IDC_EDIT4, money_c);	
    	DDX_Check(pDX, CHECK1, check1);
    	DDX_Check(pDX, CHECK2, check2);
    }
    
    BEGIN_MESSAGE_MAP(CPVZCrackerDlg, CDialogEx)
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_BN_CLICKED(IDC_BUTTON1, &CPVZCrackerDlg::OnBnClickedButton1)
    	ON_BN_CLICKED(IDC_BUTTON2, &CPVZCrackerDlg::OnBnClickedButton2)
    	ON_BN_CLICKED(IDC_BUTTON3, &CPVZCrackerDlg::OnBnClickedButton3)
    	ON_BN_CLICKED(IDC_BUTTON4, &CPVZCrackerDlg::OnBnClickedButton4)
    	ON_BN_CLICKED(IDC_BUTTON5, &CPVZCrackerDlg::OnBnClickedButton5)
    
    	
    	ON_BN_CLICKED(CHECK1, &CPVZCrackerDlg::OnBnClickedCheck1)
    	ON_BN_CLICKED(CHECK2, &CPVZCrackerDlg::OnBnClickedCheck2)
    	ON_WM_TIMER()
    	ON_WM_CLOSE()
    END_MESSAGE_MAP()
    
    
    // CPVZCrackerDlg 消息处理程序
    
    BOOL CPVZCrackerDlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    
    	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    	//  执行此操作
    	SetIcon(m_hIcon, TRUE);			// 设置大图标
    	SetIcon(m_hIcon, FALSE);		// 设置小图标
    
    	// TODO: 在此添加额外的初始化代码
    	this->SetWindowTextW(L"植物大战僵尸杂交版破解 by 和八哥的环球探险");
    	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    }
    
    // 如果向对话框添加最小化按钮,则需要下面的代码来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,这将由框架自动完成。
    
    void CPVZCrackerDlg::OnPaint()
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // 用于绘制的设备上下文
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		// 使图标在工作区矩形中居中
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// 绘制图标
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialogEx::OnPaint();
    	}
    }
    
    //当用户拖动最小化窗口时系统调用此函数取得光标
    //显示。
    HCURSOR CPVZCrackerDlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
  • 相关阅读:
    pandas
    监控方法论
    五、T100固定资产之固定资产盘点管理篇
    【App自动化测试】(十)特殊控件Toast识别
    家政服务行业怎么做微信小程序开发
    git clone:SSL: no alternative certificate subject name matches target host name
    联发科3纳米芯片预计2024年量产,此前称仍未获批给华为供货
    windows10安装其他版本cuda环境
    Vue3为什么推荐使用ref而不是reactive
    etcd和redis的对比
  • 原文地址:https://blog.csdn.net/2301_81290340/article/details/139332111