栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

槃星—第2天任务—JAVA实现游戏数据修改以及风控设计

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

槃星—第2天任务—JAVA实现游戏数据修改以及风控设计

JAVA实战训练营Day.2 ——“假如我是游戏设计师”

目录

前言

一、Day.2的目标

二、任务所涉及的知识点(参考资料)

1.JAVA 进制转换的几个方法

2.IDEA配置Java环境及基本使用

三、实现任务的工具

1.《植物大战僵尸》游戏文件

2.IDEA(社区版)

3.exe4j和inno setup complier

4.一个工具人(QAQ)

四、开始实战

1.Java实现修改关卡

2.Java实现修改金币

3.完整源码

4.个人对游戏数据渗透与风控的拙见(手动卑微)

五、总结


前言

 昨天我们通过Hex Editor Neo完成了对《植物大战僵尸》游戏数据的修改,那我们今天就尝试使用Java语言来实现对游戏数据的修改。并且还要自己当游戏设计,站在风控和渗透工程师的视角再回顾任务,改进这款游戏。


一、Day.2的目标

修改游戏《植物大战僵尸》,完成以下目标:

1.Java语言实现对游戏数据的修改

2.对游戏进行风控设计,改进游戏

二、任务所涉及的知识点(参考资料)

1.Java进制转换的几个方法

https://blog.csdn.net/m0_37961948/article/details/80438113https://blog.csdn.net/m0_37961948/article/details/80438113https://blog.csdn.net/m0_37961948/article/details/80438113

2.IDEA配置Java环境及基本使用

Java环境的配置:

https://blog.csdn.net/weixin_39536315/article/details/112793788?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163532650016780261946696%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163532650016780261946696&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-112793788.pc_search_all_es&utm_term=idea%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_39536315/article/details/112793788?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163532650016780261946696%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163532650016780261946696&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-112793788.pc_search_all_es&utm_term=idea%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_39536315/article/details/112793788?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163532650016780261946696%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163532650016780261946696&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-112793788.pc_search_all_es&utm_term=idea%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&spm=1018.2226.3001.4187

Java打包封装:

链接里exe4j和inno setup complier分享失效了,可以自行在CSDN内下载。

(会员好贵啊,官方大大啥时候发放福利QAQ)

https://blog.csdn.net/weixin_42562514/article/details/106603392https://blog.csdn.net/weixin_42562514/article/details/106603392https://blog.csdn.net/weixin_42562514/article/details/106603392

三、实现任务的工具




1.《植物大战僵尸》游戏文件

https://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNghttps://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNghttps://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNg

提取码:lput




2.IDEA(社区版)

下载地址:

IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrainshttps://www.jetbrains.com/idea/

使用VScode是同样可实现的,因为我这个小菜鸟之前没使用过IDEA,所有这里我们选择使用IDEA。

VScode下载地址附上:

https://code.visualstudio.com/https://code.visualstudio.com/https://code.visualstudio.com/

附赠配置Java环境的保姆级教程(买一送一,服务到家):

https://blog.csdn.net/qq_41119146/article/details/103835651?ops_request_misc=&request_id=&biz_id=102&utm_term=vscode%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-5-103835651.pc_search_all_es&spm=1018.2226.3001.4450https://blog.csdn.net/qq_41119146/article/details/103835651?ops_request_misc=&request_id=&biz_id=102&utm_term=vscode%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-5-103835651.pc_search_all_es&spm=1018.2226.3001.4450https://blog.csdn.net/qq_41119146/article/details/103835651?ops_request_misc=&request_id=&biz_id=102&utm_term=vscode%E9%85%8D%E7%BD%AEjava%E7%8E%AF%E5%A2%83&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-5-103835651.pc_search_all_es&spm=1018.2226.3001.4450

3.exe4j和inno setup complier

打包封装软件请自行在站内下载哦!

4.一个工具人(QAQ)

