From d9f4d257a54437be61991082a03298f9f3687161 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 27 Jun 2015 23:47:43 -0400 Subject: [PATCH] wip removal of unused methods based on execution from init. --- .../java/info/sigterm/deob/ClassFile.java | 13 +++-- .../java/info/sigterm/deob/ClassGroup.java | 14 +---- src/main/java/info/sigterm/deob/Deob.java | 6 +- src/main/java/info/sigterm/deob/Method.java | 16 +++--- .../instruction/types/InvokeInstruction.java | 2 + .../code/instructions/InvokeInterface.java | 40 +++++++++---- .../code/instructions/InvokeSpecial.java | 27 +++++---- .../code/instructions/InvokeStatic.java | 29 ++++++---- .../code/instructions/InvokeVirtual.java | 57 ++++++++----------- .../deob/deobfuscators/UnusedMethods.java | 8 ++- .../deob/deobfuscators/UnusedParameters.java | 2 +- .../sigterm/deob/execution/Execution.java | 49 ++++++++++++---- .../info/sigterm/deob/execution/Frame.java | 5 ++ 13 files changed, 161 insertions(+), 107 deletions(-) diff --git a/src/main/java/info/sigterm/deob/ClassFile.java b/src/main/java/info/sigterm/deob/ClassFile.java index 5dcd60704d..272e41b8ce 100644 --- a/src/main/java/info/sigterm/deob/ClassFile.java +++ b/src/main/java/info/sigterm/deob/ClassFile.java @@ -9,6 +9,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.List; public class ClassFile { @@ -18,7 +19,7 @@ public class ClassFile private DataInputStream is; private ClassFile parent; // super class - private ArrayList children = new ArrayList(); // classes which inherit from this + private List children = new ArrayList<>(); // classes which inherit from this private short minor_version; private short major_version; @@ -125,10 +126,12 @@ public class ClassFile public ClassFile getParent() { - String superName = super_class.getName(); - ClassFile other = group.findClass(superName); - assert other != this; - return other; + return parent; + } + + public List getChildren() + { + return children; } public Field findField(NameAndType nat) diff --git a/src/main/java/info/sigterm/deob/ClassGroup.java b/src/main/java/info/sigterm/deob/ClassGroup.java index a8b5e4c51f..fa01a49ce7 100644 --- a/src/main/java/info/sigterm/deob/ClassGroup.java +++ b/src/main/java/info/sigterm/deob/ClassGroup.java @@ -7,7 +7,7 @@ import java.util.List; public class ClassGroup { - private ArrayList classes = new ArrayList(); + private List classes = new ArrayList<>(); public ClassGroup() { @@ -45,16 +45,4 @@ public class ClassGroup for (ClassFile c : classes) c.buildInstructionGraph(); } - - public void buildCallGraph() - { - for (ClassFile c : classes) - for (Method m : c.getMethods().getMethods()) - { - m.callsTo.clear(); - m.callsFrom.clear(); - } - for (ClassFile c : classes) - c.buildCallGraph(); - } } diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index 1bed050100..e710326ac9 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -41,6 +41,7 @@ public class Deob ClassGroup group = loadJar(args[0]); + /* // remove except RuntimeException new RuntimeExceptions().run(group); @@ -48,18 +49,19 @@ public class Deob new IllegalStateExceptions().run(group); // remove code blocks that used to be the runtime exception handlers - new UnusedBlocks().run(group); + new UnusedBlocks().run(group);*/ // remove unused methods new UnusedMethods().run(group); + /* // remove unused parameters new UnusedParameters().run(group); // remove jump obfuscation new Jumps().run(group); - new ModularArithmeticDeobfuscation().run(group); + new ModularArithmeticDeobfuscation().run(group);*/ saveJar(group, args[1]); diff --git a/src/main/java/info/sigterm/deob/Method.java b/src/main/java/info/sigterm/deob/Method.java index 462ee6ee65..de6b6d054b 100644 --- a/src/main/java/info/sigterm/deob/Method.java +++ b/src/main/java/info/sigterm/deob/Method.java @@ -32,8 +32,6 @@ public class Method private String name; private Signature arguments; private Attributes attributes; - List callsTo = new ArrayList<>(); - List callsFrom = new ArrayList<>(); Method(Methods methods) throws IOException { @@ -60,11 +58,12 @@ public class Method protected void remove() { - assert callsFrom.isEmpty(); + //assert callsFrom.isEmpty(); } public void removeParameter(Execution execution, int paramIndex, int lvtIndex) { + /* Set done = new HashSet<>(); for (Node n : callsFrom) { @@ -160,6 +159,7 @@ public class Method } arguments.remove(paramIndex); + */ } public Methods getMethods() @@ -222,13 +222,13 @@ public class Method code.buildInstructionGraph(); } - public void clearCallGraph() + /*public void clearCallGraph() { callsTo.clear(); callsFrom.clear(); - } + }*/ - public boolean isUsed() + /*public boolean isUsed() { if (!callsFrom.isEmpty()) return true; @@ -240,8 +240,9 @@ public class Method } return false; - } + }*/ + /* public void addCallTo(Instruction ins, Method method) { assert method != null; @@ -249,6 +250,7 @@ public class Method callsTo.add(node); method.callsFrom.add(node); } + */ @SuppressWarnings("unchecked") public List findLVTInstructionsForVariable(int index) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/InvokeInstruction.java b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/InvokeInstruction.java index 4a70481b4c..a6fc6f29f1 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/InvokeInstruction.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/InvokeInstruction.java @@ -1,5 +1,7 @@ package info.sigterm.deob.attributes.code.instruction.types; +import java.util.List; + import info.sigterm.deob.Method; import info.sigterm.deob.pool.PoolEntry; diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeInterface.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeInterface.java index e589880e45..989480a1ee 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeInterface.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeInterface.java @@ -1,6 +1,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.ClassFile; +import info.sigterm.deob.ClassGroup; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; @@ -11,7 +12,6 @@ import info.sigterm.deob.execution.Stack; import info.sigterm.deob.execution.StackContext; import info.sigterm.deob.execution.Type; import info.sigterm.deob.pool.InterfaceMethod; -import info.sigterm.deob.pool.Method; import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.PoolEntry; import info.sigterm.deob.signature.Signature; @@ -19,6 +19,8 @@ import info.sigterm.deob.signature.Signature; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class InvokeInterface extends Instruction implements InvokeInstruction { @@ -45,20 +47,28 @@ public class InvokeInterface extends Instruction implements InvokeInstruction out.writeByte(0); } - @Override - public void buildCallGraph() - { - info.sigterm.deob.pool.Class clazz = method.getClassEntry(); - NameAndType nat = method.getNameAndType(); + private List getMethods() + { + ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); - info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); - - ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + ClassFile otherClass = group.findClass(method.getClassEntry().getName()); if (otherClass == null) - return; - info.sigterm.deob.Method other = otherClass.findMethod(nat); + return new ArrayList<>(); // not our class - thisMethod.addCallTo(this, other); + // look up this method in this class and anything that inherits from it + List list = new ArrayList<>(); + findMethodFromClass(list, otherClass); + return list; + } + + private void findMethodFromClass(List list, ClassFile clazz) + { + info.sigterm.deob.Method m = clazz.findMethod(method.getNameAndType()); + if (m != null) + list.add(m); + + for (ClassFile cf : clazz.getChildren()) + findMethodFromClass(list, cf); } @Override @@ -89,6 +99,12 @@ public class InvokeInterface extends Instruction implements InvokeInstruction } frame.addInstructionContext(ins); + + for (info.sigterm.deob.Method method : getMethods()) + { + // add possible method call to execution + frame.getExecution().addMethod(method); + } } private void handleExceptions(Frame frame) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java index 9969809bc3..383acc5053 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java @@ -1,6 +1,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.ClassFile; +import info.sigterm.deob.ClassGroup; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; @@ -18,6 +19,8 @@ import info.sigterm.deob.signature.Signature; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class InvokeSpecial extends Instruction implements InvokeInstruction { @@ -39,21 +42,19 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction out.writeShort(this.getPool().make(method)); } - @Override - public void buildCallGraph() + private List getMethods() { - info.sigterm.deob.pool.Class clazz = method.getClassEntry(); - NameAndType nat = method.getNameAndType(); + ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); - info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); - - ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + ClassFile otherClass = group.findClass(method.getClassEntry().getName()); if (otherClass == null) - return; + return new ArrayList<>(); // not our class - info.sigterm.deob.Method other = otherClass.findMethod(nat); + info.sigterm.deob.Method other = otherClass.findMethod(method.getNameAndType()); - thisMethod.addCallTo(this, other); + List list = new ArrayList<>(); + list.add(other); + return list; } @Override @@ -84,6 +85,12 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction } frame.addInstructionContext(ins); + + for (info.sigterm.deob.Method method : getMethods()) + { + // add possible method call to execution + frame.getExecution().addMethod(method); + } } private void handleExceptions(Frame frame) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeStatic.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeStatic.java index f6ede40561..e68f907f58 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeStatic.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeStatic.java @@ -1,6 +1,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.ClassFile; +import info.sigterm.deob.ClassGroup; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; @@ -18,6 +19,8 @@ import info.sigterm.deob.signature.Signature; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class InvokeStatic extends Instruction implements InvokeInstruction { @@ -39,21 +42,19 @@ public class InvokeStatic extends Instruction implements InvokeInstruction out.writeShort(this.getPool().make(method)); } - @Override - public void buildCallGraph() - { - info.sigterm.deob.pool.Class clazz = method.getClassEntry(); - NameAndType nat = method.getNameAndType(); + private List getMethods() + { + ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); - info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); - - ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + ClassFile otherClass = group.findClass(method.getClassEntry().getName()); if (otherClass == null) - return; + return new ArrayList<>(); // not our class - info.sigterm.deob.Method other = otherClass.findMethod(nat); + info.sigterm.deob.Method other = otherClass.findMethod(method.getNameAndType()); - thisMethod.addCallTo(this, other); + List list = new ArrayList<>(); + list.add(other); + return list; } @Override @@ -81,6 +82,12 @@ public class InvokeStatic extends Instruction implements InvokeInstruction } frame.addInstructionContext(ins); + + for (info.sigterm.deob.Method method : getMethods()) + { + // add possible method call to execution + frame.getExecution().addMethod(method); + } } private void handleExceptions(Frame frame) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java index 5382135bc2..6dd50ae7b4 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java @@ -19,6 +19,8 @@ import info.sigterm.deob.signature.Signature; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class InvokeVirtual extends Instruction implements InvokeInstruction { @@ -39,24 +41,6 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction super.write(out); out.writeShort(this.getPool().make(method)); } - - @Override - public void buildCallGraph() - { - info.sigterm.deob.pool.Class clazz = method.getClassEntry(); - NameAndType nat = method.getNameAndType(); - - info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); - - ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); - if (otherClass == null) - return; - info.sigterm.deob.Method other = otherClass.findMethod(nat); - if (other == null) - return; - - thisMethod.addCallTo(this, other); - } @Override public void execute(Frame frame) @@ -75,9 +59,6 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction StackContext object = stack.pop(); ins.pop(object); - // the method being invoked, looked up dynamically based on the type - //info.sigterm.deob.Method executedMethod = findVirtualMethod(object.getType()); - handleExceptions(frame); if (!method.getNameAndType().isVoid()) @@ -89,31 +70,39 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction } frame.addInstructionContext(ins); + + for (info.sigterm.deob.Method method : getMethods()) + { + // add possible method call to execution + frame.getExecution().addMethod(method); + } } - private info.sigterm.deob.Method findVirtualMethod(Type type) + // find the possible methods this instruction might be invoking. we can't know for sure + // which method is being invoked without tracking the types of objects in fields and when + // passed in parameters/return values. + private List getMethods() { - // invokevirtual 'method' on 'type', see if we can find the actual method that would be invoked based on the type of the object ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); - ClassFile otherClass = group.findClass(type.type); + ClassFile otherClass = group.findClass(method.getClassEntry().getName()); if (otherClass == null) - return null; // not our class + return new ArrayList<>(); // not our class - // now find the method with the same signature as 'method' on this class, or subclass - return findMethodFromClass(otherClass); + // look up this method in this class and anything that inherits from it + List list = new ArrayList<>(); + findMethodFromClass(list, otherClass); + return list; } - private info.sigterm.deob.Method findMethodFromClass(ClassFile clazz) + private void findMethodFromClass(List list, ClassFile clazz) { - if (clazz == null) - return null; - info.sigterm.deob.Method m = clazz.findMethod(method.getNameAndType()); if (m != null) - return m; - - return findMethodFromClass(clazz.getParent()); + list.add(m); + + for (ClassFile cf : clazz.getChildren()) + findMethodFromClass(list, cf); } private void handleExceptions(Frame frame) diff --git a/src/main/java/info/sigterm/deob/deobfuscators/UnusedMethods.java b/src/main/java/info/sigterm/deob/deobfuscators/UnusedMethods.java index 7470cc2f8c..690fdbe907 100644 --- a/src/main/java/info/sigterm/deob/deobfuscators/UnusedMethods.java +++ b/src/main/java/info/sigterm/deob/deobfuscators/UnusedMethods.java @@ -3,6 +3,7 @@ package info.sigterm.deob.deobfuscators; import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassGroup; import info.sigterm.deob.Method; +import info.sigterm.deob.execution.Execution; import java.util.ArrayList; @@ -10,7 +11,9 @@ public class UnusedMethods { public void run(ClassGroup group) { - group.buildCallGraph(); + Execution execution = new Execution(group); + execution.populateInitialMethods(); + execution.run(); int i = 0; for (ClassFile cf : group.getClasses()) @@ -21,7 +24,8 @@ public class UnusedMethods if (m.getName().length() > 2) continue; - if (!m.isUsed()) + if (!execution.methods.contains(m)) + //if (!m.isUsed()) { cf.getMethods().removeMethod(m); ++i; diff --git a/src/main/java/info/sigterm/deob/deobfuscators/UnusedParameters.java b/src/main/java/info/sigterm/deob/deobfuscators/UnusedParameters.java index 32ecb2b4b5..33c8ddd05d 100644 --- a/src/main/java/info/sigterm/deob/deobfuscators/UnusedParameters.java +++ b/src/main/java/info/sigterm/deob/deobfuscators/UnusedParameters.java @@ -22,7 +22,7 @@ public class UnusedParameters int collide = 0; int overrides = 0; - group.buildCallGraph(); // method.removeParameter uses the callgraph + //group.buildCallGraph(); // method.removeParameter uses the callgraph for (ClassFile cf : group.getClasses()) { diff --git a/src/main/java/info/sigterm/deob/execution/Execution.java b/src/main/java/info/sigterm/deob/execution/Execution.java index 6afbcf1de0..faf00cadb5 100644 --- a/src/main/java/info/sigterm/deob/execution/Execution.java +++ b/src/main/java/info/sigterm/deob/execution/Execution.java @@ -6,36 +6,65 @@ import info.sigterm.deob.Method; import info.sigterm.deob.attributes.code.Exceptions; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class Execution { private ClassGroup group; public List frames = new ArrayList<>(), processedFrames = new ArrayList<>(); + private List pendingMethods = new ArrayList<>(); // pending methods + public Set methods = new HashSet<>(); // all methods public Execution(ClassGroup group) { this.group = group; } + public void populateInitialMethods() + { + for (ClassFile cf : group.getClasses()) + { + for (Method m : cf.getMethods().getMethods()) + { + // ob'd names seem to be <= 2 + if (m.getName().length() > 2) + { + addMethod(m); // I guess this method name is overriding a jre interface (init, run, ?). + } + } + } + } + + public void addMethod(Method method) + { + if (methods.contains(method)) + return; // already processed + + pendingMethods.add(method); + methods.add(method); + } + public void run() { // XXX update pc? some instructiosn rely on it still. int count = 0, fcount = 0; - for (ClassFile cf : group.getClasses()) - for (Method method : cf.getMethods().getMethods()) - { - if (method.getCode() == null) - continue; + while (!pendingMethods.isEmpty()) + { + Method method = pendingMethods.remove(0); + + if (method.getCode() == null) + continue; - Frame f = new Frame(this, method); - frames.add(f); + Frame f = new Frame(this, method); + frames.add(f); - fcount += this.runFrames(); - ++count; - } + fcount += this.runFrames(); + ++count; + } System.out.println("Processed " + count + " methods and " + fcount + " paths"); } diff --git a/src/main/java/info/sigterm/deob/execution/Frame.java b/src/main/java/info/sigterm/deob/execution/Frame.java index 5b64c80eef..faeff4d7fc 100644 --- a/src/main/java/info/sigterm/deob/execution/Frame.java +++ b/src/main/java/info/sigterm/deob/execution/Frame.java @@ -77,6 +77,11 @@ public class Frame executing = false; } + public Execution getExecution() + { + return execution; + } + public Method getMethod() { return method;