From 5478fc7385baa1da8744801fe9ad186ab89facc5 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 30 Jul 2015 16:39:48 -0400 Subject: [PATCH] Start of constant parameter stuff --- src/main/java/info/sigterm/deob/Deob.java | 62 +++++--- .../instruction/types/InvokeInstruction.java | 2 + .../code/instructions/InvokeInterface.java | 3 +- .../code/instructions/InvokeSpecial.java | 3 +- .../code/instructions/InvokeStatic.java | 3 +- .../code/instructions/InvokeVirtual.java | 3 +- .../deob/deobfuscators/ConstantParameter.java | 133 ++++++++++++++++++ .../java/info/sigterm/deob/pool/Double.java | 6 + .../java/info/sigterm/deob/pool/Float.java | 6 + .../java/info/sigterm/deob/pool/Integer.java | 6 + .../java/info/sigterm/deob/pool/Long.java | 6 + .../info/sigterm/deob/pool/PoolEntry.java | 5 + .../java/info/sigterm/deob/pool/String.java | 6 + .../java/info/sigterm/deob/pool/UTF8.java | 6 + 14 files changed, 227 insertions(+), 23 deletions(-) create mode 100644 src/main/java/info/sigterm/deob/deobfuscators/ConstantParameter.java diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index ac2ac68459..47c37c3652 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -20,6 +20,7 @@ import info.sigterm.deob.attributes.code.instructions.Goto; import info.sigterm.deob.attributes.code.instructions.GotoW; import info.sigterm.deob.attributes.code.instructions.Return; import info.sigterm.deob.block.Block; +import info.sigterm.deob.deobfuscators.ConstantParameter; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -43,31 +44,54 @@ public class Deob ClassGroup group = loadJar(args[0]); - new RenameUnique().run(group); - - // remove except RuntimeException - new RuntimeExceptions().run(group); - // the blocks of runtime exceptions may contain interesting things like other obfuscations we identify later, but now that - // it can't be reached by the execution phase, those things become confused. so remove blocks here. - new UnusedBlocks().run(group); + new ConstantParameter().run(group); - // remove unused methods - new UnusedMethods().run(group); - - // remove illegal state exceptions, frees up some parameters - new IllegalStateExceptions().run(group); - - // remove unhit blocks - new UnusedBlocks().run(group); - - // remove unused parameters - new UnusedParameters().run(group); +// long bstart = System.currentTimeMillis(); +// new RenameUnique().run(group); +// long bdur = System.currentTimeMillis() - bstart; +// System.out.println("rename unique took " + bdur/1000L + " seconds"); +// +// // remove except RuntimeException +// bstart = System.currentTimeMillis(); +// new RuntimeExceptions().run(group); +// // the blocks of runtime exceptions may contain interesting things like other obfuscations we identify later, but now that +// // it can't be reached by the execution phase, those things become confused. so remove blocks here. +// new UnusedBlocks().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("runtime exception took " + bdur/1000L + " seconds"); +// +// // remove unused methods +// bstart = System.currentTimeMillis(); +// new UnusedMethods().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused methods took " + bdur/1000L + " seconds"); +// +// // remove illegal state exceptions, frees up some parameters +// bstart = System.currentTimeMillis(); +// new IllegalStateExceptions().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("illegal state exception took " + bdur/1000L + " seconds"); +// +// // remove unhit blocks +// bstart = System.currentTimeMillis(); +// new UnusedBlocks().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused blocks took " + bdur/1000L + " seconds"); +// +// // remove unused parameters +// bstart = System.currentTimeMillis(); +// new UnusedParameters().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused blocks took " + bdur/1000L + " seconds"); // remove jump obfuscation //new Jumps().run(group); // remove unused fields - new UnusedFields().run(group); +// bstart = System.currentTimeMillis(); +// new UnusedFields().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused fields took " + bdur/1000L + " seconds"); //new ModularArithmeticDeobfuscation().run(group); 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 a6fc6f29f1..110cb1f8cd 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 @@ -10,4 +10,6 @@ public interface InvokeInstruction public void removeParameter(int idx); public PoolEntry getMethod(); + + public List getMethods(); } 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 f2c781c705..3c636a70a2 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 @@ -48,7 +48,8 @@ public class InvokeInterface extends Instruction implements InvokeInstruction out.writeByte(0); } - private List getMethods() + @Override + public List getMethods() { ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); 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 2d6963b4d7..0ea99ea03d 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 @@ -43,7 +43,8 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction out.writeShort(this.getPool().make(method)); } - private List getMethods() + @Override + public List getMethods() { ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); 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 fa258c5ffc..701b9dfdc1 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 @@ -43,7 +43,8 @@ public class InvokeStatic extends Instruction implements InvokeInstruction out.writeShort(this.getPool().make(method)); } - private List getMethods() + @Override + public List getMethods() { ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); 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 b84ad85bfe..2a5f506782 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 @@ -83,7 +83,8 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction // 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() + @Override + public List getMethods() { ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup(); diff --git a/src/main/java/info/sigterm/deob/deobfuscators/ConstantParameter.java b/src/main/java/info/sigterm/deob/deobfuscators/ConstantParameter.java new file mode 100644 index 0000000000..560894ca4f --- /dev/null +++ b/src/main/java/info/sigterm/deob/deobfuscators/ConstantParameter.java @@ -0,0 +1,133 @@ +package info.sigterm.deob.deobfuscators; + +import info.sigterm.deob.ClassGroup; +import info.sigterm.deob.Deobfuscator; +import info.sigterm.deob.Method; +import info.sigterm.deob.attributes.code.instruction.types.InvokeInstruction; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; +import info.sigterm.deob.execution.Execution; +import info.sigterm.deob.execution.Frame; +import info.sigterm.deob.execution.InstructionContext; +import info.sigterm.deob.execution.StackContext; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.map.MultiValueMap; + +class ConstantMethodParameter +{ + public Method method; + public int paramNum; + public Object value; +} + +class MethodGroup +{ + public List methods; // methods that can be invoked + public Collection constantParameters; // parameters which are always constant for all invocations + public List cmps = new ArrayList<>(); // cmps for all methods in the group, which hold the values. +} + +public class ConstantParameter implements Deobfuscator +{ + private MultiValueMap parameters = new MultiValueMap<>(); + // methods can be in more than one group because of multiple inheritance with interfaces + private MultiValueMap methodGroups = new MultiValueMap<>(); + + private void findConstantParameter(Execution execution, Method method, InstructionContext invokeCtx) + { + List pops = invokeCtx.getPops(); + for (int i = 0; i < method.getDescriptor().size(); ++i) + { + // object is poped first + + int offset = method.isStatic() ? 0 : 1; + + StackContext ctx = pops.get(offset + i); + if (ctx.getPushed().getInstruction() instanceof PushConstantInstruction) + { + PushConstantInstruction pc = (PushConstantInstruction) ctx.getPushed().getInstruction(); + + if (!(pc.getConstant().getObject() instanceof Integer)) + continue; + + ConstantMethodParameter cmp = new ConstantMethodParameter(); + cmp.method = method; + cmp.paramNum = i; + cmp.value = pc.getConstant().getObject(); + + parameters.put(method, cmp); + } + } + } + + private Collection getParametersFor(Method method) + { + Collection params = parameters.getCollection(method); + Collection out = new ArrayList<>(); + + if (params != null) + for (ConstantMethodParameter p : params) + out.add(p.paramNum); + + return out; + } + + private void findParameters(Execution execution) + { + for (Frame frame : execution.processedFrames) + for (InstructionContext ins : frame.getInstructions()) + { + if (!(ins.getInstruction() instanceof InvokeInstruction)) + continue; + + List methods = ((InvokeInstruction) ins.getInstruction()).getMethods(); + for (Method m : methods) + findConstantParameter(execution, m, ins); + + // get common constant indexes from all methods that can possibly be called + Collection parameterIndexes = null; + for (Method m : methods) + { + Collection idxs = getParametersFor(m); + + if (parameterIndexes == null) + parameterIndexes = idxs; + else + parameterIndexes = CollectionUtils.intersection(parameterIndexes, idxs); + } + + MethodGroup group = new MethodGroup(); + group.methods = methods; + group.constantParameters = parameterIndexes; + + // build constant method parameters + for (Method m : methods) + { + Collection params = parameters.getCollection(m); + if (params != null) + group.cmps.addAll(params); + } + + // insert + for (Method m : methods) + methodGroups.put(m, group); + } + } + + @Override + public void run(ClassGroup group) + { + group.buildClassGraph(); // required for getMethods in the invoke stuff + + Execution execution = new Execution(group); + execution.populateInitialMethods(); + execution.run(); + + findParameters(execution); + + System.out.println("finished with " + methodGroups.size() + " groups"); + } + +} diff --git a/src/main/java/info/sigterm/deob/pool/Double.java b/src/main/java/info/sigterm/deob/pool/Double.java index ce6cd6846e..41f888aa20 100644 --- a/src/main/java/info/sigterm/deob/pool/Double.java +++ b/src/main/java/info/sigterm/deob/pool/Double.java @@ -54,4 +54,10 @@ public class Double extends PoolEntry { out.writeDouble(value); } + + @Override + public Object getObject() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/pool/Float.java b/src/main/java/info/sigterm/deob/pool/Float.java index 3ef228c280..e66c0d781c 100644 --- a/src/main/java/info/sigterm/deob/pool/Float.java +++ b/src/main/java/info/sigterm/deob/pool/Float.java @@ -48,4 +48,10 @@ public class Float extends PoolEntry { out.writeFloat(value); } + + @Override + public Object getObject() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/pool/Integer.java b/src/main/java/info/sigterm/deob/pool/Integer.java index c44b53cd9e..f2708753cb 100644 --- a/src/main/java/info/sigterm/deob/pool/Integer.java +++ b/src/main/java/info/sigterm/deob/pool/Integer.java @@ -54,4 +54,10 @@ public class Integer extends PoolEntry { out.writeInt(value); } + + @Override + public Object getObject() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/pool/Long.java b/src/main/java/info/sigterm/deob/pool/Long.java index 38513a0b1a..927fe642b5 100644 --- a/src/main/java/info/sigterm/deob/pool/Long.java +++ b/src/main/java/info/sigterm/deob/pool/Long.java @@ -54,4 +54,10 @@ public class Long extends PoolEntry { out.writeLong(value); } + + @Override + public Object getObject() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/pool/PoolEntry.java b/src/main/java/info/sigterm/deob/pool/PoolEntry.java index 99f621966c..3e6ad8940f 100644 --- a/src/main/java/info/sigterm/deob/pool/PoolEntry.java +++ b/src/main/java/info/sigterm/deob/pool/PoolEntry.java @@ -45,4 +45,9 @@ public abstract class PoolEntry { return 1; } + + public Object getObject() + { + return this; + } } diff --git a/src/main/java/info/sigterm/deob/pool/String.java b/src/main/java/info/sigterm/deob/pool/String.java index b10815fd76..e8ce6d56cd 100644 --- a/src/main/java/info/sigterm/deob/pool/String.java +++ b/src/main/java/info/sigterm/deob/pool/String.java @@ -61,4 +61,10 @@ public class String extends PoolEntry { out.writeShort(stringIndex); } + + @Override + public Object getObject() + { + return string; + } } diff --git a/src/main/java/info/sigterm/deob/pool/UTF8.java b/src/main/java/info/sigterm/deob/pool/UTF8.java index 491b317ec8..1adf819435 100644 --- a/src/main/java/info/sigterm/deob/pool/UTF8.java +++ b/src/main/java/info/sigterm/deob/pool/UTF8.java @@ -46,4 +46,10 @@ public class UTF8 extends PoolEntry java.lang.String s = getValue(); out.writeUTF(s); } + + @Override + public Object getObject() + { + return string; + } }