四、开始实战

 我的总体思路:将游戏文件用十六进制的方式打开,再修改相关数据,最后保存。

1.Java实现修改关卡
        public void update() {
        Scanner input = new Scanner(System.in);
        System.out.println("跳转关卡1-1  输入1  跳转关卡2-1  输入11  类推");
        System.out.println("输入当前关卡");
        tempNum = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("输入想跳转到达的关卡:");
        tempNum2 = decToHexStringDiv(Integer.parseInt(input.next()));
        System.err.println("16进制当前关卡:" + tempNum);
        System.err.println("16进制更改的关卡:" + tempNum2);
        if (Integer.parseInt(tempNum2, 16) > 50) {
            System.out.println("你个憨包儿");
            System.exit(0);
        }
        pattern = new String[][] {{tempNum, tempNum2}};
        }

为了防止同学们输错关卡,我设计了一个触发彩蛋,欢迎大家解锁成就<我是憨包儿>(斜眼笑)

2.Java实现修改金币
 private void updateMoney() {
        Scanner input = new Scanner(System.in);
        System.out.println("输入当前金币数量:");
        tempNum = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("输入更改的金币数量:");
        tempNum2 = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("16当前金币:" + tempNum);
        System.out.println("16更改金币:" + tempNum2);
        // 08位置能存储的金币最大值是ffH*10=2550D,通过昨天的测试我们知道是多位地址存储金币数量的
        if (Integer.parseInt(tempNum, 16) > 255) {
            System.out.println("输入的字节大于255");
            System.out.println("要查找的字符:" + reverseHex(tempNum));
            tempNum = reverseHex(tempNum);
        }
        if (Integer.parseInt(tempNum2, 16) > 255) {
            for (int i = 0; i <= tempNum2.length() - tempNum.length(); i++) {
                // 因为是多位地址存储金币数量的,所以我们要计算更改的数据长度
                tempNum += "0";
            }
            System.err.println("16进制当前金币:" + tempNum);
            System.err.println("16进制更改的金币:" + tempNum2);
            tempNum2 = reverseHex(tempNum2);
            System.err.println("16进制低字节转换:" + tempNum2);
        }
        pattern = new String[][] {{tempNum, tempNum2}};
    }

 

这个就很鸡肋,我们输入的是十进制,但是文件是以十六进制的形式打开的,所以是金币数量是D到H的变化。

3.完整源码

参考了不少资料,虽然没有bug了,但还会报一些警告,还请多多指教。

package com.ghcare.demo;
import java.io.*;
import java.util.Scanner;
class MainTool {
    private final String RO_HOME =
            "C:\ProgramData\PopCap Games\PlantsVsZombies\userdata\"; // 游戏文件的位置
    private final String FILE = "user1"; // 我们要修改的文件名
    private final String BAK_FILE = FILE + "_BAK.dat"; // 文件的备份扩展名
    private final String PATCH_FILE = FILE + ".dat"; // 文件的扩展名
    String tempNum = null;
    String tempNum2 = null;
    private String[][] pattern = {{"ff00", "0a1a"}};//main方法

    public static void main(String[] args) throws IOException {
        MainTool tool = new MainTool();
        tool.patch();
    }

    //  Java的16进制的高低字节序转化
    public static String reverseHex(String hex) {
        char[] charArray = hex.toCharArray();
        int length = charArray.length;
        int times = length / 2;
        for (int c1i = 0; c1i < times; c1i += 2) {
            int c2i = c1i + 1;
            char c1 = charArray[c1i];
            char c2 = charArray[c2i];
            int c3i = length - c1i - 2;
            int c4i = length - c1i - 1;
            charArray[c1i] = charArray[c3i];
            charArray[c2i] = charArray[c4i];
            charArray[c3i] = c1;
            charArray[c4i] = c2;
        }
        return new String(charArray);
    }

