diff --git a/src/main/java/wasm/GWasm.java b/src/main/java/wasm/GWasm.java index a187b2a..df4d90f 100644 --- a/src/main/java/wasm/GWasm.java +++ b/src/main/java/wasm/GWasm.java @@ -1,9 +1,15 @@ package wasm; import wasm.disassembly.InvalidOpCodeException; +import wasm.disassembly.instructions.Expression; +import wasm.disassembly.instructions.Instr; +import wasm.disassembly.instructions.InstrType; +import wasm.disassembly.instructions.misc.SingleByteInstr; import wasm.disassembly.modules.Module; import wasm.disassembly.modules.indices.FuncIdx; import wasm.disassembly.modules.indices.TypeIdx; +import wasm.disassembly.modules.sections.code.Func; +import wasm.disassembly.modules.sections.code.Locals; import wasm.disassembly.modules.sections.export.Export; import wasm.disassembly.modules.sections.export.ExportDesc; import wasm.disassembly.modules.sections.imprt.Import; @@ -11,74 +17,19 @@ 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.CodeCompare; import wasm.misc.Function; import java.io.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class GWasm { - public static void extractMethods(Module module) { -// List typesFromImports = new ArrayList<>(); -// for (Import imp : module.getImportSection().getImports()) { -// if (imp.getImportDescription().getImportType() == 0) { -// typesFromImports.add((TypeIdx)imp.getImportDescription().getImportValue()); -// } -// } -// -// List exportList = module.getExportSection().getExports(); -// for(Export export : exportList) { -// ExportDesc desc = export.getExportDesc(); -// if (desc.getExportType() == 0) { -// FuncIdx funcIdx = (FuncIdx) desc.getExportValue(); -// TypeIdx typeIdx; -// if (funcIdx.getX() < typesFromImports.size()) { -// typeIdx = typesFromImports.get((int)(funcIdx.getX())); -// } -// else { -// typeIdx = module.getFunctionSection().getTypeIdxVector().get((int)(funcIdx.getX()) - typesFromImports.size()); -// } -// FuncType funcType = module.getTypeSection().getFunctionTypes().get((int)(typeIdx.getX())); -// -// System.out.println(String.format("%s ::= %s -> %s", -// export.getName(), -// "(" + funcType.getParameterType().typeList().stream().map(Enum::name).collect(Collectors.joining(" ")) + ")", -// "(" + funcType.getResultType().typeList().stream().map(Enum::name).collect(Collectors.joining(" ")) + ")" -// )); -// } -// } - } - public static void main(String[] args) throws IOException, InvalidOpCodeException { - long start = System.currentTimeMillis(); - Module module = new Module("C:\\Users\\jonas\\Desktop\\Projects\\Jznnp\\S\\habbo2020\\rawfiles\\0.6.0_(7)\\habbo2020-global-prod.wasm.code.unityweb", - new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); - long end = System.currentTimeMillis(); - - System.out.println("Assembly time: " + (end - start)); - -// extractMethods(module); -// -// module.getImportSection().importFunctions(Collections.singletonList( -// new Import( -// "env", -// "consoleLog", -// new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType( -// new ResultType(Collections.singletonList(ValType.I32)), -// new ResultType(Collections.emptyList()) -// ))) -// ) -// )); - - start = System.currentTimeMillis(); - module.assembleToFile("C:\\Users\\jonas\\Desktop\\Projects\\Jznnp\\S\\habbo2020\\rawfiles\\0.6.0_(7)\\out\\habbo2020-global-prod.wasm.code.unityweb"); - end = System.currentTimeMillis(); - - System.out.println("Disassembly time: " + (end - start)); - } } diff --git a/src/main/java/wasm/disassembly/modules/Module.java b/src/main/java/wasm/disassembly/modules/Module.java index 6a4e92e..c02f54d 100644 --- a/src/main/java/wasm/disassembly/modules/Module.java +++ b/src/main/java/wasm/disassembly/modules/Module.java @@ -19,7 +19,9 @@ import wasm.disassembly.modules.sections.start.StartSection; import wasm.disassembly.modules.sections.table.TableSection; import wasm.disassembly.modules.sections.type.TypeSection; import wasm.disassembly.types.FuncType; +import wasm.misc.CodeCompare; import wasm.misc.Function; +import wasm.misc.StreamReplacement; import java.io.*; import java.util.ArrayList; @@ -44,37 +46,11 @@ public class Module extends WASMOpCode { private List> customSectionsList; - // ACTION TAKEN TO MINIMIZE MEM USAGE: - // everything in the function section (3) will be (on-the-go) assembled into 1 byte array - // same for element section (9) - // same for code section (10) - // same for data section (11) - - // APPROACH: - // (1) import section - add imports in front of import section. (remember funcidx) - // Every matched FuncIdx will go +len(newImports) - // In code, take action if needed, and cache the functions that need copying - // Add cached functions to the end, remember their FuncIdx - // Export section - add the 3 funcidx + public final List streamReplacements; - - // actiontaken = decides what to do with matches from "searchFunctions", - // * if 0: calls function with same index in newImports - // * if 1-Y: calls function with same index in newImports, clears the rest of the function, - // copies the function and exports the copy to name Y - - public final List newImports; - public final List searchFunctions; - public final List actionTaken; - public final List newImportsFuncTypes; - - - public Module(BufferedInputStream in, List newImports, List newImportsFuncTypes, List searchFunctions, List actionTaken) throws IOException, InvalidOpCodeException { - this.newImports = newImports; - this.searchFunctions = searchFunctions; - this.actionTaken = actionTaken; - this.newImportsFuncTypes = newImportsFuncTypes; + public Module(BufferedInputStream in, List streamReplacements) throws IOException, InvalidOpCodeException { + this.streamReplacements = streamReplacements; customSectionsList = new ArrayList<>(); @@ -104,12 +80,13 @@ public class Module extends WASMOpCode { disassembleCustomSections(in); dataSection = isNextSection(in, 11) ? new DataSection(in, this) : null; disassembleCustomSections(in); + exportSection.addShittyExports(this); in.close(); } - public Module(String fileName, List newImports, List newImportsFuncTypes, List searchFunctions, List actionTaken) throws IOException, InvalidOpCodeException { - this(new BufferedInputStream(new FileInputStream(new File(fileName))), newImports, newImportsFuncTypes, searchFunctions, actionTaken); + public Module(String fileName, List streamReplacements) throws IOException, InvalidOpCodeException { + this(new BufferedInputStream(new FileInputStream(new File(fileName))), streamReplacements); } private void disassembleCustomSections(BufferedInputStream in) throws IOException, InvalidOpCodeException { diff --git a/src/main/java/wasm/disassembly/modules/indices/FuncIdx.java b/src/main/java/wasm/disassembly/modules/indices/FuncIdx.java index 8eb1e94..46fbbd1 100644 --- a/src/main/java/wasm/disassembly/modules/indices/FuncIdx.java +++ b/src/main/java/wasm/disassembly/modules/indices/FuncIdx.java @@ -22,7 +22,7 @@ public class FuncIdx extends WASMOpCode { public FuncIdx(BufferedInputStream in, Module module) throws IOException, InvalidOpCodeException { x = WUnsignedInt.read(in, 32) - + module.newImports.size(); + + module.streamReplacements.size(); // ref = CodeSection.currentI; // debugging purpose diff --git a/src/main/java/wasm/disassembly/modules/sections/Section.java b/src/main/java/wasm/disassembly/modules/sections/Section.java index 1cda563..fc6aec1 100644 --- a/src/main/java/wasm/disassembly/modules/sections/Section.java +++ b/src/main/java/wasm/disassembly/modules/sections/Section.java @@ -39,7 +39,6 @@ public abstract class Section extends WASMOpCode { ByteArrayOutputStream fakeOutputStream = new ByteArrayOutputStream(); assemble2(fakeOutputStream); byte[] asbytes = fakeOutputStream.toByteArray(); - System.out.println("section + " + sectionId + ", size: " + asbytes.length); WUnsignedInt.write(asbytes.length, out, 32); fakeOutputStream.close(); out.write(asbytes); diff --git a/src/main/java/wasm/disassembly/modules/sections/code/CodeSection.java b/src/main/java/wasm/disassembly/modules/sections/code/CodeSection.java index d44c9d4..9fece18 100644 --- a/src/main/java/wasm/disassembly/modules/sections/code/CodeSection.java +++ b/src/main/java/wasm/disassembly/modules/sections/code/CodeSection.java @@ -14,7 +14,9 @@ import wasm.disassembly.modules.indices.LocalIdx; import wasm.disassembly.modules.sections.Section; import wasm.disassembly.modules.sections.data.Data; import wasm.disassembly.values.WUnsignedInt; +import wasm.misc.CodeCompare; import wasm.misc.Function; +import wasm.misc.StreamReplacement; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; @@ -38,7 +40,7 @@ public class CodeSection extends Section { super(in, module, CODE_SECTION_ID); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - Code[] copies = new Code[module.searchFunctions.size()]; + Code[] copies = new Code[module.streamReplacements.size()]; // codesEntries = new Vector<>(in, Code::new, module); length = WUnsignedInt.read(in, 32); @@ -47,47 +49,37 @@ public class CodeSection extends Section { Func func = code.getCode(); - for (int j = 0; j < module.searchFunctions.size(); j++) { + for (int j = 0; j < module.streamReplacements.size(); j++) { if (module.getFunctionSection().matchesSearchFunctionsTypes.get(j).contains(i)) { - Function search = module.searchFunctions.get(j); - if (func.getLocalss().equals(search.getLocals()) && func.getExpression().getInstructions().size() == search.getCode().getInstructions().size()) { + CodeCompare comparer = module.streamReplacements.get(j).getCodeCompare(); - boolean failed = false; - for (int k = 0; k < func.getExpression().getInstructions().size(); k++) { - Instr instr = func.getExpression().getInstructions().get(k); - Instr instr2 = search.getCode().getInstructions().get(k); - if (instr.getInstrType() != instr2.getInstrType()) { - failed = true; - break; + if (comparer.isEqual(func)) { + StreamReplacement.ReplacementType actionTaken = module.streamReplacements.get(j).getReplacementType(); + if (actionTaken == StreamReplacement.ReplacementType.HOOK) { + CallInstr call = new CallInstr(new FuncIdx(j, module)); + + List newInstrs = new ArrayList<>(); + for (int k = 0; k < module.streamReplacements.get(j).getFuncType().getParameterType().typeList().size(); k++) { + newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(k))); } + newInstrs.add(call); + newInstrs.addAll(func.getExpression().getInstructions()); + func.getExpression().setInstructions(newInstrs); } - if (!failed) { - String actionTaken = module.actionTaken.get(j); - if (actionTaken.startsWith("0")) { - CallInstr call = new CallInstr(new FuncIdx(j, module)); + else if (actionTaken == StreamReplacement.ReplacementType.HOOKCOPYEXPORT) { + copies[j] = new Code(new Func(func.getLocalss(), new Expression(func.getExpression().getInstructions()))); - List newInstrs = new ArrayList<>(); - for (int k = 0; k < module.newImportsFuncTypes.get(j).getParameterType().typeList().size(); k++) { - newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(k))); - } - newInstrs.add(call); - newInstrs.addAll(func.getExpression().getInstructions()); - func.getExpression().setInstructions(newInstrs); - } - else if (actionTaken.startsWith("1")) { - copies[j] = new Code(new Func(func.getLocalss(), new Expression(func.getExpression().getInstructions()))); - - CallInstr call = new CallInstr(new FuncIdx(j, module)); - List newInstrs = new ArrayList<>(); - for (int k = 0; k < module.newImportsFuncTypes.get(j).getParameterType().typeList().size(); k++) { - newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(k))); - } - newInstrs.add(call); - func.getExpression().setInstructions(newInstrs); + CallInstr call = new CallInstr(new FuncIdx(j, module)); + List newInstrs = new ArrayList<>(); + for (int k = 0; k < module.streamReplacements.get(j).getFuncType().getParameterType().typeList().size(); k++) { + newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(k))); } + newInstrs.add(call); + func.getExpression().setInstructions(newInstrs); } } + } } diff --git a/src/main/java/wasm/disassembly/modules/sections/export/ExportSection.java b/src/main/java/wasm/disassembly/modules/sections/export/ExportSection.java index 6679cb4..6a1d71b 100644 --- a/src/main/java/wasm/disassembly/modules/sections/export/ExportSection.java +++ b/src/main/java/wasm/disassembly/modules/sections/export/ExportSection.java @@ -5,6 +5,7 @@ import wasm.disassembly.conventions.Vector; import wasm.disassembly.modules.Module; import wasm.disassembly.modules.indices.FuncIdx; import wasm.disassembly.modules.sections.Section; +import wasm.misc.StreamReplacement; import java.io.BufferedInputStream; import java.io.IOException; @@ -43,11 +44,10 @@ public class ExportSection extends Section { public void addShittyExports(Module module) { int count = 0; - for (int i = 0; i < module.searchFunctions.size(); i++) { - String actionTaken = module.actionTaken.get(i); - if (actionTaken.startsWith("1")) { - String exportName = actionTaken.split("-")[1]; - getExports().add(new Export(exportName, new ExportDesc(new FuncIdx( + for (int i = 0; i < module.streamReplacements.size(); i++) { + StreamReplacement.ReplacementType actionTaken = module.streamReplacements.get(i).getReplacementType(); + if (actionTaken == StreamReplacement.ReplacementType.HOOKCOPYEXPORT) { + getExports().add(new Export(module.streamReplacements.get(i).getExportName(), new ExportDesc(new FuncIdx( module.getCodeSection().length + module.getImportSection().getTotalFuncImports() - module.getCodeSection().copiesLength + count, module )))); diff --git a/src/main/java/wasm/disassembly/modules/sections/function/FunctionSection.java b/src/main/java/wasm/disassembly/modules/sections/function/FunctionSection.java index 2fe52c2..5cbe786 100644 --- a/src/main/java/wasm/disassembly/modules/sections/function/FunctionSection.java +++ b/src/main/java/wasm/disassembly/modules/sections/function/FunctionSection.java @@ -9,7 +9,9 @@ import wasm.disassembly.modules.sections.Section; import wasm.disassembly.modules.sections.code.Code; import wasm.disassembly.modules.sections.code.Func; import wasm.disassembly.values.WUnsignedInt; +import wasm.misc.CodeCompare; import wasm.misc.Function; +import wasm.misc.StreamReplacement; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; @@ -37,8 +39,8 @@ public class FunctionSection extends Section { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); List searchFunctions = new ArrayList<>(); - for (int i = 0; i < module.searchFunctions.size(); i++) { - Function f = module.searchFunctions.get(i); + for (int i = 0; i < module.streamReplacements.size(); i++) { + StreamReplacement f = module.streamReplacements.get(i); searchFunctions.add(module.getTypeSection().getTypeIdxForFuncType(f.getFuncType())); matchesSearchFunctionsTypes.add(new HashSet<>()); } @@ -55,10 +57,10 @@ public class FunctionSection extends Section { typeIdx.assemble(buffer); } - for (int i = 0; i < module.searchFunctions.size(); i++) { - String actionTaken = module.actionTaken.get(i); + for (int i = 0; i < module.streamReplacements.size(); i++) { + StreamReplacement.ReplacementType actionTaken = module.streamReplacements.get(i).getReplacementType(); // new function will be created - if (actionTaken.startsWith("1")) { + if (actionTaken == StreamReplacement.ReplacementType.HOOKCOPYEXPORT) { searchFunctions.get(i).assemble(buffer); length++; } diff --git a/src/main/java/wasm/disassembly/modules/sections/imprt/ImportSection.java b/src/main/java/wasm/disassembly/modules/sections/imprt/ImportSection.java index 8900252..2c67098 100644 --- a/src/main/java/wasm/disassembly/modules/sections/imprt/ImportSection.java +++ b/src/main/java/wasm/disassembly/modules/sections/imprt/ImportSection.java @@ -6,6 +6,9 @@ import wasm.disassembly.conventions.Vector; import wasm.disassembly.modules.Module; import wasm.disassembly.modules.indices.FuncIdx; import wasm.disassembly.modules.sections.Section; +import wasm.disassembly.types.FuncType; +import wasm.disassembly.types.ResultType; +import wasm.misc.StreamReplacement; import java.io.BufferedInputStream; import java.io.IOException; @@ -43,17 +46,25 @@ public class ImportSection extends Section { } } - for (int i = 0; i < module.newImports.size(); i++) { - module.newImports.get(i).getImportDescription().setImportValue( - module.getTypeSection().getTypeIdxForFuncType(module.newImportsFuncTypes.get(i)) - ); + List newImports = new ArrayList<>(); + + + + for (StreamReplacement streamReplacement : module.streamReplacements) { + newImports.add(new Import("env", streamReplacement.getImportName(), new ImportDesc( + module.getTypeSection().getTypeIdxForFuncType(new FuncType( + streamReplacement.getFuncType().getParameterType(), + streamReplacement.getReplacementType() == StreamReplacement.ReplacementType.HOOK ? new ResultType(Collections.emptyList()) : + streamReplacement.getFuncType().getResultType() + )) + ))); } - List f = imports.getElements().subList(0, first); - f.addAll(module.newImports); + List f = new ArrayList<>(imports.getElements().subList(0, first)); + f.addAll(newImports); f.addAll(imports.getElements().subList(first, imports.getElements().size())); imports.setElements(f); - totalFuncImports += module.newImports.size(); + totalFuncImports += newImports.size(); } public ImportSection(Module module, List imports) { diff --git a/src/main/java/wasm/misc/CodeCompare.java b/src/main/java/wasm/misc/CodeCompare.java new file mode 100644 index 0000000..694163f --- /dev/null +++ b/src/main/java/wasm/misc/CodeCompare.java @@ -0,0 +1,10 @@ +package wasm.misc; + +import wasm.disassembly.modules.sections.code.Func; +import wasm.disassembly.types.FuncType; + +public interface CodeCompare { + + boolean isEqual(Func code); + +} diff --git a/src/main/java/wasm/misc/StreamReplacement.java b/src/main/java/wasm/misc/StreamReplacement.java new file mode 100644 index 0000000..36c7d76 --- /dev/null +++ b/src/main/java/wasm/misc/StreamReplacement.java @@ -0,0 +1,18 @@ +package wasm.misc; + +import wasm.disassembly.types.FuncType; + +public interface StreamReplacement { + + + enum ReplacementType { + HOOK, + HOOKCOPYEXPORT + } + + FuncType getFuncType(); + ReplacementType getReplacementType(); + String getImportName(); + String getExportName(); + CodeCompare getCodeCompare(); +}