前言
最近刷视频总是刷到那个杂交版的植物大战僵尸,于是就下载了一个来玩
作者主页:潜艇伟伟迷-哔哩哔哩_bilibili目前更新到了v2.0.88,这是安装程序:植物大战僵尸杂交版v2.0.88
没想到一玩就一发不可收拾,而在此期间,我突然萌生了一个做外挂的想法,于是便四处寻找资料学习。而在市面上能够找到的有关植物大战僵尸的外挂基本上都是通过易语言实现的,而我却不想使用易语言,于是便有了下面的种种
这是对应的锁定和修改阳光程序:植物大战僵尸外挂v2.0.88
我又找到一个别人写的外挂,很nb!!!
https://noobxiaomeng.top/wp-content/uploads/2024/05/憨憨问号杂交版2.088专属辅助v1.986_下载完请重启一次.zip
使用CE更改阳光数值
首先使用CE对阳光进行简单的修改,我们打开CE附加植物大战僵尸的进程,然后随便开一关,扫描游戏的初始阳光2000:
结果发现有许多引用了2000的地址,暂时无法判断哪一个才是真正的地址
随后我们使用一个盒子,又捡起来了一个阳光,于是再次扫描 1850:
这时候就只有一个地址了,我们双击地址将其移到下面来,再双击数值,就可以随意进行阳光的更改了:
例如我这里将数值改为9000,则游戏内的阳光数也会变成9000
寻找阳光基址
上述使用CE以更改阳光的数值从而达到无限阳光的方法固然可行,但由于阳光的地址并不是固定的,因此每一局游戏我们都需要重新使用上述的方法,这是很繁琐的。所以我们需要寻找到真正的阳光基址,实现全自动修改阳光
我们再开一把游戏,重复上述步骤
我们可以看见一个偏移5560,同时出现了一行字"您要查找的该地址的指针数值可能是288B3E20"
然后会出现许多行数据
我们逐个寻找什么访问了这个地址,主要查找其中的mov指令
双击进去发现EAX的地址正是288B3E20,同时得到偏移768
我们再查找ECX的地址0830A1A8
可以看见下面有一些绿色的,而绿色的代表的则是静态基址,也就是说我们查看绿色内容的地址就得到了阳光真正的基址:
可以看见真正的基址是006A9EC0
脚本
当我们知道偏移以及基址之后,我们就可以篡改其内存中的值了
#include <iostream>
#include <windows.h>
#include <thread>
#include "conio.h"
#define Ver Ver2.0
using namespace std;
DWORD DPid{ 0 };
//菜单函数 每次输入完指令都会调用它 重新打印下菜单
void menu() {
    cout << "***********************" << endl;
    cout << "**** 1、修改阳光值 ****" << endl;
    cout << "**** 2、锁定阳光值 ****" << endl;
    cout << "**** 0、退出本程序 ****" << endl;
    cout << "***********************" << endl;
    cout << "请输入相关指令:" << endl;
}
//修改阳光值
void yG(DWORD pid) {
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DPid);
    if (hProcess == NULL)
    {
        printf("你当前尚未进入关卡!请进入游戏关卡:自动获取阳光");
    }
    DWORD YGJZ{ 0x6A9EC0 }; //静态基址
    DWORD YGJZValue{ 0 };
    DWORD nSize{ 0 };
    BOOL ok = ReadProcessMemory(hProcess, (LPVOID)YGJZ, &YGJZValue, sizeof(DWORD), &nSize);
    DWORD YGjz2{ 0x768 }; //一级偏移
    DWORD YGjz2Value{ 0 };
    BOOL ok2 = ReadProcessMemory(hProcess, (LPVOID)(YGJZValue + YGjz2), &YGjz2Value, sizeof(DWORD), &nSize);
    DWORD YGJZ3{ 0x5560 }; //二级偏移
    DWORD YGJZ3Value{ 0 };
    BOOL OK3 = ReadProcessMemory(hProcess, (LPVOID)(YGjz2Value + YGJZ3), &YGJZ3Value, sizeof(DWORD), &nSize);
    cout << "当前阳光值:[ " << YGJZ3Value << " ] \n请输入要修改的阳光值:\n";  //最终及地址
    int edit;
    cin >> edit;
    BOOL wri = WriteProcessMemory(hProcess, (LPVOID)(YGjz2Value + YGJZ3), &edit, sizeof(edit), &nSize);
    if (wri == true)
    {
        cout << "写入成功!" << endl;
    }
}
//锁定阳光值
void setsun(DWORD pid) {
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DPid);
    if (hProcess == NULL)
    {
        printf("你当前尚未进入关卡!请进入游戏关卡:自动获取阳光");
    }
    DWORD YGJZ{ 0x6A9EC0 }; //静态基址
    DWORD YGJZValue{ 0 };
    DWORD nSize{ 0 };
    BOOL ok = ReadProcessMemory(hProcess, (LPVOID)YGJZ, &YGJZValue, sizeof(DWORD), &nSize);
    DWORD YGjz2{ 0x768 }; //一级偏移
    DWORD YGjz2Value{ 0 };
    BOOL ok2 = ReadProcessMemory(hProcess, (LPVOID)(YGJZValue + YGjz2), &YGjz2Value, sizeof(DWORD), &nSize);
    DWORD YGJZ3{ 0x5560 }; //二级偏移
    DWORD YGJZ3Value{ 0 };
    BOOL OK3 = ReadProcessMemory(hProcess, (LPVOID)(YGjz2Value + YGJZ3), &YGJZ3Value, sizeof(DWORD), &nSize);
    cout << "当前阳光值:[ " << YGJZ3Value << " ] \n请输入要你要锁定的阳光值:\n";  //最终及地址
    int edit;
    cin >> edit;
    while (true)
    {
        if (_kbhit()) // 如果有按键被按下
        {
            if (_getch() == 'q') //如果按下了q键则跳出循环
            {
                break;
            }
        }
        Sleep(500);
        BOOL wri = WriteProcessMemory(hProcess, (LPVOID)(YGjz2Value + YGJZ3), &edit, sizeof(edit), &nSize);
    }
}
int main()
{
    system("mode con cols=32 lines=18  ");//设置控制台大小
    system("color a");                      //设置控制台字体颜色
    SetConsoleTitle(L"ZomKill Ver2.0");   //设置控制台标题
    HWND hGame = FindWindow(L"MainWindow", L"植物大战僵尸杂交版v2.0.88");
    int select;
    while (true)
    {
        if (hGame == NULL)
        {
            cout << "游戏未运行,请打开游戏再运行本辅助\n" << endl;
            return 0;
        }
        else
        {
            GetWindowThreadProcessId(hGame, &DPid); //拿出进程ID
            cout << "+++++++++++++++++++++++++++++\n当前游戏进程ID:" << DPid << endl;
        }
        menu();
        cin >> select;
        switch (select)
        {
        case 1:
            yG(DPid);
            break;
        case 2:
            setsun(DPid);
            break;
        default:
            break;
        }
        system("pause");
        system("cls");
    }
}