    //十进制转十六进制,小于16的十进制前面补一个0
    public static String decToHexStringDiv(int n) {
        int flag = n;
        StringBuffer s = new StringBuffer();
        String a;
        char[] b = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        while (n != 0) {
            s = s.append(b[n % 16]);
            n = n / 16;
        }
        a = s.reverse().toString();
        if (flag < 16) {
            a = 0 + a;
        }
        return a;
    }

    // 备份文件恢复
    public void restore() {
        if (isExistBackup()) {
            new File(RO_HOME + PATCH_FILE).delete();
            new File(RO_HOME + BAK_FILE).renameTo(new File(RO_HOME + PATCH_FILE));
            System.out.println("[文件恢复成功]");
        } else {
            System.out.println("文件恢复失败");
            System.exit(0);
        }
    }

    public void init() {
        // 初始化操作
        if (new File(RO_HOME + PATCH_FILE).exists()) {
            System.out.println("[读取到备份文件]");
        } else {
            System.out.println("未读取到备份文件");
        }
        // 备份原始文件
        if (!isExistBackup()) {
            new File(RO_HOME + PATCH_FILE).renameTo(new File(RO_HOME + BAK_FILE));
        }
        System.out.println("[少年请选择你的英雄]");
        System.out.println("1:开始数据修改");
        System.out.println("2:恢复修改前文件");
        System.out.println("选择执行,输入1或2:");
    }

    public void success() {
        System.out.println();
        System.out.println("[修改成功,玩的开心OVO]");
        System.out.println("[CSDN第八期Java实战训练营]");
    }

    //进行16进制替换,将输入的16进制字符串替换为已定义的模式
    public String replace(String original) {
        for (int i = 0; i < pattern.length; i++) {
            original = original.replaceAll(pattern[i][0].toLowerCase(), pattern[i][1].toLowerCase());
            if (original.contains(pattern[i][0].toLowerCase())) {
                System.out.println("替换成功");
            }
        }
        return original;
    }

    //将文件读取为16进制,读取原始文件并将转换为16进制字符串
    public String readOriginal2Hex() throws IOException {
        FileInputStream fin = new FileInputStream(new File(RO_HOME + BAK_FILE));
        StringWriter sw = new StringWriter();
        int len = 1;
        byte[] temp = new byte[len];
        //16进制的方式打开文件
        for (; (fin.read(temp, 0, len)) != -1; ) {
            if (temp[0] > 0xf && temp[0] <= 0xff) {
                sw.write(Integer.toHexString(temp[0]));
            } else if (temp[0] >= 0x0 && temp[0] <= 0xf) {
                // 对于只有1位的16进制数前边补0
                sw.write("0" + Integer.toHexString(temp[0]));
            } else {
                // int<0的位转化为16进制的特殊处理,Java没有Unsigned int,所以这个int可能为负数
                sw.write(Integer.toHexString(temp[0]).substring(6));
            }
        }
        return sw.toString();
    }

    //将替换后的16进制字符串写回文件
    public void writeNew2Binary(String replaced) throws NumberFormatException, IOException {
        FileOutputStream fout = new FileOutputStream(RO_HOME + PATCH_FILE);
        for (int i = 0; i < replaced.length(); i = i + 2) {
            fout.write(Integer.parseInt(replaced.substring(i, i + 2), 16));
        }
    }

    public void writeTest(String temp) throws IOException {
        FileOutputStream fout = new FileOutputStream(RO_HOME + "test.txt");
        for (int i = 0; i < temp.length(); i++) {
            fout.write(temp.charAt(i));
        }
    }

    public boolean isExistBackup() {
        return new File(RO_HOME + BAK_FILE).exists();
    }

