js: fix deobfuscator, use new ES2015 module builder

This commit is contained in:
Alexey Andreev 2024-03-13 15:44:18 +01:00
parent 055d5df367
commit 32ae1ab8f0
11 changed files with 84 additions and 72 deletions

View File

@ -151,6 +151,17 @@ final class JS {
return result;
}
public static <T> JSArray<T> wrap(T[] array) {
if (array == null) {
return null;
}
var result = new JSArray<T>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, array[i]);
}
return result;
}
public static <T extends JSObject> WrapFunction<T[], JSArray<T>> arrayWrapper() {
return JS::wrap;
}

View File

@ -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];

View File

@ -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;

View File

@ -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);

View File

@ -18,7 +18,10 @@
<html>
<head>
<meta charset="utf-8">
<script src="deobfuscator.js"></script>
<script type="module">
import { create } from './deobfuscator.js'
window.createDeobfuscator = create;
</script>
<script src="client.js"></script>
</head>
<body>

View File

@ -44,7 +44,8 @@ val generateJs by tasks.register<JavaExec>("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<JavaExec>("generateLibJs") {
"deobfuscator",
layout.buildDirectory.dir("teavm-lib").get().asFile.absolutePath,
"deobfuscator-lib.js",
"es2015"
)
}

View File

@ -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);

View File

@ -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<Frame> 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 : "<unknown function>");
frame.setClassName("<JS>");
frame.setLineNumber(lineNumber);
return frame;
return new Frame(
"<JS>",
functionName != null ? functionName : "<unknown function>",
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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
@JSProperty
void setMethodName(String methodName);
@JSProperty
void setLineNumber(int lineNumber);
public Frame(String className, String methodName, String fileName, int lineNumber) {
this.className = className;
this.methodName = methodName;
this.fileName = fileName;
this.lineNumber = lineNumber;
}
@JSExport
@JSProperty
public String getClassName() {
return className;
}
@JSExport
@JSProperty
public String getFileName() {
return fileName;
}
@JSExport
@JSProperty
public String getMethodName() {
return methodName;
}
@JSExport
@JSProperty
public int getLineNumber() {
return lineNumber;
}
}