wip removal of unused methods based on execution from init.

This commit is contained in:
Adam
2015-06-27 23:47:43 -04:00
parent dfcc41b41c
commit d9f4d257a5
13 changed files with 161 additions and 107 deletions

View File

@@ -9,6 +9,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class ClassFile public class ClassFile
{ {
@@ -18,7 +19,7 @@ public class ClassFile
private DataInputStream is; private DataInputStream is;
private ClassFile parent; // super class private ClassFile parent; // super class
private ArrayList<ClassFile> children = new ArrayList<ClassFile>(); // classes which inherit from this private List<ClassFile> children = new ArrayList<>(); // classes which inherit from this
private short minor_version; private short minor_version;
private short major_version; private short major_version;
@@ -125,10 +126,12 @@ public class ClassFile
public ClassFile getParent() public ClassFile getParent()
{ {
String superName = super_class.getName(); return parent;
ClassFile other = group.findClass(superName); }
assert other != this;
return other; public List<ClassFile> getChildren()
{
return children;
} }
public Field findField(NameAndType nat) public Field findField(NameAndType nat)

View File

@@ -7,7 +7,7 @@ import java.util.List;
public class ClassGroup public class ClassGroup
{ {
private ArrayList<ClassFile> classes = new ArrayList<ClassFile>(); private List<ClassFile> classes = new ArrayList<>();
public ClassGroup() public ClassGroup()
{ {
@@ -45,16 +45,4 @@ public class ClassGroup
for (ClassFile c : classes) for (ClassFile c : classes)
c.buildInstructionGraph(); 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();
}
} }

View File

@@ -41,6 +41,7 @@ public class Deob
ClassGroup group = loadJar(args[0]); ClassGroup group = loadJar(args[0]);
/*
// remove except RuntimeException // remove except RuntimeException
new RuntimeExceptions().run(group); new RuntimeExceptions().run(group);
@@ -48,18 +49,19 @@ public class Deob
new IllegalStateExceptions().run(group); new IllegalStateExceptions().run(group);
// remove code blocks that used to be the runtime exception handlers // remove code blocks that used to be the runtime exception handlers
new UnusedBlocks().run(group); new UnusedBlocks().run(group);*/
// remove unused methods // remove unused methods
new UnusedMethods().run(group); new UnusedMethods().run(group);
/*
// remove unused parameters // remove unused parameters
new UnusedParameters().run(group); new UnusedParameters().run(group);
// remove jump obfuscation // remove jump obfuscation
new Jumps().run(group); new Jumps().run(group);
new ModularArithmeticDeobfuscation().run(group); new ModularArithmeticDeobfuscation().run(group);*/
saveJar(group, args[1]); saveJar(group, args[1]);

View File

@@ -32,8 +32,6 @@ public class Method
private String name; private String name;
private Signature arguments; private Signature arguments;
private Attributes attributes; private Attributes attributes;
List<Node> callsTo = new ArrayList<>();
List<Node> callsFrom = new ArrayList<>();
Method(Methods methods) throws IOException Method(Methods methods) throws IOException
{ {
@@ -60,11 +58,12 @@ public class Method
protected void remove() protected void remove()
{ {
assert callsFrom.isEmpty(); //assert callsFrom.isEmpty();
} }
public void removeParameter(Execution execution, int paramIndex, int lvtIndex) public void removeParameter(Execution execution, int paramIndex, int lvtIndex)
{ {
/*
Set<Instruction> done = new HashSet<>(); Set<Instruction> done = new HashSet<>();
for (Node n : callsFrom) for (Node n : callsFrom)
{ {
@@ -160,6 +159,7 @@ public class Method
} }
arguments.remove(paramIndex); arguments.remove(paramIndex);
*/
} }
public Methods getMethods() public Methods getMethods()
@@ -222,13 +222,13 @@ public class Method
code.buildInstructionGraph(); code.buildInstructionGraph();
} }
public void clearCallGraph() /*public void clearCallGraph()
{ {
callsTo.clear(); callsTo.clear();
callsFrom.clear(); callsFrom.clear();
} }*/
public boolean isUsed() /*public boolean isUsed()
{ {
if (!callsFrom.isEmpty()) if (!callsFrom.isEmpty())
return true; return true;
@@ -240,8 +240,9 @@ public class Method
} }
return false; return false;
} }*/
/*
public void addCallTo(Instruction ins, Method method) public void addCallTo(Instruction ins, Method method)
{ {
assert method != null; assert method != null;
@@ -249,6 +250,7 @@ public class Method
callsTo.add(node); callsTo.add(node);
method.callsFrom.add(node); method.callsFrom.add(node);
} }
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Instruction & LVTInstruction> List<T> findLVTInstructionsForVariable(int index) public <T extends Instruction & LVTInstruction> List<T> findLVTInstructionsForVariable(int index)

View File

@@ -1,5 +1,7 @@
package info.sigterm.deob.attributes.code.instruction.types; package info.sigterm.deob.attributes.code.instruction.types;
import java.util.List;
import info.sigterm.deob.Method; import info.sigterm.deob.Method;
import info.sigterm.deob.pool.PoolEntry; import info.sigterm.deob.pool.PoolEntry;

View File

@@ -1,6 +1,7 @@
package info.sigterm.deob.attributes.code.instructions; package info.sigterm.deob.attributes.code.instructions;
import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassFile;
import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.InstructionType;
import info.sigterm.deob.attributes.code.Instructions; 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.StackContext;
import info.sigterm.deob.execution.Type; import info.sigterm.deob.execution.Type;
import info.sigterm.deob.pool.InterfaceMethod; import info.sigterm.deob.pool.InterfaceMethod;
import info.sigterm.deob.pool.Method;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry; import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
@@ -19,6 +19,8 @@ import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class InvokeInterface extends Instruction implements InvokeInstruction public class InvokeInterface extends Instruction implements InvokeInstruction
{ {
@@ -45,20 +47,28 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
out.writeByte(0); out.writeByte(0);
} }
@Override private List<info.sigterm.deob.Method> getMethods()
public void buildCallGraph()
{ {
info.sigterm.deob.pool.Class clazz = method.getClassEntry(); ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
NameAndType nat = method.getNameAndType();
info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); ClassFile otherClass = group.findClass(method.getClassEntry().getName());
ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName());
if (otherClass == null) if (otherClass == null)
return; return new ArrayList<>(); // not our class
info.sigterm.deob.Method other = otherClass.findMethod(nat);
thisMethod.addCallTo(this, other); // look up this method in this class and anything that inherits from it
List<info.sigterm.deob.Method> list = new ArrayList<>();
findMethodFromClass(list, otherClass);
return list;
}
private void findMethodFromClass(List<info.sigterm.deob.Method> 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 @Override
@@ -89,6 +99,12 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
} }
frame.addInstructionContext(ins); 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) private void handleExceptions(Frame frame)

View File

@@ -1,6 +1,7 @@
package info.sigterm.deob.attributes.code.instructions; package info.sigterm.deob.attributes.code.instructions;
import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassFile;
import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.InstructionType;
import info.sigterm.deob.attributes.code.Instructions; import info.sigterm.deob.attributes.code.Instructions;
@@ -18,6 +19,8 @@ import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class InvokeSpecial extends Instruction implements InvokeInstruction public class InvokeSpecial extends Instruction implements InvokeInstruction
{ {
@@ -39,21 +42,19 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
out.writeShort(this.getPool().make(method)); out.writeShort(this.getPool().make(method));
} }
@Override private List<info.sigterm.deob.Method> getMethods()
public void buildCallGraph()
{ {
info.sigterm.deob.pool.Class clazz = method.getClassEntry(); ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
NameAndType nat = method.getNameAndType();
info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); ClassFile otherClass = group.findClass(method.getClassEntry().getName());
ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName());
if (otherClass == null) 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<info.sigterm.deob.Method> list = new ArrayList<>();
list.add(other);
return list;
} }
@Override @Override
@@ -84,6 +85,12 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
} }
frame.addInstructionContext(ins); 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) private void handleExceptions(Frame frame)

View File

@@ -1,6 +1,7 @@
package info.sigterm.deob.attributes.code.instructions; package info.sigterm.deob.attributes.code.instructions;
import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassFile;
import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.InstructionType;
import info.sigterm.deob.attributes.code.Instructions; import info.sigterm.deob.attributes.code.Instructions;
@@ -18,6 +19,8 @@ import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class InvokeStatic extends Instruction implements InvokeInstruction public class InvokeStatic extends Instruction implements InvokeInstruction
{ {
@@ -39,21 +42,19 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
out.writeShort(this.getPool().make(method)); out.writeShort(this.getPool().make(method));
} }
@Override private List<info.sigterm.deob.Method> getMethods()
public void buildCallGraph()
{ {
info.sigterm.deob.pool.Class clazz = method.getClassEntry(); ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
NameAndType nat = method.getNameAndType();
info.sigterm.deob.Method thisMethod = this.getInstructions().getCode().getAttributes().getMethod(); ClassFile otherClass = group.findClass(method.getClassEntry().getName());
ClassFile otherClass = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName());
if (otherClass == null) 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<info.sigterm.deob.Method> list = new ArrayList<>();
list.add(other);
return list;
} }
@Override @Override
@@ -81,6 +82,12 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
} }
frame.addInstructionContext(ins); 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) private void handleExceptions(Frame frame)

View File

@@ -19,6 +19,8 @@ import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class InvokeVirtual extends Instruction implements InvokeInstruction public class InvokeVirtual extends Instruction implements InvokeInstruction
{ {
@@ -40,24 +42,6 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
out.writeShort(this.getPool().make(method)); 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 @Override
public void execute(Frame frame) public void execute(Frame frame)
{ {
@@ -75,9 +59,6 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
StackContext object = stack.pop(); StackContext object = stack.pop();
ins.pop(object); ins.pop(object);
// the method being invoked, looked up dynamically based on the type
//info.sigterm.deob.Method executedMethod = findVirtualMethod(object.getType());
handleExceptions(frame); handleExceptions(frame);
if (!method.getNameAndType().isVoid()) if (!method.getNameAndType().isVoid())
@@ -89,31 +70,39 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
} }
frame.addInstructionContext(ins); 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<info.sigterm.deob.Method> 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(); ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
ClassFile otherClass = group.findClass(type.type); ClassFile otherClass = group.findClass(method.getClassEntry().getName());
if (otherClass == null) 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 // look up this method in this class and anything that inherits from it
return findMethodFromClass(otherClass); List<info.sigterm.deob.Method> list = new ArrayList<>();
findMethodFromClass(list, otherClass);
return list;
} }
private info.sigterm.deob.Method findMethodFromClass(ClassFile clazz) private void findMethodFromClass(List<info.sigterm.deob.Method> list, ClassFile clazz)
{ {
if (clazz == null)
return null;
info.sigterm.deob.Method m = clazz.findMethod(method.getNameAndType()); info.sigterm.deob.Method m = clazz.findMethod(method.getNameAndType());
if (m != null) if (m != null)
return m; list.add(m);
return findMethodFromClass(clazz.getParent()); for (ClassFile cf : clazz.getChildren())
findMethodFromClass(list, cf);
} }
private void handleExceptions(Frame frame) private void handleExceptions(Frame frame)

View File

@@ -3,6 +3,7 @@ package info.sigterm.deob.deobfuscators;
import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassFile;
import info.sigterm.deob.ClassGroup; import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.Method; import info.sigterm.deob.Method;
import info.sigterm.deob.execution.Execution;
import java.util.ArrayList; import java.util.ArrayList;
@@ -10,7 +11,9 @@ public class UnusedMethods
{ {
public void run(ClassGroup group) public void run(ClassGroup group)
{ {
group.buildCallGraph(); Execution execution = new Execution(group);
execution.populateInitialMethods();
execution.run();
int i = 0; int i = 0;
for (ClassFile cf : group.getClasses()) for (ClassFile cf : group.getClasses())
@@ -21,7 +24,8 @@ public class UnusedMethods
if (m.getName().length() > 2) if (m.getName().length() > 2)
continue; continue;
if (!m.isUsed()) if (!execution.methods.contains(m))
//if (!m.isUsed())
{ {
cf.getMethods().removeMethod(m); cf.getMethods().removeMethod(m);
++i; ++i;

View File

@@ -22,7 +22,7 @@ public class UnusedParameters
int collide = 0; int collide = 0;
int overrides = 0; int overrides = 0;
group.buildCallGraph(); // method.removeParameter uses the callgraph //group.buildCallGraph(); // method.removeParameter uses the callgraph
for (ClassFile cf : group.getClasses()) for (ClassFile cf : group.getClasses())
{ {

View File

@@ -6,36 +6,65 @@ import info.sigterm.deob.Method;
import info.sigterm.deob.attributes.code.Exceptions; import info.sigterm.deob.attributes.code.Exceptions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class Execution public class Execution
{ {
private ClassGroup group; private ClassGroup group;
public List<Frame> frames = new ArrayList<>(), public List<Frame> frames = new ArrayList<>(),
processedFrames = new ArrayList<>(); processedFrames = new ArrayList<>();
private List<Method> pendingMethods = new ArrayList<>(); // pending methods
public Set<Method> methods = new HashSet<>(); // all methods
public Execution(ClassGroup group) public Execution(ClassGroup group)
{ {
this.group = 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() public void run()
{ {
// XXX update pc? some instructiosn rely on it still. // XXX update pc? some instructiosn rely on it still.
int count = 0, fcount = 0; int count = 0, fcount = 0;
for (ClassFile cf : group.getClasses()) while (!pendingMethods.isEmpty())
for (Method method : cf.getMethods().getMethods()) {
{ Method method = pendingMethods.remove(0);
if (method.getCode() == null)
continue;
Frame f = new Frame(this, method); if (method.getCode() == null)
frames.add(f); continue;
fcount += this.runFrames(); Frame f = new Frame(this, method);
++count; frames.add(f);
}
fcount += this.runFrames();
++count;
}
System.out.println("Processed " + count + " methods and " + fcount + " paths"); System.out.println("Processed " + count + " methods and " + fcount + " paths");
} }

View File

@@ -77,6 +77,11 @@ public class Frame
executing = false; executing = false;
} }
public Execution getExecution()
{
return execution;
}
public Method getMethod() public Method getMethod()
{ {
return method; return method;