    public void patch() throws IOException {
        init();
        String input = new BufferedReader(new InputStreamReader(System.in)).readLine();
        if (input.equals("1")) {

            System.out.println("输入1更改关卡,输入2更改金币");
            String selectOption = new BufferedReader(new InputStreamReader(System.in)).readLine();
            if (selectOption.equals("1")) {
                update();
            } else if (selectOption.equals("2")) {
                updateMoney();
            }
            String temp = null;
            temp = readOriginal2Hex();
            temp = replace(temp);
            writeNew2Binary(temp);
            success();
        } else if (input.equals("2")) {
            restore();
        } else {
            System.out.println("该功能还处于研发中");
            System.exit(0);
        }
    }

    // 修改金币
    private void updateMoney() {
        Scanner input = new Scanner(System.in);
        System.out.println("输入当前金币数量:");
        tempNum = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("输入更改的金币数量:");
        tempNum2 = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("16当前金币:" + tempNum);
        System.out.println("16更改金币:" + tempNum2);
        // 08位置能存储的金币最大值是ffH*10=2550D,通过昨天的测试我们知道是多位地址存储金币数量的
        if (Integer.parseInt(tempNum, 16) > 255) {
            System.out.println("输入的字节大于255");
            System.out.println("要查找的字符:" + reverseHex(tempNum));
            tempNum = reverseHex(tempNum);
        }
        if (Integer.parseInt(tempNum2, 16) > 255) {
            for (int i = 0; i <= tempNum2.length() - tempNum.length(); i++) {
                // 因为是多位地址存储金币数量的,所以我们要计算更改的数据长度
                tempNum += "0";
            }
            System.err.println("16进制当前金币:" + tempNum);
            System.err.println("16进制更改的金币:" + tempNum2);
            tempNum2 = reverseHex(tempNum2);
            System.err.println("16进制低字节转换:" + tempNum2);
        }
        pattern = new String[][]{{tempNum, tempNum2}};
    }

    // 修改关卡
    public void update() {
        Scanner input = new Scanner(System.in);
        System.out.println("跳转关卡1-1  输入1  跳转关卡2-1  输入11  类推");
        System.out.println("输入当前关卡");
        tempNum = decToHexStringDiv(Integer.parseInt(input.next()));
        System.out.println("输入想跳转到达的关卡:");
        tempNum2 = decToHexStringDiv(Integer.parseInt(input.next()));
        System.err.println("16进制当前关卡:" + tempNum);
        System.err.println("16进制更改的关卡:" + tempNum2);
        if (Integer.parseInt(tempNum2, 16) > 50) {
            System.out.println("你个憨包儿");
            System.exit(0);
        }
        pattern = new String[][]{{tempNum, tempNum2}};
    }

}

好了,我们把程序打包好。(参照参考资料——Java的打包封装)

(打包带回家,夜宵有着落了)

至此任务1完成。

4.个人对游戏数据渗透与风控的拙见(手动卑微)

这些是训练营的老师提供的一些方法论:

关于我个人的拙见(就以植物大战僵尸为例):

之前没有接触过渗透与风控,对数据安全的知识了解的也非常有限。

所以这个做的不尽人意,多多包涵。

小结:

网络游戏就把数据统统放在服务器,再给数据包加密,加上各种反外挂操作。

(例如:鹅厂的TP,懂得都懂)
单机游戏就算加密原始数据,也只是读出来是错误的数据。

但不管是什么形式的保护措施,只要有耐心、花时间也是可以破解开的,

毕竟没有绝对的加密解密。

或许,只有在不停的攻防中达到一种动态平衡,才是真正的安全。

至此任务2完成。



五、总结

今天这个任务就提升难度了,比如16进制的高低字节转化的环节,尽管参考了一些大佬的代码,但尝试多次都是报错,反反复复的改bug。代码我给写了注释,如果有不理解的地方或者更好的方法欢迎大家评论留言。

关于渗透与风控,我想用这句话来概括一下:

“放眼去看我们的世界,看到我们的岁月静好,是因为有人为我们负重前行!”

向各位致力于保护大家信息数据安全的工程师们表示最高敬意!

Respect!!!

(完结撒花)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351220.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号