From 6df4ec1edf8005e79bcc59994cb1bc375b0bb68e Mon Sep 17 00:00:00 2001 From: SpigotRCE <128710385+SpigotRCE@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:10:17 +0530 Subject: [PATCH 1/2] feat: EmptyArrayLengthTransformer --- .../universal/UniversalNumberTransformer.java | 3 +- .../number/EmptyArrayLengthTransformer.java | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/UniversalNumberTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/UniversalNumberTransformer.java index 5386fe3f..589d4d1c 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/UniversalNumberTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/UniversalNumberTransformer.java @@ -2,7 +2,7 @@ import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.UselessPopCleanTransformer; -import uwu.narumi.deobfuscator.core.other.impl.universal.number.InlineConstantValuesTransformer; +import uwu.narumi.deobfuscator.core.other.impl.universal.number.*; /** * Simplifies number operations on constant values. @@ -11,6 +11,7 @@ public class UniversalNumberTransformer extends ComposedTransformer { public UniversalNumberTransformer() { super( InlineConstantValuesTransformer::new, + EmptyArrayLengthTransformer::new, UselessPopCleanTransformer::new ); diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java new file mode 100644 index 00000000..42b7b0d8 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java @@ -0,0 +1,49 @@ +package uwu.narumi.deobfuscator.core.other.impl.universal.number; + +import org.objectweb.asm.tree.*; +import uwu.narumi.deobfuscator.api.helper.AsmHelper; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +public class EmptyArrayLengthTransformer extends Transformer { + @Override + protected void transform() throws Exception { + scopedClasses().parallelStream() + .forEach(classWrapper -> classWrapper.methods().parallelStream().forEach(methodNode -> { + InsnList list = methodNode.instructions; + list.forEach(insn -> { + if (insn.getOpcode() == ARRAYLENGTH) { + AbstractInsnNode arrayInsn = insn.getPrevious(); + if (arrayInsn != null && arrayInsn.getOpcode() == NEWARRAY) { + AbstractInsnNode sizeInsn = arrayInsn.getPrevious(); + Integer constValue = getInt(sizeInsn); + if (constValue != null) { + list.set(insn, AsmHelper.numberInsn(constValue)); + list.remove(arrayInsn); + list.remove(sizeInsn); + } + } + } + }); + })); + } + + private Integer getInt(AbstractInsnNode insn) { + if (insn instanceof InsnNode) { + switch (insn.getOpcode()) { + case ICONST_M1: return -1; + case ICONST_0: return 0; + case ICONST_1: return 1; + case ICONST_2: return 2; + case ICONST_3: return 3; + case ICONST_4: return 4; + case ICONST_5: return 5; + } + } else if (insn instanceof IntInsnNode iinsn) { + return iinsn.operand; + } else if (insn instanceof LdcInsnNode linsn) { + Object cst = linsn.cst; + if (cst instanceof Integer) return (Integer) cst; + } + return null; + } +} From 3f577be68ba156f22b7398b5446e81d48d72e757 Mon Sep 17 00:00:00 2001 From: SpigotRCE <128710385+SpigotRCE@users.noreply.github.com> Date: Sat, 25 Oct 2025 16:18:07 +0530 Subject: [PATCH 2/2] use contexts and frame matches in empty-array-length-transformer and mark changes when made --- .../number/EmptyArrayLengthTransformer.java | 56 +++++-------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java index 42b7b0d8..a71125b4 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/number/EmptyArrayLengthTransformer.java @@ -1,49 +1,23 @@ package uwu.narumi.deobfuscator.core.other.impl.universal.number; -import org.objectweb.asm.tree.*; -import uwu.narumi.deobfuscator.api.helper.AsmHelper; +import uwu.narumi.deobfuscator.api.asm.MethodContext; +import uwu.narumi.deobfuscator.api.asm.matcher.impl.*; import uwu.narumi.deobfuscator.api.transformer.Transformer; public class EmptyArrayLengthTransformer extends Transformer { - @Override - protected void transform() throws Exception { - scopedClasses().parallelStream() - .forEach(classWrapper -> classWrapper.methods().parallelStream().forEach(methodNode -> { - InsnList list = methodNode.instructions; - list.forEach(insn -> { - if (insn.getOpcode() == ARRAYLENGTH) { - AbstractInsnNode arrayInsn = insn.getPrevious(); - if (arrayInsn != null && arrayInsn.getOpcode() == NEWARRAY) { - AbstractInsnNode sizeInsn = arrayInsn.getPrevious(); - Integer constValue = getInt(sizeInsn); - if (constValue != null) { - list.set(insn, AsmHelper.numberInsn(constValue)); - list.remove(arrayInsn); - list.remove(sizeInsn); - } - } - } + @Override protected void transform() throws Exception { + scopedClasses().forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { + MethodContext methodContext = MethodContext.of(classWrapper, methodNode); + OpcodeMatch.of(ARRAYLENGTH) + .and(FrameMatch.stack(0, + OpcodeMatch.of(NEWARRAY).and(FrameMatch.stack(0, NumberMatch.numInteger().capture("array-length"))))) + .findAllMatches(methodContext) + .forEach(matchContext -> { + methodNode.instructions.insert(matchContext.insn(), + numberInsn(matchContext.captures().get("array-length").insn().asInteger())); + matchContext.removeAll(); + markChange(); }); - })); - } - - private Integer getInt(AbstractInsnNode insn) { - if (insn instanceof InsnNode) { - switch (insn.getOpcode()) { - case ICONST_M1: return -1; - case ICONST_0: return 0; - case ICONST_1: return 1; - case ICONST_2: return 2; - case ICONST_3: return 3; - case ICONST_4: return 4; - case ICONST_5: return 5; - } - } else if (insn instanceof IntInsnNode iinsn) { - return iinsn.operand; - } else if (insn instanceof LdcInsnNode linsn) { - Object cst = linsn.cst; - if (cst instanceof Integer) return (Integer) cst; - } - return null; + })); } }