植物大战僵尸外挂原理和代码编写(附源码会指针即可)

-1.植物大战僵尸讲解

植物大战僵尸修改器制作–从入门到入土-软件逆向-看雪-安全社区|安全招聘|kanxue.com

植物大战僵尸逆向解析
今天主要的目的就是讲解一下外挂的基本实现原理

  1. 实现阳光值无限
  2. 修改游戏逻辑
  3. 用c++编写游戏外挂

1.程序的前置知识:

  1. 程序的基本概念
    其实所有的exe,本质来说都是一个文本文件
    无论是浏览器还是QQ,微信等等,电脑和手机同理
    本质来说都是一个文本文件
    类比来说就是一个写满数据的txt文本!

  2. Cheat Engine一款exe程序文本读取器
    既然程序是一个文本,那我们就需要一个文本读取器来帮我们阅读这个文本,因为exe是不断在运行代码的,所有也可以说它是一个动态文本
    而Cheat Engine就可以帮我们读取!

Cheat Engine及可以是笔也是眼睛!

2.实战寻找阳光变量的所在位置

通过Cheat Engine找到阳光变量的位置,并且尝试对他进行修改!
成功修改!
将该变量存储下来,并且重新开始一个游戏
发现这个阳光值不可以修改了,需要再次寻找阳光的地址!
这个问题留到最后编写外挂的时候讲解!

请添加图片描述

3.汇编的前置知识

这里我们又要补充一个概念:程序的本质的本质是什么?
之前我们说"其实所有的exe,本质来说都是一个文本文件"
那”文本文件txt“的本质又是什么呢???
其实”文本文件txt,电脑里的图片,exe“的本质都是0和1,组成的数据矩阵
本质来说就是0和1
知道了什么是代码什么是汇编

在学习汇编前我们需要知道什么是汇编!!!
机器码-》汇编语言-》高级语言

三条基本的汇编指令:
add A,B
sub A,B
mov A, B

4.实战修该游戏代码逻辑

  1. 修该种植阳光的代码
  2. 修改收集阳光的代码

5.实战编写植物大战僵尸外挂

请添加图片描述

6A9EC0 0x768 0x5560
请添加图片描述

0.单局修改阳光数值

使用cheatengine打开植物大战僵尸
请添加图片描述
阳光初始值为50,进行第一次搜索,左边的结果有577个!
请添加图片描述
改变阳光的值继续搜索!
将阳光的值消耗掉,阳光值变为0
再次搜索查看之前的搜索结果是否有值被改变成0,发现有两个!继续
请添加图片描述
再次收集阳光,数量变成25,再次搜索结果
发现只有一个变量存在!!可以确定这就是目标!
请添加图片描述
尝试修改阳光的值为999!
手动修改成功!
请添加图片描述
虽然这里的阳光地址可以修改阳光值,但如果这局游戏结束,再次使用这个地址修改阳光就会失效!
这是由于该地址不是基址会随程序的变化而变化,所以当重启游戏的时候,该地址就会失效需要寻找新的解决方案!

1.全局修改阳光数值

根据[[0.单局修改阳光数值]]获取到的变量地址进行分析,用来推导出阳光变量的基址
选中变量右击查看是什么地方访问了这个地址!
请添加图片描述

点击完"找出是什么访问了这个地址"后,就会弹出相应的汇编指令,与计数
其中计数会不断变化,按下esc可以暂停计数!
发现共有两条汇编指令在访问阳光的数值!
请添加图片描述

是一个地址加上偏移的值存储了阳光的值:

0041BAB5 - 03 82 60550000  - add eax,[edx+00005560]
00489825 - 8B 86 60550000  - mov eax,[esi+00005560]

可以得出此时edx或eax的值+0x00005560位置存储的就是阳光的值!

可以获取到edx或eax的值来继续追寻阳光变量的基址!
请添加图片描述

右击指令查看详细信息,可以找到eax的值0x1076DE98

这个可能与阳光的基址有关,将该值继续使用0x1076DE98搜索

