diff --git a/docs/bug-naturalisation-pass.drawio.drawio b/docs/bug-naturalisation-pass.drawio.drawio
new file mode 100644
index 00000000..9616469c
--- /dev/null
+++ b/docs/bug-naturalisation-pass.drawio.drawio
@@ -0,0 +1 @@
+7VxbX9o8GP80XOqvRw6XoHXzHYob25yXgUboa2lYGibu0y+h6SFJS6u2Bd28wOZpmob/c36eaMc8W20/YLBeXiEX+h1Dc7cd87xjGAOrSz8Z4Ski6D2DUxbYczktJUy935ATNU7deC4MhYkEIZ94a5E4R0EA50SgAYzRozjtHvniW9dgARXCdA58lXrruWQZUftGL6V/hN5iGb9Z7w6iOysQT+bfJFwCFz1mSKbTMc8wQiS6Wm3PoM/Ai3GJnrsouJtsDMOAVHmgO5wNb39+/v7p5OrzZPP7vzXYjk/MaJVfwN/wLzxG9MuHfMvkKcaB7n7NLuebGf01elx6BE7XYM5oj5T1lLYkK5+OdHo5Q5vAhe54lhDA/GGBGXWyIb4XQE53AX6Y0GU8wgREO9VskWjsqGwm3yjEBG4LEdATXKlAQrSCBD/RKfwBMxYqLow9PnxMGavH3FpmmNrnNMBlaZGsnMJNLzjiz0C/r8AMXSp9fIgwWaIFCoDvpNQRjqBluNBROmeM0JqD+j8k5ImrEtgQJPIGbj3yI3N9t4PY5qPzLV95N3iKBwH9uj+yg7vsIH1oN2JPmcnwBmKPwgUxnzPf4F+7/Uf8D5fJIEKDQbCfwdQEALyApEyuVUHA0AfE+yWun8dW/ugN8uibEwHSe6IA6QNbXCJEGzyH/ClJOJJtvFxe9JcIjIB3bdKTSsxd5k6Z9EQPVZEfrV550BsSCEMUiMRttSUQqv0egdCbU9LIR/OHDtufaajW/NFb+YBZ4VFIMHpIfJtRj6WVYcmxtIaWY2kTYu2mVu8pSHlhMja0IYOKktkdbaQAhpdoNduE5Z6vEnjPEtF8SHUtx3l1cyC1m0LUVGXvGinAURiIiFAkcGfIR8wjBGgnhfee70sk4HuLgEUcFDbmPEYMVI8GJ0N+Y+W5rl8UjIiGrjGuDCSudFWu5DHFbIophlHFIOj7DEKWFS68BxuftGQmcsDLtRJ6YwFZnJxk4FM9buAOWWLBRNMHIQNXkG9R8gTvm+88tUM5z70SFHmuChNLfa9RoEIZNtt7DNdrXbQU9Ccuu8RFqwt187OHeJ0Ih8ZcvaGa2w+QZDzYPUaryJHJvksQyMb8VyQPhbpu2WW6nnCqHUtpKXhOCcIwg2jH6O5s3wzTqwW7SjHWaGCcFyjEeTKFC/g+9NECgxV9cp3JgoR7mfSojDf33hbGJZJmeVWgMmWJcnPMslUz/AYSn+ZtsFnVBlv5DK9sXF/HvsEL2HeQQkcFjukVeRNlHM2nnHKAX+CHaMwCnjLT1mxCWPweUxPfY/JaR5F7lOfH+0rlJtpBrU4xNjgZI34H1eLlG0pCSgJmKZgxcxLrVvONnNpCi5pdsy0+vGafmtmfnsBrW66NNBxwmmqA1LFHDsW0Y5+/XxWTMno7p87SrobZKht4XLrU47j0MvCIB9haUwojwB6K59B3ptPeL9f0Xu9UTDBO8oLWQaucU4sJ77i51rfy0+ODNddi83n8Qefb6651G3GA3b6Ud7bcXrNUU3vExVPbFNGqWj215B5VbRpn/auexiJUGkPGE0t1zSoINv9VT58lmmr777iqp5E8vJnqadc6pHN9Tt53jwJyAVaezwjfIXZBADiZv2fQir73K+q73X+lb32dCe8revL3VMXLdPDYquLWS8qqb7cqXl3XelV960F1zVZ17ciOpJQohFSJTo5XHuxIij1QEH2HR1JKuCIVsA5eIo5fdvyhQuOG6dW+vSC21sTCcezEuQRYVruxdtdQtDCOGVjUxYJtwGHq/tyw4++jOC5LCIK8xERW2jqJZZZZx8i6aWzVk3AnCYw6WG939HStKEy5gvRru3TCjCXzYaZCGm3r7ddIX2Iu5H5icrgqYy9aLZvaB7UXNTeLj9VeCCyXqmw1NZAN6bC8ae5vIMvz4wJ+YUVB2ztfbDirT0u1RlM2kg3XGm1dMZLvunPdk4PFQ4cltnqe7m9ob3Zl3T90f9POaTMr/c0bFJKTAJANpnCGLDn6S/uc9iDf6GXZl5iydsJ71ZCp/jst+nNYhc5Uhi2MfgMIhTrYUQzNzO2fiMAmwX69zrvqeZCiCKudEr3cB0rU97kl+p6yULXAoLa8QbXIt8Mv15fXH6K4/qPzxaG/vn5kn9+H429OVBfRbi/HY1YvGd8O76aMxm58cabOVzZ9EpVS6J60q+Enthpb45JNHI6mk/G3r874jg6+TZ2xM52eJq8YTyY3u9XOJlcOm+5cn7MZR2pdqhW62TDeRMcwLy5YwliPberr4oGlRMCz9SDLbNE26WpD8mwJgkW2nL2v46PXVFwrOdQnFZbNvD/tMpLzLe0gp1bS9ln1Nlq5NRrsoj/qaqmnKp/gHbzQYMsLmS03VW21qXqE6tWT1Su3b1OXetFh+i8dIqDTf4xhOn8A
\ No newline at end of file
diff --git a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ApplicationClassSource.java b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ApplicationClassSource.java
index f6def313..babb6e86 100644
--- a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ApplicationClassSource.java
+++ b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ApplicationClassSource.java
@@ -57,10 +57,6 @@ public void addLibraries(LibraryClassSource... libs) {
libraries.sort(Comparator.comparingInt(LibraryClassSource::getPriority));
Collections.reverse(libraries);
-
- for (LibraryClassSource library : libraries) {
- System.out.println("LIBRARY --> " + library.parent.getName() + " [priority: " + library.getPriority() + "]");
- }
}
public ClassNode findClassNode(String name) {
diff --git a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ClassTree.java b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ClassTree.java
index 7832b00a..c7bc4420 100644
--- a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ClassTree.java
+++ b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/ClassTree.java
@@ -161,7 +161,7 @@ protected ClassNode findClass(String name) {
private ClassNode requestClass0(String name, String from) {
try {
- return source.findClassNode(name);
+ return findClass(name);
} catch(RuntimeException e) {
throw new RuntimeException("request from " + from, e);
}
diff --git a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/CompleteResolvingJarDumper.java b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/CompleteResolvingJarDumper.java
index fe68a3e6..2b3a2e70 100644
--- a/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/CompleteResolvingJarDumper.java
+++ b/maple-ir/org.mapleir.app-services/src/main/java/org/mapleir/app/service/CompleteResolvingJarDumper.java
@@ -4,6 +4,7 @@
import org.objectweb.asm.ClassWriter;
import org.mapleir.asm.ClassNode;
import org.mapleir.asm.MethodNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarContents;
import org.topdank.byteengineer.commons.data.JarResource;
import org.topdank.byteio.out.JarDumper;
@@ -25,14 +26,14 @@
*/
public class CompleteResolvingJarDumper implements JarDumper {
- private final JarContents> contents;
+ private final JarContents contents;
private final ApplicationClassSource source;
/**
* Creates a new JarDumper.
*
* @param contents Contents of jar.
*/
- public CompleteResolvingJarDumper(JarContents contents, ApplicationClassSource source) {
+ public CompleteResolvingJarDumper(JarContents contents, ApplicationClassSource source) {
this.contents = contents;
this.source = source;
}
@@ -50,8 +51,8 @@ public void dump(File file) throws IOException {
JarOutputStream jos = new JarOutputStream(new FileOutputStream(file));
int classesDumped = 0;
int resourcesDumped = 0;
- for (ClassNode cn : contents.getClassContents()) {
- classesDumped += dumpClass(jos, cn.getName(), cn);
+ for (JarClassData cn : contents.getClassContents()) {
+ classesDumped += dumpClass(jos, cn);
}
for (JarResource res : contents.getResourceContents()) {
resourcesDumped += dumpResource(jos, res.getName(), res.getData());
@@ -66,13 +67,13 @@ public void dump(File file) throws IOException {
* Writes the {@link ClassNode} to the Jar.
*
* @param out The {@link JarOutputStream}.
- * @param cn The ClassNode.
- * @param name The entry name.
+ * @param classData The {@link JarClassData}
* @throws IOException If there is a write error.
* @return The amount of things dumped, 1 or if you're not dumping it 0.
*/
@Override
- public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOException {
+ public int dumpClass(JarOutputStream out, JarClassData classData) throws IOException {
+ ClassNode cn = classData.getClassNode();
JarEntry entry = new JarEntry(cn.getName() + ".class");
out.putNextEntry(entry);
ClassTree tree = source.getClassTree();
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/DefaultBlockFactory.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/DefaultBlockFactory.java
index 949f7a6b..c44001b5 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/DefaultBlockFactory.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/DefaultBlockFactory.java
@@ -7,11 +7,14 @@
import org.mapleir.ir.cfg.builder.ssa.BlockBuilder;
import org.mapleir.ir.cfg.builder.ssa.CfgBuilder;
import org.mapleir.ir.cfg.builder.ssa.expr.*;
+import org.mapleir.ir.cfg.builder.ssa.expr.invoke.StaticInvocationExprBuilder;
import org.mapleir.ir.cfg.builder.ssa.stmt.*;
import org.mapleir.ir.cfg.builder.ssa.stmt.copy.CopyPhiStmtBuilder;
import org.mapleir.ir.cfg.builder.ssa.stmt.copy.CopyVarStmtBuilder;
import org.mapleir.ir.code.Expr;
import org.mapleir.ir.code.expr.*;
+import org.mapleir.ir.code.expr.invoke.InvocationExpr;
+import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
import org.mapleir.ir.code.stmt.*;
import org.mapleir.ir.code.stmt.copy.CopyPhiStmt;
import org.mapleir.ir.code.stmt.copy.CopyVarStmt;
@@ -304,6 +307,63 @@ public ConstantExpr build() {
};
}
+ @Override
+ public StaticInvocationExprBuilder static_invoke_expr() {
+ return new StaticInvocationExprBuilder() {
+ private InvocationExpr.CallType callType = InvocationExpr.CallType.STATIC;
+ private Expr[] args;
+ private String owner;
+ private String name;
+ private String desc;
+
+ @Override
+ public StaticInvocationExprBuilder callType(InvocationExpr.CallType callType) {
+ this.callType = callType;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder args(Expr[] args) {
+ this.args = args;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder owner(String owner) {
+ this.owner = owner;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder desc(String desc) {
+ this.desc = desc;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExpr build() {
+ assert owner != null : "Owner name cannot be null";
+ assert name != null : "Name cannot be null";
+ assert desc != null : "Description cannot be null";
+
+
+ return new StaticInvocationExpr(
+ callType,
+ args,
+ owner,
+ name,
+ desc
+ );
+ }
+ };
+ }
+
@Override
public FieldLoadExprBuilder field_load_expr() {
return new FieldLoadExprBuilder() {
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/SSAFactory.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/SSAFactory.java
index 8e4f54e9..ddc19626 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/SSAFactory.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/SSAFactory.java
@@ -3,6 +3,7 @@
import org.mapleir.ir.cfg.builder.ssa.BlockBuilder;
import org.mapleir.ir.cfg.builder.ssa.CfgBuilder;
import org.mapleir.ir.cfg.builder.ssa.expr.*;
+import org.mapleir.ir.cfg.builder.ssa.expr.invoke.StaticInvocationExprBuilder;
import org.mapleir.ir.cfg.builder.ssa.stmt.*;
import org.mapleir.ir.cfg.builder.ssa.stmt.copy.CopyPhiStmtBuilder;
import org.mapleir.ir.cfg.builder.ssa.stmt.copy.CopyVarStmtBuilder;
@@ -43,6 +44,8 @@ public interface SSAFactory {
VarExprBuilder var_expr();
+ StaticInvocationExprBuilder static_invoke_expr();
+
CopyPhiStmtBuilder copy_phi_stmt();
CopyVarStmtBuilder copy_var_stmt();
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/GenerationPass.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/GenerationPass.java
index 51fb3f8a..09886f16 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/GenerationPass.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/GenerationPass.java
@@ -1249,7 +1249,13 @@ protected void _call(int op, String owner, String name, String desc) {
callExpr = new VirtualInvocationExpr(VirtualInvocationExpr.resolveCallType(op), args, owner, name, desc);
break;
case Opcodes.INVOKESTATIC:
- callExpr = new StaticInvocationExpr(args, owner, name, desc);
+ callExpr = builder.factory
+ .static_invoke_expr()
+ .args(args)
+ .owner(owner)
+ .name(name)
+ .desc(desc)
+ .build();
break;
default:
throw new IllegalArgumentException("invalid call opcode " + op);
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/NaturalisationPass.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/NaturalisationPass.java
index 53a16edc..ad90d555 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/NaturalisationPass.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/NaturalisationPass.java
@@ -155,6 +155,19 @@ class MergePair {
continue;
}
Set> inSuccs = in.cfg.getSuccessors(e -> !(e instanceof TryCatchEdge), in);
+ /*
+ * In a nutshell, to be able to properly merge two blocks, we're looking for this
+ * exact scenario:
+ *
+ * B.. B..
+ * \ / <-- No matters. We don't really care
+ * BX1 (in)
+ * | <-- CRITICAL! Must only be ONE edge which is a successor and
+ * v only one reverse edge for the successor
+ * BX2 (b)
+ * / \ <-- We don't really care from here on out
+ * B.. B.;
+ */
if(inSuccs.size() != 1 || builder.graph.getReverseEdges(b).size() != 1) {
continue;
}
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/ssa/expr/invoke/StaticInvocationExprBuilder.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/ssa/expr/invoke/StaticInvocationExprBuilder.java
new file mode 100644
index 00000000..0b4afc40
--- /dev/null
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/cfg/builder/ssa/expr/invoke/StaticInvocationExprBuilder.java
@@ -0,0 +1,14 @@
+package org.mapleir.ir.cfg.builder.ssa.expr.invoke;
+
+import org.mapleir.app.factory.Builder;
+import org.mapleir.ir.code.Expr;
+import org.mapleir.ir.code.expr.invoke.InvocationExpr;
+import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
+
+public interface StaticInvocationExprBuilder extends Builder {
+ StaticInvocationExprBuilder callType(InvocationExpr.CallType callType);
+ StaticInvocationExprBuilder args(Expr[] args);
+ StaticInvocationExprBuilder owner(String owner);
+ StaticInvocationExprBuilder name(String name);
+ StaticInvocationExprBuilder desc(String desc);
+}
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/expr/invoke/StaticInvocationExpr.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/expr/invoke/StaticInvocationExpr.java
index 659bd79a..a42a94a0 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/expr/invoke/StaticInvocationExpr.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/expr/invoke/StaticInvocationExpr.java
@@ -2,7 +2,9 @@
import org.mapleir.app.service.InvocationResolver;
import org.mapleir.ir.code.Expr;
+import org.mapleir.ir.code.Opcode;
import org.mapleir.stdlib.collections.CollectionUtils;
+import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.mapleir.asm.MethodNode;
@@ -15,6 +17,10 @@ public StaticInvocationExpr(Expr[] args, String owner, String name, String desc)
super(CallType.STATIC, args, owner, name, desc);
}
+ public StaticInvocationExpr(CallType callType, Expr[] args, String owner, String name, String desc) {
+ super(callType, args, owner, name, desc);
+ }
+
@Override
public StaticInvocationExpr copy() {
return new StaticInvocationExpr(copyArgs(), getOwner(), getName(), getDesc());
@@ -32,7 +38,13 @@ public boolean isDynamic() {
@Override
protected void generateCallCode(MethodVisitor visitor) {
- visitor.visitMethodInsn(Opcodes.INVOKESTATIC, getOwner(), getName(), getDesc(), getCallType() == CallType.INTERFACE);
+ visitor.visitMethodInsn(
+ Opcodes.INVOKESTATIC,
+ getOwner(),
+ getName(),
+ getDesc(),
+ getCallType() == CallType.INTERFACE
+ );
}
@Override
diff --git a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/stmt/NopStmt.java b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/stmt/NopStmt.java
index 14d272d2..4eeeaeed 100644
--- a/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/stmt/NopStmt.java
+++ b/maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/stmt/NopStmt.java
@@ -5,6 +5,7 @@
import org.mapleir.ir.codegen.BytecodeFrontend;
import org.mapleir.stdlib.util.TabbedStringWriter;
import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
public class NopStmt extends Stmt {
public NopStmt() {
@@ -23,6 +24,7 @@ public void toString(TabbedStringWriter printer) {
@Override
public void toCode(MethodVisitor visitor, BytecodeFrontend assembler) {
+ visitor.visitInsn(Opcodes.NOP);
}
@Override
diff --git a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot.java b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot.java
index 47e8c211..2362e108 100644
--- a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot.java
+++ b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot.java
@@ -24,6 +24,7 @@
import org.mapleir.ir.codegen.ControlFlowGraphDumper;
import org.mapleir.asm.ClassNode;
import org.mapleir.asm.MethodNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
import org.topdank.byteio.in.SingleJarDownloader;
@@ -34,6 +35,7 @@
import java.util.*;
import java.util.Map.Entry;
import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
public class Boot {
@@ -63,7 +65,10 @@ public static void main(String[] args) throws Exception {
SingleJarDownloader dl = new SingleJarDownloader<>(new JarInfo(f));
dl.download();
String appName = f.getName().substring(0, f.getName().length() - 4);
- ApplicationClassSource app = new ApplicationClassSource(appName, dl.getJarContents().getClassContents());
+ ApplicationClassSource app = new ApplicationClassSource(
+ appName,
+ dl.getJarContents().getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList())
+ );
//
// ApplicationClassSource app = new ApplicationClassSource("test", ClassHelper.parseClasses(CGExample.class));
// app.addLibraries(new InstalledRuntimeClassSource(app));
diff --git a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot2.java b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot2.java
index acd603d4..12647d66 100644
--- a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot2.java
+++ b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/Boot2.java
@@ -24,6 +24,7 @@
import org.mapleir.ir.codegen.ControlFlowGraphDumper;
import org.mapleir.asm.ClassNode;
import org.mapleir.asm.MethodNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
import org.topdank.byteio.in.SingleJarDownloader;
@@ -31,6 +32,7 @@
import java.util.*;
import java.util.Map.Entry;
import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
public class Boot2 {
@@ -58,7 +60,10 @@ public static void main(String[] args) throws Exception {
SingleJarDownloader dl = new SingleJarDownloader<>(new JarInfo(f));
dl.download();
String appName = f.getName().substring(0, f.getName().length() - 4);
- ApplicationClassSource app = new ApplicationClassSource(appName, dl.getJarContents().getClassContents());
+ ApplicationClassSource app = new ApplicationClassSource(
+ appName,
+ dl.getJarContents().getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList())
+ );
//
// ApplicationClassSource app = new ApplicationClassSource("test", ClassHelper.parseClasses(CGExample.class));
// app.addLibraries(new InstalledRuntimeClassSource(app));
diff --git a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/DataFlowDemoBoot.java b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/DataFlowDemoBoot.java
index e545682c..9692fc02 100644
--- a/maple-ir/org.mapleir.main/src/main/java/org/mapleir/DataFlowDemoBoot.java
+++ b/maple-ir/org.mapleir.main/src/main/java/org/mapleir/DataFlowDemoBoot.java
@@ -21,6 +21,7 @@
import org.mapleir.stdlib.util.JavaDescUse;
import org.mapleir.asm.ClassNode;
import org.mapleir.asm.MethodNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
import org.topdank.byteio.in.SingleJarDownloader;
@@ -28,6 +29,7 @@
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
+import java.util.stream.Collectors;
public class DataFlowDemoBoot {
@@ -58,7 +60,10 @@ public static void main(String[] args) throws Exception {
SingleJarDownloader dl = new SingleJarDownloader<>(new JarInfo(f));
dl.download();
String appName = f.getName().substring(0, f.getName().length() - 4);
- ApplicationClassSource app = new ApplicationClassSource(appName, dl.getJarContents().getClassContents());
+ ApplicationClassSource app = new ApplicationClassSource(
+ appName,
+ dl.getJarContents().getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList())
+ );
//
// ApplicationClassSource app = new ApplicationClassSource("test", ClassHelper.parseClasses(CGExample.class));
// app.addLibraries(new InstalledcoRuntimeClassSource(app));
diff --git a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassHelper.java b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassHelper.java
index ae128141..c1d6341e 100644
--- a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassHelper.java
+++ b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassHelper.java
@@ -10,8 +10,8 @@
import java.util.List;
import java.util.Map;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.JSRInlinerAdapter;
/**
* @author Bibl (don't ban me pls)
@@ -41,7 +41,13 @@ public static ClassNode create(byte[] bytes) {
public static ClassNode create(byte[] bytes, int flags) {
ClassReader reader = new ClassReader(bytes);
org.objectweb.asm.tree.ClassNode node = new org.objectweb.asm.tree.ClassNode();
- reader.accept(node, flags);
+ ClassVisitor visitor = new ClassVisitor(Opcodes.ASM9, node) {
+ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions);
+ }
+ };
+
+ reader.accept(visitor, flags);
return new ClassNode(node);
}
diff --git a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassNode.java b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassNode.java
index e3b22434..facb8c95 100644
--- a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassNode.java
+++ b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/ClassNode.java
@@ -94,4 +94,19 @@ public boolean isPrivate() {
public boolean isSynthetic() {
return (node.access & Opcodes.ACC_SYNTHETIC) != 0;
}
+
+ public boolean isInterface() {
+ return (node.access & Opcodes.ACC_INTERFACE) != 0;
+ }
+
+ public boolean isAnnoyingVersion() {
+ return (node.version & 0xFFFF) < Opcodes.V1_8;
+ }
+
+ @Override
+ public String toString() {
+ return "ClassNode{" +
+ "node=" + node +
+ '}';
+ }
}
diff --git a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/MethodNode.java b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/MethodNode.java
index d0beeebf..c85df17b 100644
--- a/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/MethodNode.java
+++ b/maple-ir/org.mapleir.modasm/src/main/java/org/mapleir/asm/MethodNode.java
@@ -21,7 +21,7 @@ public MethodNode(org.objectweb.asm.tree.MethodNode node, ClassNode owner) {
@Override
public String toString() {
- return (owner != null ? getOwner() : "null") + "." + getName() + getDesc();
+ return (owner != null ? getOwner() : "null") + "#" + getName() + getDesc();
}
@Override
diff --git a/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/undirected/FakeFastUndirectedGraph.java b/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/undirected/FakeFastUndirectedGraph.java
index 65d89490..417588db 100644
--- a/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/undirected/FakeFastUndirectedGraph.java
+++ b/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/undirected/FakeFastUndirectedGraph.java
@@ -4,6 +4,8 @@
import org.mapleir.stdlib.collections.graph.util.FakeFastEdge;
import org.mapleir.stdlib.collections.graph.util.FakeFastVertex;
+import java.util.Collection;
+
public class FakeFastUndirectedGraph extends FastUndirectedGraph {
public FakeFastEdge pubGetSisterEdge(FakeFastEdge e) {
@@ -18,7 +20,12 @@ public FakeFastEdge pubGetSisterEdge(FakeFastEdge e) {
public FakeFastEdge clone(FakeFastEdge e, FakeFastVertex src, FakeFastVertex dst) {
return new FakeFastEdge(src, dst, false);
}
-
+
+ @Override
+ public Collection getCommonAncestor(Collection nodes) {
+ return null;
+ }
+
@Override
public String toString() {
return makeDotGraph().toString();
diff --git a/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/util/OrderedNode.java b/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/util/OrderedNode.java
index 12e1725b..72371a65 100644
--- a/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/util/OrderedNode.java
+++ b/maple-ir/org.mapleir.stdlib/src/test/java/org/mapleir/stdlib/collections/graph/util/OrderedNode.java
@@ -68,5 +68,9 @@ public static class ODirectedGraph extends FastDirectedGraph implements OGraph {
+ @Override
+ public Collection getCommonAncestor(Collection nodes) {
+ return null;
+ }
}
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/classloader/JarClassLoader.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/classloader/JarClassLoader.java
index f61fa42c..eb76f35e 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/classloader/JarClassLoader.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/classloader/JarClassLoader.java
@@ -9,6 +9,7 @@
import org.mapleir.asm.ClassNode;
import org.topdank.byteengineer.commons.asm.ASMFactory;
import org.topdank.byteengineer.commons.asm.DefaultASMFactory;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.LocateableJarContents;
/**
@@ -25,14 +26,14 @@ public class JarClassLoader extends ClassLoader {
private Map> cache;
private ClassLoader ucp;
- public JarClassLoader(LocateableJarContents contents) {
+ public JarClassLoader(LocateableJarContents contents) {
this(contents, null, new DefaultASMFactory());
}
/**
* @param contents Reference to the JarContents object.
*/
- public JarClassLoader(LocateableJarContents contents, ClassLoader parent) {
+ public JarClassLoader(LocateableJarContents contents, ClassLoader parent) {
this(contents, parent, new DefaultASMFactory());
}
@@ -41,7 +42,7 @@ public JarClassLoader(LocateableJarContents contents, ClassLoader par
* @param parent
* @param factory ASMFactory.
*/
- public JarClassLoader(LocateableJarContents contents, ClassLoader parent, ASMFactory factory) {
+ public JarClassLoader(LocateableJarContents contents, ClassLoader parent, ASMFactory factory) {
this.factory = factory;
ClassLoader _parent = parent;
@@ -74,12 +75,12 @@ private static StackTraceElement creator(boolean cl) {
return null;
}
- public void add(LocateableJarContents contents) {
+ public void add(LocateableJarContents contents) {
for (URL url : contents.getJarUrls()) {
URLClassLoaderUtil.addLast(url, ucp);
}
- for (ClassNode cn : contents.getClassContents()) {
- fastNodeCache.put(cn.getName(), cn);
+ for (JarClassData cn : contents.getClassContents()) {
+ fastNodeCache.put(cn.getName(), cn.getClassNode());
}
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarClassData.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarClassData.java
new file mode 100644
index 00000000..5019a708
--- /dev/null
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarClassData.java
@@ -0,0 +1,58 @@
+package org.topdank.byteengineer.commons.data;
+
+import org.mapleir.asm.ClassNode;
+
+import java.util.Arrays;
+
+public final class JarClassData {
+
+ private final String name;
+ private final byte[] data;
+ private final ClassNode classNode;
+
+ public JarClassData(String name, byte[] data, ClassNode classNode) {
+ this.name = name;
+ this.data = data;
+ this.classNode = classNode;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public ClassNode getClassNode() {
+ return classNode;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + Arrays.hashCode(data);
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ JarClassData other = (JarClassData) obj;
+ if (!Arrays.equals(data, other.data))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarContents.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarContents.java
index 388df3d0..3bf2870e 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarContents.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/JarContents.java
@@ -9,65 +9,57 @@
import org.mapleir.asm.ClassNode;
-public class JarContents {
+public class JarContents {
- private final DataContainer classContents;
- private final DataContainer classData;
+ private final DataContainer classContents;
private final DataContainer resourceContents;
public JarContents() {
- classContents = new ClassNodeContainer();
- classData = new ResourceContainer();
+ classContents = new ClassNodeContainer();
resourceContents = new ResourceContainer();
}
- public JarContents(DataContainer classContents, DataContainer classData, DataContainer resourceContents) {
- this.classContents = classContents == null ? new ClassNodeContainer() : classContents;
- this.classData = classData == null ? new ResourceContainer() : classData;
+ public JarContents(DataContainer classContents, DataContainer classData, DataContainer resourceContents) {
+ this.classContents = classContents == null ? new ClassNodeContainer() : classContents;
this.resourceContents = resourceContents == null ? new ResourceContainer() : resourceContents;
}
- public final DataContainer getClassContents() {
+ public final DataContainer getClassContents() {
return classContents;
}
-
- public final DataContainer getClassData() {
- return classData;
- }
-
public final DataContainer getResourceContents() {
return resourceContents;
}
- public void merge(JarContents contents) {
+ public void merge(JarContents contents) {
classContents.addAll(contents.classContents);
resourceContents.addAll(contents.resourceContents);
}
- public JarContents add(JarContents contents) {
- List c1 = classContents;
- List c2 = contents.classContents;
+ public JarContents add(JarContents contents) {
+ List c1 = classContents;
+ List c2 = contents.classContents;
List r1 = resourceContents;
List r2 = contents.resourceContents;
- List c3 = new ArrayList(c1.size() + c2.size());
+ List c3 = new ArrayList<>(c1.size() + c2.size());
c3.addAll(c1);
c3.addAll(c2);
- List r3 = new ArrayList(r1.size() + r2.size());
+ List r3 = new ArrayList<>(r1.size() + r2.size());
r3.addAll(r1);
r3.addAll(r2);
// TODO add jar data here
- return new JarContents(new ClassNodeContainer<>(c3), null, new ResourceContainer(r3));
+ return new JarContents(new ClassNodeContainer(c3), null, new ResourceContainer(r3));
}
- public static class ClassNodeContainer extends DataContainer {
+ public static class ClassNodeContainer extends DataContainer {
private static final long serialVersionUID = -6169578803641192235L;
- private Map lastMap = new HashMap();
+ private Map lastMap = new HashMap<>();
private boolean invalidated;
public ClassNodeContainer() {
@@ -78,18 +70,18 @@ public ClassNodeContainer(int cap) {
super(cap);
}
- public ClassNodeContainer(Collection data) {
+ public ClassNodeContainer(Collection data) {
super(data);
}
@Override
- public boolean add(C c) {
+ public boolean add(JarClassData c) {
invalidated = true;
return super.add(c);
}
@Override
- public boolean addAll(Collection extends C> c) {
+ public boolean addAll(Collection extends JarClassData> c) {
invalidated = true;
return super.addAll(c);
}
@@ -101,13 +93,13 @@ public boolean remove(Object c) {
}
@Override
- public Map namedMap() {
+ public Map namedMap() {
if (invalidated) {
invalidated = false;
- Map nodeMap = new HashMap();
- Iterator it = iterator();
+ Map nodeMap = new HashMap<>();
+ Iterator it = iterator();
while (it.hasNext()) {
- C cn = it.next();
+ JarClassData cn = it.next();
if (nodeMap.containsKey(cn.getName())) {
it.remove();
} else {
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/LocateableJarContents.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/LocateableJarContents.java
index e69c2be6..0c3f4d64 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/LocateableJarContents.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteengineer/commons/data/LocateableJarContents.java
@@ -4,7 +4,7 @@
import org.mapleir.asm.ClassNode;
-public class LocateableJarContents extends JarContents {
+public class LocateableJarContents extends JarContents {
private final URL[] jarUrls;
@@ -13,7 +13,7 @@ public LocateableJarContents(URL... jarUrls) {
this.jarUrls = jarUrls;
}
- public LocateableJarContents(DataContainer classContents, DataContainer resourceContents, URL... jarUrls) {
+ public LocateableJarContents(DataContainer classContents, DataContainer resourceContents, URL... jarUrls) {
super(classContents, null, resourceContents);
this.jarUrls = jarUrls;
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/AbstractJarDownloader.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/AbstractJarDownloader.java
index 9d0a5b17..1b313c57 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/AbstractJarDownloader.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/AbstractJarDownloader.java
@@ -10,7 +10,7 @@
public abstract class AbstractJarDownloader {
protected final ASMFactory factory;
- protected LocateableJarContents contents;
+ protected LocateableJarContents contents;
@SuppressWarnings("unchecked")
public AbstractJarDownloader() {
@@ -23,7 +23,7 @@ public AbstractJarDownloader(ASMFactory factory) {
public abstract void download() throws IOException;
- public LocateableJarContents getJarContents() {
+ public LocateableJarContents getJarContents() {
return contents;
}
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/MultiJarDownloader.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/MultiJarDownloader.java
index d7ca3862..a00cd241 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/MultiJarDownloader.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/MultiJarDownloader.java
@@ -13,6 +13,7 @@
import com.google.common.io.ByteStreams;
import org.mapleir.asm.ClassNode;
import org.topdank.byteengineer.commons.asm.ASMFactory;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
import org.topdank.byteengineer.commons.data.JarResource;
import org.topdank.byteengineer.commons.data.LocateableJarContents;
@@ -38,7 +39,7 @@ public void download() throws IOException {
for (int i = 0; i < jarInfos.length; i++) {
urls[i] = new URL(jarInfos[i].formattedURL());
}
- contents = new LocateableJarContents(urls);
+ contents = new LocateableJarContents(urls);
for (JarInfo jarinfo : jarInfos) {
JarURLConnection connection = (JarURLConnection) new URL(jarinfo.formattedURL()).openConnection();
JarFile jarFile = connection.getJarFile();
@@ -52,7 +53,11 @@ public void download() throws IOException {
if (entry.getName().endsWith(".class")) {
C cn = factory.create(bytes, entry.getName());
if(!map.containsKey(cn.getName())) {
- contents.getClassContents().add(cn);
+ contents.getClassContents().add(new JarClassData(
+ entry.getName(),
+ bytes,
+ cn
+ ));
} else {
throw new IllegalStateException("duplicate: " + cn.getName());
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJarDownloader.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJarDownloader.java
index a5f11138..77c79830 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJarDownloader.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJarDownloader.java
@@ -12,6 +12,7 @@
import org.mapleir.asm.ClassNode;
import org.topdank.byteengineer.commons.asm.ASMFactory;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
import org.topdank.byteengineer.commons.data.JarResource;
import org.topdank.byteengineer.commons.data.LocateableJarContents;
@@ -38,7 +39,7 @@ public void download() throws IOException {
JarURLConnection connection = (JarURLConnection) (url = new URL(jarInfo.formattedURL())).openConnection();
JarFile jarFile = connection.getJarFile();
Enumeration entries = jarFile.entries();
- contents = new LocateableJarContents<>(url);
+ contents = new LocateableJarContents(url);
Map map = new HashMap<>();
@@ -48,7 +49,11 @@ public void download() throws IOException {
if (entry.getName().endsWith(".class")) {
C cn = factory.create(bytes, entry.getName());
if(!map.containsKey(cn.getName())) {
- contents.getClassContents().add(cn);
+ contents.getClassContents().add(new JarClassData(
+ entry.getName(),
+ bytes,
+ cn
+ ));
} else {
throw new IllegalStateException("duplicate: " + cn.getName());
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJmodDownloader.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJmodDownloader.java
new file mode 100644
index 00000000..944d6a8b
--- /dev/null
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/in/SingleJmodDownloader.java
@@ -0,0 +1,76 @@
+package org.topdank.byteio.in;
+
+import com.google.common.io.ByteStreams;
+import org.mapleir.asm.ClassNode;
+import org.topdank.byteengineer.commons.asm.ASMFactory;
+import org.topdank.byteengineer.commons.data.JarClassData;
+import org.topdank.byteengineer.commons.data.JarInfo;
+import org.topdank.byteengineer.commons.data.JarResource;
+import org.topdank.byteengineer.commons.data.LocateableJarContents;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class SingleJmodDownloader extends AbstractJarDownloader {
+
+ protected final JarInfo jarInfo;
+
+ public SingleJmodDownloader(JarInfo jarInfo) {
+ super();
+ this.jarInfo = jarInfo;
+ }
+
+ public SingleJmodDownloader(ASMFactory factory, JarInfo jarInfo) {
+ super(factory);
+ this.jarInfo = jarInfo;
+ }
+
+ @Override
+ public void download() throws IOException {
+ File file;
+ try (ZipFile jarFile = new ZipFile((file = new File(jarInfo.getPath())))) {
+ Enumeration extends ZipEntry> entries = jarFile.entries();
+ contents = new LocateableJarContents(file.toURI().toURL());
+
+ Map map = new HashMap<>();
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ byte[] bytes = read(jarFile.getInputStream(entry));
+ if (entry.getName().endsWith(".class")) {
+ C cn = factory.create(bytes, entry.getName());
+ if(!map.containsKey(cn.getName())) {
+ contents.getClassContents().add(new JarClassData(
+ entry.getName(),
+ bytes,
+ cn
+ ));
+ } else {
+ throw new IllegalStateException("duplicate: " + cn.getName());
+ }
+
+ //if(cn.name.equals("org/xmlpull/v1/XmlPullParser")) {
+ // System.out.println("SingleJarDownloader.download() " +entry.getName() + " " + bytes.length);
+ //}
+ } else {
+ JarResource resource = new JarResource(entry.getName(), bytes);
+ contents.getResourceContents().add(resource);
+ }
+ }
+ }
+ }
+
+ private byte[] read(InputStream inputStream) throws IOException {
+ return ByteStreams.toByteArray(inputStream);
+ }
+}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/CompleteJarDumper.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/CompleteJarDumper.java
index c8ec4121..f2ccaa66 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/CompleteJarDumper.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/CompleteJarDumper.java
@@ -9,6 +9,7 @@
import org.mapleir.asm.ClassHelper;
import org.objectweb.asm.ClassWriter;
import org.mapleir.asm.ClassNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarContents;
import org.topdank.byteengineer.commons.data.JarResource;
import org.topdank.byteio.util.Debug;
@@ -20,14 +21,14 @@
*/
public class CompleteJarDumper implements JarDumper {
- private final JarContents> contents;
+ private final JarContents contents;
/**
* Creates a new JarDumper.
*
* @param contents Contents of jar.
*/
- public CompleteJarDumper(JarContents contents) {
+ public CompleteJarDumper(JarContents contents) {
this.contents = contents;
}
@@ -44,8 +45,8 @@ public void dump(File file) throws IOException {
JarOutputStream jos = new JarOutputStream(new FileOutputStream(file));
int classesDumped = 0;
int resourcesDumped = 0;
- for (ClassNode cn : contents.getClassContents()) {
- classesDumped += dumpClass(jos, cn.getName(), cn);
+ for (JarClassData cn : contents.getClassContents()) {
+ classesDumped += dumpClass(jos, cn);
}
for (JarResource res : contents.getResourceContents()) {
resourcesDumped += dumpResource(jos, res.getName(), res.getData());
@@ -60,16 +61,15 @@ public void dump(File file) throws IOException {
* Writes the {@link ClassNode} to the Jar.
*
* @param out The {@link JarOutputStream}.
- * @param cn The ClassNode.
- * @param name The entry name.
+ * @param classData The {@link JarClassData}.
* @throws IOException If there is a write error.
* @return The amount of things dumped, 1 or if you're not dumping it 0.
*/
@Override
- public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOException {
- JarEntry entry = new JarEntry(cn.getName() + ".class");
+ public int dumpClass(JarOutputStream out, JarClassData classData) throws IOException {
+ JarEntry entry = new JarEntry(classData.getClassNode().getName() + ".class");
out.putNextEntry(entry);
- out.write(ClassHelper.toByteArray(cn, ClassWriter.COMPUTE_FRAMES));
+ out.write(ClassHelper.toByteArray(classData.getClassNode(), ClassWriter.COMPUTE_FRAMES));
return 1;
}
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/JarDumper.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/JarDumper.java
index 94d2b76a..af14dda8 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/JarDumper.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/JarDumper.java
@@ -5,12 +5,13 @@
import java.util.jar.JarOutputStream;
import org.mapleir.asm.ClassNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
-public abstract interface JarDumper {
+public interface JarDumper {
- public void dump(File file) throws IOException;
+ void dump(File file) throws IOException;
- public abstract int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOException;
+ int dumpClass(JarOutputStream out, JarClassData classData) throws IOException;
- public abstract int dumpResource(JarOutputStream out, String name, byte[] file) throws IOException;
+ int dumpResource(JarOutputStream out, String name, byte[] file) throws IOException;
} //?
diff --git a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/NonMetaJarDumper.java b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/NonMetaJarDumper.java
index 4fa74a9b..d82ee5ac 100644
--- a/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/NonMetaJarDumper.java
+++ b/maple-ir/org.mapleir.topdank-services/src/main/java/org/topdank/byteio/out/NonMetaJarDumper.java
@@ -8,7 +8,7 @@
public class NonMetaJarDumper extends CompleteJarDumper {
- public NonMetaJarDumper(JarContents contents) {
+ public NonMetaJarDumper(JarContents contents) {
super(contents);
}
diff --git a/obfuscator/dependency-reduced-pom.xml b/obfuscator/dependency-reduced-pom.xml
index 2e6c8f3f..b87311c1 100644
--- a/obfuscator/dependency-reduced-pom.xml
+++ b/obfuscator/dependency-reduced-pom.xml
@@ -46,6 +46,18 @@
1.18.22
provided
+
+ com.github.xxDark
+ SSVM
+ 1.7.1
+ test
+
+
+ CAFED00D
+ com.github.Col-E
+
+
+
3.21.0
diff --git a/obfuscator/pom.xml b/obfuscator/pom.xml
index cc9aa29a..06aac7a2 100644
--- a/obfuscator/pom.xml
+++ b/obfuscator/pom.xml
@@ -112,6 +112,12 @@
jline
${jline.version}
+
+ com.github.xxDark
+ SSVM
+ 1.7.1
+ test
+
\ No newline at end of file
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java
index 40007cd7..960a1249 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java
@@ -19,7 +19,7 @@
import dev.skidfuscator.obfuscator.hierarchy.Hierarchy;
import dev.skidfuscator.obfuscator.hierarchy.SkidHierarchy;
import dev.skidfuscator.obfuscator.order.OrderAnalysis;
-import dev.skidfuscator.obfuscator.phantom.PhantomJarDownloader;
+import dev.skidfuscator.obfuscator.phantom.jphantom.PhantomJarDownloader;
import dev.skidfuscator.obfuscator.predicate.PredicateAnalysis;
import dev.skidfuscator.obfuscator.predicate.SimplePredicateAnalysis;
import dev.skidfuscator.obfuscator.predicate.factory.PredicateFactory;
@@ -38,7 +38,6 @@
import dev.skidfuscator.obfuscator.transform.impl.SwitchTransformer;
import dev.skidfuscator.obfuscator.transform.impl.flow.BasicConditionTransformer;
import dev.skidfuscator.obfuscator.transform.impl.flow.BasicExceptionTransformer;
-import dev.skidfuscator.obfuscator.transform.impl.flow.FlatteningFlowTransformer;
import dev.skidfuscator.obfuscator.transform.impl.misc.AhegaoTransformer;
import dev.skidfuscator.obfuscator.transform.impl.number.NumberTransformer;
import dev.skidfuscator.obfuscator.transform.impl.string.StringTransformer;
@@ -61,15 +60,17 @@
import org.mapleir.deob.PassGroup;
import org.mapleir.deob.dataflow.LiveDataFlowAnalysisImpl;
import org.mapleir.ir.cfg.ControlFlowGraph;
-import org.objectweb.asm.Opcodes;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteio.in.AbstractJarDownloader;
import org.topdank.byteio.in.SingleJarDownloader;
+import org.topdank.byteio.in.SingleJmodDownloader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
+import java.util.stream.Collectors;
@Getter
public class Skidfuscator {
@@ -98,7 +99,7 @@ public Skidfuscator(SkidfuscatorSession session) {
public void run() {
LOGGER.post("Beginning Skidfuscator Enterprise...");
SkiddedDirectory.init(null);
- this.irFactory = new SkidCache();
+ this.irFactory = new SkidCache(this);
this.exemptAnalysis = new SimpleExemptAnalysis();
LOGGER.post("Resolving predicate analysis...");
@@ -184,7 +185,7 @@ public ClassOpaquePredicate build(SkidClassNode skidClassNode) {
/* Create a new library class source with superior to default priority */
final ApplicationClassSource libraryClassSource = new ApplicationClassSource(
"libraries",
- jar.getJarContents().getClassContents()
+ jar.getJarContents().getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList())
);
LOGGER.post("Imported " + jar.getJarContents().getClassContents().size() + " library classes...");
@@ -213,7 +214,7 @@ public ClassOpaquePredicate build(SkidClassNode skidClassNode) {
this.classSource.addLibraries(new LibraryClassSource(
new ApplicationClassSource(
"phantom",
- downloader.getPhantomContents().getClassContents()
+ downloader.getPhantomContents().getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList())
),
-1
));
@@ -221,28 +222,44 @@ public ClassOpaquePredicate build(SkidClassNode skidClassNode) {
/* Import JVM */
LOGGER.post("Beginning importing of the JVM...");
- final SingleJarDownloader libs = MapleJarUtil.importJar(
- session.getRuntime()
- );
- this.classSource.addLibraries((jvmClassSource = new LibraryClassSource(
- new ApplicationClassSource(
- "runtime",
- libs.getJarContents().getClassContents()
- ),
- 0
- )));
- LOGGER.log("Finished importing the JVM!");
-
- if (session.getLibs() != null) {
- final ClassNode classNode = classSource.findClassNode("org/json/simple/parser/ParseException");
- if (classNode == null) {
- System.err.println("HAHAHHAHAHAH");
- for (ClassNode vertex : classSource.iterateWithLibraries()) {
- if (classSource.isLibraryClass(vertex.getName()) && vertex.getName().contains("org") && !vertex.getName().contains("sun"))
- System.out.println(vertex.getDisplayName());
- }
+ if (!session.isJmod()) {
+ final SingleJarDownloader libs = MapleJarUtil.importJar(
+ session.getRuntime()
+ );
+ this.classSource.addLibraries((jvmClassSource = new LibraryClassSource(
+ new ApplicationClassSource(
+ "runtime",
+ libs.getJarContents()
+ .getClassContents()
+ .stream()
+ .map(JarClassData::getClassNode)
+ .collect(Collectors.toList())
+ ),
+ 0
+ )));
+ } else {
+ for (File file : session.getRuntime().listFiles()) {
+ if (!file.getAbsolutePath().endsWith(".jmod"))
+ continue;
+ LOGGER.post("↳ Trying to download " + file.toString());
+ final SingleJmodDownloader libs = MapleJarUtil.importJmod(
+ file
+ );
+ this.classSource.addLibraries((jvmClassSource = new LibraryClassSource(
+ new ApplicationClassSource(
+ file.getName(),
+ libs.getJarContents().getClassContents()
+ .stream()
+ .map(JarClassData::getClassNode)
+ .collect(Collectors.toList())
+ ),
+ 0
+ )));
+ LOGGER.post("✓ Success");
}
+
}
+ LOGGER.log("Finished importing the JVM!");
/* Resolve context */
LOGGER.post("Resolving basic context...");
@@ -274,7 +291,7 @@ public ClassOpaquePredicate build(SkidClassNode skidClassNode) {
*/
for (Listener o : Arrays.asList(
new StringTransformer(this),
- new NegationTransformer(this),
+ //new NegationTransformer(this),
//new FlatteningFlowTransformer(this),
new NumberTransformer(this),
new SwitchTransformer(this),
@@ -300,25 +317,17 @@ public ClassOpaquePredicate build(SkidClassNode skidClassNode) {
try(ProgressBar progressBar = ProgressUtil.progress(cxt.getIRCache().size())) {
for(Map.Entry e : new HashSet<>(cxt.getIRCache().entrySet())) {
MethodNode mn = e.getKey();
-
- if (exemptAnalysis.isExempt(mn.owner)) {
- progressBar.step();
- continue;
- }
-
- if (exemptAnalysis.isExempt(mn)) {
- progressBar.step();
- continue;
- }
-
ControlFlowGraph cfg = e.getValue();
try {
cfg.verify();
+ (new SkidFlowGraphDumper(this, cfg, mn)).dump();
} catch (Exception ex){
+ if (ex instanceof IllegalStateException) {
+ throw ex;
+ }
ex.printStackTrace();
}
- (new SkidFlowGraphDumper(this, cfg, mn)).dump();
progressBar.step();
}
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java
index a19966e1..bf6c355f 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java
@@ -49,6 +49,7 @@ public static void main(String[] args) {
null,
null,
new File(System.getProperty("java.home"), "lib/rt.jar"),
+ false,
false
);
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorSession.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorSession.java
index 43a9514e..9c344b69 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorSession.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorSession.java
@@ -14,4 +14,5 @@ public class SkidfuscatorSession {
private File exempt;
private File runtime;
private boolean phantom;
+ private boolean jmod;
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/command/ObfuscateCommand.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/command/ObfuscateCommand.java
index 5731f4b2..6715403b 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/command/ObfuscateCommand.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/command/ObfuscateCommand.java
@@ -58,6 +58,12 @@ public class ObfuscateCommand implements Callable {
)
private boolean phantom;
+ @CommandLine.Option(
+ names = {"-jm", "--jmod"},
+ description = "Declare if jmod computation should be used"
+ )
+ private boolean jmod;
+
@Override
public Integer call() {
final String[] logo = new String[] {
@@ -99,6 +105,7 @@ public Integer call() {
.runtime(runtime)
.exempt(exempt)
.phantom(phantom)
+ .jmod(jmod)
.build();
final Skidfuscator skidfuscator = new Skidfuscator(skidInstance);
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidApplicationClassSource.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidApplicationClassSource.java
index df6a87b5..8a65f59e 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidApplicationClassSource.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidApplicationClassSource.java
@@ -2,19 +2,21 @@
import org.mapleir.app.service.ApplicationClassSource;
import org.mapleir.asm.ClassNode;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.LocateableJarContents;
import java.util.Collection;
import java.util.Map;
+import java.util.stream.Collectors;
public class SkidApplicationClassSource extends ApplicationClassSource {
//private final LocateableJarContents nodes;
- public SkidApplicationClassSource(String name, LocateableJarContents nodes) {
- super(name, nodes.getClassContents());
+ public SkidApplicationClassSource(String name, LocateableJarContents nodes) {
+ super(name, nodes.getClassContents().stream().map(JarClassData::getClassNode).collect(Collectors.toList()));
}
- public SkidApplicationClassSource(String name, Map nodeMap, LocateableJarContents nodes) {
+ public SkidApplicationClassSource(String name, Map nodeMap, LocateableJarContents nodes) {
super(name, nodeMap);
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidCache.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidCache.java
index 9b2a477f..03c8a4bc 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidCache.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidCache.java
@@ -1,9 +1,10 @@
package dev.skidfuscator.obfuscator.creator;
+import dev.skidfuscator.obfuscator.Skidfuscator;
import org.mapleir.context.IRCache;
public class SkidCache extends IRCache {
- public SkidCache() {
- super(SkidFlowGraphBuilder::build);
+ public SkidCache(final Skidfuscator skidfuscator) {
+ super(e -> SkidFlowGraphBuilder.build(skidfuscator, e));
}
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphBuilder.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphBuilder.java
index e7e0abb8..e777151a 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphBuilder.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphBuilder.java
@@ -1,12 +1,13 @@
package dev.skidfuscator.obfuscator.creator;
+import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.skidasm.cfg.SkidBlockFactory;
import org.mapleir.asm.MethodNode;
import org.mapleir.ir.algorithms.BoissinotDestructor;
import org.mapleir.ir.algorithms.LocalsReallocator;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.cfg.SSAFactory;
-import org.mapleir.ir.cfg.builder.ControlFlowGraphBuilder;
+import org.mapleir.ir.cfg.builder.*;
public class SkidFlowGraphBuilder extends ControlFlowGraphBuilder {
@@ -22,8 +23,18 @@ public SkidFlowGraphBuilder(MethodNode method, SSAFactory SSAFactory, boolean op
super(method, SSAFactory, optimise);
}
- public static ControlFlowGraph build(MethodNode method) {
- ControlFlowGraphBuilder builder = new SkidFlowGraphBuilder(method, SkidBlockFactory.INSTANCE);
+ @Override
+ protected BuilderPass[] resolvePasses() {
+ return new BuilderPass[] {
+ new GenerationPass(this),
+ new DeadBlocksPass(this),
+ //new NaturalisationPass(this),
+ new SSAGenPass(this, false),
+ };
+ }
+
+ public static ControlFlowGraph build(final Skidfuscator skidfuscator, final MethodNode method) {
+ ControlFlowGraphBuilder builder = new SkidFlowGraphBuilder(method, SkidBlockFactory.v(skidfuscator));
final ControlFlowGraph cfg = builder.buildImpl();
BoissinotDestructor.leaveSSA(cfg);
LocalsReallocator.realloc(cfg);
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphDumper.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphDumper.java
index 5d537e61..cb8d707c 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphDumper.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/creator/SkidFlowGraphDumper.java
@@ -13,6 +13,7 @@
import org.mapleir.ir.cfg.BasicBlock;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.code.Stmt;
+import org.mapleir.ir.code.stmt.NopStmt;
import org.mapleir.ir.code.stmt.UnconditionalJumpStmt;
import org.mapleir.ir.codegen.BytecodeFrontend;
import org.mapleir.stdlib.collections.graph.*;
@@ -55,6 +56,9 @@ public void dump() {
labels.put(b, new LabelNode());
}
+ // Fix ranges
+ fixRanges();
+
// Linearize
linearize();
@@ -84,7 +88,19 @@ public void dump() {
m.node.visitEnd();
}
-
+
+ private void fixRanges() {
+ /*
+ * Short term fix to prevent TryCatchNode-s from being optimized
+ * out, leaving an open range
+ */
+ for (ExceptionRange range : cfg.getRanges()) {
+ range.getNodes().stream().filter(BasicBlock::isEmpty).forEach(e -> {
+ e.add(new NopStmt());
+ });
+ }
+ }
+
private void linearize() {
if (cfg.getEntries().size() != 1)
throw new IllegalStateException("CFG doesn't have exactly 1 entry");
@@ -274,7 +290,7 @@ private void dumpRange(ExceptionRange er) {
.findClassNode(type1);
if (classNode == null) {
- System.err.println("Failed to find class of type " + type1 + "!" );
+ System.err.println("\r\nFailed to find class of type " + type1 + "!\n" );
try {
final ClassReader reader = new ClassReader(type1);
final org.objectweb.asm.tree.ClassNode node = new org.objectweb.asm.tree.ClassNode();
@@ -408,10 +424,12 @@ private void dumpRange(ExceptionRange er) {
for (;;) {
// check for endpoints
if (orderIdx + 1 == order.size()) { // end of method
+ assert start != terminalLabel.getLabel() : "Label assigned is semantically identical.";
m.node.visitTryCatchBlock(start, terminalLabel.getLabel(), handler, type.getInternalName());
break;
} else if (rangeIdx + 1 == range.size()) { // end of range
Label end = getLabel(order.get(orderIdx + 1));
+ assert start != end : "Label assigned is semantically identical.";
m.node.visitTryCatchBlock(start, end, handler, type.getInternalName());
break;
}
@@ -420,8 +438,9 @@ private void dumpRange(ExceptionRange er) {
BasicBlock nextBlock = range.get(rangeIdx + 1);
int nextOrderIdx = order.indexOf(nextBlock);
if (nextOrderIdx - orderIdx > 1) { // blocks in-between, end the handler and begin anew
- System.err.println("[warn] Had to split up a range: " + m);
+ System.err.println("\r\n[warn] Had to split up a range: " + m + "\n");
Label end = getLabel(order.get(orderIdx + 1));
+ assert start != end : "Label assigned is semantically identical.";
m.node.visitTryCatchBlock(start, end, handler, type.getInternalName());
start = getLabel(nextBlock);
}
@@ -452,6 +471,10 @@ private void verifyRanges() {
handler = i;
}
}
+
+ if (start == end) {
+ throw new IllegalStateException("Try block ends on starting position in " + m);
+ }
if (start == -1 || end == -1 || handler == -1)
throw new IllegalStateException("Try/catch endpoints missing: " + start + " " + end + " " + handler + m);
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/ExclusionHelper.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/ExclusionHelper.java
index 4d104521..6a48d630 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/ExclusionHelper.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/ExclusionHelper.java
@@ -67,7 +67,6 @@ public Exclusion renderExclusion(final String pattern) {
switch (type) {
case CLASS: {
final Pattern regex = Pattern.compile(parsed);
- System.out.println("Found pattern for clazz: [" + regex + "]");
map.put(type, new ExclusionTester() {
@Override
public boolean test(ClassNode var) {
@@ -83,8 +82,6 @@ public boolean test(ClassNode var) {
System.out.println("Oh?");
}
- System.out.println("Testing if match: " + var.getName());
-
return initialMatch
&& regex.matcher(var.getName()).find();
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/SimpleExemptAnalysis.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/SimpleExemptAnalysis.java
index 0ee6bbd6..13f5ee4b 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/SimpleExemptAnalysis.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/exempt/SimpleExemptAnalysis.java
@@ -23,7 +23,7 @@ public void add(final String exclusionStr) {
final Exclusion exclusion = ExclusionHelper.renderExclusion(exclusionStr);
exclusions.add(exclusion);
- System.out.println(this);
+ //System.out.println(this);
}
@Override
@@ -57,11 +57,11 @@ public boolean isExempt(ClassNode classNode) {
return var;
for (Exclusion exclusion : exclusions) {
- System.out.println("Testing " + exclusion);
+ //System.out.println("Testing " + exclusion);
try {
if (exclusion.test(classNode)) {
classCache.put(classNode, true);
- System.out.println("EXCLUDED --> " + classNode.getName());
+ //System.out.println("EXCLUDED --> " + classNode.getName());
return true;
}
} catch (AssertionError e) {
@@ -69,7 +69,7 @@ public boolean isExempt(ClassNode classNode) {
e.printStackTrace();
}
}
- System.out.println("INCLUDED --> " + classNode.getName());
+ //System.out.println("INCLUDED --> " + classNode.getName());
classCache.put(classNode, false);
return false;
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/hierarchy/SkidHierarchy.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/hierarchy/SkidHierarchy.java
index 9c7a3c28..7e216e17 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/hierarchy/SkidHierarchy.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/hierarchy/SkidHierarchy.java
@@ -9,6 +9,10 @@
import org.mapleir.asm.MethodNode;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.code.expr.invoke.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.JSRInlinerAdapter;
import org.objectweb.asm.tree.AnnotationNode;
import java.util.*;
@@ -131,7 +135,9 @@ public void cache() {
this.annotations = new HashMap<>();
try (ProgressBar progressBar = ProgressUtil.progress(skidfuscator.getClassSource().size())){
- nodes = skidfuscator.getClassSource().getClassTree().vertices().parallelStream()
+ nodes = skidfuscator.getClassSource().getClassTree()
+ .vertices()
+ .parallelStream()
.filter(e -> {
progressBar.step();
return skidfuscator.getClassSource().isApplicationClass(e.getName());
@@ -167,13 +173,14 @@ private void setupInvoke() {
try (ProgressBar invocationBar = ProgressUtil.progress(nodes.size())) {
nodes.forEach(c -> {
for (MethodNode method : c.getMethods()) {
- final ControlFlowGraph cfg = skidfuscator.getCxt().getIRCache().get(method);
+ final ControlFlowGraph cfg = skidfuscator.getCxt().getIRCache().getFor(method);
- if (cfg == null)
+ if (cfg == null) {
+ System.err.println("Failed to compute CFG for method " + method.toString());
continue;
+ }
cfg.allExprStream()
- .parallel()
.filter(e -> e instanceof Invokable && !(e instanceof DynamicInvocationExpr))
.map(e -> (Invocation) e)
.forEach(invocation -> {
@@ -227,9 +234,15 @@ private SkidGroup getGroup(final Skidfuscator session, final MethodNode methodNo
SkidGroup group = methodToGroupMap.get(methodNode);
if (group == null) {
- final Set h = session.getCxt()
+ final Set h = session
+ .getCxt()
.getInvocationResolver()
- .getHierarchyMethodChain(methodNode.owner, methodNode.getName(), methodNode.getDesc(), true);
+ .getHierarchyMethodChain(
+ methodNode.owner,
+ methodNode.getName(),
+ methodNode.getDesc(),
+ true
+ );
h.add(methodNode);
final List methods = new ArrayList<>(h);
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomManager.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomManager.java
deleted file mode 100644
index 3b009312..00000000
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomManager.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package dev.skidfuscator.obfuscator.phantom;
-
-public class PhantomManager {
-
-}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/Ghost.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/Ghost.java
new file mode 100644
index 00000000..a22df7b9
--- /dev/null
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/Ghost.java
@@ -0,0 +1,16 @@
+package dev.skidfuscator.obfuscator.phantom.jghost;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class Ghost {
+ private static final Gson GSON = new GsonBuilder()
+ .setPrettyPrinting()
+ .serializeNulls()
+ .disableHtmlEscaping()
+ .create();
+
+ public static Gson gson() {
+ return GSON;
+ }
+}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/GhostReader.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/GhostReader.java
new file mode 100644
index 00000000..4eb89aee
--- /dev/null
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/GhostReader.java
@@ -0,0 +1,5 @@
+package dev.skidfuscator.obfuscator.phantom.jghost;
+
+public class GhostReader {
+
+}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostClassNode.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostClassNode.java
new file mode 100644
index 00000000..261f6b69
--- /dev/null
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostClassNode.java
@@ -0,0 +1,7 @@
+package dev.skidfuscator.obfuscator.phantom.jghost.tree;
+
+import org.mapleir.asm.ClassNode;
+
+public class GhostClassNode extends ClassNode {
+
+}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostMethodNode.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostMethodNode.java
new file mode 100644
index 00000000..7ed7409e
--- /dev/null
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jghost/tree/GhostMethodNode.java
@@ -0,0 +1,10 @@
+package dev.skidfuscator.obfuscator.phantom.jghost.tree;
+
+import org.mapleir.asm.ClassNode;
+import org.mapleir.asm.MethodNode;
+
+public class GhostMethodNode extends MethodNode {
+ public GhostMethodNode(org.objectweb.asm.tree.MethodNode node, ClassNode owner) {
+ super(node, owner);
+ }
+}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomJarDownloader.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomJarDownloader.java
similarity index 91%
rename from obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomJarDownloader.java
rename to obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomJarDownloader.java
index 720b9995..46e0bb12 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomJarDownloader.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomJarDownloader.java
@@ -1,4 +1,4 @@
-package dev.skidfuscator.obfuscator.phantom;
+package dev.skidfuscator.obfuscator.phantom.jphantom;
import ch.qos.logback.classic.Level;
import com.google.common.io.ByteStreams;
@@ -26,10 +26,7 @@
import org.mapleir.asm.ClassNode;
import org.objectweb.asm.*;
import org.topdank.byteengineer.commons.asm.ASMFactory;
-import org.topdank.byteengineer.commons.data.JarContents;
-import org.topdank.byteengineer.commons.data.JarInfo;
-import org.topdank.byteengineer.commons.data.JarResource;
-import org.topdank.byteengineer.commons.data.LocateableJarContents;
+import org.topdank.byteengineer.commons.data.*;
import org.topdank.byteio.in.AbstractJarDownloader;
import java.io.File;
@@ -45,21 +42,21 @@
public class PhantomJarDownloader extends AbstractJarDownloader {
private final Skidfuscator skidfuscator;
protected final JarInfo jarInfo;
- protected LocateableJarContents phantomContents;
+ protected LocateableJarContents phantomContents;
private final Logger logger = LogManager.getLogger(this.getClass());
public PhantomJarDownloader(Skidfuscator skidfuscator, JarInfo jarInfo) {
super();
this.skidfuscator = skidfuscator;
this.jarInfo = jarInfo;
- this.phantomContents = new LocateableJarContents<>();
+ this.phantomContents = new LocateableJarContents();
}
public PhantomJarDownloader(Skidfuscator skidfuscator, ASMFactory factory, JarInfo jarInfo) {
super(factory);
this.skidfuscator = skidfuscator;
this.jarInfo = jarInfo;
- this.phantomContents = new LocateableJarContents<>();
+ this.phantomContents = new LocateableJarContents();
}
@SneakyThrows
@@ -69,7 +66,7 @@ public void download() throws IOException {
JarURLConnection connection = (JarURLConnection) (url = new URL(jarInfo.formattedURL())).openConnection();
JarFile jarFile = connection.getJarFile();
Enumeration entries = jarFile.entries();
- contents = new LocateableJarContents<>(url);
+ contents = new LocateableJarContents(url);
/*
* Map holding all the regular data
@@ -85,12 +82,7 @@ public void download() throws IOException {
byte[] bytes = read(jarFile.getInputStream(entry));
if (entry.getName().endsWith(".class")) {
data.put(entry.getName(), bytes);
-
- System.out.println("[+] " + entry.getName());
- contents.getClassData().add(new JarResource(
- entry.getName(),
- bytes
- ));
+ //System.out.println("[+] " + entry.getName());
} else {
JarResource resource = new JarResource(entry.getName(), bytes);
contents.getResourceContents().add(resource);
@@ -110,7 +102,11 @@ public void download() throws IOException {
try {
cn = factory.create(db, name);
if(!data.containsKey(cn.getName())) {
- contents.getClassContents().add(cn);
+ contents.getClassContents().add(new JarClassData(
+ name,
+ db,
+ cn
+ ));
} else {
throw new IllegalStateException("duplicate: " + cn.getName());
}
@@ -199,11 +195,12 @@ public void download() throws IOException {
* class cache. This will be used as a library during obfuscation.
*/
logger.info("[$] Outputting phantom classes...");
- final Map namedMap = contents.getClassContents().namedMap();
+ final Map namedMap = contents.getClassContents().namedMap();
try (ProgressBar progressBar = ProgressUtil.progress(phantom.getGenerated().size())){
phantom.getGenerated().forEach((k, v) -> {
- final ClassReader reader = new ClassReader(decorate(v));
+ final byte[] bytes = decorate(v);
+ final ClassReader reader = new ClassReader(bytes);
final org.objectweb.asm.tree.ClassNode node = new org.objectweb.asm.tree.ClassNode();
reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
@@ -213,7 +210,11 @@ public void download() throws IOException {
if (namedMap.containsKey(classNode.getName()))
return;
- phantomContents.getClassContents().add((C) classNode);
+ phantomContents.getClassContents().add(new JarClassData(
+ classNode.getName() + ".class",
+ v,
+ classNode
+ ));
progressBar.step();
});
}
@@ -233,7 +234,7 @@ public void download() throws IOException {
java.nio.file.Files.deleteIfExists(input.toPath());
}
- public LocateableJarContents getPhantomContents() {
+ public LocateableJarContents getPhantomContents() {
return phantomContents;
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomManager.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomManager.java
new file mode 100644
index 00000000..efff1ace
--- /dev/null
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomManager.java
@@ -0,0 +1,5 @@
+package dev.skidfuscator.obfuscator.phantom.jphantom;
+
+public class PhantomManager {
+
+}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomResolvingJarDumper.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomResolvingJarDumper.java
similarity index 75%
rename from obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomResolvingJarDumper.java
rename to obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomResolvingJarDumper.java
index 304d46ba..78ce82bb 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/PhantomResolvingJarDumper.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/phantom/jphantom/PhantomResolvingJarDumper.java
@@ -1,8 +1,10 @@
-package dev.skidfuscator.obfuscator.phantom;
+package dev.skidfuscator.obfuscator.phantom.jphantom;
import com.google.common.collect.Lists;
import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.skidasm.SkidClassNode;
+import dev.skidfuscator.obfuscator.util.ProgressUtil;
+import me.tongfei.progressbar.ProgressBar;
import org.mapleir.app.service.ApplicationClassSource;
import org.mapleir.app.service.ClassTree;
import org.mapleir.asm.ClassHelper;
@@ -10,6 +12,7 @@
import org.mapleir.asm.MethodNode;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarContents;
import org.topdank.byteengineer.commons.data.JarResource;
import org.topdank.byteio.out.JarDumper;
@@ -22,6 +25,8 @@
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
+import java.util.zip.ZipError;
+import java.util.zip.ZipException;
/**
* Dumps ClassNodes and JarResources back into a file on the local system.
@@ -32,14 +37,14 @@
public class PhantomResolvingJarDumper implements JarDumper {
private final Skidfuscator skidfuscator;
- private final JarContents> contents;
+ private final JarContents contents;
private final ApplicationClassSource source;
/**
* Creates a new JarDumper.
*
* @param contents Contents of jar.
*/
- public PhantomResolvingJarDumper(Skidfuscator skidfuscator, JarContents> contents, ApplicationClassSource source) {
+ public PhantomResolvingJarDumper(Skidfuscator skidfuscator, JarContents contents, ApplicationClassSource source) {
this.skidfuscator = skidfuscator;
this.contents = contents;
this.source = source;
@@ -58,12 +63,25 @@ public void dump(File file) throws IOException {
JarOutputStream jos = new JarOutputStream(new FileOutputStream(file));
int classesDumped = 0;
int resourcesDumped = 0;
- for (ClassNode cn : contents.getClassContents()) {
- classesDumped += dumpClass(jos, cn.getName(), cn);
- }
- for (JarResource res : contents.getResourceContents()) {
- resourcesDumped += dumpResource(jos, res.getName(), res.getData());
+
+ try (ProgressBar progressBar = ProgressUtil.progress(contents.getClassContents().size() + contents.getResourceContents().size())) {
+ for (JarClassData cn : contents.getClassContents()) {
+ try {
+ classesDumped += dumpClass(jos, cn);
+ } catch (ZipException e) {
+ System.out.println("\r[!] Failed to dump " + cn.getName() + "!\n");
+ throw e;
+ }
+
+ progressBar.step();
+ }
+
+ for (JarResource res : contents.getResourceContents()) {
+ resourcesDumped += dumpResource(jos, res.getName(), res.getData());
+ progressBar.step();
+ }
}
+
if(!Debug.debugging)
System.out.println("Dumped " + classesDumped + " classes and " + resourcesDumped + " resources to " + file.getAbsolutePath());
@@ -74,14 +92,14 @@ public void dump(File file) throws IOException {
* Writes the {@link ClassNode} to the Jar.
*
* @param out The {@link JarOutputStream}.
- * @param cn The ClassNode.
- * @param name The entry name.
+ * @param classData The {@link JarClassData}
* @throws IOException If there is a write error.
* @return The amount of things dumped, 1 or if you're not dumping it 0.
*/
@Override
- public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOException {
- JarEntry entry = new JarEntry(cn.getName() + ".class");
+ public int dumpClass(JarOutputStream out, JarClassData classData) throws IOException {
+ ClassNode cn = classData.getClassNode();
+ JarEntry entry = new JarEntry(cn.getName());
out.putNextEntry(entry);
if (skidfuscator.getExemptAnalysis().isExempt(cn)) {
@@ -89,9 +107,9 @@ public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOEx
skidfuscator
.getJarDownloader()
.getJarContents()
- .getClassData()
+ .getClassContents()
.namedMap()
- .get(cn.getName() + ".class")
+ .get(classData.getName())
.getData()
);
return 1;
@@ -114,8 +132,8 @@ public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOEx
ClassWriter writer = this.buildClassWriter(tree, ClassWriter.COMPUTE_MAXS);
cn.node.accept(writer); // must use custom writer which overrides getCommonSuperclass
out.write(writer.toByteArray());
- System.err.println("Failed to write " + cn.getName() + "! Writing with COMPUTE_MAXS, " +
- "which may cause runtime abnormalities");
+ System.err.println("\rFailed to write " + cn.getName() + "! Writing with COMPUTE_MAXS, " +
+ "which may cause runtime abnormalities\n");
}
} catch (Exception e) {
System.err.println("Failed to write " + cn.getName() + "! Skipping class...");
@@ -144,44 +162,37 @@ protected String getCommonSuperClass(String type1, String type2) {
boolean debug = false;
if(ccn == null) {
-// return "java/lang/Object";
ClassNode c;
try {
final ClassReader reader = new ClassReader(type1);
final org.objectweb.asm.tree.ClassNode node = new org.objectweb.asm.tree.ClassNode();
- reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE);
c = new SkidClassNode(node, skidfuscator);
skidfuscator.getClassSource().getClassTree().addVertex(c);
} catch (IOException e) {
- e.printStackTrace();
- return "java/lang/Object";
- }
- if(c == null) {
+ System.err.println("[FATAL] Failed to find common superclass due to failed " + type1);
return "java/lang/Object";
}
ccn = c;
- debug = true;
- //throw new UnsupportedOperationException(c.toString());
- // classTree.build(c);
- // return getCommonSuperClass(type1, type2);
}
if(dcn == null) {
-
-// return "java/lang/Object";
ClassNode c;
try {
- c = ClassHelper.create(type2);
+ final ClassReader reader = new ClassReader(type1);
+ final org.objectweb.asm.tree.ClassNode node = new org.objectweb.asm.tree.ClassNode();
+ reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE);
+
+ c = new SkidClassNode(node, skidfuscator);
+ skidfuscator.getClassSource().getClassTree().addVertex(c);
} catch (IOException e) {
- e.printStackTrace();
- return "java/lang/Object";
- }
- if(c == null) {
+ System.err.println("[FATAL] Failed to find common superclass due to failed " + type1);
return "java/lang/Object";
}
- throw new UnsupportedOperationException(c.toString());
+
+ dcn = c;
// classTree.build(c);
// return getCommonSuperClass(type1, type2);
}
@@ -200,13 +211,14 @@ protected String getCommonSuperClass(String type1, String type2) {
}
if (true)
- return skidfuscator.getClassSource().getClassTree()
+ return skidfuscator
+ .getClassSource()
+ .getClassTree()
.getCommonAncestor(Arrays.asList(ccn, dcn))
.iterator()
.next()
.getName();
-
{
throw new IllegalStateException("Could not find common class type between " + Arrays.toString(new Object[]{ccn.getDisplayName(), dcn.getDisplayName()}));
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/predicate/renderer/impl/IntegerBlockPredicateRenderer.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/predicate/renderer/impl/IntegerBlockPredicateRenderer.java
index 1f3cf991..c322f0d1 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/predicate/renderer/impl/IntegerBlockPredicateRenderer.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/predicate/renderer/impl/IntegerBlockPredicateRenderer.java
@@ -68,7 +68,7 @@ void handle(final InitMethodTransformEvent event) {
final Local local = methodNode
.getCfg()
.getLocals()
- .get(methodNode.getCfg().getLocals().getMaxLocals() + 2);
+ .get(methodNode.getCfg().getLocals().getMaxLocals() + 3);
flowPredicate.setGetter(new PredicateFlowGetter() {
@Override
@@ -248,7 +248,6 @@ public Stmt apply(Expr expr) {
);
}
});
-
};
/*
@@ -356,14 +355,13 @@ void handle(final InitGroupTransformEvent event) {
return;
}
- final boolean entryPoint = skidGroup.getInvokers().isEmpty()
- || skidGroup.isAnnotation();
+ final boolean entryPoint = skidGroup.isEntryPoint();
Local local = null;
int stackHeight = -1;
String desc = null;
if (entryPoint) {
- System.err.println("SkidGroup " + skidGroup.getName() + "#" + skidGroup.getDesc() + " is an entry point!");
+ //System.err.println("SkidGroup " + skidGroup.getName() + "#" + skidGroup.getDesc() + " is an entry point!");
}
if (!entryPoint) {
@@ -427,8 +425,6 @@ void handle(final InitGroupTransformEvent event) {
invoker.getExpr().setArgumentExprs(args);
invoker.getExpr().setDesc(desc);
-
- //System.out.println("Fixed invoker " + invoker.toString());
}
}
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidGroup.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidGroup.java
index b909e74f..381ea389 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidGroup.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidGroup.java
@@ -22,16 +22,24 @@ public class SkidGroup {
private String desc;
private int stackHeight;
+ private transient boolean application;
// TODO: Add parameter and parameter compilation
public SkidGroup(List methodNodeList, Skidfuscator skidfuscator) {
this.methodNodeList = methodNodeList;
this.skidfuscator = skidfuscator;
+ this.invokers = new ArrayList<>();
this.predicate = skidfuscator
.getPredicateAnalysis()
.getMethodPredicate(this);
- this.invokers = new ArrayList<>();
+
+ this.application = methodNodeList
+ .stream()
+ .allMatch(e -> skidfuscator.getClassSource().isApplicationClass(e.owner.getName())
+ && !skidfuscator.getExemptAnalysis().isExempt(e)
+ && !skidfuscator.getExemptAnalysis().isExempt(e.owner)
+ );
}
public void setStatical(boolean statical) {
@@ -45,7 +53,7 @@ public MethodNode first() {
}
public boolean isEntryPoint() {
- return this.getInvokers().isEmpty() || this.isAnnotation();
+ return !application || this.getInvokers().isEmpty() || this.isAnnotation();
}
@Override
public boolean equals(Object o) {
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidMethodNode.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidMethodNode.java
index 5c3ae59f..b5ba51f1 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidMethodNode.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidMethodNode.java
@@ -28,10 +28,10 @@ public class SkidMethodNode extends MethodNode {
public SkidMethodNode(org.objectweb.asm.tree.MethodNode node, ClassNode owner, Skidfuscator skidfuscator) {
super(node, owner);
this.skidfuscator = skidfuscator;
+ this.invokers = new ArrayList<>();
this.flowPredicate = skidfuscator
.getPredicateAnalysis()
.getBlockPredicate(this);
- this.invokers = new ArrayList<>();
}
public int getBlockPredicate(final SkidBlock block) {
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/cfg/SkidBlockFactory.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/cfg/SkidBlockFactory.java
index 5871386a..31658040 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/cfg/SkidBlockFactory.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/cfg/SkidBlockFactory.java
@@ -1,22 +1,110 @@
package dev.skidfuscator.obfuscator.skidasm.cfg;
+import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.skidasm.expr.SkidConstantExpr;
import dev.skidfuscator.obfuscator.skidasm.stmt.SkidSwitchStmt;
+import org.mapleir.asm.ClassNode;
import org.mapleir.ir.cfg.BasicBlock;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.cfg.DefaultBlockFactory;
import org.mapleir.ir.cfg.builder.ssa.BlockBuilder;
import org.mapleir.ir.cfg.builder.ssa.expr.ConstantExprBuilder;
+import org.mapleir.ir.cfg.builder.ssa.expr.invoke.StaticInvocationExprBuilder;
import org.mapleir.ir.cfg.builder.ssa.stmt.SwitchStmtBuilder;
import org.mapleir.ir.code.Expr;
import org.mapleir.ir.code.expr.ConstantExpr;
+import org.mapleir.ir.code.expr.invoke.InvocationExpr;
+import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
import org.mapleir.ir.code.stmt.SwitchStmt;
import org.objectweb.asm.Type;
import java.util.LinkedHashMap;
public class SkidBlockFactory extends DefaultBlockFactory {
- public static final SkidBlockFactory INSTANCE = new SkidBlockFactory();
+ public static SkidBlockFactory INSTANCE = null;
+
+ public static SkidBlockFactory v(final Skidfuscator skidfuscator) {
+ if (INSTANCE == null) {
+ INSTANCE = new SkidBlockFactory(skidfuscator);
+ }
+ return INSTANCE;
+ }
+
+ private final Skidfuscator skidfuscator;
+
+ public SkidBlockFactory(Skidfuscator skidfuscator) {
+ this.skidfuscator = skidfuscator;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder static_invoke_expr() {
+ return new StaticInvocationExprBuilder() {
+ private InvocationExpr.CallType callType = InvocationExpr.CallType.STATIC;
+ private Expr[] args;
+ private String owner;
+ private String name;
+ private String desc;
+
+ @Override
+ public StaticInvocationExprBuilder callType(InvocationExpr.CallType callType) {
+ this.callType = callType;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder args(Expr[] args) {
+ this.args = args;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder owner(String owner) {
+ this.owner = owner;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExprBuilder desc(String desc) {
+ this.desc = desc;
+ return this;
+ }
+
+ @Override
+ public StaticInvocationExpr build() {
+ assert owner != null : "Owner name cannot be null";
+ assert name != null : "Name cannot be null";
+ assert desc != null : "Description cannot be null";
+
+ final ClassNode classNode = skidfuscator
+ .getClassSource()
+ .findClassNode(owner);
+
+ if (classNode == null) {
+ //System.out.println("Failed to find " + owner + " in reference path...");
+ } else if (classNode.isInterface()){
+ //System.out.println("Class " + owner + " is of version " + classNode.node.version + " (annoying: " + classNode.isAnnoyingVersion() + ")");
+ }
+
+ final boolean isInterface = classNode != null && classNode.isInterface();
+
+ return new StaticInvocationExpr(
+ isInterface
+ ? InvocationExpr.CallType.INTERFACE
+ : InvocationExpr.CallType.STATIC,
+ args,
+ owner,
+ name,
+ desc
+ );
+ }
+ };
+ }
@Override
public SwitchStmtBuilder switch_stmt() {
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ClassUtil.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ClassUtil.java
index 3107fa18..792278ea 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ClassUtil.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ClassUtil.java
@@ -2,6 +2,7 @@
import dev.skidfuscator.obfuscator.util.misc.Pair;
import org.objectweb.asm.*;
+import org.objectweb.asm.commons.JSRInlinerAdapter;
import org.objectweb.asm.tree.*;
import java.io.IOException;
@@ -418,5 +419,4 @@ public static boolean isValidClass(byte[] value) {
return false;
}
}
-
}
\ No newline at end of file
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/MapleJarUtil.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/MapleJarUtil.java
index 7c64e3e6..4e913c8b 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/MapleJarUtil.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/MapleJarUtil.java
@@ -2,21 +2,19 @@
import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.creator.SkidASMFactory;
-import dev.skidfuscator.obfuscator.phantom.PhantomJarDownloader;
-import dev.skidfuscator.obfuscator.phantom.PhantomResolvingJarDumper;
+import dev.skidfuscator.obfuscator.phantom.jphantom.PhantomJarDownloader;
+import dev.skidfuscator.obfuscator.phantom.jphantom.PhantomResolvingJarDumper;
import lombok.SneakyThrows;
-import org.mapleir.app.service.ApplicationClassSource;
import org.mapleir.app.service.ClassTree;
import org.mapleir.asm.ClassNode;
import org.mapleir.asm.MethodNode;
import org.mapleir.deob.PassGroup;
-import org.mapleir.deob.passes.rename.ClassRenamerPass;
import org.objectweb.asm.ClassWriter;
-import org.topdank.byteengineer.commons.asm.DefaultASMFactory;
+import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteengineer.commons.data.JarInfo;
-import org.topdank.byteio.in.AbstractJarDownloader;
import org.topdank.byteio.in.MultiJarDownloader;
import org.topdank.byteio.in.SingleJarDownloader;
+import org.topdank.byteio.in.SingleJmodDownloader;
import java.io.*;
import java.util.jar.JarEntry;
@@ -30,61 +28,25 @@
public class MapleJarUtil {
public static void dumpJar(Skidfuscator skidfuscator, PassGroup masterGroup, String outputFile) throws IOException {
(new PhantomResolvingJarDumper(skidfuscator, skidfuscator.getJarDownloader().getJarContents(), skidfuscator.getClassSource()) {
- @Override
- public int dumpResource(JarOutputStream out, String name, byte[] file) throws IOException {
-// if(name.startsWith("META-INF")) {
-// System.out.println(" ignore " + name);
-// return 0;
-// }
- if(name.equals("META-INF/MANIFEST.MF")) {
- ClassRenamerPass renamer = (ClassRenamerPass) masterGroup.getPass(e -> e.is(ClassRenamerPass.class));
-
- if(renamer != null) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(baos));
- BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(file)));
-
- String line;
- while((line = br.readLine()) != null) {
- String[] parts = line.split(": ", 2);
- if(parts.length != 2) {
- bw.write(line);
- continue;
- }
-
- if(parts[0].equals("Main-Class")) {
- String newMain = renamer.getRemappedName(parts[1].replace(".", "/")).replace("/", ".");
- parts[1] = newMain;
- }
-
- bw.write(parts[0]);
- bw.write(": ");
- bw.write(parts[1]);
- bw.write(System.lineSeparator());
- }
-
- br.close();
- bw.close();
-
- file = baos.toByteArray();
- }
- }
- return super.dumpResource(out, name, file);
- }
- public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOException {
- JarEntry entry = new JarEntry(cn.getName() + ".class");
- out.putNextEntry(entry);
+ @Override
+ public int dumpClass(JarOutputStream out, JarClassData classData) throws IOException {
+ ClassNode cn = classData.getClassNode();
+ JarEntry entry = new JarEntry(classData.getName());
- if (skidfuscator.getExemptAnalysis().isExempt(cn)) {
- out.write(
- skidfuscator
+ if (cn.isAnnoyingVersion()) {
+ final JarClassData resource = skidfuscator
.getJarDownloader()
.getJarContents()
- .getClassData()
- .namedMap().get(cn.getName() + ".class")
- .getData()
- );
+ .getClassContents()
+ .namedMap()
+ .get(classData.getName());
+
+ if (resource == null) {
+ throw new IllegalStateException("Failed to find class source for " + cn.getName());
+ }
+ out.putNextEntry(entry);
+ out.write(resource.getData());
return 1;
}
@@ -92,11 +54,12 @@ public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOEx
for (MethodNode m : cn.getMethods()) {
if (m.node.instructions.size() > 10000) {
- System.out.println("large method: " + m + " @" + m.node.instructions.size());
+ System.out.println("\rlarge method: " + m + " @" + m.node.instructions.size() + "\n");
}
}
try {
+ out.putNextEntry(entry);
try {
ClassWriter writer = this.buildClassWriter(tree, ClassWriter.COMPUTE_FRAMES);
cn.node.accept(writer);
@@ -106,10 +69,10 @@ public int dumpClass(JarOutputStream out, String name, ClassNode cn) throws IOEx
cn.node.accept(writer);
out.write(writer.toByteArray());
var8.printStackTrace();
- System.err.println("Failed to write " + cn.getName() + "! Writing with COMPUTE_MAXS, which may cause runtime abnormalities");
+ System.err.println("\rFailed to write " + cn.getName() + "! Writing with COMPUTE_MAXS, which may cause runtime abnormalities\n");
}
} catch (Exception var9) {
- System.err.println("Failed to write " + cn.getName() + "! Skipping class...");
+ System.err.println("\rFailed to write " + cn.getName() + "! Skipping class...\n");
var9.printStackTrace();
}
@@ -140,6 +103,14 @@ public static SingleJarDownloader importJar(File file) {
return dl;
}
+ @SneakyThrows
+ public static SingleJmodDownloader importJmod(File file) {
+ SingleJmodDownloader dl = new SingleJmodDownloader<>(new JarInfo(file));
+ dl.download();
+
+ return dl;
+ }
+
@SneakyThrows
public static PhantomJarDownloader importPhantomJar(File file, Skidfuscator skidfuscator) {
PhantomJarDownloader dl = new PhantomJarDownloader<>(
diff --git a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ProgressUtil.java b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ProgressUtil.java
index 8c22994c..0e6db044 100644
--- a/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ProgressUtil.java
+++ b/obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/ProgressUtil.java
@@ -11,7 +11,7 @@
@UtilityClass
public class ProgressUtil {
public ProgressBar progress(final int count) {
- return new ProgressBar("",
+ return new ProgressBar("Executing...",
count,
1000,
System.err,
diff --git a/obfuscator/src/test/java/dev/skidfuscator/test/SampleJarTest.java b/obfuscator/src/test/java/dev/skidfuscator/test/SampleJarTest.java
index ce62ab2d..6f5bdc03 100644
--- a/obfuscator/src/test/java/dev/skidfuscator/test/SampleJarTest.java
+++ b/obfuscator/src/test/java/dev/skidfuscator/test/SampleJarTest.java
@@ -2,9 +2,29 @@
import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.SkidfuscatorSession;
+import dev.xdark.ssvm.VirtualMachine;
+import dev.xdark.ssvm.api.VMInterface;
+import dev.xdark.ssvm.asm.Modifier;
+import dev.xdark.ssvm.execution.VMException;
+import dev.xdark.ssvm.fs.FileDescriptorManager;
+import dev.xdark.ssvm.fs.HostFileDescriptorManager;
+import dev.xdark.ssvm.jit.JitClass;
+import dev.xdark.ssvm.jit.JitCompiler;
+import dev.xdark.ssvm.jit.JitInstaller;
+import dev.xdark.ssvm.mirror.InstanceJavaClass;
+import dev.xdark.ssvm.mirror.JavaMethod;
+import dev.xdark.ssvm.symbol.VMSymbols;
+import dev.xdark.ssvm.util.VMHelper;
+import dev.xdark.ssvm.value.InstanceValue;
+import dev.xdark.ssvm.value.ObjectValue;
+import dev.xdark.ssvm.value.Value;
import org.junit.Test;
+import org.objectweb.asm.MethodTooLargeException;
+import org.objectweb.asm.tree.MethodNode;
import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* @author Ghast
@@ -28,7 +48,93 @@ public void test2() throws Exception {
final Skidfuscator skidfuscator = new Skidfuscator(session);
skidfuscator.run();
- //Bootstrapper.main(new String[]{"C:\\Users\\sanja\\Documents\\GitHub\\SkidfuscatorV2\\dev.skidfuscator.obfuscator\\src\\test\\resources\\test.jar"});
+
+ // TODO: Fix SSVM
+ if (true)
+ return;
+
+ VirtualMachine vm = new VirtualMachine();
+ VMHelper helper = vm.getHelper();
+ try {
+ VMInterface vmi = vm.getInterface();
+ // Enable JIT, if needed
+ JitClassLoader definer = new JitClassLoader();
+ vmi.registerMethodEnter(
+ ctx -> {
+ JavaMethod jm = ctx.getMethod();
+ int count = jm.getInvocationCount();
+ if (count == 256 && !Modifier.isCompiledMethod(jm.getAccess())) {
+ if (JitCompiler.isCompilable(jm)) {
+ try {
+ JitClass jit = JitCompiler.compile(jm, 3);
+ JitInstaller.install(jm, definer, jit);
+ } catch (MethodTooLargeException ex) {
+ MethodNode node = jm.getNode();
+ node.access |= Modifier.ACC_JIT;
+ } catch (Throwable ex) {
+ throw new IllegalStateException("Could not install JIT class for " + jm, ex);
+ }
+ }
+ }
+ });
+ // Bootstrap VM
+ vm.bootstrap();
+ VMSymbols symbols = vm.getSymbols();
+
+ // Add jar to system class loader
+ Value cl = helper
+ .invokeStatic(
+ symbols.java_lang_ClassLoader(),
+ "getSystemClassLoader",
+ "()Ljava/lang/ClassLoader;",
+ new Value[0],
+ new Value[0])
+ .getResult();
+ assert cl instanceof ObjectValue : "ClassLoader must be ObjectValue";
+ addURL(vm, cl, output.getPath());
+
+ // Invoke main, setup hooks to do stuff, etc
+ InstanceJavaClass klass = (InstanceJavaClass) helper.findClass((ObjectValue) cl, "dev.sim0n.evaluator.Main", true);
+ JavaMethod method = klass.getStaticMethod("main", "([Ljava/lang/String;)V");
+
+ helper.invokeStatic(
+ klass, method, new Value[0], new Value[] {helper.emptyArray(symbols.java_lang_String())});
+ } catch (VMException ex) {
+ helper.invokeVirtual("printStackTrace", "()V", new Value[0], new Value[] {ex.getOop()});
+ throw ex;
+ }
+ }
+
+ private static final class JitClassLoader extends ClassLoader
+ implements JitInstaller.ClassDefiner {
+
+ @Override
+ public Class> define(JitClass jitClass) {
+ byte[] code = jitClass.getCode();
+ return defineClass(jitClass.getClassName().replace('/', '.'), code, 0, code.length);
+ }
+ }
+
+ private static void addURL(VirtualMachine vm, Value loader, String path) {
+ // ((URLClassLoader)loader).addURL(new File(path).toURI().toURL());
+ VMHelper helper = vm.getHelper();
+ InstanceJavaClass fileClass = (InstanceJavaClass) vm.findBootstrapClass("java/io/File", true);
+ InstanceValue file = vm.getMemoryManager().newInstance(fileClass);
+ helper.invokeExact(
+ fileClass,
+ "",
+ "(Ljava/lang/String;)V",
+ new Value[0],
+ new Value[] {file, helper.newUtf8(path)});
+ Value uri =
+ helper
+ .invokeVirtual("toURI", "()Ljava/net/URI;", new Value[0], new Value[] {file})
+ .getResult();
+ Value url =
+ helper
+ .invokeVirtual("toURL", "()Ljava/net/URL;", new Value[0], new Value[] {uri})
+ .getResult();
+ helper.invokeVirtual("addURL", "(Ljava/net/URL;)V", new Value[0], new Value[] {loader, url});
}
}
diff --git a/obfuscator/src/test/resources/test-out.jar b/obfuscator/src/test/resources/test-out.jar
index e7517662..41765c17 100644
Binary files a/obfuscator/src/test/resources/test-out.jar and b/obfuscator/src/test/resources/test-out.jar differ
diff --git a/obfuscator/src/test/resources/test.jar b/obfuscator/src/test/resources/test.jar
index 2bcdfc3f..97d08a8c 100644
Binary files a/obfuscator/src/test/resources/test.jar and b/obfuscator/src/test/resources/test.jar differ