From 32ae1ab8f0b9b612748127c628138e95038faf17 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 13 Mar 2024 15:44:18 +0100 Subject: [PATCH] js: fix deobfuscator, use new ES2015 module builder --- .../src/main/java/org/teavm/jso/impl/JS.java | 11 +++++ .../java/org/teavm/jso/impl/JSMethods.java | 1 + .../org/teavm/jso/impl/JSValueMarshaller.java | 4 +- .../src/main/resources/test-server/client.js | 11 +++-- .../src/main/resources/test-server/index.html | 5 ++- tools/deobfuscator-js/build.gradle.kts | 4 +- .../tooling/deobfuscate/js/Compiler.java | 2 + .../tooling/deobfuscate/js/Deobfuscator.java | 33 ++++++++------- .../deobfuscate/js/DeobfuscatorJs.java | 24 ----------- .../deobfuscate/js/DeobfuscatorLib.java | 21 +++------- .../teavm/tooling/deobfuscate/js/Frame.java | 40 +++++++++++++++---- 11 files changed, 84 insertions(+), 72 deletions(-) delete mode 100644 tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorJs.java diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JS.java b/jso/impl/src/main/java/org/teavm/jso/impl/JS.java index 74eaa79bc..11eabb122 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JS.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JS.java @@ -151,6 +151,17 @@ final class JS { return result; } + public static JSArray wrap(T[] array) { + if (array == null) { + return null; + } + var result = new JSArray(array.length); + for (int i = 0; i < array.length; ++i) { + result.set(i, array[i]); + } + return result; + } + public static WrapFunction> arrayWrapper() { return JS::wrap; } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java index f17816277..4633cb7f9 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java @@ -126,6 +126,7 @@ final class JSMethods { String.class, JSObject.class); public static final ValueType JS_OBJECT = ValueType.object(JSObject.class.getName()); + public static final ValueType OBJECT = ValueType.object("java.lang.Object"); public static final ValueType JS_ARRAY = ValueType.object(JSArray.class.getName()); private static final MethodReference[] INVOKE_METHODS = new MethodReference[13]; private static final MethodReference[] CONSTRUCT_METHODS = new MethodReference[13]; diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java index a8e8dcc6b..b8c4e0521 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java @@ -205,8 +205,10 @@ class JSValueMarshaller { } else if (type instanceof ValueType.Object) { if (type.isObject(String.class)) { return type; - } else { + } else if (typeHelper.isJavaScriptClass(((ValueType.Object) type).getClassName())) { return JSMethods.JS_OBJECT; + } else { + return JSMethods.OBJECT; } } else { return type; diff --git a/tools/browser-runner/src/main/resources/test-server/client.js b/tools/browser-runner/src/main/resources/test-server/client.js index e4c6b4c36..9ec0d740e 100644 --- a/tools/browser-runner/src/main/resources/test-server/client.js +++ b/tools/browser-runner/src/main/resources/test-server/client.js @@ -18,9 +18,6 @@ let logging = false; let deobfuscation = false; -if (typeof deobfuscator !== 'undefined') { - deobfuscator(); -} function tryConnect() { let ws = new WebSocket("ws://localhost:{{PORT}}/ws"); @@ -82,7 +79,7 @@ function runSingleTest(test, callback) { console.log("Running test " + test.name); } if (deobfuscation) { - const fileName = test.file + ".teavmdbg"; + const fileName = test.file.path + ".teavmdbg"; if (lastDeobfuscatorFile === fileName) { if (lastDeobfuscatorPromise === null) { runSingleTestWithDeobfuscator(test, lastDeobfuscator, callback); @@ -100,7 +97,7 @@ function runSingleTest(test, callback) { xhr.onreadystatechange = () => { if (xhr.readyState === 4) { const newDeobfuscator = xhr.status === 200 - ? deobfuscator.create(xhr.response, "http://localhost:{{PORT}}/" + test.file) + ? createDeobfuscator(xhr.response, "http://localhost:{{PORT}}/" + test.file.path) : null; if (lastDeobfuscatorFile === fileName) { lastDeobfuscator = newDeobfuscator; @@ -139,7 +136,9 @@ function runSingleTestWithDeobfuscator(test, deobfuscator, callback) { }; window.addEventListener("message", listener); - iframe.contentWindow.$rt_decodeStack = deobfuscator; + iframe.contentWindow.$rt_decodeStack = deobfuscator != null + ? deobfuscator.deobfuscate.bind(deobfuscator) + : null; iframe.contentWindow.postMessage(test, "*"); }; window.addEventListener("message", handshakeListener); diff --git a/tools/browser-runner/src/main/resources/test-server/index.html b/tools/browser-runner/src/main/resources/test-server/index.html index 7d00aa01b..bee9996c9 100644 --- a/tools/browser-runner/src/main/resources/test-server/index.html +++ b/tools/browser-runner/src/main/resources/test-server/index.html @@ -18,7 +18,10 @@ - + diff --git a/tools/deobfuscator-js/build.gradle.kts b/tools/deobfuscator-js/build.gradle.kts index ceee4509a..80013a09a 100644 --- a/tools/deobfuscator-js/build.gradle.kts +++ b/tools/deobfuscator-js/build.gradle.kts @@ -44,7 +44,8 @@ val generateJs by tasks.register("generateJs") { "org.teavm.tooling.deobfuscate.js.Deobfuscator", "\$teavm_deobfuscator", layout.buildDirectory.dir("teavm").get().asFile.absolutePath, - "deobfuscator.js" + "deobfuscator.js", + "none" ) } @@ -59,6 +60,7 @@ val generateLibJs by tasks.register("generateLibJs") { "deobfuscator", layout.buildDirectory.dir("teavm-lib").get().asFile.absolutePath, "deobfuscator-lib.js", + "es2015" ) } diff --git a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Compiler.java b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Compiler.java index c47b0a35c..6218d5acd 100644 --- a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Compiler.java +++ b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Compiler.java @@ -16,6 +16,7 @@ package org.teavm.tooling.deobfuscate.js; import java.io.File; +import org.teavm.backend.javascript.JSModuleType; import org.teavm.tooling.ConsoleTeaVMToolLog; import org.teavm.tooling.TeaVMProblemRenderer; import org.teavm.tooling.TeaVMTargetType; @@ -35,6 +36,7 @@ public final class Compiler { tool.setEntryPointName(args[1]); tool.setTargetDirectory(new File(args[2])); tool.setTargetFileName(args[3]); + tool.setJsModuleType(JSModuleType.valueOf(args[4].toUpperCase())); tool.setObfuscated(true); tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED); diff --git a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Deobfuscator.java b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Deobfuscator.java index d4753fd9a..8408340fa 100644 --- a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Deobfuscator.java +++ b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Deobfuscator.java @@ -24,6 +24,8 @@ import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.GeneratedLocation; import org.teavm.debugging.information.SourceLocation; import org.teavm.jso.JSBody; +import org.teavm.jso.JSClass; +import org.teavm.jso.JSExport; import org.teavm.jso.ajax.XMLHttpRequest; import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSObjects; @@ -33,6 +35,7 @@ import org.teavm.jso.typedarrays.ArrayBuffer; import org.teavm.jso.typedarrays.Int8Array; import org.teavm.model.MethodReference; +@JSClass public final class Deobfuscator { private static final JSRegExp FRAME_PATTERN = new JSRegExp("" + "(^ +at ([^(]+) *\\((.+):([0-9]+):([0-9]+)\\) *$)|" @@ -60,6 +63,7 @@ public final class Deobfuscator { xhr.send(); } + @JSExport public Frame[] deobfuscate(String stack) { List frames = new ArrayList<>(); for (String line : splitLines(stack)) { @@ -125,14 +129,16 @@ public final class Deobfuscator { decodedFileName = decodedFileName.substring(decodedFileName.lastIndexOf('/') + 1); } - Frame frame = createEmptyFrame(); - frame.setClassName(method.getClassName()); - frame.setMethodName(method.getName()); - frame.setFileName(decodedFileName); + var javaLineNumber = -1; if (location != null) { - frame.setLineNumber(location.getLine()); + javaLineNumber = location.getLine(); } - result.add(frame); + result.add(new Frame( + method.getClassName(), + method.getName(), + decodedFileName, + javaLineNumber + )); } if (result.isEmpty()) { @@ -143,12 +149,12 @@ public final class Deobfuscator { } private static Frame createDefaultFrame(String fileName, String functionName, int lineNumber) { - Frame frame = createEmptyFrame(); - frame.setFileName(fileName); - frame.setMethodName(functionName != null ? functionName : ""); - frame.setClassName(""); - frame.setLineNumber(lineNumber); - return frame; + return new Frame( + "", + functionName != null ? functionName : "", + fileName, + lineNumber + ); } private static String[] splitLines(String text) { @@ -165,9 +171,6 @@ public final class Deobfuscator { return result.toArray(new String[0]); } - @JSBody(script = "return {};") - private static native Frame createEmptyFrame(); - @JSBody(params = "f", script = "window.$rt_decodeStack = f;") private static native void setDeobfuscateFunction(DeobfuscateFunction f); diff --git a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorJs.java b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorJs.java deleted file mode 100644 index 09d1ee872..000000000 --- a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorJs.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2021 Alexey Andreev. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.teavm.tooling.deobfuscate.js; - -import org.teavm.jso.JSObject; -import org.teavm.jso.typedarrays.ArrayBuffer; - -public interface DeobfuscatorJs extends JSObject { - DeobfuscateFunction create(ArrayBuffer buffer, String classesFileName); -} - diff --git a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorLib.java b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorLib.java index ec8ed2034..7422788d5 100644 --- a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorLib.java +++ b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/DeobfuscatorLib.java @@ -16,31 +16,20 @@ package org.teavm.tooling.deobfuscate.js; import java.io.IOException; -import org.teavm.jso.JSBody; +import org.teavm.jso.JSExport; import org.teavm.jso.typedarrays.ArrayBuffer; -public final class DeobfuscatorLib implements DeobfuscatorJs { +public final class DeobfuscatorLib { private DeobfuscatorLib() { } - @Override - public DeobfuscateFunction create(ArrayBuffer buffer, String classesFileName) { + @JSExport + public static Deobfuscator create(ArrayBuffer buffer, String classesFileName) { try { - return new Deobfuscator(buffer, classesFileName)::deobfuscate; + return new Deobfuscator(buffer, classesFileName); } catch (IOException e) { throw new RuntimeException(e); } } - - public static void main(String[] args) { - install(new DeobfuscatorLib()); - } - - @JSBody(params = "instance", script = - "deobfuscator.create = function(buffer, classesFileName) {" - + "return instance.create(buffer, classesFileName);" - + "}" - ) - private static native void install(DeobfuscatorJs js); } diff --git a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Frame.java b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Frame.java index b4a425406..98c90bc4e 100644 --- a/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Frame.java +++ b/tools/deobfuscator-js/src/main/java/org/teavm/tooling/deobfuscate/js/Frame.java @@ -15,19 +15,43 @@ */ package org.teavm.tooling.deobfuscate.js; -import org.teavm.jso.JSObject; +import org.teavm.jso.JSExport; import org.teavm.jso.JSProperty; -public interface Frame extends JSObject { - @JSProperty - void setClassName(String className); +public class Frame { + private String className; + private String fileName; + private String methodName; + private int lineNumber; - @JSProperty - void setFileName(String fileName); + public Frame(String className, String methodName, String fileName, int lineNumber) { + this.className = className; + this.methodName = methodName; + this.fileName = fileName; + this.lineNumber = lineNumber; + } + @JSExport @JSProperty - void setMethodName(String methodName); + public String getClassName() { + return className; + } + @JSExport @JSProperty - void setLineNumber(int lineNumber); + public String getFileName() { + return fileName; + } + + @JSExport + @JSProperty + public String getMethodName() { + return methodName; + } + + @JSExport + @JSProperty + public int getLineNumber() { + return lineNumber; + } }