From 3444655f09a0befb7fb0ef35c2166af92649f1ec Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 25 Mar 2016 21:52:23 -0400 Subject: [PATCH] Rewrite constant parameter. A bit faster now. Can't tell if its right. Seems to compile. --- pom.xml | 2 +- .../deob/deobfuscators/UnusedParameters.java | 230 ++++++++---------- .../deobfuscators/UnusedParametersTest.java | 32 ++- 3 files changed, 134 insertions(+), 130 deletions(-) diff --git a/pom.xml b/pom.xml index cd9bc692a1..a867b47ec8 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ org.ow2.asm - asm-all + asm-debug-all 5.0.4 diff --git a/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java b/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java index 12f129a3a3..0f36421924 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java +++ b/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java @@ -10,25 +10,73 @@ import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; import net.runelite.asm.execution.Execution; -import net.runelite.asm.execution.Frame; import net.runelite.asm.execution.InstructionContext; -import net.runelite.asm.pool.NameAndType; -import net.runelite.asm.pool.PoolEntry; import net.runelite.asm.signature.Signature; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import net.runelite.asm.execution.StackContext; import net.runelite.asm.signature.util.VirtualMethods; import org.apache.commons.collections4.CollectionUtils; public class UnusedParameters implements Deobfuscator -{ - private List findUnusedParameters(Method method) +{ + private Map, Collection> unused = new HashMap<>(); + + private void buildUnused(ClassGroup group) + { + unused.clear(); + + for (ClassFile cf : group.getClasses()) + for (Method m : cf.getMethods().getMethods()) + { + if (!Deob.isObfuscated(m.getName())) + continue; + + List ms = VirtualMethods.getVirutalMethods(m); + Collection u = this.findUnusedParameters(ms); + if (!u.isEmpty()) + unused.put(ms, u); + } + } + + private int processUnused(Execution execution, ClassGroup group) + { + int count = 0; + + for (List m : unused.keySet()) + { + Collection u = unused.get(m); + + int offset = m.size() == 1 && m.get(0).isStatic() ? 0 : 1; + + for (int unusedParameter : u) + { + Signature signature = m.get(0).getDescriptor(); + //int[] lvtIndexes = getLvtIndexes(signature, offset);//XX reverse this + int lvtIndex = this.getLvtIndex(signature, offset, unusedParameter); + /* removing the parameter can't cause collisions on other (overloaded) methods because prior to this we rename + * all classes/fields/methods to have unique names. + */ + System.out.println("Removing parameter " + unusedParameter + " at index " + lvtIndex + " from " + m); + removeParameter(group, m, signature, execution, unusedParameter, lvtIndex); + break; + } + + ++count; + + //break; + } + + return count; + } + + public List findUnusedParameters(Method method) { int offset = method.isStatic() ? 0 : 1; Signature signature = method.getNameAndType().getDescriptor(); @@ -46,19 +94,18 @@ public class UnusedParameters implements Deobfuscator return unusedParams; } - private int[] getLvtIndexes(Signature signature, int offset) + @SuppressWarnings("empty-statement") + private int getLvtIndex(Signature signature, int offset, int parameter) { - int[] i = new int[signature.size()]; - for (int variableIndex = 0, lvtIndex = offset; - variableIndex < signature.size(); - lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots()) - { - i[variableIndex] = lvtIndex; - } - return i; + // get lvt index for parameter + int lvtIndex = offset; + for (int variableIndex = 0; + variableIndex < parameter; + lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots()); + return lvtIndex; } - private Collection findUnusedParameters(Collection methods) + public Collection findUnusedParameters(Collection methods) { Collection list = null; @@ -72,82 +119,56 @@ public class UnusedParameters implements Deobfuscator list = CollectionUtils.intersection(list, p); } - return list; + List l = new ArrayList<>(list); + Collections.sort(l); + Collections.reverse(l); + return l; } - public void removeParameter(List methods, Signature signature, Execution execution, int paramIndex, int lvtIndex) + public void removeParameter(ClassGroup group, List methods, Signature signature, Execution execution, int paramIndex, int lvtIndex) { - Set done = new HashSet<>(); + int slots = signature.getTypeOfArg(paramIndex).getSlots(); - assert signature.getTypeOfArg(paramIndex).getSlots() == 1; - - for (Frame f : execution.processedFrames) - for (InstructionContext ins : f.getInstructions()) - if (!ins.getInvokes().isEmpty() && methods.containsAll(ins.getInvokes())) + for (ClassFile cf : group.getClasses()) + for (Method m : cf.getMethods().getMethods()) + { + Code c = m.getCode(); + + if (c == null) + continue; + + for (Instruction i : new ArrayList<>(c.getInstructions().getInstructions())) { - int pops = signature.size() - paramIndex - 1; // index from top of stack of parameter. 0 is the last parameter - - StackContext sctx = ins.getPops().get(pops); - if (sctx.getPushed().getInstruction().getInstructions() == null) + if (!(i instanceof InvokeInstruction)) continue; - ins.removeStack(pops); // remove parameter from stack + InvokeInstruction ii = (InvokeInstruction) i; - if (done.contains(ins.getInstruction())) + if (!ii.getMethods().containsAll(methods)) continue; - InvokeInstruction iins = (InvokeInstruction) ins.getInstruction(); - iins.removeParameter(paramIndex); // remove parameter from instruction + ii.removeParameter(paramIndex); // remove parameter from instruction - done.add(ins.getInstruction()); - } - - for (Method method : methods) - // this double checks that all calls to this have been located - for (ClassFile cf : method.getMethods().getClassFile().getGroup().getClasses()) - for (Method m : cf.getMethods().getMethods()) - { - Code c = m.getCode(); - if (c == null) - continue; - - for (Instruction i : c.getInstructions().getInstructions()) + Collection ics = execution.getInstructonContexts(i); + if (ics != null) { - if (i instanceof InvokeInstruction) - { - InvokeInstruction ii = (InvokeInstruction) i; - PoolEntry pool = ii.getMethod(); - - if (pool instanceof net.runelite.asm.pool.Method) - { - net.runelite.asm.pool.Method pm = (net.runelite.asm.pool.Method) pool; - - if (pm.getClassEntry().getName().equals(method.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(method.getNameAndType()) && !done.contains(i)) - { - // for some reason this wasn't removed above? - System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution"); - //assert false; - } - } - else if (pool instanceof net.runelite.asm.pool.InterfaceMethod) - { - net.runelite.asm.pool.InterfaceMethod pm = (net.runelite.asm.pool.InterfaceMethod) pool; - - if (pm.getClassEntry().getName().equals(method.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(method.getNameAndType()) && !done.contains(i)) - { - // for some reason this wasn't removed above? - System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution"); - //assert false; - } - } - } + InstructionContext ins = ics.toArray(new InstructionContext[0])[0]; + + int pops = signature.size() - paramIndex - 1; // index from top of stack of parameter. 0 is the last parameter + + StackContext sctx = ins.getPops().get(pops); + if (sctx.getPushed().getInstruction().getInstructions() == null) + continue; + + ins.removeStack(pops); // remove parameter from stack } } + } for (Method method : methods) if (method.getCode() != null) // adjust lvt indexes to get rid of idx in the method - for (Instruction ins : new ArrayList<>(method.getCode().getInstructions().getInstructions())) + for (Instruction ins : method.getCode().getInstructions().getInstructions()) { if (ins instanceof LVTInstruction) { @@ -160,8 +181,9 @@ public class UnusedParameters implements Deobfuscator if (i > lvtIndex) { assert i > 0; + assert i >= lvtIndex + slots; - Instruction newIns = lins.setVariableIndex(--i); + Instruction newIns = lins.setVariableIndex(i - slots); assert ins == newIns; // this doesn't work because we'd have to reexecute or the above Frames would be messing with these instructions //if (newIns != ins) @@ -173,57 +195,6 @@ public class UnusedParameters implements Deobfuscator for (Method method : methods) method.arguments.remove(paramIndex); } - - private int checkParametersOnce(Execution execution, ClassGroup group) - { - // removing parameters shifts the others around which is annoying. - // if more than one is unused, we'll just remove the one - // and do the others on another pass - - Set done = new HashSet<>(); - int count = 0; - - for (ClassFile cf : group.getClasses()) - { - for (Method m : cf.getMethods().getMethods()) - { - if (done.contains(m) || !Deob.isObfuscated(m.getName())) - continue; - - int offset = m.isStatic() ? 0 : 1; - Signature signature = m.getNameAndType().getDescriptor(); - - // for a parameter to be unused it must be unused on all methods that override it - - List methods = VirtualMethods.getVirutalMethods(m); - - Collection unusedParameters = findUnusedParameters(methods); - - if (unusedParameters.isEmpty()) - continue; - - int unusedParameter = (int) unusedParameters.toArray()[0]; - int[] lvtIndexes = getLvtIndexes(signature, offset); - - for (Method m2 : methods) - { - assert !done.contains(m2); - done.add(m2); - } - - /* removing the parameter can't cause collisions on other (overloaded) methods because prior to this we rename - * all classes/fields/methods to have unique names. - */ - System.out.println("Removing parameter " + unusedParameter + " from " + methods.get(0).getName()); - removeParameter(methods, signature, execution, unusedParameter, lvtIndexes[unusedParameter]); - - ++count; - - break; - } - } - return count; - } private int count; @@ -231,6 +202,7 @@ public class UnusedParameters implements Deobfuscator public void run(ClassGroup group) { int i; + int pnum = 1; do { group.buildClassGraph(); @@ -239,7 +211,9 @@ public class UnusedParameters implements Deobfuscator execution.populateInitialMethods(); execution.run(); - i = checkParametersOnce(execution, group); + this.buildUnused(group); + i = this.processUnused(execution, group); + System.out.println("PASS " + pnum++ + " " + i); count += i; } diff --git a/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java b/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java index 2f9cbb5a58..8580775afe 100644 --- a/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java +++ b/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java @@ -2,7 +2,10 @@ package net.runelite.deob.deobfuscators; import java.io.File; import java.io.IOException; +import java.util.List; import net.runelite.asm.ClassGroup; +import net.runelite.asm.Method; +import net.runelite.asm.signature.util.VirtualMethods; import net.runelite.deob.util.JarUtil; import org.junit.After; import org.junit.Assert; @@ -34,8 +37,35 @@ public class UnusedParametersTest @Test public void testRun() - { + { + RenameUnique r = new RenameUnique(); + r.run(group); + r = null; + System.gc(); + + RuntimeExceptions re = new RuntimeExceptions(); + re.run(group); + re = null; + System.gc(); + + UnreachedCode uc = new UnreachedCode(); + uc.run(group); + uc = null; + System.gc(); + + UnusedMethods um = new UnusedMethods(); + um.run(group); + um = null; + System.gc(); + + IllegalStateExceptions ise = new IllegalStateExceptions(); + ise.run(group); + ise = null; + System.gc(); + UnusedParameters cp = new UnusedParameters(); cp.run(group); + cp = null; + System.gc(); } }