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/80438113
https://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.4187
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.4187
Java打包封裝:
鏈接里exe4j和inno setup complier分享失效了,可以自行在CSDN內下載,
(會員好貴啊,官方大大啥時候發放福利QAQ)
https://blog.csdn.net/weixin_42562514/article/details/106603392https://blog.csdn.net/weixin_42562514/article/details/106603392
https://blog.csdn.net/weixin_42562514/article/details/106603392
三、實作任務的工具
1.《植物大戰僵尸》游戲檔案
https://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNghttps://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNg
https://pan.baidu.com/s/1aNyrPxklN8NViut3bC8LNg
提取碼:lput
2.IDEA(社區版)
下載地址:
IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrains
https://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.4450
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.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!!!
(完結撒花)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/340561.html
標籤:其他