请添加图片描述

搜索结果有52个,但其中并没有基址所以阳光的基地址可能是二级偏移继续寻找

这个可能与阳光的基址有关,将该值继续使用0x1076DE98搜索
请添加图片描述
搜索结果有52个,但其中并没有基址所以阳光的基地址可能是二级偏移继续寻找

怀疑这些地址是关键,由于阳光是会被不断访问数值的所以监测一下这些数值被谁访问过!
请添加图片描述
都一一看过后
请添加图片描述
发现这个地址最可疑0257B0D8,他这里的0x768,记录一下EDI=0257A970请添加图片描述

去内存里搜索看0257A970是不是存储在固定基址里的!’
果然成功找到固定的基址:
请添加图片描述

编写外挂的代码:


#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");   //设置控制台标题
    int z;

    HWND hGame = FindWindow(L"MainWindow", L"植物大战僵尸中文版");
    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");
    }
}
  • 35
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
植物大战僵尸” 这个游戏是一款十分有趣的塔防游戏,其中玩家需要种植各种植物来抵挡不断涌来的僵尸。这个游戏代码使用Python语言编写,下面我们来一起探究一下。 首先,游戏的整体框架主要包括三个部分:植物、僵尸和游戏场景。每个部分都有相应的类,例如,植物部分的类包括 “豌豆射手”、“向日葵”、“坚果墙”、“土豆雷”、“大嘴花”等等;僵尸部分的类有 “普通僵尸”、“路障僵尸”、“撑杆跳僵尸”、“飞行僵尸”等等;而游戏场景部分则包括一个游戏场景类。 在这里,我们以 “豌豆射手” 这个类为例来进行分析。 豌豆射手继承来自植物类,也就是说它继承了植物所具有的一些基础属性。对应到代码上,这部分主要包括以下内容: class Plant(object): def __init__(self, x, y): """初始化植物""" self.x = x #植物所在x轴坐标 self.y = y #植物所在y轴坐标 self.hp = 100 #植物的血量 self.width = 70 #植物的宽度 self.height = 81 #植物的高度 豌豆射手这个类除了继承了 Plant 类的属性之外,它还有一些自己特有的属性和方法。例如,豌豆射手的攻击属性由攻击力和攻击速度两个属性组成: class Peashooter(Plant): def __init__(self, x, y): Plant.__init__(self, x, y) self.attack = 20 #攻击力 self.speed = 18 #攻击速度 在上面的代码中,我们可以看到,豌豆射手这个类初始化时继承了 Plant 的初始化方法,之后还有自己的初始化方法。其余的属性与方法也都类似。 再来看看 “普通僵尸” 这个类。普通僵尸与豌豆射手类似,它也继承了僵尸类的基础属性,例如: class Zombie(object): """僵尸""" def __init__(self, y): """初始化僵尸""" self.y = y #僵尸所在y轴坐标 self.width = 100 #僵尸的宽度 self.height = 120 #僵尸的高度 self.hp = 100 #僵尸的血量 普通僵尸还有一个特有的属性:移动速度。 class NormalZombie(Zombie): def __init__(self, y): Zombie.__init__(self, y) self.speed = 6 #移动速度 同样,这个类的其余属性和方法也都类似。 最后,我们再来看看游戏场景部分,也就是游戏的主程序游戏的主程序使用一个 QGameLoop 类来实现,其中主要包括以下内容: #1.初始化游戏 def init(self): ... #2.显示游戏关卡 def showMission(self): ... #3.绘制游戏界面 def paint(self, painter, option, widget): ... #4.处理游戏事件 def processEvents(self): ... #5.更新游戏状态 def updateGameState(self): ... #6.检查游戏是否结束 def checkGameOver(self): ... #7.游戏主循环 def gameLoop(self): ... 以上内容是 QGameLoop 类的主要内容,每个工作的具体细节可以参考源代码。 总的来说,这个游戏的源代码比较清晰,在代码设计上也比较规范。对于 Python 程序员而言,这个源代码也是一个比较不错的学习资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值