From 9a5415a199d032e2bbfd462ad4f60ace6b070d5e Mon Sep 17 00:00:00 2001
From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com>
Date: Sun, 27 Dec 2020 21:30:47 +0100
Subject: [PATCH] unity wasm crack
---
G-Earth/pom.xml | 14 +-
.../services/unity_tools/WasmCodePatcher.java | 225 ++++++++++++++++++
2 files changed, 238 insertions(+), 1 deletion(-)
create mode 100644 G-Earth/src/main/java/gearth/services/unity_tools/WasmCodePatcher.java
diff --git a/G-Earth/pom.xml b/G-Earth/pom.xml
index 207afac..25c618c 100644
--- a/G-Earth/pom.xml
+++ b/G-Earth/pom.xml
@@ -12,7 +12,7 @@
1.8
- 9.2.14.v20151106
+ 9.4.35.v20201120
@@ -190,8 +190,20 @@
javax-websocket-server-impl
${jettyVersion}
+
+ org.eclipse.jetty
+ jetty-http
+ ${jettyVersion}
+
+
+
+ G-Earth
+ G-Wasm
+ 1.0
+
+
diff --git a/G-Earth/src/main/java/gearth/services/unity_tools/WasmCodePatcher.java b/G-Earth/src/main/java/gearth/services/unity_tools/WasmCodePatcher.java
new file mode 100644
index 0000000..07477a6
--- /dev/null
+++ b/G-Earth/src/main/java/gearth/services/unity_tools/WasmCodePatcher.java
@@ -0,0 +1,225 @@
+package gearth.services.unity_tools;
+
+import wasm.disassembly.InvalidOpCodeException;
+import wasm.disassembly.instructions.Expression;
+import wasm.disassembly.instructions.Instr;
+import wasm.disassembly.instructions.InstrType;
+import wasm.disassembly.instructions.control.CallInstr;
+import wasm.disassembly.instructions.variable.LocalVariableInstr;
+import wasm.disassembly.modules.Module;
+import wasm.disassembly.modules.indices.FuncIdx;
+import wasm.disassembly.modules.indices.LocalIdx;
+import wasm.disassembly.modules.indices.TypeIdx;
+import wasm.disassembly.modules.sections.code.Func;
+import wasm.disassembly.modules.sections.export.Export;
+import wasm.disassembly.modules.sections.export.ExportDesc;
+import wasm.disassembly.modules.sections.imprt.Import;
+import wasm.disassembly.modules.sections.imprt.ImportDesc;
+import wasm.disassembly.types.FuncType;
+import wasm.disassembly.types.ResultType;
+import wasm.disassembly.types.ValType;
+import wasm.misc.Function;
+
+import java.io.*;
+import java.util.*;
+
+public class WasmCodePatcher {
+
+ private final Module module;
+ private String file;
+
+ public WasmCodePatcher(String file) throws IOException, InvalidOpCodeException {
+ module = new Module(file);
+ this.file = file;
+ }
+
+ public void patch() throws IOException, InvalidOpCodeException {
+ FuncIdx returnByteId = findReturnByteFunc();
+ FuncIdx setkey = findSetKeyFunc();
+ FuncIdx outgoingIdx = findOutFunc();
+ FuncIdx incomingIdx = findInFunc();
+
+ hook(setkey, "g_chacha_setkey");
+ copyEmptyHook(returnByteId, "_gearth_returnbyte_copy", "g_chacha_returnbyte");
+ copyEmptyHook(outgoingIdx, "_gearth_outgoing_copy", "g_outgoing_packet");
+ copyEmptyHook(incomingIdx, "_gearth_incoming_copy", "g_incoming_packet");
+
+ module.assembleToFile(file);
+ }
+
+
+ private FuncIdx findOutFunc() {
+ TypeIdx expectedTypeIdx = module.getTypeSection().getTypeIdxForFuncType(new FuncType(
+ new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
+ new ResultType(Collections.emptyList())
+ ));
+
+ outerloop:
+ for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
+ FuncIdx currentIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
+
+ Func func = module.getCodeSection().getByIdx(currentIdx);
+ if (func.getLocalss().size() != 0) continue;
+ if (!module.getFunctionSection().getByIdx(currentIdx).equals(expectedTypeIdx)) continue;
+
+ List expression = func.getExpression().getInstructions();
+
+ if (expression.size() != 6) continue;
+
+ if (expression.get(0).getInstrType() != InstrType.LOCAL_GET) continue;
+ if (expression.get(1).getInstrType() != InstrType.LOCAL_GET) continue;
+ if (expression.get(2).getInstrType() != InstrType.LOCAL_GET) continue;
+ if (expression.get(3).getInstrType() != InstrType.I32_LOAD) continue;
+ if (expression.get(4).getInstrType() != InstrType.I32_CONST) continue;
+ if (expression.get(5).getInstrType() != InstrType.CALL) continue;
+
+ return currentIdx;
+ }
+
+ return null;
+ }
+ private FuncIdx findSetKeyFunc() {
+ FuncType expectedType = new FuncType(
+ new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
+ new ResultType(Collections.emptyList())
+ );
+
+ List expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
+ InstrType.I32_EQZ, InstrType.IF, InstrType.BLOCK, InstrType.LOCAL_GET, InstrType.I32_CONST,
+ InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.I32_CONST, InstrType.I32_CONST, InstrType.I32_CONST,
+ InstrType.CALL);
+
+ outerloop:
+ for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
+ FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
+
+ Function function = new Function(module, funcIdx);
+ if (!function.getFuncType().equals(expectedType)) continue;
+ if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
+ if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
+
+ for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
+ Instr instr = function.getCode().getInstructions().get(j);
+ if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
+ }
+
+ return funcIdx;
+ }
+
+ return null;
+ }
+ private FuncIdx findReturnByteFunc() {
+ FuncType expectedType = new FuncType(
+ new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
+ new ResultType(Collections.singletonList(ValType.I32))
+ );
+
+ outerloop:
+ for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
+ FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
+
+ Function function = new Function(module, funcIdx);
+ if (!function.getFuncType().equals(expectedType)) continue;
+ if (function.getLocalsFloored().size() != 0) continue;
+ if (function.getCode().getInstructions().size() != 30) continue;
+
+ List expr = function.getCode().getInstructions();
+ if (expr.get(expr.size() - 1).getInstrType() != InstrType.I32_XOR) continue;
+
+ return funcIdx;
+ }
+
+ return null;
+ }
+ private FuncIdx findInFunc() {
+ FuncType expectedType = new FuncType(
+ new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
+ new ResultType(Collections.emptyList())
+ );
+
+ List expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
+ InstrType.I32_EQZ, InstrType.IF, InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.LOCAL_TEE,
+ InstrType.IF);
+
+ outerloop:
+ for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
+ FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
+
+ Function function = new Function(module, funcIdx);
+ if (!function.getFuncType().equals(expectedType)) continue;
+ if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
+ if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
+
+ for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
+ Instr instr = function.getCode().getInstructions().get(j);
+ if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
+ }
+
+ return funcIdx;
+ }
+
+ return null;
+ }
+
+ private void copyEmptyHook(FuncIdx orgFuncIdx, String exportName, String hookname) throws InvalidOpCodeException, IOException {
+ // copies the method, empties the first one
+ // export the copy
+ // hooks to the emptied one
+
+ Func func = module.getCodeSection().getByIdx(orgFuncIdx);
+ FuncType funcType = module.getTypeSection().getByFuncIdx(orgFuncIdx);
+
+ // copy the function
+ Function copy = new Function(funcType, func.getLocalss(), func.getExpression());
+ FuncIdx copyIdx = copy.addToModule(module);
+
+ module.getExportSection().getExports().add(new Export(exportName, new ExportDesc(copyIdx)));
+
+
+ // clear & hook original function, let it return whatever JS returns
+ Import imp = new Import(
+ "env",
+ hookname,
+ new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
+ funcType.getParameterType(),
+ funcType.getResultType()
+ )))
+ );
+ FuncIdx hookIdx = module.getImportSection().importFunction(imp);
+
+ CallInstr call = new CallInstr(hookIdx);
+ List newInstrs = new ArrayList<>();
+ for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
+ newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
+ }
+ newInstrs.add(call);
+ func.setExpression(new Expression(newInstrs));
+
+ }
+
+ private void hook(FuncIdx funcIdx, String jsFunctionName) throws InvalidOpCodeException, IOException {
+ FuncType funcType = module.getTypeSection().getByFuncIdx(funcIdx);
+
+ Import imp = new Import(
+ "env",
+ jsFunctionName,
+ new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
+ funcType.getParameterType(),
+ new ResultType(Collections.emptyList())
+ )))
+ );
+ FuncIdx hookIdx = module.getImportSection().importFunction(imp);
+
+ CallInstr call = new CallInstr(hookIdx);
+
+ Func root = module.getCodeSection().getByIdx(funcIdx);
+ List newInstrs = new ArrayList<>();
+ for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
+ newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
+ }
+ newInstrs.add(call);
+ newInstrs.addAll(root.getExpression().getInstructions());
+ root.getExpression().setInstructions(newInstrs);
+ }
+
+}