Skip to content

Commit

Permalink
more work
Browse files Browse the repository at this point in the history
  • Loading branch information
EpicPlayerA10 committed Aug 24, 2024
1 parent ab1258d commit d442b95
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 extends AbstractInsnNode> T getPreviousAs() {
return (T) getPrevious();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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<BasicValue> 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);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,6 +15,7 @@ public class ComposedGeneralFlowTransformer extends ComposedTransformer {
public ComposedGeneralFlowTransformer() {
super(
// Preparation
DeadCodeCleanTransformer::new,
LineNumberCleanTransformer::new,
UnUsedLabelCleanTransformer::new,
() -> new InlineStaticFieldTransformer(true, true),
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,46 @@ public class UselessPopCleanTransformer extends FramedInstructionsTransformer {
@Override
protected Stream<AbstractInsnNode> getInstructionsStream(Stream<AbstractInsnNode> 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<OriginalSourceValue> 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;
}
}
9 changes: 9 additions & 0 deletions testData/results/java/TestInlineLocalVariables.dec
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
12 changes: 12 additions & 0 deletions testData/src/java/src/main/java/TestInlineLocalVariables.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit d442b95

Please sign in to comment.