From 8d3a70b3256549d28e2e46a2285595c97ba8bcd6 Mon Sep 17 00:00:00 2001 From: Dawid Date: Tue, 30 Sep 2025 14:59:29 +0200 Subject: [PATCH 01/18] Branchlock salting complete --- .../deobfuscator/TestDeobfuscation.java | 8 +- .../BranchlockSaltingTransformer.java | 82 ++++++++- .../pack/Clazz.dec | 8 + .../pack/Main.dec | 166 ++++++++++++++++++ .../pack/tests/basics/accu/Digi.dec | 23 +++ .../pack/tests/basics/cross/Abst1.dec | 14 ++ .../pack/tests/basics/cross/Inte.dec | 5 + .../pack/tests/basics/cross/Top.dec | 46 +++++ .../pack/tests/basics/ctrl/Ctrl.dec | 32 ++++ .../pack/tests/basics/inner/Exec.dec | 32 ++++ .../pack/tests/basics/inner/Test.dec | 31 ++++ .../pack/tests/basics/overwirte/Face.dec | 5 + .../pack/tests/basics/overwirte/Sub.dec | 34 ++++ .../pack/tests/basics/overwirte/Super.dec | 13 ++ .../pack/tests/basics/runable/Exec.dec | 16 ++ .../pack/tests/basics/runable/Pool.dec | 13 ++ .../pack/tests/basics/runable/Task.dec | 49 ++++++ .../pack/tests/basics/sub/SolAdd.dec | 12 ++ .../pack/tests/basics/sub/Solver.dec | 13 ++ .../pack/tests/basics/sub/flo.dec | 12 ++ .../pack/tests/basics/sub/med.dec | 10 ++ .../pack/tests/bench/Calc.dec | 59 +++++++ .../pack/tests/reflects/annot/anno.dec | 11 ++ .../pack/tests/reflects/annot/annoe.dec | 36 ++++ .../pack/tests/reflects/annot/annot.dec | 26 +++ .../pack/tests/reflects/counter/Count.dec | 12 ++ .../pack/tests/reflects/counter/Countee.dec | 24 +++ .../pack/tests/reflects/field/FObject.dec | 14 ++ .../pack/tests/reflects/field/FTest.dec | 110 ++++++++++++ .../pack/tests/reflects/loader/LRun.dec | 17 ++ .../pack/tests/reflects/loader/LTest.dec | 23 +++ .../pack/tests/reflects/loader/Loader.dec | 27 +++ .../pack/tests/reflects/res/Accesor.dec | 14 ++ .../pack/tests/reflects/retrace/Tracee.dec | 21 +++ .../pack/tests/reflects/retrace/Tracer.dec | 31 ++++ .../pack/tests/security/SecExec.dec | 12 ++ .../pack/tests/security/SecTest.dec | 46 +++++ .../pack/tests/security/Sman.dec | 17 ++ .../pack/tests/basics/overwirte/Sub.dec | 2 +- .../pack/tests/basics/overwirte/Super.dec | 2 +- 40 files changed, 1118 insertions(+), 10 deletions(-) create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Clazz.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Main.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/accu/Digi.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Abst1.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Inte.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Top.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/ctrl/Ctrl.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Exec.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Test.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Face.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Sub.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Super.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Exec.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Pool.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Task.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/SolAdd.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/Solver.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/flo.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/med.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/bench/Calc.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/anno.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annoe.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annot.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Count.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Countee.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FObject.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FTest.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LRun.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LTest.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/Loader.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/res/Accesor.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracee.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracer.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecExec.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecTest.dec create mode 100644 testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/Sman.dec diff --git a/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java b/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java index ab45c233..b192baff 100644 --- a/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java +++ b/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java @@ -225,10 +225,10 @@ protected void registerAll() { .inputJar("branchlock/branchlock-string-flow-number.jar") .register(); -// test("Branchlock String + Salting + Flow + Number") -// .transformers(ComposedBranchlockTransformer::new) -// .inputJar("branchlock/branchlock-string-salting-flow-number.jar") -// .register(); + test("Branchlock String + Salting + Flow + Number") + .transformers(ComposedBranchlockTransformer::new) + .inputJar("branchlock/branchlock-string-salting-flow-number.jar") + .register(); test("Branchlock Flow 9") .transformers(BranchlockFlowTransformer::new) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockSaltingTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockSaltingTransformer.java index 9743bf7c..bfd305c2 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockSaltingTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockSaltingTransformer.java @@ -3,6 +3,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import uwu.narumi.deobfuscator.api.asm.ClassWrapper; import uwu.narumi.deobfuscator.api.asm.MethodContext; import uwu.narumi.deobfuscator.api.asm.matcher.Match; import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; @@ -11,8 +12,7 @@ import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; import uwu.narumi.deobfuscator.api.transformer.Transformer; -import java.util.Map; -import java.util.WeakHashMap; +import java.util.*; public class BranchlockSaltingTransformer extends Transformer { @@ -22,8 +22,6 @@ public class BranchlockSaltingTransformer extends Transformer { private final Map salts = new WeakHashMap<>(); - //TODO: Fix superClass`s / interface`s overridden methods not being deobfuscated - @Override protected void transform() throws Exception { scopedClasses().forEach(classWrapper -> { @@ -48,6 +46,21 @@ protected void transform() throws Exception { }); }); /* Replace ILOAD var with saved salts */ + salts.forEach((min, salt) -> { + resolvePossibleTargets(min, context().getClassesMap(), buildSubclassMap(context().getClassesMap())).forEach(resolvedMethod -> { + MethodNode methodNode = resolvedMethod.mn(); + ClassNode cn = resolvedMethod.cn(); + int lastParamIndex = getLastParameterSlot(methodNode.access, methodNode.desc); + MethodContext methodContext = MethodContext.of(context().getClassesMap().get(cn.name), methodNode); + saltingXor.findAllMatches(methodContext).forEach(matchContext -> { + VarInsnNode varInsnNode = (VarInsnNode) matchContext.insn(); + if (varInsnNode.var == lastParamIndex) { + methodNode.instructions.set(matchContext.insn(), pushInt(salt)); + markChange(); + } + }); + }); + }); scopedClasses().forEach(classWrapper -> { classWrapper.methods().forEach(methodNode -> { int lastParamIndex = getLastParameterSlot(methodNode.access, methodNode.desc); @@ -77,6 +90,64 @@ public AbstractInsnNode pushInt(int value) { } } + public static Map> buildSubclassMap(Map classMap) { + Map> subclassMap = new HashMap<>(); + + for (ClassWrapper cw : classMap.values()) { + ClassNode cn = cw.classNode(); + if (cn.superName != null) { + subclassMap.computeIfAbsent(cn.superName, k -> new ArrayList<>()).add(cn.name); + } + if (cn.interfaces != null) { + for (String iface : cn.interfaces) { + subclassMap.computeIfAbsent(iface, k -> new ArrayList<>()).add(cn.name); + } + } + } + + return subclassMap; + } + + public static List resolvePossibleTargets(MethodInsnNode methodInsn, Map classMap, Map> subclassMap) { + String methodName = methodInsn.name; + String methodDesc = methodInsn.desc; + String ownerInternalName = methodInsn.owner; + + Set visited = new HashSet<>(); + Queue toVisit = new ArrayDeque<>(); + List results = new ArrayList<>(); + + toVisit.add(ownerInternalName); + + while (!toVisit.isEmpty()) { + String className = toVisit.poll(); + if (!visited.add(className)) continue; + + ClassWrapper cw = classMap.get(className); + if (cw == null) continue; + ClassNode cn = cw.classNode(); + + for (MethodNode mn : cn.methods) { + if (mn.name.equals(methodName) && mn.desc.equals(methodDesc)) { + results.add(new ResolvedMethod(cn, mn)); + } + } + + if (cn.superName != null) { + toVisit.add(cn.superName); + } + if (cn.interfaces != null) { + toVisit.addAll(cn.interfaces); + } + + List subclasses = subclassMap.getOrDefault(className, Collections.emptyList()); + toVisit.addAll(subclasses); + } + + return results; + } + + public int getLastParameterSlot(int access, String desc) { Type[] args = Type.getArgumentTypes(desc); int index = ((access & Opcodes.ACC_STATIC) != 0) ? 0 : 1; @@ -86,4 +157,7 @@ public int getLastParameterSlot(int access, String desc) { } return index; } + + public record ResolvedMethod(ClassNode cn, MethodNode mn) { + } } diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Clazz.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Clazz.dec new file mode 100644 index 00000000..f1191857 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Clazz.dec @@ -0,0 +1,8 @@ +package pack; + +public class Clazz { + public String BRANCHLOCK_DOT_NET_DEMO; + + public Clazz(int var1) { + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Main.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Main.dec new file mode 100644 index 00000000..ee2594b9 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/Main.dec @@ -0,0 +1,166 @@ +package pack; + +import java.io.File; +import pack.tests.basics.accu.Digi; +import pack.tests.basics.ctrl.Ctrl; +import pack.tests.basics.inner.Test; +import pack.tests.basics.overwirte.Sub; +import pack.tests.basics.runable.Task; +import pack.tests.basics.sub.Solver; +import pack.tests.bench.Calc; +import pack.tests.reflects.annot.annot; +import pack.tests.reflects.counter.Count; +import pack.tests.reflects.field.FTest; +import pack.tests.reflects.loader.LRun; +import pack.tests.reflects.res.Accesor; +import pack.tests.reflects.retrace.Tracer; +import pack.tests.security.SecTest; + +public class Main { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Main(int var1) { + } + + public static void main(String[] var0) { + System.out + .println( + "-----------------------------------------------------------------------------------------\n| This java application has been obfuscated using a demo version of Branchlock 4. |\n| Did you know that anyone can read the source code of your exported java software? |\n| For more information about how to protect your projects, visit https://branchlock.net |\n-----------------------------------------------------------------------------------------\n" + ); + System.out.println("Obfuscator Test Program"); + System.out.println("Author: huzpsb"); + System.out.println("Version: 1.0r"); + System.out.println("Link: https://github.com/huzpsb/JavaObfuscatorTest"); + File var1 = new File("IK"); + if (!var1.exists()) { + var1.createNewFile(); + System.out.println(); + System.out.println("[HINT]"); + System.out.println("Only compatibility and efficiency are tested here!"); + System.out.println("For most users, pass all of the basics means the obfuscator is good enough."); + System.out.println("The Test #2 is for SpringBoot and Android like environment."); + System.out.println("Choose wisely among strength, compatibility, efficiency, size, and price."); + System.out.println("[HINT]"); + System.out.println(); + } + + System.out.println("-------------Test #1: Basics-------------"); + System.out.print("Test 1.1: Inheritance "); + + try { + new Sub(8122).run(29865); + } catch (Throwable var15) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.2: Cross "); + + try { + new Sub(8122).run(29865); + } catch (Throwable var14) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.3: Throw "); + + try { + new Ctrl(32735).run(12620); + } catch (Throwable var13) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.4: Accuracy "); + + try { + new Digi(7043).run(22257); + } catch (Throwable var12) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.5: SubClass "); + + try { + new Solver(16217); + } catch (Throwable var11) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.6: Pool "); + + try { + new Task(30959).run(15887); + } catch (Throwable var10) { + System.out.println("ERROR"); + } + + System.out.print("Test 1.7: InnerClass "); + + try { + new Test(9340).run(18150); + } catch (Throwable var9) { + System.out.println("ERROR"); + } + + System.out.println("-------------Test #2: Reflects-------------"); + System.out.print("Test 2.1: Counter "); + + try { + new Count(4824).run(18228); + } catch (Throwable var8) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.2: Chinese 通过LMAO\b\b\b\b \n"); + System.out.print("Test 2.3: Resource "); + + try { + new Accesor(15232).run(27444); + } catch (Throwable var7) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.4: Field "); + + try { + new FTest(3122).run(29896); + } catch (Throwable var6) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.5: Loader "); + + try { + new LRun(4393).run(12617); + } catch (Throwable var5) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.6: ReTrace "); + + try { + new Tracer(23239).run(20986); + } catch (Throwable var4) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.7: Annotation "); + + try { + new annot(615).run(27375); + } catch (Throwable var3) { + System.out.println("ERROR"); + } + + System.out.print("Test 2.8: Sec "); + + try { + new SecTest(30139).run(22458); + } catch (Throwable var2) { + System.out.println("ERROR"); + } + + System.out.println("-------------Test #3: Efficiency-------------"); + Calc.runAll(28038); + System.out.println("-------------Tests r Finished-------------"); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/accu/Digi.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/accu/Digi.dec new file mode 100644 index 00000000..0476af59 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/accu/Digi.dec @@ -0,0 +1,23 @@ +package pack.tests.basics.accu; + +public class Digi { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Digi(int var1) { + } + + public void run(int var1) { + double var2 = 0.0; + int var4 = 0; + + do { + var2 += 1.0E-18; + } while (++var4 <= 100 && (float)var2 != 2.0E-17F); + + if (var4 == 20) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Abst1.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Abst1.dec new file mode 100644 index 00000000..58e5e377 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Abst1.dec @@ -0,0 +1,14 @@ +package pack.tests.basics.cross; + +public abstract class Abst1 { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Abst1(int var1) { + } + + public abstract int add(int var1, int var2, int var3); + + public int mul(int var1, int var2, int var3) { + return var1 * var2; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Inte.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Inte.dec new file mode 100644 index 00000000..09f014a9 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Inte.dec @@ -0,0 +1,5 @@ +package pack.tests.basics.cross; + +public interface Inte { + int mul(int var1, int var2, int var3); +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Top.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Top.dec new file mode 100644 index 00000000..e47273a1 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/cross/Top.dec @@ -0,0 +1,46 @@ +package pack.tests.basics.cross; + +public class Top extends Abst1 implements Inte { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Top(int var1) { + super(var1 ^ var1 ^ 8775); + } + + public void run(int var1) { + while (true) { + label26: { + label25: { + if (this.add(1, var1 ^ 8702, (var1 | var1 ^ 26621) & (var1 ^ 32663)) == (var1 ^ 8703)) { + if (var1 < 0) { + break label26; + } + + if (this.mul(var1 ^ 8702, var1 ^ 8703, var1 ^ var1 ^ 10972) == (var1 ^ 8698)) { + if (var1 < 0) { + break; + } + break label25; + } + } + + if (var1 >= 0) { + System.out.println(d[var1 ^ 8700]); + break; + } + } + + System.out.println(d[var1 ^ 8701]); + } + + if (var1 >= 0) { + return; + } + } + } + + @Override + public int add(int var1, int var2, int var3) { + return var1 + var2; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/ctrl/Ctrl.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/ctrl/Ctrl.dec new file mode 100644 index 00000000..66baf6c3 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/ctrl/Ctrl.dec @@ -0,0 +1,32 @@ +package pack.tests.basics.ctrl; + +public class Ctrl { + private String ret = "FAIL"; + public String BRANCHLOCK_DOT_NET_DEMO; + + public Ctrl(int var1) { + } + + public void runt(int var1) { + if (var1 >= 0) { + throw new UnsupportedOperationException(); + } + } + + public void runf(int var1) { + this.runt(29872); + + try { + this.runt(29872); + this.ret = "FAIL"; + } catch (Exception var2) { + } + } + + public void run(int var1) { + do { + this.runf(950); + System.out.println(this.ret); + } while (var1 < 0); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Exec.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Exec.dec new file mode 100644 index 00000000..2641d91e --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Exec.dec @@ -0,0 +1,32 @@ +package pack.tests.basics.inner; + +public class Exec { + public int fuss = 1; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Exec(int var1) { + } + + public void addF(int var1) { + do { + this.fuss += 2; + } while (var1 < 0); + } + + public class Inner { + int i; + final Exec this$0; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Inner(Exec var1, int var2, int var3) { + this.this$0 = var1; + this.i = var2; + } + + public void doAdd(int var1) { + do { + this.this$0.fuss = this.this$0.fuss + this.i; + } while (var1 < 0); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Test.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Test.dec new file mode 100644 index 00000000..85bef78f --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/inner/Test.dec @@ -0,0 +1,31 @@ +package pack.tests.basics.inner; + +public class Test { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Test(int var1) { + } + + // $VF: Irreducible bytecode was duplicated to produce valid code + public void run(int var1) { + Exec var2 = new Exec(20620); + Exec.Inner var3 = var2.new Inner(var2, 3, 22005); + var3.doAdd(15352); + Exec.Inner var4 = var2.new Inner(var2, 100, 22005); + if (var1 >= 0) { + do { + var4.doAdd(15352); + } while (var1 < 0); + } + + if (var2.fuss == 108) { + System.out.println("PASS"); + } else { + System.out.println("ERROR"); + } + + while (var1 < 0) { + System.out.println("PASS"); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Face.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Face.dec new file mode 100644 index 00000000..e7c36d04 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Face.dec @@ -0,0 +1,5 @@ +package pack.tests.basics.overwirte; + +public interface Face { + String face(int var1, int var2); +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Sub.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Sub.dec new file mode 100644 index 00000000..1ab48873 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Sub.dec @@ -0,0 +1,34 @@ +package pack.tests.basics.overwirte; + +public class Sub extends Super { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Sub(int var1) { + super(4305); + } + + @Override + public void run(int var1) { + System.out.println(this.face(1, 6600)); + } + + @Override + public String face(int var1, int var2) { + if (var1 == 1) { + return "PASS"; + } else { + while (var2 < 0) { + } + + return "FAIL"; + } + } + + public static Throwable m(Throwable var0) { + if (Super.m == null) { + Super.m = var0; + } + + return var0; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Super.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Super.dec new file mode 100644 index 00000000..a0241135 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/overwirte/Super.dec @@ -0,0 +1,13 @@ +package pack.tests.basics.overwirte; + +public abstract class Super implements Face { + public int BRANCHLOCK_DOT_NET_DEMO; + public static Throwable m; + + public Super(int var1) { + } + + public void run(int var1) { + System.out.println("FAIL"); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Exec.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Exec.dec new file mode 100644 index 00000000..ea4c43b6 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Exec.dec @@ -0,0 +1,16 @@ +package pack.tests.basics.runable; + +public class Exec { + public static int i = 1; + private int d; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Exec(int var1, int var2) { + this.d = var1; + } + + void doAdd() { + Thread.sleep(200L); + i = i + this.d; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Pool.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Pool.dec new file mode 100644 index 00000000..8b6c9545 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Pool.dec @@ -0,0 +1,13 @@ +package pack.tests.basics.runable; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class Pool { + public static ThreadPoolExecutor tpe = new ThreadPoolExecutor(0, 1, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1)); + public int BRANCHLOCK_DOT_NET_DEMO; + + public Pool(int var1) { + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Task.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Task.dec new file mode 100644 index 00000000..1b3ba6da --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/runable/Task.dec @@ -0,0 +1,49 @@ +package pack.tests.basics.runable; + +import java.util.concurrent.RejectedExecutionException; + +public class Task { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Task(int var1) { + } + + public void run(int var1) { + Exec var2 = new Exec(2, 8325); + Exec var3 = new Exec(3, 8325); + Exec var4 = new Exec(100, 8325); + + try { + Pool.tpe.submit(var3::doAdd); + + try { + Thread.sleep(50L); + } catch (InterruptedException var6) { + } + + Pool.tpe.submit(Task::lambda$run$0); + + try { + Thread.sleep(50L); + } catch (InterruptedException var5) { + } + + Pool.tpe.submit(var4::doAdd); + } catch (RejectedExecutionException var7) { + Exec.i += 10; + } + + Thread.sleep(300L); + if (Exec.i == 30) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } + + private static void lambda$run$0(Exec var0) { + int var1 = Exec.i; + var0.doAdd(); + Exec.i += var1; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/SolAdd.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/SolAdd.dec new file mode 100644 index 00000000..441d606d --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/SolAdd.dec @@ -0,0 +1,12 @@ +package pack.tests.basics.sub; + +public class SolAdd { + public int BRANCHLOCK_DOT_NET_DEMO; + + public SolAdd(int var1) { + } + + public static int get(int var0) { + return (new med(1, 2, 6691)).result; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/Solver.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/Solver.dec new file mode 100644 index 00000000..9dc27195 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/Solver.dec @@ -0,0 +1,13 @@ +package pack.tests.basics.sub; + +public class Solver { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Solver(int var1) { + if (SolAdd.get(9795) == 3) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/flo.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/flo.dec new file mode 100644 index 00000000..6233fc73 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/flo.dec @@ -0,0 +1,12 @@ +package pack.tests.basics.sub; + +class flo { + public int BRANCHLOCK_DOT_NET_DEMO; + + flo(int var1) { + } + + int solve(int var1, int var2, int var3) { + return var1 + var2; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/med.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/med.dec new file mode 100644 index 00000000..59cf5d71 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/basics/sub/med.dec @@ -0,0 +1,10 @@ +package pack.tests.basics.sub; + +class med { + int result; + public int BRANCHLOCK_DOT_NET_DEMO; + + med(int var1, int var2, int var3) { + this.result = new flo(29775).solve(var1, var2, 18621); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/bench/Calc.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/bench/Calc.dec new file mode 100644 index 00000000..b13eefc8 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/bench/Calc.dec @@ -0,0 +1,59 @@ +package pack.tests.bench; + +public class Calc { + public static int count = 0; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Calc(int var1) { + } + + public static void runAll(int var0) { + long var1 = System.currentTimeMillis(); + + for (int var3 = 0; var3 < 10000; var3++) { + call(100, 29033); + runAdd(25806); + runStr(31991); + } + + System.out.println("Calc: " + (System.currentTimeMillis() - var1) + "ms"); + if (count != 30000) { + throw new RuntimeException("[ERROR]: Errors occurred in calc!"); + } + } + + private static void runAdd(int var0) { + double var1 = 0.0; + + while (var1 < 100.1) { + var1 += 0.99; + } + + count++; + } + + // $VF: Irreducible bytecode was duplicated to produce valid code + private static void runStr(int var0) { + String var1 = ""; + + while (true) { + label19: { + if (var1.length() < 101) { + if (var0 >= 0) { + break label19; + } + } else { + count++; + } + + do { + if (var0 >= 0) { + return; + } + } while (var0 < 0); + } + + var1 = var1 + "ax"; + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/anno.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/anno.dec new file mode 100644 index 00000000..4149deff --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/anno.dec @@ -0,0 +1,11 @@ +package pack.tests.reflects.annot; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface anno { + String val() default "yes"; + + String val2() default "yes"; +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annoe.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annoe.dec new file mode 100644 index 00000000..47859ad4 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annoe.dec @@ -0,0 +1,36 @@ +package pack.tests.reflects.annot; + +import java.lang.reflect.Field; + +public class annoe { + @anno( + val = "PASS" + ) + private static final String fail = "WHAT"; + public int BRANCHLOCK_DOT_NET_DEMO; + + public annoe(int var1) { + } + + @anno + public void dox() { + String var1 = "FAIL"; + + for (Field var5 : annoe.class.getDeclaredFields()) { + var5.setAccessible(true); + anno var6 = var5.getAnnotation(anno.class); + if (var6 != null) { + var1 = var6.val(); + } + } + + System.out.println(var1); + } + + @anno( + val = "no" + ) + public void dov() { + System.out.println("FAIL"); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annot.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annot.dec new file mode 100644 index 00000000..ef74e884 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/annot/annot.dec @@ -0,0 +1,26 @@ +package pack.tests.reflects.annot; + +import java.lang.reflect.Method; + +public class annot { + public int BRANCHLOCK_DOT_NET_DEMO; + + public annot(int var1) { + } + + public void run(int var1) { + annoe var2 = new annoe(8983); + + for (Method var6 : annoe.class.getDeclaredMethods()) { + var6.setAccessible(true); + anno var7 = var6.getAnnotation(anno.class); + + while (var1 < 0 || var7 != null && var1 >= 0 && var7.val().equals("yes")) { + var6.invoke(var2); + if (var1 >= 0) { + break; + } + } + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Count.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Count.dec new file mode 100644 index 00000000..4a57897d --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Count.dec @@ -0,0 +1,12 @@ +package pack.tests.reflects.counter; + +public class Count { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Count(int var1) { + } + + public void run(int var1) { + System.out.println("PASS"); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Countee.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Countee.dec new file mode 100644 index 00000000..ba0d3fea --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/counter/Countee.dec @@ -0,0 +1,24 @@ +package pack.tests.reflects.counter; + +public class Countee { + public int cpuli = 0; + protected int cprot = 0; + int cpackp = 1; + private int cpriv = 0; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Countee(int var1) { + } + + public void mpuli() { + } + + public void mprot() { + } + + public void mpackp() { + } + + public void mpriv() { + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FObject.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FObject.dec new file mode 100644 index 00000000..787d05d3 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FObject.dec @@ -0,0 +1,14 @@ +package pack.tests.reflects.field; + +public class FObject extends Throwable { + private int i; + public int BRANCHLOCK_DOT_NET_DEMO; + + private FObject(int var1) { + this.i = var1; + } + + private void add() { + this.i += 3; + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FTest.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FTest.dec new file mode 100644 index 00000000..680acefb --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/field/FTest.dec @@ -0,0 +1,110 @@ +package pack.tests.reflects.field; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class FTest { + public int BRANCHLOCK_DOT_NET_DEMO; + + public FTest(int var1) { + } + + // $VF: Irreducible bytecode was duplicated to produce valid code + public void run(int var1) { + Constructor var2 = FObject.class.getDeclaredConstructor(int.class); + if (var2.isAccessible()) { + System.out.println("FAIL"); + } else { + var2.setAccessible(true); + FObject var3 = (FObject)var2.newInstance(1); + Method var4 = FObject.class.getDeclaredMethod("add", null); + if (var4.isAccessible()) { + System.out.println("FAIL"); + } else { + var4.setAccessible(true); + var4.invoke(var3); + Field var5 = FObject.class.getDeclaredField("i"); + if (var1 >= 0) { + if (var5.isAccessible()) { + if (var1 >= 0) { + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + + return; + } + + if (var1 < 0) { + return; + } + + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + } + } else { + if (var5.getInt(var3) == 4) { + System.out.println("PASS"); + return; + } + + if (var1 < 0) { + return; + } + + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + } + + do { + while (var1 < 0) { + if (var5.isAccessible()) { + if (var1 >= 0) { + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + + return; + } + + if (var1 < 0) { + return; + } + + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + } + } + + var5.setAccessible(true); + if (var1 < 0) { + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + break; + } + + if (var5.getInt(var3) == 4) { + System.out.println("PASS"); + return; + } + + if (var1 < 0) { + return; + } + + System.out.println("FAIL"); + } while (var1 < 0); + } + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LRun.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LRun.dec new file mode 100644 index 00000000..855ec57a --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LRun.dec @@ -0,0 +1,17 @@ +package pack.tests.reflects.loader; + +public class LRun { + public int BRANCHLOCK_DOT_NET_DEMO; + + public LRun(int var1) { + } + + public void run(int var1) { + Loader var2 = new Loader(5640); + Class var3 = var2.findClass("pack.tests.reflects.loader.LTest"); + Object var4 = var3.newInstance(); + if (var1 >= 0) { + var3.getMethod("run").invoke(var4); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LTest.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LTest.dec new file mode 100644 index 00000000..99eb63fe --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/LTest.dec @@ -0,0 +1,23 @@ +package pack.tests.reflects.loader; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +public class LTest { + public int BRANCHLOCK_DOT_NET_DEMO; + + public LTest(int var1) { + } + + public static byte[] readAllBytes(InputStream var0, int var1) { + ByteArrayOutputStream var2 = new ByteArrayOutputStream(); + byte[] var3 = new byte[var1 ^ 6433]; + + int var4; + while ((var4 = var0.read(var3)) != (var1 ^ -7458) && var1 >= 0) { + var2.write(var3, 0, var4); + } + + return var2.toByteArray(); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/Loader.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/Loader.dec new file mode 100644 index 00000000..bac2880e --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/loader/Loader.dec @@ -0,0 +1,27 @@ +package pack.tests.reflects.loader; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +public class Loader extends ClassLoader { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Loader(int var1) { + } + + public static byte[] readAllBytes(InputStream var0, int var1) { + while (true) { + } + } + + @Override + public InputStream getResourceAsStream(String var1) { + return (InputStream)(var1.contains("TEST") ? new ByteArrayInputStream("PASS".getBytes()) : super.getResourceAsStream(var1)); + } + + @Override + public Class findClass(String var1) { + byte[] var2 = readAllBytes(Loader.class.getClassLoader().getResourceAsStream("pack/tests/reflects/loader/LTest.class"), 20488); + return this.defineClass(var1, var2, 0, var2.length); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/res/Accesor.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/res/Accesor.dec new file mode 100644 index 00000000..1f143a85 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/res/Accesor.dec @@ -0,0 +1,14 @@ +package pack.tests.reflects.res; + +public class Accesor { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Accesor(int var1) { + } + + public void run(int var1) { + Accesor.class.getResourceAsStream("/pack/tests/reflects/res/file").read(); + byte var10001 = 97; + throw new RuntimeException(); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracee.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracee.dec new file mode 100644 index 00000000..93aead4f --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracee.dec @@ -0,0 +1,21 @@ +package pack.tests.reflects.retrace; + +public class Tracee { + public static int p = 0; + public int BRANCHLOCK_DOT_NET_DEMO; + + public Tracee(int var1) { + } + + private void doTrace(int var1) { + p++; + StackTraceElement var2 = new Throwable().getStackTrace()[1]; + Tracee.class.getDeclaredMethod(var2.getMethodName(), int.class).invoke(this, var1 - 1); + } + + public void toTrace(int var1) { + if (var1 != 0) { + this.doTrace(var1); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracer.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracer.dec new file mode 100644 index 00000000..8591d6ea --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/reflects/retrace/Tracer.dec @@ -0,0 +1,31 @@ +package pack.tests.reflects.retrace; + +public class Tracer { + public String BRANCHLOCK_DOT_NET_DEMO; + + public Tracer(int var1) { + } + + // $VF: Irreducible bytecode was duplicated to produce valid code + public void run(int var1) { + while (true) { + new Tracee(29130).toTrace(5); + if (var1 < 0 || Tracee.p == 5) { + if (var1 >= 0) { + System.out.println("PASS"); + } + + if (var1 >= 0) { + return; + } + } + + while (var1 >= 0) { + System.out.println("FAIL"); + if (var1 >= 0) { + return; + } + } + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecExec.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecExec.dec new file mode 100644 index 00000000..b28d9f27 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecExec.dec @@ -0,0 +1,12 @@ +package pack.tests.security; + +public class SecExec { + public int BRANCHLOCK_DOT_NET_DEMO; + + public SecExec(int var1) { + } + + private static void doShutdown() { + System.exit(-1); + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecTest.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecTest.dec new file mode 100644 index 00000000..dfe9bce6 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/SecTest.dec @@ -0,0 +1,46 @@ +package pack.tests.security; + +import java.lang.reflect.Method; + +public class SecTest { + public int BRANCHLOCK_DOT_NET_DEMO; + + public SecTest(int var1) { + } + + public void run(int var1) { + System.setSecurityManager(new Sman(23927)); + System.out.print("FAIL"); + + try { + Method var2 = SecExec.class.getDeclaredMethod("doShutdown"); + var2.setAccessible(true); + var2.invoke(null); + } catch (Throwable var6) { + Throwable var4 = var6; + + while (true) { + Throwable var3 = var4.getCause(); + if (var3 == null) { + String var5 = var4.getMessage(); + if (var1 >= 0) { + do { + if (var5 == null) { + return; + } + + if (!var5.contains("HOOK")) { + return; + } + } while (var1 < 0); + } + + System.out.println("\b\b\b\bPASS"); + break; + } + + var4 = var3; + } + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/Sman.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/Sman.dec new file mode 100644 index 00000000..edeb7011 --- /dev/null +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-flow-number/pack/tests/security/Sman.dec @@ -0,0 +1,17 @@ +package pack.tests.security; + +import java.security.Permission; + +public class Sman extends SecurityManager { + public int BRANCHLOCK_DOT_NET_DEMO; + + public Sman(int var1) { + } + + @Override + public void checkPermission(Permission var1) { + if (var1.getName().contains("exitVM")) { + throw new SecurityException("HOOKED"); + } + } +} diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Sub.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Sub.dec index e6535e54..f0fca306 100644 --- a/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Sub.dec +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Sub.dec @@ -14,6 +14,6 @@ public class Sub extends Super { @Override public String face(int var1, int var2) { - return var1 == 1 ? d[var2 ^ 8362] : d[var2 ^ 8363]; + return var1 == 1 ? "PASS" : "FAIL"; } } diff --git a/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Super.dec b/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Super.dec index 03fe6bf3..f751147f 100644 --- a/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Super.dec +++ b/testData/results/custom-jars/branchlock/branchlock-string-salting-number/pack/tests/basics/overwirte/Super.dec @@ -7,6 +7,6 @@ public abstract class Super implements Face { } public void run(int var1) { - System.out.println(d[var1 ^ 25940]); + System.out.println("FAIL"); } } From 76709522dff9be474fc7170c370bb1c6e0a1dfc9 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 14 Oct 2025 20:56:11 +0200 Subject: [PATCH 02/18] SkidFuscator --- .../skidfuscator/SkidNumberTransformer.java | 44 +++ .../skidfuscator/SkidStringTransformer.java | 269 ++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidNumberTransformer.java create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidNumberTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidNumberTransformer.java new file mode 100644 index 00000000..80314900 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidNumberTransformer.java @@ -0,0 +1,44 @@ +package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; + +import org.objectweb.asm.tree.LdcInsnNode; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +import java.util.Random; + +public class SkidNumberTransformer extends Transformer { + + Match randomNextMatch = SequenceMatch.of( + OpcodeMatch.of(NEW), + OpcodeMatch.of(DUP), + NumberMatch.numLong().capture("init-random"), + MethodMatch.invokeSpecial().owner("java/util/Random").name("").desc("(J)V"), + MethodMatch.invokeVirtual().owner("java/util/Random").capture("method") + ); + + @Override + protected void transform() throws Exception { + scopedClasses().forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext = MethodContext.of(classWrapper, methodNode); + randomNextMatch.findAllMatches(methodContext).forEach(matchContext -> { + Random random = new Random(matchContext.captures().get("init-random").insn().asLong()); + Object object = switch (matchContext.captures().get("method").insn().asMethodInsn().name) { + case "nextInt" -> random.nextInt(); + case "nextLong" -> random.nextLong(); + case "nextBoolean" -> random.nextBoolean(); + case "nextFloat" -> random.nextFloat(); + case "nextDouble" -> random.nextDouble(); + default -> throw new IllegalStateException("Unexpected value: " + matchContext.captures().get("method").insn().asMethodInsn().name); + }; + methodNode.instructions.insert(matchContext.insn(), new LdcInsnNode(object)); + matchContext.removeAll(); + markChange(); + }); + })); + } +} diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java new file mode 100644 index 00000000..806768df --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java @@ -0,0 +1,269 @@ +package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; + +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.MethodRef; +import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.MatchContext; +import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.FieldMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +public class SkidStringTransformer extends Transformer { + + Match fieldPutStaticByteArray = SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("method"), + FieldMatch.putStatic().desc("[B").capture("field") + ); + + Match fieldPutStaticString = SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("method"), + MethodMatch.invokeStatic().owner("java/nio/ByteBuffer").name("wrap").desc("([B)Ljava/nio/ByteBuffer;"), + MethodMatch.invokeVirtual().owner("java/nio/ByteBuffer").name("asCharBuffer").desc("()Ljava/nio/CharBuffer;"), + MethodMatch.invokeVirtual().owner("java/nio/CharBuffer").name("toString").desc("()Ljava/lang/String;"), + FieldMatch.putStatic().desc("Ljava/lang/String;").capture("field") + ); + + @Override + protected void transform() throws Exception { + scopedClasses().forEach(classWrapper -> { + Set trashMethods = new HashSet<>(); + classWrapper.findClInit().ifPresent(clinitNode -> { + MethodContext clinitContext = MethodContext.of(classWrapper, clinitNode); + MethodNode decryptionMethod = classWrapper.methods().stream().filter(methodNode -> methodNode.name.length() == 10 && methodNode.desc.endsWith("I)Ljava/lang/String;")).findFirst().orElse(null); + if (decryptionMethod != null) { + MethodContext methodContext = MethodContext.of(classWrapper, decryptionMethod); + int methodSize = Match.of(ctx -> ctx.insn().isMathOperator()).findAllMatches(methodContext).size(); + if (methodSize == 24) { + MatchContext byteBufferMatch = fieldPutStaticString.findFirstMatch(clinitContext); + MethodNode toRemove; + String decryptHash = ByteBuffer.wrap( + resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove = findMethod( + classWrapper.classNode(), + MethodRef.of( + byteBufferMatch.captures().get("method").insn().asMethodInsn() + ) + ).get() + ) + ) + ).asCharBuffer().toString(); + trashMethods.add(toRemove); + byteBufferMatch.removeAll(); + classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); + SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("byte-array"), + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().name(decryptionMethod.name) + ).findAllMatches(methodContext1).forEach(matchContext -> { + int salt = matchContext.captures().get("salt").insn().asInteger(); + MethodNode toRemove1; + byte[] stringBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method25(stringBytes, decryptHash, salt))); + markChange(); + matchContext.removeAll(); + }); + }); + } else if (methodSize == 5) { + if (decryptionMethod.desc.equals("([B[BI)Ljava/lang/String;")) { + classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); + SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("byte-array1"), + MethodMatch.invokeStatic().desc("()[B").capture("byte-array2"), + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().name(decryptionMethod.name) + ).findAllMatches(methodContext1).forEach(matchContext -> { + int salt = matchContext.captures().get("salt").insn().asInteger(); + MethodNode toRemove1; + byte[] stringBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array1").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + byte[] decryptBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array2").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method5(stringBytes, decryptBytes, salt))); + markChange(); + matchContext.removeAll(); + }); + }); + } else if (decryptionMethod.desc.equals("([BI)Ljava/lang/String;")) { + MatchContext bytesMatch = fieldPutStaticByteArray.findFirstMatch(clinitContext); + MethodNode toRemove; + byte[] decryptBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove = findMethod( + classWrapper.classNode(), + MethodRef.of( + bytesMatch.captures().get("method").insn().asMethodInsn() + ) + ).get() + ) + ); + classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); + SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("byte-array"), + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().name(decryptionMethod.name) + ).findAllMatches(methodContext1).forEach(matchContext -> { + int salt = matchContext.captures().get("salt").insn().asInteger(); + MethodNode toRemove1; + byte[] stringBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method5(stringBytes, decryptBytes, salt))); + markChange(); + matchContext.removeAll(); + }); + }); + trashMethods.add(toRemove); + bytesMatch.removeAll(); + } + } + trashMethods.add(decryptionMethod); + } + }); + classWrapper.methods().removeAll(trashMethods); + }); + } + + public static String method5(byte[] var0, byte[] var1, int var2) { + byte[] var9 = Integer.toString(var2).getBytes(); + int var10 = 0; + + while (true) { + int var18 = var0.length; + if (var10 >= var18) { + Charset var6 = StandardCharsets.UTF_16; + return new String(var0, var6); + } + + byte var21 = var0[var10]; + int var34 = var9.length; + int var31 = var10 % var34; + byte var28 = var9[var31]; + byte var23 = (byte)(var21 ^ var28); + var0[var10] = var23; + byte var24 = var0[var10]; + int var36 = var1.length; + int var33 = var10 % var36; + byte var30 = var1[var33]; + byte var26 = (byte)(var24 ^ var30); + var0[var10] = var26; + var10++; + } + } + + public static String method25(byte[] var0, String var1, int var2) { + byte[] var8 = Integer.toString(var2).getBytes(); + int var18 = (var0[0] & 255) << 24; + int var41 = (var0[1] & 255) << 16; + int var19 = var18 | var41; + int var45 = (var0[2] & 255) << 8; + int var20 = var19 | var45; + int var48 = var0[3] & 255; + int var9 = var20 | var48; + int var25 = (var0[4] & 255) << 24; + int var55 = (var0[5] & 255) << 16; + int var26 = var25 | var55; + int var59 = (var0[6] & 255) << 8; + int var27 = var26 | var59; + int var62 = var0[7] & 255; + int var10 = var27 | var62; + String var29 = var1; + int var84 = var10 + var9; + String var30 = var29.substring(var10, var84); + Charset var64 = StandardCharsets.UTF_16BE; + byte[] var11 = var30.getBytes(var64); + int var12 = 0; + + while (true) { + int var66 = var11.length; + if (var12 >= var66) { + Charset var91 = StandardCharsets.UTF_16BE; + return new String(var11, var91); + } + + byte var85 = var11[var12]; + int var93 = var8.length; + int var92 = var12 % var93; + byte var90 = var8[var92]; + byte var87 = (byte)(var85 ^ var90); + var11[var12] = var87; + var12++; + } + } + + public byte[] resolveByteArrayFromMethod(MethodContext methodContext) { + MatchContext decryptMethod = SequenceMatch.of( + NumberMatch.numInteger(), + OpcodeMatch.of(NEWARRAY) + ).findFirstMatch(methodContext); + if (decryptMethod != null) { + byte[] bytes = new byte[decryptMethod.insn().asInteger()]; + SequenceMatch.of( + OpcodeMatch.of(DUP), + NumberMatch.numInteger().capture("array-index"), + NumberMatch.of().capture("array-value"), + OpcodeMatch.of(BASTORE) + ).findAllMatches(methodContext).forEach(matchContext -> { + bytes[matchContext.captures().get("array-index").insn().asInteger()] = matchContext.captures().get("array-value").insn().asNumber().byteValue(); + }); + return bytes; + } + return null; + } +} From 74c1692181c80806a674a6ca59fa4fc9f9927f51 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 14 Oct 2025 20:58:22 +0200 Subject: [PATCH 03/18] Flow, undone --- .../composed/ComposedSkidTransformer.java | 25 ++ .../skidfuscator/SkidFlowTransformer.java | 308 ++++++++++++++++++ 2 files changed, 333 insertions(+) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java new file mode 100644 index 00000000..fbc0c6e3 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java @@ -0,0 +1,25 @@ +package uwu.narumi.deobfuscator.core.other.composed; + +import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; +import uwu.narumi.deobfuscator.core.other.composed.general.ComposedGeneralFlowTransformer; +import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.NopCleanTransformer; +import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidFlowTransformer; +import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidNumberTransformer; +import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidStringTransformer; +import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalNumberTransformer; + +public class ComposedSkidTransformer extends ComposedTransformer { + + public ComposedSkidTransformer() { + super( + UniversalNumberTransformer::new, + SkidNumberTransformer::new, + () -> new ComposedTransformer(true, + NopCleanTransformer::new, + SkidFlowTransformer::new, + ComposedGeneralFlowTransformer::new + ), + SkidStringTransformer::new + ); + } +} diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java new file mode 100644 index 00000000..47b6d0e7 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java @@ -0,0 +1,308 @@ +package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; + +import org.objectweb.asm.tree.*; +import uwu.narumi.deobfuscator.api.asm.ClassWrapper; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.MethodRef; +import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.JumpMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class SkidFlowTransformer extends Transformer { + + /** + * Useless storing vars: + * getstatic java/lang/System.out Ljava/io/PrintStream; + * astore v29 - useless + * invokestatic pack/tests/basics/accu/Digi.hwahaewjduusqug ()[B + * iload i39 + * invokestatic pack/tests/basics/accu/Digi.shmyiqcznk ([BI)Ljava/lang/String; + * astore v36 - useless + * aload v29 - useless + * aload v36 - useless + * invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + */ + Match uselessStoring = SequenceMatch.of( + Match.of(ctx -> true), + OpcodeMatch.of(ASTORE).capture("store-1"), + OpcodeMatch.of(LDC), + OpcodeMatch.of(ASTORE).capture("store-2"), + OpcodeMatch.of(ALOAD).capture("load-1"), + OpcodeMatch.of(ALOAD).capture("load-2"), + MethodMatch.create() + ); + + Match switchJump = SequenceMatch.of( + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), + OpcodeMatch.of(LOOKUPSWITCH).capture("switch") + ); + + Match ldcPredicateTryCatch = SequenceMatch.of( + NumberMatch.numInteger().capture("salt"), + OpcodeMatch.of(ISTORE).capture("store"), + OpcodeMatch.of(ILOAD).capture("load"), + MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), + NumberMatch.numInteger().capture("comparator"), + JumpMatch.of().capture("jump"), + OpcodeMatch.of(ACONST_NULL), + OpcodeMatch.of(ATHROW) + ); + + /** + * Jump conditional loop + * ldc 574275566 + * invokestatic qvpewqdjuboryazl/wnvkiiljelvpkhzf.jlkfagybberpshgu (I)I + * ldc 427176201 + * if_icmpeq L + */ + Match jumpConditionalLoop = SequenceMatch.of( + NumberMatch.numInteger().capture("start"), + MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), + NumberMatch.numInteger().capture("comparator"), + JumpMatch.of().capture("jump-1"), + JumpMatch.of().capture("jump-2") + ); + + Match staticDecryption = SequenceMatch.of( + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method") + ); + + Match selfClassXor = SequenceMatch.of( + NumberMatch.numInteger().capture("salt1"), + NumberMatch.numInteger().capture("salt2"), + MethodMatch.invokeStatic().desc("(II)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method") + ); + + Match setVarJump = SequenceMatch.of( + NumberMatch.numInteger().capture("salt1"), + OpcodeMatch.of(ISTORE).capture("var"), + JumpMatch.of().capture("jump") + ); + + /** + * Trash tcb + * P: + // try-start: range=[P-Q] handler=Q:java/io/IOException + new java/io/IOException + dup + invokespecial java/io/IOException. ()V + athrow + Q: + // try-end: range=[P-Q] handler=Q:java/io/IOException + // try-handler: range=[P-Q] handler=Q:java/io/IOException + pop + ldc 982899003 + istore i140 + goto S + **/ + Match trashTcb = SequenceMatch.of( + Match.of(ctx -> ctx.insn() instanceof LabelNode).capture("label"), + OpcodeMatch.of(NEW), + OpcodeMatch.of(DUP), + OpcodeMatch.of(INVOKESPECIAL), + OpcodeMatch.of(ATHROW), + Match.of(ctx -> ctx.insn() instanceof LabelNode), + OpcodeMatch.of(POP) + ).doNotSkipLabels(); + + + @Override + protected void transform() throws Exception { + ClassWrapper decryptStaticClass = scopedClasses().stream().filter(classWrapper -> classWrapper.name().length() == 33 && (classWrapper.methods().size() == 3 || classWrapper.methods().size() == 2) && classWrapper.methods().stream().map(methodNode -> methodNode.desc).allMatch(desc -> desc.equals("(I)I"))).findFirst().get(); + String method1Name = decryptStaticClass.findMethod(methodNode -> NumberMatch.of(31).findFirstMatch(MethodContext.of(decryptStaticClass, methodNode)) != null).get().name; + scopedClasses().forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext = MethodContext.of(classWrapper, methodNode); + + uselessStoring.findAllMatches(methodContext).forEach(matchContext -> { + VarInsnNode store1 = (VarInsnNode) matchContext.captures().get("store-1").insn(); + VarInsnNode store2 = (VarInsnNode) matchContext.captures().get("store-2").insn(); + VarInsnNode load1 = (VarInsnNode) matchContext.captures().get("load-1").insn(); + VarInsnNode load2 = (VarInsnNode) matchContext.captures().get("load-2").insn(); + if (store1.var == load1.var && store2.var == load2.var) { + if (Arrays.stream(methodNode.instructions.toArray()).filter(insn -> !insn.equals(load1)).noneMatch(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode)insn).var == store1.var)) { + methodNode.instructions.remove(store1); + methodNode.instructions.remove(load1); + methodNode.instructions.remove(store2); + methodNode.instructions.remove(load2); + markChange(); + } + } + }); + + switchJump.findAllMatches(methodContext).forEach(matchContext -> { + int salt = matchContext.captures().get("salt").insn().asInteger(); + MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); + methodNode.instructions.remove(methodInsnNode); + + methodNode.instructions.set(matchContext.captures().get("salt").insn(), new LdcInsnNode(method1Name.equals(methodInsnNode.name) ? m1(salt) : m2_m3(salt))); + markChange(); + }); + + Set toRemove = new HashSet<>(); + Set fakeLabels = new HashSet<>(); + ldcPredicateTryCatch.findAllMatches(methodContext).forEach(matchContext -> { + int salt = m1(matchContext.captures().get("salt").insn().asInteger()); + int comparator = matchContext.captures().get("comparator").insn().asInteger(); + int storeVar = ((VarInsnNode)matchContext.captures().get("store").insn()).var; + int loadVar = ((VarInsnNode)matchContext.captures().get("load").insn()).var; + if (salt == comparator && storeVar == loadVar) { + toRemove.addAll(matchContext.collectedInsns()); + toRemove.remove(matchContext.captures().get("salt").insn()); + toRemove.remove(matchContext.captures().get("store").insn()); + AbstractInsnNode labelNode = matchContext.captures().get("jump").insn().asJump().label; + fakeLabels.add((LabelNode) labelNode); + fakeLabels.add((LabelNode) matchContext.captures().get("load").insn().getPrevious()); + while (labelNode.getNext() != null && !(labelNode.getNext() instanceof LabelNode)) { + toRemove.add(labelNode.getNext()); + labelNode = labelNode.getNext(); + } + while (labelNode.getNext() != null && labelNode.getOpcode() != POP) { + labelNode = labelNode.getNext(); + } + toRemove.add(labelNode); + markChange(); + } + }); + trashTcb.findAllMatches(methodContext).forEach(matchContext -> { + toRemove.addAll(matchContext.collectedInsns()); + toRemove.remove(matchContext.captures().get("label").insn()); + fakeLabels.add((LabelNode) matchContext.captures().get("label").insn()); + }); + toRemove.forEach(methodNode.instructions::remove); + methodNode.tryCatchBlocks.removeIf(tcb -> fakeLabels.contains(tcb.start) || fakeLabels.contains(tcb.handler) || fakeLabels.contains(tcb.end)); + jumpConditionalLoop.findAllMatches(methodContext).forEach(matchContext -> { + MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); + int start = method1Name.equals(methodInsnNode.name) ? m1(matchContext.captures().get("start").insn().asInteger()) : m2_m3(matchContext.captures().get("start").insn().asInteger()); + int comparator = matchContext.captures().get("comparator").insn().asInteger(); + JumpInsnNode validJump = matchContext.captures().get("jump-1").insn().asJump(); + JumpInsnNode fakeJump = matchContext.captures().get("jump-2").insn().asJump(); + if (start == comparator) { + validJump = matchContext.captures().get("jump-2").insn().asJump(); + fakeJump = matchContext.captures().get("jump-1").insn().asJump(); + } + methodNode.instructions.insert(validJump, new JumpInsnNode(GOTO, validJump.label)); + matchContext.removeAll(); + AbstractInsnNode fakeJumpTarget = fakeJump.label; + toRemove.clear(); + while (fakeJumpTarget.getNext() != null && !(fakeJumpTarget.getNext() instanceof LabelNode)) { + if (toRemove.contains(fakeJumpTarget)) break; + toRemove.add(fakeJumpTarget.getNext()); + if (fakeJumpTarget.getNext().isJump()) { + fakeJumpTarget = fakeJumpTarget.getNext().asJump().label; + } else { + fakeJumpTarget = fakeJumpTarget.getNext(); + } + } + toRemove.forEach(methodNode.instructions::remove); + markChange(); + }); + staticDecryption.findAllMatches(methodContext).forEach(matchContext -> { + MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); + AbstractInsnNode salt = matchContext.captures().get("salt").insn(); + int decrypted = method1Name.equals(methodInsnNode.name) ? m1(salt.asInteger()) : m2_m3(salt.asInteger()); + methodNode.instructions.set(salt, new LdcInsnNode(decrypted)); + methodNode.instructions.remove(methodInsnNode); + markChange(); + }); + + selfClassXor.findAllMatches(methodContext).forEach(matchContext -> { + MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); + findMethod(classWrapper.classNode(), MethodRef.of(methodInsnNode)).ifPresent(xorMethod -> { + AbstractInsnNode salt1 = matchContext.captures().get("salt1").insn(); + AbstractInsnNode salt2 = matchContext.captures().get("salt2").insn(); + methodNode.instructions.set(salt1, new LdcInsnNode(salt2.asInteger() ^ salt1.asInteger())); + methodNode.instructions.remove(methodInsnNode); + methodNode.instructions.remove(salt2); + markChange(); + }); + }); + + JumpMatch.of().capture("jump").findAllMatches(methodContext).forEach(matchContext -> { + JumpInsnNode jumpInsnNode = matchContext.captures().get("jump").insn().asJump(); + if (jumpInsnNode.label.getNext() instanceof LdcInsnNode intLdc && jumpInsnNode.label.getNext(2) instanceof VarInsnNode varStore && jumpInsnNode.label.getNext(3) instanceof JumpInsnNode jump1) { + methodNode.instructions.remove(varStore); + methodNode.instructions.remove(intLdc); + methodNode.instructions.insert(jump1.label, varStore); + methodNode.instructions.insert(jump1.label, intLdc); + markChange(); + } + LdcInsnNode lastLdcOfLabel = null; + AbstractInsnNode node = jumpInsnNode; + while (node != null && !(node.getNext() instanceof LabelNode)) { + if (node instanceof LdcInsnNode ldc) { + lastLdcOfLabel = ldc; + } + node = node.getNext(); + } + if (lastLdcOfLabel != null) { + LdcInsnNode finalLastLdcOfLabel = lastLdcOfLabel; + setVarJump.findAllMatches(methodContext).forEach(matchContext1 -> { + if (finalLastLdcOfLabel.cst instanceof Integer && matchContext1.captures().get("salt1").insn().asInteger() == (int) finalLastLdcOfLabel.cst) { + VarInsnNode var = (VarInsnNode) matchContext1.captures().get("var").insn(); + methodNode.instructions.insert(matchContext1.captures().get("jump").insn().asJump().label, new VarInsnNode(ISTORE, var.var)); + methodNode.instructions.insert(matchContext1.captures().get("jump").insn().asJump().label, new LdcInsnNode(finalLastLdcOfLabel.cst)); + } + }); + } + }); + + + methodNode.tryCatchBlocks.forEach(tcb -> { + try { + if (tcb.start.getPrevious() instanceof VarInsnNode var && tcb.start.getPrevious(2) instanceof LdcInsnNode ldc) { + if (tcb.handler.getNext() instanceof VarInsnNode varLoad) { + if (var.var == varLoad.var) { + methodNode.instructions.insertBefore(varLoad, new LdcInsnNode(ldc.cst)); + methodNode.instructions.insertBefore(varLoad, new VarInsnNode(ISTORE, var.var)); + markChange(); + } + } + } + if (tcb.end.getNext() instanceof JumpInsnNode jump) { + if (jump.label.getNext() instanceof LdcInsnNode intLdc && jump.label.getNext(2) instanceof VarInsnNode varStore && jump.label.getNext(3) instanceof JumpInsnNode jump1) { + jump.label = jump1.label; + methodNode.instructions.remove(varStore); + methodNode.instructions.remove(intLdc); + methodNode.instructions.remove(jump1); + methodNode.instructions.insert(jump.label, varStore); + methodNode.instructions.insert(jump.label, intLdc); + markChange(); + } + } + if (tcb.end.getNext() instanceof LdcInsnNode intLdc && tcb.end.getNext(2) instanceof VarInsnNode varStore && tcb.end.getNext(3) instanceof JumpInsnNode jump1) { + methodNode.instructions.remove(varStore); + methodNode.instructions.remove(intLdc); + methodNode.instructions.insert(jump1.label, varStore); + methodNode.instructions.insert(jump1.label, intLdc); + markChange(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + }); + })); + } + + + public int m1(int n) { + if (n != 0) { + return (n * 31 >>> 4) % n ^ n >>> 16; + } + return 0; + } + + public int m2_m3(int n) { + return (n & 0xE0000000) >> 29 | n << 3; + } +} From 716a896f8d6921bd103a73636edec8ac068ad0e0 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:13:08 +0200 Subject: [PATCH 04/18] Fix string decryption for non-flow jars --- .../skidfuscator/SkidStringTransformer.java | 122 +++++++++--------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java index 806768df..dd23d90a 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java @@ -38,13 +38,12 @@ public class SkidStringTransformer extends Transformer { protected void transform() throws Exception { scopedClasses().forEach(classWrapper -> { Set trashMethods = new HashSet<>(); - classWrapper.findClInit().ifPresent(clinitNode -> { - MethodContext clinitContext = MethodContext.of(classWrapper, clinitNode); - MethodNode decryptionMethod = classWrapper.methods().stream().filter(methodNode -> methodNode.name.length() == 10 && methodNode.desc.endsWith("I)Ljava/lang/String;")).findFirst().orElse(null); - if (decryptionMethod != null) { - MethodContext methodContext = MethodContext.of(classWrapper, decryptionMethod); - int methodSize = Match.of(ctx -> ctx.insn().isMathOperator()).findAllMatches(methodContext).size(); - if (methodSize == 24) { + classWrapper.methods().stream().filter(methodNode -> methodNode.name.length() == 10 && methodNode.desc.endsWith("I)Ljava/lang/String;")).forEach(decryptionMethod -> { + MethodContext methodContext = MethodContext.of(classWrapper, decryptionMethod); + int methodSize = Match.of(ctx -> ctx.insn().isMathOperator()).findAllMatches(methodContext).size(); + if (methodSize == 24) { + classWrapper.findClInit().ifPresent(clinitNode -> { + MethodContext clinitContext = MethodContext.of(classWrapper, clinitNode); MatchContext byteBufferMatch = fieldPutStaticString.findFirstMatch(clinitContext); MethodNode toRemove; String decryptHash = ByteBuffer.wrap( @@ -88,61 +87,64 @@ protected void transform() throws Exception { matchContext.removeAll(); }); }); - } else if (methodSize == 5) { - if (decryptionMethod.desc.equals("([B[BI)Ljava/lang/String;")) { - classWrapper.methods().forEach(methodNode -> { - MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); - SequenceMatch.of( - MethodMatch.invokeStatic().desc("()[B").capture("byte-array1"), - MethodMatch.invokeStatic().desc("()[B").capture("byte-array2"), - NumberMatch.numInteger().capture("salt"), - MethodMatch.invokeStatic().name(decryptionMethod.name) - ).findAllMatches(methodContext1).forEach(matchContext -> { - int salt = matchContext.captures().get("salt").insn().asInteger(); - MethodNode toRemove1; - byte[] stringBytes = resolveByteArrayFromMethod( - MethodContext.of( - classWrapper, - toRemove1 = findMethod( - classWrapper.classNode(), - MethodRef.of( - matchContext.captures().get("byte-array1").insn().asMethodInsn() - ) - ).get() - ) - ); - trashMethods.add(toRemove1); - byte[] decryptBytes = resolveByteArrayFromMethod( - MethodContext.of( - classWrapper, - toRemove1 = findMethod( - classWrapper.classNode(), - MethodRef.of( - matchContext.captures().get("byte-array2").insn().asMethodInsn() - ) - ).get() - ) - ); - trashMethods.add(toRemove1); - methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method5(stringBytes, decryptBytes, salt))); - markChange(); - matchContext.removeAll(); - }); + }); + } else if (methodSize == 5) { + if (decryptionMethod.desc.equals("([B[BI)Ljava/lang/String;")) { + classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); + SequenceMatch.of( + MethodMatch.invokeStatic().desc("()[B").capture("byte-array1"), + MethodMatch.invokeStatic().desc("()[B").capture("byte-array2"), + NumberMatch.numInteger().capture("salt"), + MethodMatch.invokeStatic().name(decryptionMethod.name) + ).findAllMatches(methodContext1).forEach(matchContext -> { + int salt = matchContext.captures().get("salt").insn().asInteger(); + MethodNode toRemove1; + byte[] stringBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array1").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + byte[] decryptBytes = resolveByteArrayFromMethod( + MethodContext.of( + classWrapper, + toRemove1 = findMethod( + classWrapper.classNode(), + MethodRef.of( + matchContext.captures().get("byte-array2").insn().asMethodInsn() + ) + ).get() + ) + ); + trashMethods.add(toRemove1); + methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method5(stringBytes, decryptBytes, salt))); + markChange(); + matchContext.removeAll(); }); - } else if (decryptionMethod.desc.equals("([BI)Ljava/lang/String;")) { + }); + } else if (decryptionMethod.desc.equals("([BI)Ljava/lang/String;")) { + classWrapper.findClInit().ifPresent(clinitNode -> { + MethodContext clinitContext = MethodContext.of(classWrapper, clinitNode); MatchContext bytesMatch = fieldPutStaticByteArray.findFirstMatch(clinitContext); MethodNode toRemove; byte[] decryptBytes = resolveByteArrayFromMethod( - MethodContext.of( - classWrapper, - toRemove = findMethod( - classWrapper.classNode(), - MethodRef.of( - bytesMatch.captures().get("method").insn().asMethodInsn() - ) - ).get() - ) - ); + MethodContext.of( + classWrapper, + toRemove = findMethod( + classWrapper.classNode(), + MethodRef.of( + bytesMatch.captures().get("method").insn().asMethodInsn() + ) + ).get() + ) + ); classWrapper.methods().forEach(methodNode -> { MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); SequenceMatch.of( @@ -171,10 +173,10 @@ protected void transform() throws Exception { }); trashMethods.add(toRemove); bytesMatch.removeAll(); - } + }); } - trashMethods.add(decryptionMethod); } + trashMethods.add(decryptionMethod); }); classWrapper.methods().removeAll(trashMethods); }); From fe62fb1f74de190cc4b095e291407735dfe0f974 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:56:21 +0200 Subject: [PATCH 05/18] API --- .../deobfuscator/api/asm/matcher/Match.java | 5 +++++ .../deobfuscator/api/helper/AsmHelper.java | 20 +++++++++++++++++++ ...ranchlockCompabilityStringTransformer.java | 20 ------------------- .../GuardProtectorFlowTransformer.java | 20 ------------------- 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/Match.java b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/Match.java index 5872ecbe..cbbdc081 100644 --- a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/Match.java +++ b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/Match.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; /** @@ -72,6 +73,10 @@ public MatchContext findFirstMatch(MethodContext methodContext) { return this.findAllMatches(methodContext).stream().findFirst().orElse(null); } + public Optional findAny(MethodContext methodContext) { + return this.findAllMatches(methodContext).stream().findAny(); + } + /** * @return {@link MatchContext} if matches or {@code null} if it does not match */ diff --git a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/AsmHelper.java b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/AsmHelper.java index c154c5c2..8970f092 100644 --- a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/AsmHelper.java +++ b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/AsmHelper.java @@ -141,6 +141,26 @@ public static AbstractInsnNode toPop(Value value) { return value.getSize() == 1 ? new InsnNode(POP) : new InsnNode(POP2); } + public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) { + InsnList instructions = method.instructions; + + int startIndex = instructions.indexOf(startLabel); + if (startIndex == -1) return false; + + int insnIndex = instructions.indexOf(insn); + if (insnIndex == -1) return false; + + int endIndex = instructions.size(); + for (int i = startIndex + 1; i < instructions.size(); i++) { + if (instructions.get(i) instanceof LabelNode) { + endIndex = i; + break; + } + } + + return insnIndex > startIndex && insnIndex < endIndex; + } + /** * Update method descriptor in the current class, a superclass and interfaces * diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockCompabilityStringTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockCompabilityStringTransformer.java index 8cdcccaa..1dcd6df0 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockCompabilityStringTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockCompabilityStringTransformer.java @@ -248,24 +248,4 @@ public LabelNode getLabelByKey(TableSwitchInsnNode tsi, int key) { int index = key - tsi.min; return tsi.labels.get(index); } - - public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) { - InsnList instructions = method.instructions; - - int startIndex = instructions.indexOf(startLabel); - if (startIndex == -1) return false; - - int insnIndex = instructions.indexOf(insn); - if (insnIndex == -1) return false; - - int endIndex = instructions.size(); - for (int i = startIndex + 1; i < instructions.size(); i++) { - if (instructions.get(i) instanceof LabelNode) { - endIndex = i; - break; - } - } - - return insnIndex > startIndex && insnIndex < endIndex; - } } diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java index e575a40f..3c741251 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java @@ -79,26 +79,6 @@ protected void transform() throws Exception { })); } - public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) { - InsnList instructions = method.instructions; - - int startIndex = instructions.indexOf(startLabel); - if (startIndex == -1) return false; - - int insnIndex = instructions.indexOf(insn); - if (insnIndex == -1) return false; - - int endIndex = instructions.size(); - for (int i = startIndex + 1; i < instructions.size(); i++) { - if (instructions.get(i) instanceof LabelNode) { - endIndex = i; - break; - } - } - - return insnIndex > startIndex && insnIndex < endIndex; - } - boolean hasPutStatic(ClassNode classNode, FieldInsnNode target) { for (MethodNode method : classNode.methods) { for (AbstractInsnNode insn : method.instructions) { From 425d26d51bccd91151b05a9caa371a2311945b72 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:30:10 +0200 Subject: [PATCH 06/18] SkidFuscator's FlowTry-Catch Transformer --- .../SkidTryCatchRemoveTransformer.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java new file mode 100644 index 00000000..aac62e8f --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java @@ -0,0 +1,97 @@ +package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; +import uwu.narumi.deobfuscator.api.asm.ClassWrapper; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.group.AnyMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.JumpMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +import java.util.HashSet; +import java.util.Set; + +public class SkidTryCatchRemoveTransformer extends Transformer { + @Override + protected void transform() throws Exception { + scopedClasses().forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> resolveFakeTcb(classWrapper, methodNode))); + } + + /** + * Skid's transformer basically does some whacky stuff: + * Source: https://github.com/skidfuscatordev/skidfuscator-java-obfuscator/blob/master/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/transform/impl/flow/BasicRangeTransformer.java + * + * Original flow: Obfuscated Flow: + * + * ┌─────────┐ ┌─────────┐ + * │ Block A │ │ Block A │ + * └────┬────┘ └────┬────┘ + * │ │ + * ┌────▼────┐ ┌───────▼────────┐ + * │ Block B │ │ Random If Stmt │ + * └─────────┘ └───────┬────────┘ + * │ + * ┌─────┐◄──┴───►┌─────┐ + * │ Yes │ │ No │ + * └─────┘ └──┬──┘ + * │ + * ┌─────▼─────┐ + * │ Exception │ + * └───────────┘ + * + * ┌─────────────┐ + * │ Exception │ + * │ Catcher │ + * └──────┬──────┘ + * │ + * ┌────▼────┐ + * │ Block B │ + * └─────────┘ + */ + public void resolveFakeTcb(ClassWrapper classWrapper, MethodNode methodNode) { + MethodContext methodContext = MethodContext.of(classWrapper, methodNode); + Set tcbToRemove = new HashSet<>(); + Set toRemove = new HashSet<>(); + methodNode.tryCatchBlocks.forEach(tcb -> { + if (tcb.handler.equals(tcb.end)) { + /* Checking if start block has throw null */ + SequenceMatch.of( + AnyMatch.of(OpcodeMatch.of(ILOAD), OpcodeMatch.of(LDC)).and(Match.of(ctx -> isInsnInLabelRange(methodNode, tcb.start, ctx.insn()))), + MethodMatch.invokeStatic(), + OpcodeMatch.of(LDC), + JumpMatch.of().capture("throw-label"), + OpcodeMatch.of(ACONST_NULL), + OpcodeMatch.of(ATHROW) + ).findAny(methodContext).ifPresent(matchContext -> { + /* Clearing "else" block which throws exception */ + toRemove.addAll(matchContext.collectedInsns()); + LabelNode fakeJump = matchContext.captures().get("throw-label").insn().asJump().label; + SequenceMatch.of( + OpcodeMatch.of(NEW).and(Match.of(ctx -> isInsnInLabelRange(methodNode, fakeJump, ctx.insn()))), + OpcodeMatch.of(DUP), + MethodMatch.invokeSpecial(), + OpcodeMatch.of(ATHROW) + ).findAny(methodContext).ifPresent(matchContext1 -> { + toRemove.addAll(matchContext1.collectedInsns()); + }); + toRemove.add(fakeJump); + AbstractInsnNode abstractInsnNode = fakeJump; + while (abstractInsnNode.getNext() != null && abstractInsnNode.getOpcode() != POP) { + abstractInsnNode = abstractInsnNode.getNext(); + } + toRemove.add(abstractInsnNode); + tcbToRemove.add(tcb); + markChange(); + }); + } + }); + toRemove.forEach(methodNode.instructions::remove); + methodNode.tryCatchBlocks.removeAll(tcbToRemove); + } +} From de38ba8939968ff58ed0456b1a1b549d16ae931e Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:30:21 +0200 Subject: [PATCH 07/18] Fixes to string, and cleanup --- .../impl/skidfuscator/SkidStringTransformer.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java index dd23d90a..4af88bc4 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidStringTransformer.java @@ -41,7 +41,7 @@ protected void transform() throws Exception { classWrapper.methods().stream().filter(methodNode -> methodNode.name.length() == 10 && methodNode.desc.endsWith("I)Ljava/lang/String;")).forEach(decryptionMethod -> { MethodContext methodContext = MethodContext.of(classWrapper, decryptionMethod); int methodSize = Match.of(ctx -> ctx.insn().isMathOperator()).findAllMatches(methodContext).size(); - if (methodSize == 24) { + if (methodSize == 24 || methodSize == 23) { classWrapper.findClInit().ifPresent(clinitNode -> { MethodContext clinitContext = MethodContext.of(classWrapper, clinitNode); MatchContext byteBufferMatch = fieldPutStaticString.findFirstMatch(clinitContext); @@ -59,6 +59,7 @@ protected void transform() throws Exception { ) ) ).asCharBuffer().toString(); + classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals(byteBufferMatch.captures().get("field").insn().asFieldInsn().name)); trashMethods.add(toRemove); byteBufferMatch.removeAll(); classWrapper.methods().forEach(methodNode -> { @@ -88,7 +89,7 @@ protected void transform() throws Exception { }); }); }); - } else if (methodSize == 5) { + } else if (methodSize == 5 || methodSize == 4) { if (decryptionMethod.desc.equals("([B[BI)Ljava/lang/String;")) { classWrapper.methods().forEach(methodNode -> { MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); @@ -112,10 +113,11 @@ protected void transform() throws Exception { ) ); trashMethods.add(toRemove1); + MethodNode toRemove; byte[] decryptBytes = resolveByteArrayFromMethod( MethodContext.of( classWrapper, - toRemove1 = findMethod( + toRemove = findMethod( classWrapper.classNode(), MethodRef.of( matchContext.captures().get("byte-array2").insn().asMethodInsn() @@ -123,7 +125,7 @@ protected void transform() throws Exception { ).get() ) ); - trashMethods.add(toRemove1); + trashMethods.add(toRemove); methodNode.instructions.insertBefore(matchContext.insn(), new LdcInsnNode(method5(stringBytes, decryptBytes, salt))); markChange(); matchContext.removeAll(); @@ -145,6 +147,8 @@ protected void transform() throws Exception { ).get() ) ); + trashMethods.add(toRemove); + classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals(bytesMatch.captures().get("field").insn().asFieldInsn().name)); classWrapper.methods().forEach(methodNode -> { MethodContext methodContext1 = MethodContext.of(classWrapper, methodNode); SequenceMatch.of( @@ -171,7 +175,6 @@ protected void transform() throws Exception { matchContext.removeAll(); }); }); - trashMethods.add(toRemove); bytesMatch.removeAll(); }); } From a3e0fc915e8730f652696ee9af81d5c7e261c58a Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:30:32 +0200 Subject: [PATCH 08/18] Rewrite flow transformer --- .../skidfuscator/SkidFlowTransformer.java | 252 ++++-------------- 1 file changed, 46 insertions(+), 206 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java index 47b6d0e7..a14d0276 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidFlowTransformer.java @@ -5,6 +5,7 @@ import uwu.narumi.deobfuscator.api.asm.MethodContext; import uwu.narumi.deobfuscator.api.asm.MethodRef; import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.MatchContext; import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; import uwu.narumi.deobfuscator.api.asm.matcher.impl.JumpMatch; import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; @@ -12,66 +13,11 @@ import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; import uwu.narumi.deobfuscator.api.transformer.Transformer; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class SkidFlowTransformer extends Transformer { - /** - * Useless storing vars: - * getstatic java/lang/System.out Ljava/io/PrintStream; - * astore v29 - useless - * invokestatic pack/tests/basics/accu/Digi.hwahaewjduusqug ()[B - * iload i39 - * invokestatic pack/tests/basics/accu/Digi.shmyiqcznk ([BI)Ljava/lang/String; - * astore v36 - useless - * aload v29 - useless - * aload v36 - useless - * invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - */ - Match uselessStoring = SequenceMatch.of( - Match.of(ctx -> true), - OpcodeMatch.of(ASTORE).capture("store-1"), - OpcodeMatch.of(LDC), - OpcodeMatch.of(ASTORE).capture("store-2"), - OpcodeMatch.of(ALOAD).capture("load-1"), - OpcodeMatch.of(ALOAD).capture("load-2"), - MethodMatch.create() - ); - - Match switchJump = SequenceMatch.of( - NumberMatch.numInteger().capture("salt"), - MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), - OpcodeMatch.of(LOOKUPSWITCH).capture("switch") - ); - - Match ldcPredicateTryCatch = SequenceMatch.of( - NumberMatch.numInteger().capture("salt"), - OpcodeMatch.of(ISTORE).capture("store"), - OpcodeMatch.of(ILOAD).capture("load"), - MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), - NumberMatch.numInteger().capture("comparator"), - JumpMatch.of().capture("jump"), - OpcodeMatch.of(ACONST_NULL), - OpcodeMatch.of(ATHROW) - ); - - /** - * Jump conditional loop - * ldc 574275566 - * invokestatic qvpewqdjuboryazl/wnvkiiljelvpkhzf.jlkfagybberpshgu (I)I - * ldc 427176201 - * if_icmpeq L - */ - Match jumpConditionalLoop = SequenceMatch.of( - NumberMatch.numInteger().capture("start"), - MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method"), - NumberMatch.numInteger().capture("comparator"), - JumpMatch.of().capture("jump-1"), - JumpMatch.of().capture("jump-2") - ); - Match staticDecryption = SequenceMatch.of( NumberMatch.numInteger().capture("salt"), MethodMatch.invokeStatic().desc("(I)I").and(Match.of(ctx -> ctx.insn().asMethodInsn().name.length() == 16)).capture("predicate-method") @@ -89,132 +35,18 @@ public class SkidFlowTransformer extends Transformer { JumpMatch.of().capture("jump") ); - /** - * Trash tcb - * P: - // try-start: range=[P-Q] handler=Q:java/io/IOException - new java/io/IOException - dup - invokespecial java/io/IOException. ()V - athrow - Q: - // try-end: range=[P-Q] handler=Q:java/io/IOException - // try-handler: range=[P-Q] handler=Q:java/io/IOException - pop - ldc 982899003 - istore i140 - goto S - **/ - Match trashTcb = SequenceMatch.of( - Match.of(ctx -> ctx.insn() instanceof LabelNode).capture("label"), - OpcodeMatch.of(NEW), - OpcodeMatch.of(DUP), - OpcodeMatch.of(INVOKESPECIAL), - OpcodeMatch.of(ATHROW), - Match.of(ctx -> ctx.insn() instanceof LabelNode), - OpcodeMatch.of(POP) - ).doNotSkipLabels(); + private static ClassWrapper decryptStaticClass; + private static String method1Name; @Override protected void transform() throws Exception { - ClassWrapper decryptStaticClass = scopedClasses().stream().filter(classWrapper -> classWrapper.name().length() == 33 && (classWrapper.methods().size() == 3 || classWrapper.methods().size() == 2) && classWrapper.methods().stream().map(methodNode -> methodNode.desc).allMatch(desc -> desc.equals("(I)I"))).findFirst().get(); - String method1Name = decryptStaticClass.findMethod(methodNode -> NumberMatch.of(31).findFirstMatch(MethodContext.of(decryptStaticClass, methodNode)) != null).get().name; + if (decryptStaticClass == null) decryptStaticClass = scopedClasses().stream().filter(classWrapper -> classWrapper.name().length() == 33 && (classWrapper.methods().size() == 3 || classWrapper.methods().size() == 2) && classWrapper.methods().stream().map(methodNode -> methodNode.desc).allMatch(desc -> desc.equals("(I)I"))).findFirst().get(); + if (method1Name == null) method1Name = decryptStaticClass.findMethod(methodNode -> NumberMatch.of(31).findFirstMatch(MethodContext.of(decryptStaticClass, methodNode)) != null).get().name; scopedClasses().forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { MethodContext methodContext = MethodContext.of(classWrapper, methodNode); - uselessStoring.findAllMatches(methodContext).forEach(matchContext -> { - VarInsnNode store1 = (VarInsnNode) matchContext.captures().get("store-1").insn(); - VarInsnNode store2 = (VarInsnNode) matchContext.captures().get("store-2").insn(); - VarInsnNode load1 = (VarInsnNode) matchContext.captures().get("load-1").insn(); - VarInsnNode load2 = (VarInsnNode) matchContext.captures().get("load-2").insn(); - if (store1.var == load1.var && store2.var == load2.var) { - if (Arrays.stream(methodNode.instructions.toArray()).filter(insn -> !insn.equals(load1)).noneMatch(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode)insn).var == store1.var)) { - methodNode.instructions.remove(store1); - methodNode.instructions.remove(load1); - methodNode.instructions.remove(store2); - methodNode.instructions.remove(load2); - markChange(); - } - } - }); - - switchJump.findAllMatches(methodContext).forEach(matchContext -> { - int salt = matchContext.captures().get("salt").insn().asInteger(); - MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); - methodNode.instructions.remove(methodInsnNode); - - methodNode.instructions.set(matchContext.captures().get("salt").insn(), new LdcInsnNode(method1Name.equals(methodInsnNode.name) ? m1(salt) : m2_m3(salt))); - markChange(); - }); - - Set toRemove = new HashSet<>(); - Set fakeLabels = new HashSet<>(); - ldcPredicateTryCatch.findAllMatches(methodContext).forEach(matchContext -> { - int salt = m1(matchContext.captures().get("salt").insn().asInteger()); - int comparator = matchContext.captures().get("comparator").insn().asInteger(); - int storeVar = ((VarInsnNode)matchContext.captures().get("store").insn()).var; - int loadVar = ((VarInsnNode)matchContext.captures().get("load").insn()).var; - if (salt == comparator && storeVar == loadVar) { - toRemove.addAll(matchContext.collectedInsns()); - toRemove.remove(matchContext.captures().get("salt").insn()); - toRemove.remove(matchContext.captures().get("store").insn()); - AbstractInsnNode labelNode = matchContext.captures().get("jump").insn().asJump().label; - fakeLabels.add((LabelNode) labelNode); - fakeLabels.add((LabelNode) matchContext.captures().get("load").insn().getPrevious()); - while (labelNode.getNext() != null && !(labelNode.getNext() instanceof LabelNode)) { - toRemove.add(labelNode.getNext()); - labelNode = labelNode.getNext(); - } - while (labelNode.getNext() != null && labelNode.getOpcode() != POP) { - labelNode = labelNode.getNext(); - } - toRemove.add(labelNode); - markChange(); - } - }); - trashTcb.findAllMatches(methodContext).forEach(matchContext -> { - toRemove.addAll(matchContext.collectedInsns()); - toRemove.remove(matchContext.captures().get("label").insn()); - fakeLabels.add((LabelNode) matchContext.captures().get("label").insn()); - }); - toRemove.forEach(methodNode.instructions::remove); - methodNode.tryCatchBlocks.removeIf(tcb -> fakeLabels.contains(tcb.start) || fakeLabels.contains(tcb.handler) || fakeLabels.contains(tcb.end)); - jumpConditionalLoop.findAllMatches(methodContext).forEach(matchContext -> { - MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); - int start = method1Name.equals(methodInsnNode.name) ? m1(matchContext.captures().get("start").insn().asInteger()) : m2_m3(matchContext.captures().get("start").insn().asInteger()); - int comparator = matchContext.captures().get("comparator").insn().asInteger(); - JumpInsnNode validJump = matchContext.captures().get("jump-1").insn().asJump(); - JumpInsnNode fakeJump = matchContext.captures().get("jump-2").insn().asJump(); - if (start == comparator) { - validJump = matchContext.captures().get("jump-2").insn().asJump(); - fakeJump = matchContext.captures().get("jump-1").insn().asJump(); - } - methodNode.instructions.insert(validJump, new JumpInsnNode(GOTO, validJump.label)); - matchContext.removeAll(); - AbstractInsnNode fakeJumpTarget = fakeJump.label; - toRemove.clear(); - while (fakeJumpTarget.getNext() != null && !(fakeJumpTarget.getNext() instanceof LabelNode)) { - if (toRemove.contains(fakeJumpTarget)) break; - toRemove.add(fakeJumpTarget.getNext()); - if (fakeJumpTarget.getNext().isJump()) { - fakeJumpTarget = fakeJumpTarget.getNext().asJump().label; - } else { - fakeJumpTarget = fakeJumpTarget.getNext(); - } - } - toRemove.forEach(methodNode.instructions::remove); - markChange(); - }); - staticDecryption.findAllMatches(methodContext).forEach(matchContext -> { - MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); - AbstractInsnNode salt = matchContext.captures().get("salt").insn(); - int decrypted = method1Name.equals(methodInsnNode.name) ? m1(salt.asInteger()) : m2_m3(salt.asInteger()); - methodNode.instructions.set(salt, new LdcInsnNode(decrypted)); - methodNode.instructions.remove(methodInsnNode); - markChange(); - }); - + /* Example: var4 = afglgogiwinhilog(var4, 1845606652); */ selfClassXor.findAllMatches(methodContext).forEach(matchContext -> { MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); findMethod(classWrapper.classNode(), MethodRef.of(methodInsnNode)).ifPresent(xorMethod -> { @@ -227,6 +59,20 @@ protected void transform() throws Exception { }); }); + /** Example + * ldc 952006311 + * invokestatic ikjlkypytwnvkuzi/erfobcthglyygbhq.jwmyqfvhltjhsidh (I)I + * */ + staticDecryption.findAllMatches(methodContext).forEach(matchContext -> { + MethodInsnNode methodInsnNode = matchContext.captures().get("predicate-method").insn().asMethodInsn(); + AbstractInsnNode salt = matchContext.captures().get("salt").insn(); + int decrypted = method1Name.equals(methodInsnNode.name) ? m1(salt.asInteger()) : m2_m3(salt.asInteger()); + methodNode.instructions.set(salt, new LdcInsnNode(decrypted)); + methodNode.instructions.remove(methodInsnNode); + markChange(); + }); + + /* Its moving hash LDC out of context for example, when IF/ELSE ends with same LDC and InlineVariable cant push var to next instructions because it has no context */ JumpMatch.of().capture("jump").findAllMatches(methodContext).forEach(matchContext -> { JumpInsnNode jumpInsnNode = matchContext.captures().get("jump").insn().asJump(); if (jumpInsnNode.label.getNext() instanceof LdcInsnNode intLdc && jumpInsnNode.label.getNext(2) instanceof VarInsnNode varStore && jumpInsnNode.label.getNext(3) instanceof JumpInsnNode jump1) { @@ -256,44 +102,38 @@ protected void transform() throws Exception { } }); - - methodNode.tryCatchBlocks.forEach(tcb -> { - try { - if (tcb.start.getPrevious() instanceof VarInsnNode var && tcb.start.getPrevious(2) instanceof LdcInsnNode ldc) { - if (tcb.handler.getNext() instanceof VarInsnNode varLoad) { - if (var.var == varLoad.var) { - methodNode.instructions.insertBefore(varLoad, new LdcInsnNode(ldc.cst)); - methodNode.instructions.insertBefore(varLoad, new VarInsnNode(ISTORE, var.var)); - markChange(); + if (!isChanged()) { + MatchContext matchContext = SequenceMatch.of(NumberMatch.numInteger().capture("hash"), OpcodeMatch.of(ISTORE).capture("param"), Match.of(ctx -> ctx.insn() instanceof LabelNode).capture("label")).doNotSkipLabels().findFirstMatch(methodContext); + if (matchContext != null) { + int salt = matchContext.captures().get("hash").insn().asInteger(); + int param = ((VarInsnNode)matchContext.captures().get("param").insn()).var; + LabelNode label = (LabelNode) matchContext.captures().get("label").insn(); + if (label.getNext() instanceof JumpInsnNode jumpInsnNode) label = jumpInsnNode.label; + if (blessedLabels.contains(label)) return; + LabelNode finalLabel = label; + methodNode.tryCatchBlocks.forEach(tcb -> { + if (finalLabel.equals(tcb.start) || finalLabel.equals(tcb.handler) || finalLabel.equals(tcb.end)) { + methodNode.instructions.insert(tcb.start, new VarInsnNode(ISTORE, param)); + methodNode.instructions.insert(tcb.start, new LdcInsnNode(salt)); + methodNode.instructions.insert(tcb.handler, new VarInsnNode(ISTORE, param)); + methodNode.instructions.insert(tcb.handler, new LdcInsnNode(salt)); + methodNode.instructions.insert(tcb.end, new VarInsnNode(ISTORE, param)); + methodNode.instructions.insert(tcb.end, new LdcInsnNode(salt)); + blessedLabels.add(tcb.start); + blessedLabels.add(tcb.handler); + blessedLabels.add(tcb.end); } - } - } - if (tcb.end.getNext() instanceof JumpInsnNode jump) { - if (jump.label.getNext() instanceof LdcInsnNode intLdc && jump.label.getNext(2) instanceof VarInsnNode varStore && jump.label.getNext(3) instanceof JumpInsnNode jump1) { - jump.label = jump1.label; - methodNode.instructions.remove(varStore); - methodNode.instructions.remove(intLdc); - methodNode.instructions.remove(jump1); - methodNode.instructions.insert(jump.label, varStore); - methodNode.instructions.insert(jump.label, intLdc); - markChange(); - } - } - if (tcb.end.getNext() instanceof LdcInsnNode intLdc && tcb.end.getNext(2) instanceof VarInsnNode varStore && tcb.end.getNext(3) instanceof JumpInsnNode jump1) { - methodNode.instructions.remove(varStore); - methodNode.instructions.remove(intLdc); - methodNode.instructions.insert(jump1.label, varStore); - methodNode.instructions.insert(jump1.label, intLdc); + }); + methodNode.instructions.insert(label, new VarInsnNode(ISTORE, param)); + methodNode.instructions.insert(label, new LdcInsnNode(salt)); markChange(); + blessedLabels.add(label); } - - } catch (Exception e) { - e.printStackTrace(); - } - }); + } })); } + private final static Set blessedLabels = new HashSet<>(); public int m1(int n) { if (n != 0) { From 555d0fa219d0310d8b62de3ecd56e498d637f798 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:30:47 +0200 Subject: [PATCH 09/18] Clean skidfuscator's trash --- .../skidfuscator/SkidCleanTransformer.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java new file mode 100644 index 00000000..65f16039 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java @@ -0,0 +1,124 @@ +package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import uwu.narumi.deobfuscator.api.asm.ClassWrapper; +import uwu.narumi.deobfuscator.api.asm.FieldRef; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.matcher.Match; +import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.FieldMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class SkidCleanTransformer extends Transformer { + + /** + * Useless storing vars: + * getstatic java/lang/System.out Ljava/io/PrintStream; + * astore v29 - useless + * invokestatic pack/tests/basics/accu/Digi.hwahaewjduusqug ()[B + * iload i39 + * invokestatic pack/tests/basics/accu/Digi.shmyiqcznk ([BI)Ljava/lang/String; + * astore v36 - useless + * aload v29 - useless + * aload v36 - useless + * invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + */ + Match uselessStoring = SequenceMatch.of( + Match.of(ctx -> true), + OpcodeMatch.of(ASTORE).capture("store-1"), + OpcodeMatch.of(LDC), + OpcodeMatch.of(ASTORE).capture("store-2"), + OpcodeMatch.of(ALOAD).capture("load-1"), + OpcodeMatch.of(ALOAD).capture("load-2"), + MethodMatch.create() + ); + + @Override + protected void transform() throws Exception { + /* Delete static decryption class */ + ClassWrapper decryptStaticClass = scopedClasses().stream().filter(classWrapper -> classWrapper.name().length() == 33 && (classWrapper.methods().size() == 3 || classWrapper.methods().size() == 2) && classWrapper.methods().stream().map(methodNode -> methodNode.desc).allMatch(desc -> desc.equals("(I)I"))).findFirst().get(); + context().getClassesMap().remove(decryptStaticClass.name()); + scopedClasses().forEach(classWrapper -> { + /* Clean ASCII aheagos/etc */ + findClInit(classWrapper.classNode()).ifPresent(clinit -> { + AbstractInsnNode firstInsn = clinit.instructions.getFirst(); + boolean hasASCII = false; + while (firstInsn.getNext() != null) { + if (firstInsn.isInteger() && firstInsn.getNext().getOpcode() == ANEWARRAY && firstInsn.getNext(2).asFieldInsn().name.equalsIgnoreCase("nothing_to_see_here")) { + hasASCII = true; + break; + } + firstInsn = firstInsn.getNext(); + } + + Set toRemove = new HashSet<>(); + if (hasASCII) { + toRemove.add(firstInsn); + toRemove.add(firstInsn.getNext()); + toRemove.add(firstInsn.getNext(2)); + firstInsn = firstInsn.getNext(3); + while (firstInsn != null && firstInsn.getOpcode() == GETSTATIC && firstInsn.getNext() != null && firstInsn.getNext().isInteger() && firstInsn.getNext(2) != null && firstInsn.getNext(2).isString() && firstInsn.getNext(3) != null && firstInsn.getNext(3).getOpcode() == AASTORE) { + toRemove.add(firstInsn); + toRemove.add(firstInsn.getNext()); + toRemove.add(firstInsn.getNext(2)); + toRemove.add(firstInsn.getNext(3)); + firstInsn = firstInsn.getNext(4); + } + toRemove.forEach(clinit.instructions::remove); + classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals("nothing_to_see_here") && fieldNode.desc.equals("[Ljava/lang/String;")); + markChange(); + } + }); + + /* Clear hash-int */ + classWrapper.fields().removeIf(fieldNode -> { + boolean matchField = isAccess(fieldNode.access, ACC_PRIVATE, ACC_TRANSIENT) && fieldNode.desc.equals("I"); + if (matchField) { + classWrapper.methods().forEach(methodNode1 -> { + if (methodNode1.name.equals("")) { + SequenceMatch.of( + NumberMatch.of(), + FieldMatch.putField().fieldRef(FieldRef.of(classWrapper.classNode(), fieldNode)) + ).findAny(MethodContext.of(classWrapper, methodNode1)).ifPresent(matchContext -> { + matchContext.removeAll(); + markChange(); + }); + } + }); + } + return matchField; + }); + + /* Clear self-class-xor from flow-obfuscation */ + classWrapper.methods().removeIf(methodNode -> methodNode.name.length() == 16 && isAccess(methodNode.access, ACC_PRIVATE, ACC_STATIC) && methodNode.desc.equals("(II)I") && methodNode.instructions.size() == 4); + + classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext = MethodContext.of(classWrapper, methodNode); + + uselessStoring.findAllMatches(methodContext).forEach(matchContext -> { + VarInsnNode store1 = (VarInsnNode) matchContext.captures().get("store-1").insn(); + VarInsnNode store2 = (VarInsnNode) matchContext.captures().get("store-2").insn(); + VarInsnNode load1 = (VarInsnNode) matchContext.captures().get("load-1").insn(); + VarInsnNode load2 = (VarInsnNode) matchContext.captures().get("load-2").insn(); + if (store1.var == load1.var && store2.var == load2.var) { + if (Arrays.stream(methodNode.instructions.toArray()).filter(insn -> !insn.equals(load1)).noneMatch(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode)insn).var == store1.var)) { + methodNode.instructions.remove(store1); + methodNode.instructions.remove(load1); + methodNode.instructions.remove(store2); + methodNode.instructions.remove(load2); + markChange(); + } + } + }); + }); + }); + } +} From 7708523a9f045e03070cf36bd3b4ad59589cb555 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:30:53 +0200 Subject: [PATCH 10/18] ComposedSkidTransformer --- .../composed/ComposedSkidTransformer.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java index fbc0c6e3..9cecd622 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java @@ -1,11 +1,11 @@ package uwu.narumi.deobfuscator.core.other.composed; import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; -import uwu.narumi.deobfuscator.core.other.composed.general.ComposedGeneralFlowTransformer; -import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.NopCleanTransformer; -import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidFlowTransformer; -import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidNumberTransformer; -import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.SkidStringTransformer; +import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.*; +import uwu.narumi.deobfuscator.core.other.impl.pool.InlineLocalVariablesTransformer; +import uwu.narumi.deobfuscator.core.other.impl.pool.InlineStaticFieldTransformer; +import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.*; +import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalFlowTransformer; import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalNumberTransformer; public class ComposedSkidTransformer extends ComposedTransformer { @@ -14,12 +14,25 @@ public ComposedSkidTransformer() { super( UniversalNumberTransformer::new, SkidNumberTransformer::new, + SkidTryCatchRemoveTransformer::new, + InlineStaticFieldTransformer::new, () -> new ComposedTransformer(true, + InlineLocalVariablesTransformer::new, /* Passthrough Hash */ + SkidFlowTransformer::new, /* Resolve SkidFuscator's Flow */ + + UniversalFlowTransformer::new, /* Solve SkidFuscator's Switches/Jumps */ + NopCleanTransformer::new, - SkidFlowTransformer::new, - ComposedGeneralFlowTransformer::new + UnUsedLabelCleanTransformer::new, + UselessGotosCleanTransformer::new, + + () -> new ComposedTransformer(true, + PopUnUsedLocalVariablesTransformer::new, + UselessPopCleanTransformer::new + ) ), - SkidStringTransformer::new + SkidStringTransformer::new, + SkidCleanTransformer::new ); } } From c6264cadb66fe529d73cb1f100912980aa796549 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:35:52 +0200 Subject: [PATCH 11/18] tests --- .../deobfuscator/TestDeobfuscation.java | 5 + .../compiled/custom-jars/skidfuscator.jar | Bin 0 -> 113539 bytes .../custom-jars/skidfuscator/pack/Clazz.dec | 4 + .../custom-jars/skidfuscator/pack/Main.dec | 171 ++++++++++++++++++ .../pack/tests/basics/accu/Digi.dec | 22 +++ .../pack/tests/basics/cross/Abst1.dec | 9 + .../pack/tests/basics/cross/Inte.dec | 5 + .../pack/tests/basics/cross/Top.dec | 16 ++ .../pack/tests/basics/ctrl/Ctrl.dec | 40 ++++ .../pack/tests/basics/inner/Exec.dec | 27 +++ .../pack/tests/basics/inner/Test.dec | 16 ++ .../pack/tests/basics/overwirte/Face.dec | 5 + .../pack/tests/basics/overwirte/Sub.dec | 17 ++ .../pack/tests/basics/overwirte/Super.dec | 7 + .../pack/tests/basics/runable/Exec.dec | 21 +++ .../pack/tests/basics/runable/Pool.dec | 16 ++ .../pack/tests/basics/runable/Task.dec | 106 +++++++++++ .../pack/tests/basics/sub/SolAdd.dec | 8 + .../pack/tests/basics/sub/Solver.dec | 11 ++ .../pack/tests/basics/sub/flo.dec | 7 + .../pack/tests/basics/sub/med.dec | 11 ++ .../skidfuscator/pack/tests/bench/Calc.dec | 60 ++++++ .../pack/tests/reflects/annot/anno.dec | 11 ++ .../pack/tests/reflects/annot/annoe.dec | 34 ++++ .../pack/tests/reflects/annot/annot.dec | 19 ++ .../pack/tests/reflects/counter/Count.dec | 14 ++ .../pack/tests/reflects/counter/Countee.dec | 20 ++ .../pack/tests/reflects/field/FObject.dec | 94 ++++++++++ .../pack/tests/reflects/field/FTest.dec | 44 +++++ .../pack/tests/reflects/loader/LRun.dec | 16 ++ .../pack/tests/reflects/loader/LTest.dec | 31 ++++ .../pack/tests/reflects/loader/Loader.dec | 77 ++++++++ .../pack/tests/reflects/res/Accesor.dec | 68 +++++++ .../pack/tests/reflects/retrace/Tracee.dec | 27 +++ .../pack/tests/reflects/retrace/Tracer.dec | 13 ++ .../pack/tests/security/SecExec.dec | 7 + .../pack/tests/security/SecTest.dec | 39 ++++ .../skidfuscator/pack/tests/security/Sman.dec | 14 ++ 38 files changed, 1112 insertions(+) create mode 100644 testData/compiled/custom-jars/skidfuscator.jar create mode 100644 testData/results/custom-jars/skidfuscator/pack/Clazz.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/Main.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/accu/Digi.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/cross/Abst1.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/cross/Inte.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/cross/Top.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/ctrl/Ctrl.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/inner/Exec.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/inner/Test.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/overwirte/Face.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/overwirte/Sub.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/overwirte/Super.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/runable/Exec.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/runable/Pool.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/runable/Task.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/SolAdd.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/Solver.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/flo.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/med.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/bench/Calc.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/anno.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annoe.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annot.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Count.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Countee.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FObject.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FTest.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LRun.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LTest.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/Loader.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/res/Accesor.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracee.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracer.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/security/SecExec.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/security/SecTest.dec create mode 100644 testData/results/custom-jars/skidfuscator/pack/tests/security/Sman.dec diff --git a/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java b/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java index b192baff..8dee30f3 100644 --- a/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java +++ b/deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java @@ -239,5 +239,10 @@ protected void registerAll() { .transformers(ComposedGuardProtectorTransformer::new) .inputClass(InputType.CUSTOM_CLASS, "guardprotector/Class951.class") .register(); + + test("SkidFuscator 2.0.11 - Pure hash encryption") + .transformers(ComposedSkidTransformer::new) + .inputJar("skidfuscator.jar") + .register(); } } diff --git a/testData/compiled/custom-jars/skidfuscator.jar b/testData/compiled/custom-jars/skidfuscator.jar new file mode 100644 index 0000000000000000000000000000000000000000..d67314f2450cc493f990a995c087553f632337e8 GIT binary patch literal 113539 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

  • }m6lr&Y!A3mfidHWh@TIpp&#XMe{3ou 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 (II)V + // 0b: aload 2 + // 0c: astore 4 + // 0e: new pack/tests/basics/runable/Exec + // 11: astore 8 + // 13: aload 8 + // 15: bipush 3 + // 16: ldc 1800938360 + // 18: invokespecial pack/tests/basics/runable/Exec. (II)V + // 1b: aload 8 + // 1d: astore 5 + // 1f: new pack/tests/basics/runable/Exec + // 22: astore 9 + // 24: aload 9 + // 26: bipush 100 + // 28: ldc 1800938360 + // 2a: invokespecial pack/tests/basics/runable/Exec. (II)V + // 2d: aload 9 + // 2f: astore 6 + // 31: getstatic pack/tests/basics/runable/Pool.tpe Ljava/util/concurrent/ThreadPoolExecutor; + // 34: astore 10 + // 36: aload 5 + // 38: astore 30 + // 3a: aload 30 + // 3c: invokevirtual java/lang/Object.getClass ()Ljava/lang/Class; + // 3f: pop + // 40: aload 30 + // 42: invokedynamic run (Lpack/tests/basics/runable/Exec;)Ljava/lang/Runnable; bsm=java/lang/invoke/LambdaMetafactory.metafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; args=[ ()V, pack/tests/basics/runable/Exec.doAdd ()V, ()V ] + // 47: astore 31 + // 49: aload 10 + // 4b: aload 31 + // 4d: invokevirtual java/util/concurrent/ThreadPoolExecutor.submit (Ljava/lang/Runnable;)Ljava/util/concurrent/Future; + // 50: pop + // 51: ldc2_w 50 + // 54: invokestatic java/lang/Thread.sleep (J)V + // 57: goto a1 + // 5a: pop + // 5b: getstatic pack/tests/basics/runable/Pool.tpe Ljava/util/concurrent/ThreadPoolExecutor; + // 5e: astore 15 + // 60: aload 4 + // 62: invokedynamic run (Lpack/tests/basics/runable/Exec;)Ljava/lang/Runnable; bsm=java/lang/invoke/LambdaMetafactory.metafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; args=[ ()V, pack/tests/basics/runable/Task.lambda$run$0 (Lpack/tests/basics/runable/Exec;)V, ()V ] + // 67: astore 33 + // 69: aload 15 + // 6b: aload 33 + // 6d: invokevirtual java/util/concurrent/ThreadPoolExecutor.submit (Ljava/lang/Runnable;)Ljava/util/concurrent/Future; + // 70: pop + // 71: ldc2_w 50 + // 74: invokestatic java/lang/Thread.sleep (J)V + // 77: goto 9e + // 7a: pop + // 7b: getstatic pack/tests/basics/runable/Pool.tpe Ljava/util/concurrent/ThreadPoolExecutor; + // 7e: astore 20 + // 80: aload 6 + // 82: astore 34 + // 84: aload 34 + // 86: invokevirtual java/lang/Object.getClass ()Ljava/lang/Class; + // 89: pop + // 8a: aload 34 + // 8c: invokedynamic run (Lpack/tests/basics/runable/Exec;)Ljava/lang/Runnable; bsm=java/lang/invoke/LambdaMetafactory.metafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; args=[ ()V, pack/tests/basics/runable/Exec.doAdd ()V, ()V ] + // 91: astore 35 + // 93: aload 20 + // 95: aload 35 + // 97: invokevirtual java/util/concurrent/ThreadPoolExecutor.submit (Ljava/lang/Runnable;)Ljava/util/concurrent/Future; + // 9a: pop + // 9b: goto a7 + // 9e: goto 7b + // a1: goto 5b + // a4: goto 5a + // a7: goto b4 + // aa: pop + // ab: getstatic pack/tests/basics/runable/Exec.i I + // ae: bipush 10 + // b0: iadd + // b1: putstatic pack/tests/basics/runable/Exec.i I + // b4: ldc2_w 300 + // b7: invokestatic java/lang/Thread.sleep (J)V + // ba: getstatic pack/tests/basics/runable/Exec.i I + // bd: bipush 30 + // bf: if_icmpne cd + // c2: getstatic java/lang/System.out Ljava/io/PrintStream; + // c5: ldc "PASS" + // c7: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // ca: goto d5 + // cd: getstatic java/lang/System.out Ljava/io/PrintStream; + // d0: ldc "FAIL" + // d2: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // d5: return + // d6: goto 7a + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/SolAdd.dec b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/SolAdd.dec new file mode 100644 index 00000000..0a40227d --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/SolAdd.dec @@ -0,0 +1,8 @@ +package pack.tests.basics.sub; + +public class SolAdd { + public static int get(int var0) { + med var1 = new med(1, 2, 1753962384); + return var1.result; + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/Solver.dec b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/Solver.dec new file mode 100644 index 00000000..65269381 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/Solver.dec @@ -0,0 +1,11 @@ +package pack.tests.basics.sub; + +public class Solver { + public Solver() { + if (SolAdd.get(1227979901) == 3) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/flo.dec b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/flo.dec new file mode 100644 index 00000000..879bfef8 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/flo.dec @@ -0,0 +1,7 @@ +package pack.tests.basics.sub; + +class flo { + int solve(int var1, int var2, int var3) { + return var1 + var2; + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/med.dec b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/med.dec new file mode 100644 index 00000000..3dd485b1 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/basics/sub/med.dec @@ -0,0 +1,11 @@ +package pack.tests.basics.sub; + +class med { + int result; + + med(int var1, int var2, int var3) { + flo var5 = new flo(); + int var8 = var5.solve(var1, var2, 638043422); + this.result = var8; + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/bench/Calc.dec b/testData/results/custom-jars/skidfuscator/pack/tests/bench/Calc.dec new file mode 100644 index 00000000..9d9ae81d --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/bench/Calc.dec @@ -0,0 +1,60 @@ +package pack.tests.bench; + +import java.io.PrintStream; + +public class Calc { + public static int count = 0; + + public static void runAll(int var0) { + long var6 = System.currentTimeMillis(); + + for (int var8 = 0; var8 < 10000; var8++) { + call(100, 1301919330); + runAdd(1390077608); + runStr(1564474936); + } + + PrintStream var11 = System.out; + StringBuilder var15 = new StringBuilder(); + String var21 = "Calc: "; + StringBuilder var16 = var15.append(var21); + long var22 = System.currentTimeMillis(); + long var24 = var22 - var6; + String var19 = var16.append(var24).append("ms").toString(); + var11.println(var19); + if (count != 30000) { + String var27 = "[ERROR]: Errors occurred in calc!"; + RuntimeException var13 = new RuntimeException(var27); + throw var13; + } + } + + private static void call(int var0, int var1) { + if (var0 == 0) { + count++; + } else { + call(var0 - 1, 1301919330); + } + } + + private static void runAdd(int var0) { + double var6 = 0.0; + + while (var6 < 100.1) { + var6 += 0.99; + } + + count++; + } + + private static void runStr(int var0) { + String var3 = ""; + + while (var3.length() < 101) { + StringBuilder var8 = new StringBuilder(); + var3 = var8.append(var3).append("ax").toString(); + } + + count++; + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/anno.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/anno.dec new file mode 100644 index 00000000..4149deff --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/anno.dec @@ -0,0 +1,11 @@ +package pack.tests.reflects.annot; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface anno { + String val() default "yes"; + + String val2() default "yes"; +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annoe.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annoe.dec new file mode 100644 index 00000000..378cd289 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annoe.dec @@ -0,0 +1,34 @@ +package pack.tests.reflects.annot; + +import java.io.PrintStream; +import java.lang.reflect.Field; + +public class annoe { + @anno( + val = "PASS" + ) + private static final String fail = "WHAT"; + + @anno + public void dox() throws Exception { + String var3 = "FAIL"; + + for (Field var7 : annoe.class.getDeclaredFields()) { + var7.setAccessible(true); + anno var8 = var7.getAnnotation(anno.class); + if (var8 != null) { + var3 = var8.val(); + } + } + + PrintStream var15 = System.out; + var15.println(var3); + } + + @anno( + val = "no" + ) + public void dov() { + System.out.println("FAIL"); + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annot.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annot.dec new file mode 100644 index 00000000..baaeece5 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/annot/annot.dec @@ -0,0 +1,19 @@ +package pack.tests.reflects.annot; + +import java.lang.reflect.Method; + +public class annot { + public void run(int var1) throws Exception { + annoe var2 = new annoe(); + annoe var4 = var2; + + for (Method var8 : annoe.class.getDeclaredMethods()) { + var8.setAccessible(true); + anno var9 = var8.getAnnotation(anno.class); + if (var9 != null && var9.val().equals("yes")) { + Object[] var34 = new Object[0]; + var8.invoke(var4, var34); + } + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Count.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Count.dec new file mode 100644 index 00000000..e2e645d3 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Count.dec @@ -0,0 +1,14 @@ +package pack.tests.reflects.counter; + +public class Count { + public void run(int var1) throws Throwable { + if (Countee.class.getFields().length == 1 + && Countee.class.getDeclaredFields().length == 4 + && Countee.class.getMethods().length > 4 + && Countee.class.getDeclaredMethods().length == 4) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Countee.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Countee.dec new file mode 100644 index 00000000..f8806a75 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/counter/Countee.dec @@ -0,0 +1,20 @@ +package pack.tests.reflects.counter; + +public class Countee { + public int cpuli = 0; + protected int cprot = 0; + int cpackp = 1; + private int cpriv = 0; + + public void mpuli() { + } + + public void mprot() { + } + + public void mpackp() { + } + + public void mpriv() { + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FObject.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FObject.dec new file mode 100644 index 00000000..31c568d2 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FObject.dec @@ -0,0 +1,94 @@ +package pack.tests.reflects.field; + +public class FObject { + private int i; + + private FObject(int var1) { + this.i = var1; + } + + private void add() { + int var4 = this.i + 3; + this.i = var4; + } + + private static byte[] gnmdizzzuakykcp() { + return new byte[]{ + 75, + 69, + 68, + 109, + 32, + 34, + 65, + 13, + 108, + 25, + 57, + 69, + 59, + 81, + 87, + 122, + 49, + 17, + 46, + 45, + 85, + 91, + 51, + 45, + 76, + 97, + 91, + 81, + 11, + 52, + 45, + 91, + 64, + 4, + 76, + 112, + 94, + 12, + 21, + 44, + 8, + 4, + 120, + 57, + 58, + 102, + 26, + 64, + 126, + 126, + 49, + 60, + 69, + 18, + 24, + 34, + 81, + 58, + 2, + 105, + 1, + 95, + 24, + 106, + 65, + 21, + 74, + 83, + 44, + 59, + 104, + 82, + 17, + 39, + 3 + }; + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FTest.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FTest.dec new file mode 100644 index 00000000..20979c29 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/field/FTest.dec @@ -0,0 +1,44 @@ +package pack.tests.reflects.field; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class FTest { + public void run(int var1) throws Exception { + Class[] var36 = new Class[1]; + Class var5 = int.class; + var36[0] = var5; + Constructor var6 = FObject.class.getDeclaredConstructor(var36); + if (var6.isAccessible()) { + System.out.println("FAIL"); + } else { + var6.setAccessible(true); + Object[] var40 = new Object[1]; + Integer var57 = 1; + var40[0] = var57; + FObject var7 = (FObject)var6.newInstance(var40); + String var41 = "add"; + Method var8 = FObject.class.getDeclaredMethod(var41, null); + if (var8.isAccessible()) { + System.out.println("FAIL"); + } else { + var8.setAccessible(true); + Object[] var54 = new Object[0]; + var8.invoke(var7, var54); + String var45 = "i"; + Field var9 = FObject.class.getDeclaredField(var45); + if (var9.isAccessible()) { + System.out.println("FAIL"); + } else { + var9.setAccessible(true); + if (var9.getInt(var7) != 4) { + System.out.println("FAIL"); + } else { + System.out.println("PASS"); + } + } + } + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LRun.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LRun.dec new file mode 100644 index 00000000..bd8bb6a2 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LRun.dec @@ -0,0 +1,16 @@ +package pack.tests.reflects.loader; + +import java.lang.reflect.Method; + +public class LRun { + public void run(int var1) throws Exception { + Loader var2 = new Loader(); + Class var5 = var2.findClass("pack.tests.reflects.loader.LTest"); + Object var6 = var5.newInstance(); + String var15 = "run"; + Class[] var17 = new Class[0]; + Method var12 = var5.getMethod(var15, var17); + Object[] var19 = new Object[0]; + var12.invoke(var6, var19); + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LTest.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LTest.dec new file mode 100644 index 00000000..f13f4eeb --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/LTest.dec @@ -0,0 +1,31 @@ +package pack.tests.reflects.loader; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; + +public class LTest { + public static byte[] readAllBytes(InputStream var0, int var1) throws IOException { + ByteArrayOutputStream var2 = new ByteArrayOutputStream(); + ByteArrayOutputStream var5 = var2; + byte[] var6 = new byte[1024]; + + while (true) { + int var11 = var0.read(var6); + if (var11 == -1) { + return var5.toByteArray(); + } + + var5.write(var6, 0, var11); + } + } + + public void run() throws Exception { + PrintStream var1 = System.out; + String var4 = "TEST"; + byte[] var6 = readAllBytes(LTest.class.getResourceAsStream(var4), 1160298099); + String var2 = new String(var6); + var1.println(var2); + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/Loader.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/Loader.dec new file mode 100644 index 00000000..b5e3e309 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/loader/Loader.dec @@ -0,0 +1,77 @@ +package pack.tests.reflects.loader; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +public class Loader extends ClassLoader { + public static byte[] readAllBytes(InputStream param0, int param1) { + // $VF: Couldn't be decompiled + // Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!) + // java.lang.RuntimeException: parsing failure! + // at org.jetbrains.java.decompiler.modules.decompiler.decompose.DomHelper.parseGraph(DomHelper.java:211) + // at org.jetbrains.java.decompiler.main.rels.MethodProcessor.codeToJava(MethodProcessor.java:166) + // + // Bytecode: + // 00: new java/io/ByteArrayOutputStream + // 03: astore 2 + // 04: aload 2 + // 05: invokespecial java/io/ByteArrayOutputStream. ()V + // 08: aload 2 + // 09: astore 5 + // 0b: sipush 1024 + // 0e: newarray 8 + // 10: astore 6 + // 12: aload 0 + // 13: astore 10 + // 15: aload 6 + // 17: astore 17 + // 19: aload 10 + // 1b: aload 17 + // 1d: invokevirtual java/io/InputStream.read ([B)I + // 20: istore 11 + // 22: iload 11 + // 24: istore 7 + // 26: iload 11 + // 28: bipush -1 + // 29: if_icmpeq 52 + // 2c: aload 5 + // 2e: astore 16 + // 30: aload 6 + // 32: astore 19 + // 34: iload 7 + // 36: istore 4 + // 38: aload 16 + // 3a: aload 19 + // 3c: bipush 0 + // 3d: iload 4 + // 3f: invokevirtual java/io/ByteArrayOutputStream.write ([BII)V + // 42: goto 4f + // 45: aload 5 + // 47: invokevirtual java/io/ByteArrayOutputStream.toByteArray ()[B + // 4a: astore 13 + // 4c: aload 13 + // 4e: areturn + // 4f: goto 12 + // 52: goto 45 + // 55: pop + // 56: aconst_null + // 57: areturn + } + + @Override + public InputStream getResourceAsStream(String var1) { + if (var1.contains("TEST")) { + byte[] var10 = "PASS".getBytes(); + return new ByteArrayInputStream(var10); + } else { + return super.getResourceAsStream(var1); + } + } + + @Override + public Class findClass(String var1) throws ClassNotFoundException { + byte[] var7 = readAllBytes(Loader.class.getClassLoader().getResourceAsStream("pack/tests/reflects/loader/LTest.class"), 52053976); + int var14 = var7.length; + return this.defineClass(var1, var7, 0, var14); + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/res/Accesor.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/res/Accesor.dec new file mode 100644 index 00000000..d75cb75f --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/res/Accesor.dec @@ -0,0 +1,68 @@ +package pack.tests.reflects.res; + +public class Accesor { + public void run(int param1) { + // $VF: Couldn't be decompiled + // Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!) + // java.lang.RuntimeException: parsing failure! + // at org.jetbrains.java.decompiler.modules.decompiler.decompose.DomHelper.parseGraph(DomHelper.java:211) + // at org.jetbrains.java.decompiler.main.rels.MethodProcessor.codeToJava(MethodProcessor.java:166) + // + // Bytecode: + // 00: ldc "/pack/tests/reflects/res/file" + // 02: astore 3 + // 03: ldc pack/tests/reflects/res/Accesor + // 05: aload 3 + // 06: invokevirtual java/lang/Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; + // 09: invokevirtual java/io/InputStream.read ()I + // 0c: bipush 97 + // 0e: if_icmpeq 7e + // 11: new java/lang/RuntimeException + // 14: astore 19 + // 16: aload 19 + // 18: invokespecial java/lang/RuntimeException. ()V + // 1b: aload 19 + // 1d: athrow + // 1e: ldc "file2" + // 20: astore 21 + // 22: ldc pack/tests/reflects/res/Accesor + // 24: aload 21 + // 26: invokevirtual java/lang/Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; + // 29: invokevirtual java/io/InputStream.read ()I + // 2c: bipush 114 + // 2e: if_icmpeq 68 + // 31: new java/lang/RuntimeException + // 34: astore 18 + // 36: aload 18 + // 38: invokespecial java/lang/RuntimeException. ()V + // 3b: aload 18 + // 3d: athrow + // 3e: ldc pack/tests/reflects/res/Accesor + // 40: invokevirtual java/lang/Class.getClassLoader ()Ljava/lang/ClassLoader; + // 43: ldc "pack/tests/reflects/res/file3" + // 45: invokevirtual java/lang/ClassLoader.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; + // 48: invokevirtual java/io/InputStream.read ()I + // 4b: bipush 99 + // 4d: if_icmpeq 7b + // 50: new java/lang/RuntimeException + // 53: astore 14 + // 55: aload 14 + // 57: invokespecial java/lang/RuntimeException. ()V + // 5a: aload 14 + // 5c: athrow + // 5d: getstatic java/lang/System.out Ljava/io/PrintStream; + // 60: ldc "PASS" + // 62: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 65: goto 6e + // 68: goto 3e + // 6b: goto 71 + // 6e: goto 7a + // 71: pop + // 72: getstatic java/lang/System.out Ljava/io/PrintStream; + // 75: ldc "FAIL" + // 77: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 7a: return + // 7b: goto 5d + // 7e: goto 1e + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracee.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracee.dec new file mode 100644 index 00000000..9f012bd9 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracee.dec @@ -0,0 +1,27 @@ +package pack.tests.reflects.retrace; + +import java.lang.reflect.Method; + +public class Tracee { + public static int p = 0; + + private void doTrace(int var1, int var2) throws Exception { + p++; + Throwable var11 = new Throwable(); + String var19 = var11.getStackTrace()[1].getMethodName(); + Class[] var21 = new Class[1]; + Class var7 = int.class; + var21[0] = var7; + Method var15 = Tracee.class.getDeclaredMethod(var19, var21); + Object[] var23 = new Object[1]; + Integer var27 = var1 - 1; + var23[0] = var27; + var15.invoke(this, var23); + } + + public void toTrace(int var1, int var2) throws Exception { + if (var1 != 0) { + this.doTrace(var1, 2090156866); + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracer.dec b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracer.dec new file mode 100644 index 00000000..afa2678f --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/reflects/retrace/Tracer.dec @@ -0,0 +1,13 @@ +package pack.tests.reflects.retrace; + +public class Tracer { + public void run(int var1) throws Exception { + Tracee var2 = new Tracee(); + var2.toTrace(5, 1697579845); + if (Tracee.p == 5) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/security/SecExec.dec b/testData/results/custom-jars/skidfuscator/pack/tests/security/SecExec.dec new file mode 100644 index 00000000..009cef2a --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/security/SecExec.dec @@ -0,0 +1,7 @@ +package pack.tests.security; + +public class SecExec { + private static void doShutdown() { + System.exit(-1); + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/security/SecTest.dec b/testData/results/custom-jars/skidfuscator/pack/tests/security/SecTest.dec new file mode 100644 index 00000000..fe4a4ac8 --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/security/SecTest.dec @@ -0,0 +1,39 @@ +package pack.tests.security; + +import java.lang.reflect.Method; + +public class SecTest { + public void run(int var1) { + Sman var2 = new Sman(); + System.setSecurityManager(var2); + System.out.print("FAIL"); + + try { + String var27 = "doShutdown"; + Class[] var32 = new Class[0]; + Method var4 = SecExec.class.getDeclaredMethod(var27, var32); + var4.setAccessible(true); + Object[] var34 = new Object[0]; + var4.invoke(null, var34); + } catch (Throwable var35) { + Throwable var6 = var35; + + while (true) { + Throwable var5 = var6.getCause(); + if (var5 == null) { + String var7 = var6.getMessage(); + if (var7 == null) { + return; + } + + if (var7.contains("HOOK")) { + System.out.println("\b\b\b\bPASS"); + } + break; + } + + var6 = var5; + } + } + } +} diff --git a/testData/results/custom-jars/skidfuscator/pack/tests/security/Sman.dec b/testData/results/custom-jars/skidfuscator/pack/tests/security/Sman.dec new file mode 100644 index 00000000..93ed13ec --- /dev/null +++ b/testData/results/custom-jars/skidfuscator/pack/tests/security/Sman.dec @@ -0,0 +1,14 @@ +package pack.tests.security; + +import java.security.Permission; + +public class Sman extends SecurityManager { + @Override + public void checkPermission(Permission var1) { + if (var1.getName().contains("exitVM")) { + String var4 = "HOOKED"; + SecurityException var7 = new SecurityException(var4); + throw var7; + } + } +} From 0f04b2216eea4694dbd22cf58839c84fb4cee819 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:37:43 +0200 Subject: [PATCH 12/18] Better Try-Catch handling for aggresive nested FlowException --- .../SkidTryCatchRemoveTransformer.java | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java index aac62e8f..b2381384 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidTryCatchRemoveTransformer.java @@ -1,9 +1,6 @@ package uwu.narumi.deobfuscator.core.other.impl.skidfuscator; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.TryCatchBlockNode; +import org.objectweb.asm.tree.*; import uwu.narumi.deobfuscator.api.asm.ClassWrapper; import uwu.narumi.deobfuscator.api.asm.MethodContext; import uwu.narumi.deobfuscator.api.asm.matcher.Match; @@ -59,37 +56,40 @@ public void resolveFakeTcb(ClassWrapper classWrapper, MethodNode methodNode) { Set tcbToRemove = new HashSet<>(); Set toRemove = new HashSet<>(); methodNode.tryCatchBlocks.forEach(tcb -> { - if (tcb.handler.equals(tcb.end)) { - /* Checking if start block has throw null */ - SequenceMatch.of( - AnyMatch.of(OpcodeMatch.of(ILOAD), OpcodeMatch.of(LDC)).and(Match.of(ctx -> isInsnInLabelRange(methodNode, tcb.start, ctx.insn()))), - MethodMatch.invokeStatic(), - OpcodeMatch.of(LDC), - JumpMatch.of().capture("throw-label"), - OpcodeMatch.of(ACONST_NULL), - OpcodeMatch.of(ATHROW) - ).findAny(methodContext).ifPresent(matchContext -> { - /* Clearing "else" block which throws exception */ - toRemove.addAll(matchContext.collectedInsns()); - LabelNode fakeJump = matchContext.captures().get("throw-label").insn().asJump().label; + /* Checking if start block has throw null */ + SequenceMatch.of( + AnyMatch.of(OpcodeMatch.of(ILOAD), OpcodeMatch.of(LDC)).and(Match.of(ctx -> isInsnInLabelRange(methodNode, tcb.start, ctx.insn()))), + MethodMatch.invokeStatic(), + OpcodeMatch.of(LDC), + JumpMatch.of().capture("throw-label"), + OpcodeMatch.of(ACONST_NULL), + OpcodeMatch.of(ATHROW) + ).or( SequenceMatch.of( - OpcodeMatch.of(NEW).and(Match.of(ctx -> isInsnInLabelRange(methodNode, fakeJump, ctx.insn()))), + OpcodeMatch.of(NEW).and(Match.of(ctx -> isInsnInLabelRange(methodNode, tcb.start, ctx.insn()))), OpcodeMatch.of(DUP), MethodMatch.invokeSpecial(), OpcodeMatch.of(ATHROW) - ).findAny(methodContext).ifPresent(matchContext1 -> { - toRemove.addAll(matchContext1.collectedInsns()); - }); + ) + ).findAny(methodContext).ifPresent(matchContext -> { + /* Clearing "else" block which throws exception */ + toRemove.addAll(matchContext.collectedInsns()); + LabelNode fakeJump; + if (matchContext.captures().containsKey("throw-label")) { + fakeJump = matchContext.captures().get("throw-label").insn().asJump().label; toRemove.add(fakeJump); - AbstractInsnNode abstractInsnNode = fakeJump; - while (abstractInsnNode.getNext() != null && abstractInsnNode.getOpcode() != POP) { - abstractInsnNode = abstractInsnNode.getNext(); - } - toRemove.add(abstractInsnNode); - tcbToRemove.add(tcb); - markChange(); - }); - } + } else { + fakeJump = tcb.handler; + } + AbstractInsnNode abstractInsnNode = fakeJump; + while (abstractInsnNode.getNext() != null && abstractInsnNode.getOpcode() != POP) { + abstractInsnNode = abstractInsnNode.getNext(); + } + toRemove.add(abstractInsnNode); + tcbToRemove.add(tcb); + methodNode.instructions.insert(tcb.start, new JumpInsnNode(GOTO, tcb.handler)); + markChange(); + }); }); toRemove.forEach(methodNode.instructions::remove); methodNode.tryCatchBlocks.removeAll(tcbToRemove); From ca7369c38380616813d2a42b1697bcb9198e01e6 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:38:04 +0200 Subject: [PATCH 13/18] Better Try-Catch handling for aggresive nested FlowException --- .../core/other/composed/ComposedSkidTransformer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java index 9cecd622..64d660a1 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java @@ -1,6 +1,7 @@ package uwu.narumi.deobfuscator.core.other.composed; import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; +import uwu.narumi.deobfuscator.core.other.composed.general.ComposedGeneralFlowTransformer; import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.*; import uwu.narumi.deobfuscator.core.other.impl.pool.InlineLocalVariablesTransformer; import uwu.narumi.deobfuscator.core.other.impl.pool.InlineStaticFieldTransformer; @@ -15,6 +16,7 @@ public ComposedSkidTransformer() { UniversalNumberTransformer::new, SkidNumberTransformer::new, SkidTryCatchRemoveTransformer::new, + ComposedGeneralFlowTransformer::new, InlineStaticFieldTransformer::new, () -> new ComposedTransformer(true, InlineLocalVariablesTransformer::new, /* Passthrough Hash */ From cc5a6fac01f098fab9d630083567c59eab4e03b5 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:03:09 +0200 Subject: [PATCH 14/18] Clean fix check --- .../core/other/impl/skidfuscator/SkidCleanTransformer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java index 65f16039..01a99435 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/skidfuscator/SkidCleanTransformer.java @@ -52,7 +52,7 @@ protected void transform() throws Exception { AbstractInsnNode firstInsn = clinit.instructions.getFirst(); boolean hasASCII = false; while (firstInsn.getNext() != null) { - if (firstInsn.isInteger() && firstInsn.getNext().getOpcode() == ANEWARRAY && firstInsn.getNext(2).asFieldInsn().name.equalsIgnoreCase("nothing_to_see_here")) { + if (firstInsn.isInteger() && firstInsn.getNext().getOpcode() == ANEWARRAY && firstInsn.getNext(2).isFieldInsn() && firstInsn.getNext(2).asFieldInsn().name.equalsIgnoreCase("nothing_to_see_here")) { hasASCII = true; break; } From 022c27abe1a86dd6af9fc9e2c57c6788ff3cdf64 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:47:04 +0100 Subject: [PATCH 15/18] Fix for gp flow --- .../GuardProtectorFlowTransformer.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java index 3c741251..6734f580 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java @@ -32,8 +32,7 @@ protected void transform() throws Exception { flowVarStore.findAllMatches(methodContext).forEach(varStore -> { FieldInsnNode fieldInsn = varStore.captures().get("stored-type").insn().asFieldInsn(); if (!hasPutStatic(classWrapper.classNode(), fieldInsn)) { -// FieldRef fieldRef = FieldRef.of(fieldInsn); //This doesn`t work. Fields are still present in classes (maybe because they are private static final) -// context().removeField(fieldRef); + classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals(fieldInsn.name) && fieldNode.desc.equals(fieldInsn.desc)); boolean ifNeJump = fieldInsn.desc.equals("Z"); int varIndex = ((VarInsnNode) varStore.captures().get("stored-var").insn()).var; toRemove.addAll(varStore.collectedInsns()); @@ -41,16 +40,7 @@ protected void transform() throws Exception { int loadedVarIndex = ((VarInsnNode) jumpEquation.captures().get("loaded-var").insn()).var; JumpInsnNode jump = jumpEquation.captures().get("stored-jump").insn().asJump(); if ((ifNeJump && jump.getOpcode() == IFNE) || (!ifNeJump && jump.getOpcode() == IFEQ) && varIndex == loadedVarIndex) { -// if (jump.label != null) { -// toRemove.add(jump.label); -// markChange(); -// methodNode.instructions.forEach(insn -> { -// if (isInsnInLabelRange(methodNode, jump.label, insn)) { -// toRemove.add(insn); -// } -// }); -// } - methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label)); + //methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label)); toRemove.addAll(jumpEquation.collectedInsns()); markChange(); } From 01e31d42c4770715813a750e8d81e62bb11557a8 Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:49:15 +0100 Subject: [PATCH 16/18] Skid javadocs --- .../core/other/composed/ComposedSkidTransformer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java index 64d660a1..18c74cbc 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java @@ -9,6 +9,11 @@ import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalFlowTransformer; import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalNumberTransformer; +/** + * SkidFuscator 2.0.11 Community version + * https://github.com/skidfuscatordev/skidfuscator-java-obfuscator + */ + public class ComposedSkidTransformer extends ComposedTransformer { public ComposedSkidTransformer() { From e05287fadcd935c26078ba32b600c14075cfcbfe Mon Sep 17 00:00:00 2001 From: Dawid <50593784+Animowany@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:19:45 +0100 Subject: [PATCH 17/18] tests --- testData/results/custom-classes/guardprotector/Class951.dec | 2 -- 1 file changed, 2 deletions(-) diff --git a/testData/results/custom-classes/guardprotector/Class951.dec b/testData/results/custom-classes/guardprotector/Class951.dec index d5b138c9..f319b5c0 100644 --- a/testData/results/custom-classes/guardprotector/Class951.dec +++ b/testData/results/custom-classes/guardprotector/Class951.dec @@ -16,8 +16,6 @@ public class Class951 { private static final ScheduledExecutorService field2971 = Executors.newScheduledThreadPool(1); private static int field2972 = 325170080; private static long[] field2973; - private static final int field2974; - private static final int field2975; @Class295 public static synchronized void method3419(Class320 var0) { From a6132220657205d94bbb348ef8791bc26c352dfe Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 <62206933+EpicPlayerA10@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:35:11 +0100 Subject: [PATCH 18/18] asd --- .../core/other/composed/ComposedSkidTransformer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java index 18c74cbc..1983ef4d 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedSkidTransformer.java @@ -13,7 +13,6 @@ * SkidFuscator 2.0.11 Community version * https://github.com/skidfuscatordev/skidfuscator-java-obfuscator */ - public class ComposedSkidTransformer extends ComposedTransformer { public ComposedSkidTransformer() {