From e31db4a1707de3b720ccd3a15156ca26bb14c881 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 Date: Mon, 26 Aug 2024 17:46:44 +0200 Subject: [PATCH 1/3] Also account iinc --- .../peephole/PopUnUsedLocalVariablesTransformer.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/PopUnUsedLocalVariablesTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/PopUnUsedLocalVariablesTransformer.java index 1637f5d8..e1193b8a 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/PopUnUsedLocalVariablesTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/PopUnUsedLocalVariablesTransformer.java @@ -1,6 +1,7 @@ package uwu.narumi.deobfuscator.core.other.impl.clean.peephole; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.OriginalSourceValue; @@ -27,11 +28,18 @@ protected boolean transform(ClassWrapper scope, Context context) throws Exceptio // Find all local variables in use for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof VarInsnNode varInsnNode && insn.isVarLoad()) { + if ((insn instanceof VarInsnNode && !insn.isVarStore()) || insn instanceof IincInsnNode) { Frame frame = frames.get(insn); if (frame == null) return; - OriginalSourceValue localVariableSourceValue = frame.getLocal(varInsnNode.var); + int varIndex; + if (insn instanceof VarInsnNode varInsnNode) { + varIndex = varInsnNode.var; + } else { + varIndex = ((IincInsnNode) insn).var; + } + + OriginalSourceValue localVariableSourceValue = frame.getLocal(varIndex); for (AbstractInsnNode sourceInsn : localVariableSourceValue.insns) { // Save var stores in use if (sourceInsn.isVarStore()) { From ea33560167f6bc5780308c9d5610552171ec5b42 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 Date: Mon, 26 Aug 2024 18:03:33 +0200 Subject: [PATCH 2/3] Fix method matcher wrongly matching method names --- .../asm/matcher/rule/impl/MethodMatch.java | 2 +- .../deobfuscator/TestDeobfuscation.java | 2 + .../ComposedGeneralFlowTransformer.java | 8 +--- .../clean/InvalidMethodCleanTransformer.java | 38 ++++++++++++++++ .../peephole/DeadCodeCleanTransformer.java | 43 ++++++++----------- .../results/java/TestInlineStaticFields.dec | 6 +-- .../results/java/TestInlineStaticFields2.dec | 28 ++++++++++++ .../main/java/TestInlineStaticFields2.java | 28 ++++++++++++ 8 files changed, 120 insertions(+), 35 deletions(-) create mode 100644 deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/InvalidMethodCleanTransformer.java create mode 100644 testData/results/java/TestInlineStaticFields2.dec create mode 100644 testData/src/java/src/main/java/TestInlineStaticFields2.java diff --git a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/rule/impl/MethodMatch.java b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/rule/impl/MethodMatch.java index eda1c349..cfc5ae00 100644 --- a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/rule/impl/MethodMatch.java +++ b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/rule/impl/MethodMatch.java @@ -59,7 +59,7 @@ public boolean test(AbstractInsnNode node) { return node instanceof MethodInsnNode && (opcode == -1 || node.getOpcode() == opcode) && (owner == null || ((MethodInsnNode) node).owner.equals(owner)) - && (name == null || Arrays.binarySearch(name, ((MethodInsnNode) node).name) != -1) + && (name == null || Arrays.binarySearch(name, ((MethodInsnNode) node).name) >= 0) && (desc == null || ((MethodInsnNode) node).desc.equals(desc)); } diff --git a/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java b/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java index 42ba0293..1893133a 100644 --- a/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java +++ b/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java @@ -21,6 +21,8 @@ protected void registerAll() { register("Simple flow obfuscation", InputType.JAVA_CODE, List.of(ComposedGeneralFlowTransformer::new), "TestSimpleFlowObfuscation"); register("Universal Number Transformer", InputType.JAVA_CODE, List.of(UniversalNumberTransformer::new), "TestUniversalNumberTransformer"); register("Inline static fields", InputType.JAVA_CODE, List.of(InlineStaticFieldTransformer::new), "TestInlineStaticFields"); + // TODO: Account for static field modification + register("Inline static fields with modification", InputType.JAVA_CODE, List.of(InlineStaticFieldTransformer::new), "TestInlineStaticFields2"); // Samples // TODO: Deobfuscate switches diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedGeneralFlowTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedGeneralFlowTransformer.java index 266f2299..5d0eec8d 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedGeneralFlowTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/composed/ComposedGeneralFlowTransformer.java @@ -1,10 +1,8 @@ package uwu.narumi.deobfuscator.core.other.composed; import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; +import uwu.narumi.deobfuscator.core.other.impl.clean.InvalidMethodCleanTransformer; import uwu.narumi.deobfuscator.core.other.impl.clean.PeepholeCleanTransformer; -import uwu.narumi.deobfuscator.core.other.impl.clean.LineNumberCleanTransformer; -import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.DeadCodeCleanTransformer; -import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.UnUsedLabelCleanTransformer; 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.universal.UniversalNumberTransformer; @@ -15,9 +13,7 @@ public class ComposedGeneralFlowTransformer extends ComposedTransformer { public ComposedGeneralFlowTransformer() { super( // Preparation - DeadCodeCleanTransformer::new, - LineNumberCleanTransformer::new, - UnUsedLabelCleanTransformer::new, + InvalidMethodCleanTransformer::new, () -> new InlineStaticFieldTransformer(true, true), InlineLocalVariablesTransformer::new, diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/InvalidMethodCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/InvalidMethodCleanTransformer.java new file mode 100644 index 00000000..ab0c8699 --- /dev/null +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/InvalidMethodCleanTransformer.java @@ -0,0 +1,38 @@ +package uwu.narumi.deobfuscator.core.other.impl.clean; + +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.AnalyzerException; +import org.objectweb.asm.tree.analysis.BasicInterpreter; +import uwu.narumi.deobfuscator.api.asm.ClassWrapper; +import uwu.narumi.deobfuscator.api.context.Context; +import uwu.narumi.deobfuscator.api.transformer.Transformer; + +/** + * Remove invalid methods. WARNING: If some transformer will produce invalid bytecode in methods, this transformer will remove them. + */ +public class InvalidMethodCleanTransformer extends Transformer { + private boolean changed = false; + + @Override + protected boolean transform(ClassWrapper scope, Context context) throws Exception { + context.classes(scope).forEach(classWrapper -> { + var iterator = classWrapper.methods().iterator(); + while (iterator.hasNext()) { + MethodNode methodNode = iterator.next(); + + Analyzer analyzer = new Analyzer<>(new BasicInterpreter()); + try { + analyzer.analyze(classWrapper.name(), methodNode); + } catch (AnalyzerException e) { + // Remove invalid method + LOGGER.warn("Found invalid method: {}#{}{}. Removing...", classWrapper.name(), methodNode.name, methodNode.desc); + iterator.remove(); + changed = true; + } + } + }); + + return changed; + } +} diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/DeadCodeCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/DeadCodeCleanTransformer.java index d3ab274b..64dd6065 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/DeadCodeCleanTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/DeadCodeCleanTransformer.java @@ -15,34 +15,27 @@ public class DeadCodeCleanTransformer extends Transformer { @Override protected boolean transform(ClassWrapper scope, Context context) throws Exception { - context.classes(scope).forEach(classWrapper -> { - var iterator = classWrapper.methods().iterator(); - while (iterator.hasNext()) { - MethodNode methodNode = iterator.next(); - - Analyzer analyzer = new Analyzer<>(new BasicInterpreter()); - try { - analyzer.analyze(classWrapper.name(), methodNode); - } catch (AnalyzerException e) { - // Remove invalid method - LOGGER.warn("Found invalid method: {}#{}{}. Removing...", classWrapper.name(), methodNode.name, methodNode.desc); - iterator.remove(); - return; - } - Frame[] frames = analyzer.getFrames(); - AbstractInsnNode[] insns = methodNode.instructions.toArray(); - for (int i = 0; i < frames.length; i++) { - AbstractInsnNode insn = insns[i]; + context.classes(scope).forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { + Analyzer analyzer = new Analyzer<>(new BasicInterpreter()); + try { + analyzer.analyze(classWrapper.name(), methodNode); + } catch (AnalyzerException e) { + // Skip invalid methods + return; + } + Frame[] frames = analyzer.getFrames(); + AbstractInsnNode[] insns = methodNode.instructions.toArray(); + for (int i = 0; i < frames.length; i++) { + AbstractInsnNode insn = insns[i]; - // If frame is null then it means that the code is unreachable - if (frames[i] == null && insn.getType() != AbstractInsnNode.LABEL) { - methodNode.instructions.remove(insn); - insns[i] = null; - changed = true; - } + // If frame is null then it means that the code is unreachable + if (frames[i] == null && insn.getType() != AbstractInsnNode.LABEL) { + methodNode.instructions.remove(insn); + insns[i] = null; + changed = true; } } - }); + })); return changed; } diff --git a/testData/results/java/TestInlineStaticFields.dec b/testData/results/java/TestInlineStaticFields.dec index d396e4c6..15c622b6 100644 --- a/testData/results/java/TestInlineStaticFields.dec +++ b/testData/results/java/TestInlineStaticFields.dec @@ -4,9 +4,9 @@ public class TestInlineStaticFields { public static boolean TEST3 = true; public static void test() { - byte var10001 = 123; - String var10003 = "placki"; - boolean var10005 = true; + System.out.println(123); + System.out.println("placki"); + System.out.println(true); } public static void modifyStatic() { diff --git a/testData/results/java/TestInlineStaticFields2.dec b/testData/results/java/TestInlineStaticFields2.dec new file mode 100644 index 00000000..8b918907 --- /dev/null +++ b/testData/results/java/TestInlineStaticFields2.dec @@ -0,0 +1,28 @@ +import java.io.File; + +public class TestInlineStaticFields2 { + private static final char SYSTEM_SEPARATOR = File.separatorChar; + private static final char OTHER_SEPARATOR; + + private static int getAdsCriticalOffset(String fileName) { + int offset1 = fileName.lastIndexOf(SYSTEM_SEPARATOR); + int offset2 = fileName.lastIndexOf(92); + if (offset1 == -1) { + return offset2 == -1 ? 0 : offset2 + 1; + } else { + return offset2 == -1 ? offset1 + 1 : Math.max(offset1, offset2) + 1; + } + } + + static boolean isSystemWindows() { + return SYSTEM_SEPARATOR == '\\'; + } + + static { + if (isSystemWindows()) { + OTHER_SEPARATOR = '/'; + } else { + OTHER_SEPARATOR = '\\'; + } + } +} diff --git a/testData/src/java/src/main/java/TestInlineStaticFields2.java b/testData/src/java/src/main/java/TestInlineStaticFields2.java new file mode 100644 index 00000000..6781fc3f --- /dev/null +++ b/testData/src/java/src/main/java/TestInlineStaticFields2.java @@ -0,0 +1,28 @@ +import java.io.File; + +public class TestInlineStaticFields2 { + private static final char SYSTEM_SEPARATOR = File.separatorChar; + private static final char OTHER_SEPARATOR; + + private static int getAdsCriticalOffset(String fileName) { + int offset1 = fileName.lastIndexOf(SYSTEM_SEPARATOR); + int offset2 = fileName.lastIndexOf(OTHER_SEPARATOR); + if (offset1 == -1) { + return offset2 == -1 ? 0 : offset2 + 1; + } else { + return offset2 == -1 ? offset1 + 1 : Math.max(offset1, offset2) + 1; + } + } + + static { + if (isSystemWindows()) { + OTHER_SEPARATOR = '/'; + } else { + OTHER_SEPARATOR = '\\'; + } + } + + static boolean isSystemWindows() { + return SYSTEM_SEPARATOR == '\\'; + } +} From f054a3d0c822cab54621cd7890bce7c4437f7313 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 Date: Mon, 26 Aug 2024 18:07:31 +0200 Subject: [PATCH 3/3] rename test --- .../test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java | 2 +- ...icFields2.dec => TestInlineStaticFieldsWithModification.dec} | 2 +- ...Fields2.java => TestInlineStaticFieldsWithModification.java} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename testData/results/java/{TestInlineStaticFields2.dec => TestInlineStaticFieldsWithModification.dec} (93%) rename testData/src/java/src/main/java/{TestInlineStaticFields2.java => TestInlineStaticFieldsWithModification.java} (92%) diff --git a/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java b/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java index 1893133a..284722db 100644 --- a/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java +++ b/deobfuscator-impl/src/test/java/uwu/narumii/deobfuscator/TestDeobfuscation.java @@ -22,7 +22,7 @@ protected void registerAll() { register("Universal Number Transformer", InputType.JAVA_CODE, List.of(UniversalNumberTransformer::new), "TestUniversalNumberTransformer"); register("Inline static fields", InputType.JAVA_CODE, List.of(InlineStaticFieldTransformer::new), "TestInlineStaticFields"); // TODO: Account for static field modification - register("Inline static fields with modification", InputType.JAVA_CODE, List.of(InlineStaticFieldTransformer::new), "TestInlineStaticFields2"); + register("Inline static fields with modification", InputType.JAVA_CODE, List.of(InlineStaticFieldTransformer::new), "TestInlineStaticFieldsWithModification"); // Samples // TODO: Deobfuscate switches diff --git a/testData/results/java/TestInlineStaticFields2.dec b/testData/results/java/TestInlineStaticFieldsWithModification.dec similarity index 93% rename from testData/results/java/TestInlineStaticFields2.dec rename to testData/results/java/TestInlineStaticFieldsWithModification.dec index 8b918907..e8f71373 100644 --- a/testData/results/java/TestInlineStaticFields2.dec +++ b/testData/results/java/TestInlineStaticFieldsWithModification.dec @@ -1,6 +1,6 @@ import java.io.File; -public class TestInlineStaticFields2 { +public class TestInlineStaticFieldsWithModification { private static final char SYSTEM_SEPARATOR = File.separatorChar; private static final char OTHER_SEPARATOR; diff --git a/testData/src/java/src/main/java/TestInlineStaticFields2.java b/testData/src/java/src/main/java/TestInlineStaticFieldsWithModification.java similarity index 92% rename from testData/src/java/src/main/java/TestInlineStaticFields2.java rename to testData/src/java/src/main/java/TestInlineStaticFieldsWithModification.java index 6781fc3f..fced879e 100644 --- a/testData/src/java/src/main/java/TestInlineStaticFields2.java +++ b/testData/src/java/src/main/java/TestInlineStaticFieldsWithModification.java @@ -1,6 +1,6 @@ import java.io.File; -public class TestInlineStaticFields2 { +public class TestInlineStaticFieldsWithModification { private static final char SYSTEM_SEPARATOR = File.separatorChar; private static final char OTHER_SEPARATOR;