From d442b95baad2afdbab8526623de332d550f5401f Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 Date: Sun, 25 Aug 2024 00:04:31 +0200 Subject: [PATCH] more work --- .../objectweb/asm/tree/AbstractInsnNode.java | 9 ++++ .../api/transformer/Transformer.java | 32 ++++++++++++++ .../ComposedGeneralFlowTransformer.java | 2 + .../peephole/DeadCodeCleanTransformer.java | 44 +++++++++++-------- .../UnUsedLocalVariablesCleanTransformer.java | 6 +-- .../peephole/UselessPopCleanTransformer.java | 33 ++++++++++++-- .../results/java/TestInlineLocalVariables.dec | 9 ++++ .../main/java/TestInlineLocalVariables.java | 12 +++++ 8 files changed, 122 insertions(+), 25 deletions(-) diff --git a/deobfuscator-api/src/main/java/org/objectweb/asm/tree/AbstractInsnNode.java b/deobfuscator-api/src/main/java/org/objectweb/asm/tree/AbstractInsnNode.java index 0527ee66..2b0cb77d 100644 --- a/deobfuscator-api/src/main/java/org/objectweb/asm/tree/AbstractInsnNode.java +++ b/deobfuscator-api/src/main/java/org/objectweb/asm/tree/AbstractInsnNode.java @@ -474,6 +474,15 @@ public AbstractInsnNode getPrevious(int offset) { return current; } + public InsnNode toPop() { + if (this.getOpcode() == LSTORE || this.getOpcode() == DSTORE) { + // Long and double values take up two stack values. Need to use pop2 + return new InsnNode(POP2); + } else { + return new InsnNode(POP); + } + } + public T getPreviousAs() { return (T) getPrevious(); } diff --git a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/transformer/Transformer.java b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/transformer/Transformer.java index 7006090f..36a4f343 100644 --- a/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/transformer/Transformer.java +++ b/deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/transformer/Transformer.java @@ -4,6 +4,12 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; +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.BasicValue; +import org.objectweb.asm.tree.analysis.BasicVerifier; +import org.objectweb.asm.tree.analysis.SimpleVerifier; import uwu.narumi.deobfuscator.api.asm.ClassWrapper; import uwu.narumi.deobfuscator.api.context.Context; import uwu.narumi.deobfuscator.api.exception.TransformerException; @@ -79,6 +85,16 @@ private static boolean transform( } LOGGER.info("Ended {} transformer in {} ms", transformer.name(), (System.currentTimeMillis() - start)); + + // Bytecode verification + /*if (oldInstance == null && changed) { + // Verify if code is valid + try { + verifyBytecode(scope, context); + } catch (RuntimeException e) { + LOGGER.error("Transformer {} produced invalid bytecode", transformer.name(), e); + } + }*/ } catch (TransformerException e) { LOGGER.error("! {}: {}", transformer.name(), e.getMessage()); } catch (Exception e) { @@ -88,4 +104,20 @@ private static boolean transform( return changed; } + + /** + * Verifies if the bytecode is valid + */ + private static void verifyBytecode(@Nullable ClassWrapper scope, Context context) throws IllegalStateException { + for (ClassWrapper classWrapper : context.classes(scope)) { + for (MethodNode methodNode : classWrapper.methods()) { + Analyzer analyzer = new Analyzer<>(new BasicVerifier()); + try { + analyzer.analyzeAndComputeMaxs(classWrapper.name(), methodNode); + } catch (AnalyzerException e) { + throw new IllegalStateException("Invalid bytecode in " + classWrapper.name() + "#" + methodNode.name + methodNode.desc, e); + } + } + } + } } 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 e2f50676..266f2299 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 @@ -3,6 +3,7 @@ import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer; 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; @@ -14,6 +15,7 @@ public class ComposedGeneralFlowTransformer extends ComposedTransformer { public ComposedGeneralFlowTransformer() { super( // Preparation + DeadCodeCleanTransformer::new, LineNumberCleanTransformer::new, UnUsedLabelCleanTransformer::new, () -> new InlineStaticFieldTransformer(true, true), 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 83924253..d3ab274b 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 @@ -1,6 +1,7 @@ package uwu.narumi.deobfuscator.core.other.impl.clean.peephole; import org.objectweb.asm.tree.AbstractInsnNode; +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; @@ -14,27 +15,34 @@ public class DeadCodeCleanTransformer extends Transformer { @Override protected boolean transform(ClassWrapper scope, Context context) throws Exception { - context.classes(scope).forEach(classWrapper -> classWrapper.methods().forEach(methodNode -> { - Analyzer analyzer = new Analyzer<>(new BasicInterpreter()); - try { - analyzer.analyze(classWrapper.name(), methodNode); - } catch (AnalyzerException e) { - // Ignore - 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 -> { + 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]; - // 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/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UnUsedLocalVariablesCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UnUsedLocalVariablesCleanTransformer.java index a7b3781e..d18292c4 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UnUsedLocalVariablesCleanTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UnUsedLocalVariablesCleanTransformer.java @@ -22,17 +22,17 @@ 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.getOpcode() >= ILOAD && insn.getOpcode() <= SALOAD) { + if (insn instanceof VarInsnNode varInsnNode && insn.getOpcode() >= ILOAD && insn.getOpcode() <= ALOAD) { localVariablesInUse.add(varInsnNode.var); } } // Remove all local variables that are not in use for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof VarInsnNode varInsnNode && insn.getOpcode() >= ISTORE && insn.getOpcode() <= SASTORE) { + if (insn instanceof VarInsnNode varInsnNode && insn.getOpcode() >= ISTORE && insn.getOpcode() <= ASTORE) { if (!localVariablesInUse.contains(varInsnNode.var)) { // Pop the value from the stack - methodNode.instructions.set(insn, new InsnNode(POP)); + methodNode.instructions.set(insn, insn.toPop()); removedVars.incrementAndGet(); } diff --git a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UselessPopCleanTransformer.java b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UselessPopCleanTransformer.java index ab0573c5..52f5088e 100644 --- a/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UselessPopCleanTransformer.java +++ b/deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/clean/peephole/UselessPopCleanTransformer.java @@ -14,21 +14,46 @@ public class UselessPopCleanTransformer extends FramedInstructionsTransformer { @Override protected Stream getInstructionsStream(Stream stream) { return stream - .filter(insn -> insn.getOpcode() == POP); + .filter(insn -> insn.getOpcode() == POP || insn.getOpcode() == POP2); } @Override protected boolean transformInstruction(ClassWrapper classWrapper, MethodNode methodNode, AbstractInsnNode insn, Frame frame) { - OriginalSourceValue sourceValue = frame.getStack(frame.getStackSize() - 1); + boolean changed = false; + + OriginalSourceValue firstValue = frame.getStack(frame.getStackSize() - 1); + for (AbstractInsnNode producer : firstValue.insns) { + if (insn.getOpcode() == POP2) { + // If the producer is a double or long, remove the pop2 and the double/long + if (producer.isDouble() || producer.isLong()) { + methodNode.instructions.remove(producer); + methodNode.instructions.remove(insn); + changed = true; + } else { + // Pop two values + OriginalSourceValue secondValue = frame.getStack(frame.getStackSize() - 2); + popSourceValue(insn, secondValue, methodNode); + popSourceValue(insn, firstValue, methodNode); + } + } else if (insn.getOpcode() == POP) { + changed |= popSourceValue(insn, firstValue, methodNode); + } + } + + return changed; + } + + private boolean popSourceValue(AbstractInsnNode insn, OriginalSourceValue sourceValue, MethodNode methodNode) { + boolean changed = false; for (AbstractInsnNode producer : sourceValue.insns) { // If the producer is a constant, remove the pop and the constant if (producer.isConstant()) { methodNode.instructions.remove(producer); methodNode.instructions.remove(insn); - return true; + changed = true; } } - return false; + return changed; } } diff --git a/testData/results/java/TestInlineLocalVariables.dec b/testData/results/java/TestInlineLocalVariables.dec index 36aa99ed..ec738e2e 100644 --- a/testData/results/java/TestInlineLocalVariables.dec +++ b/testData/results/java/TestInlineLocalVariables.dec @@ -25,4 +25,13 @@ public class TestInlineLocalVariables { return testVar; } + + public static void test4() { + long c = 123123123123123123L; + double d = 123123.123123; + float e = 123123.125F; + String f = "test"; + System.out.println("" + 5 + true + c); + System.out.println(d + (double)e + f); + } } diff --git a/testData/src/java/src/main/java/TestInlineLocalVariables.java b/testData/src/java/src/main/java/TestInlineLocalVariables.java index 24f89674..27348599 100644 --- a/testData/src/java/src/main/java/TestInlineLocalVariables.java +++ b/testData/src/java/src/main/java/TestInlineLocalVariables.java @@ -29,4 +29,16 @@ public static boolean test3() { return testVar; } + + public static void test4() { + int a = 5; + boolean b = true; + long c = 123123123123123123L; + double d = 123123.123123; + float e = 123123.123123f; + String f = "test"; + + System.out.println("" + a + b + c); + System.out.println(d + e + f); + } }