From 5839452b3bc2a8a5cac1652e45ee3a6b5862f10c Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 16 Aug 2015 21:15:51 -0400 Subject: [PATCH] requires some work to move static field initializers --- .../java/net/runelite/deob/ClassFile.java | 5 + src/main/java/net/runelite/deob/Deob.java | 122 +++++++++--------- src/main/java/net/runelite/deob/Method.java | 14 ++ .../runelite/deob/attributes/Attribute.java | 12 +- .../runelite/deob/attributes/Attributes.java | 7 +- .../net/runelite/deob/attributes/Code.java | 18 ++- .../deob/attributes/ConstantValue.java | 16 ++- .../runelite/deob/attributes/Exceptions.java | 12 +- .../net/runelite/deob/attributes/Unknown.java | 10 +- .../deob/attributes/code/Instructions.java | 6 +- .../attributes/code/instructions/VReturn.java | 3 +- .../deob/deobfuscators/FieldMover.java | 113 ++++++++++++++-- .../deob/execution/InstructionContext.java | 7 +- .../runelite/deob/execution/StackContext.java | 15 ++- 14 files changed, 250 insertions(+), 110 deletions(-) diff --git a/src/main/java/net/runelite/deob/ClassFile.java b/src/main/java/net/runelite/deob/ClassFile.java index c1bc7aad38..1ad261847d 100644 --- a/src/main/java/net/runelite/deob/ClassFile.java +++ b/src/main/java/net/runelite/deob/ClassFile.java @@ -193,6 +193,11 @@ public class ClassFile return methods.findMethod(nat); } + public Method findMethod(String name) + { + return methods.findMethod(name); + } + public Method findMethodDeep(String name) { Method m = methods.findMethod(name); diff --git a/src/main/java/net/runelite/deob/Deob.java b/src/main/java/net/runelite/deob/Deob.java index 2a7d7fd37e..7f31a058cd 100644 --- a/src/main/java/net/runelite/deob/Deob.java +++ b/src/main/java/net/runelite/deob/Deob.java @@ -46,72 +46,72 @@ public class Deob // bdur = System.currentTimeMillis() - bstart; // System.out.println("rename unique took " + bdur/1000L + " seconds"); - // remove except RuntimeException - bstart = System.currentTimeMillis(); - new RuntimeExceptions().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"); - - new UnreachedCode().run(group); - - // 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 constant logically dead parameters - bstart = System.currentTimeMillis(); - new ConstantParameter().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("constant param took " + bdur/1000L + " seconds"); - - // remove unhit blocks - bstart = System.currentTimeMillis(); - new UnreachedCode().run(group); - //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 params took " + bdur/1000L + " seconds"); - - // remove jump obfuscation - //new Jumps().run(group); - - // remove unused fields - bstart = System.currentTimeMillis(); - new UnusedFields().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused fields took " + bdur/1000L + " seconds"); - - // remove unused methods, again? - bstart = System.currentTimeMillis(); - new UnusedMethods().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused methods took " + bdur/1000L + " seconds"); - - - new MethodInliner().run(group); +// // remove except RuntimeException +// bstart = System.currentTimeMillis(); +// new RuntimeExceptions().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"); +// +// new UnreachedCode().run(group); +// +// // 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 constant logically dead parameters +// bstart = System.currentTimeMillis(); +// new ConstantParameter().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("constant param took " + bdur/1000L + " seconds"); +// +// // remove unhit blocks +// bstart = System.currentTimeMillis(); +// new UnreachedCode().run(group); +// //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 params took " + bdur/1000L + " seconds"); +// +// // remove jump obfuscation +// //new Jumps().run(group); +// +// // remove unused fields +// bstart = System.currentTimeMillis(); +// new UnusedFields().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused fields took " + bdur/1000L + " seconds"); +// +// // remove unused methods, again? +// bstart = System.currentTimeMillis(); +// new UnusedMethods().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused methods took " + bdur/1000L + " seconds"); +// +// +// new MethodInliner().run(group); // new ModularArithmeticDeobfuscation().run(group); - - new MethodMover().run(group); +// +// new MethodMover().run(group); new FieldMover().run(group); +// +// new FieldInliner().run(group); - new FieldInliner().run(group); - - new UnusedClass().run(group); + //new UnusedClass().run(group); saveJar(group, args[1]); diff --git a/src/main/java/net/runelite/deob/Method.java b/src/main/java/net/runelite/deob/Method.java index 45830a7870..710fa636c9 100644 --- a/src/main/java/net/runelite/deob/Method.java +++ b/src/main/java/net/runelite/deob/Method.java @@ -38,6 +38,15 @@ public class Method name = pool.getUTF8(is.readUnsignedShort()); arguments = new Signature(pool.getUTF8(is.readUnsignedShort())); attributes = new Attributes(this); + attributes.load(); + } + + public Method(Methods methods, String name, Signature signature) + { + this.methods = methods; + this.name = name; + this.arguments = signature; + attributes = new Attributes(this); } public void write(DataOutputStream out) throws IOException @@ -62,6 +71,11 @@ public class Method this.methods = methods; } + public Attributes getAttributes() + { + return attributes; + } + public String getName() { return name; diff --git a/src/main/java/net/runelite/deob/attributes/Attribute.java b/src/main/java/net/runelite/deob/attributes/Attribute.java index 08e9c54b3b..71d48e8f7b 100644 --- a/src/main/java/net/runelite/deob/attributes/Attribute.java +++ b/src/main/java/net/runelite/deob/attributes/Attribute.java @@ -11,20 +11,16 @@ public abstract class Attribute private AttributeType type; private int length; - Attribute(Attributes attr, AttributeType type) throws IOException + Attribute(Attributes attr, AttributeType type) { this.attributes = attr; this.type = type; - - DataInputStream is = attr.getStream(); - this.length = is.readInt(); } - Attribute(Attributes attr, AttributeType type, int length) + public void load() throws IOException { - this.attributes = attr; - this.type = type; - this.length = length; + DataInputStream is = attributes.getStream(); + this.length = is.readInt(); } public final void write(DataOutputStream out) throws IOException diff --git a/src/main/java/net/runelite/deob/attributes/Attributes.java b/src/main/java/net/runelite/deob/attributes/Attributes.java index c18d178278..648a0113fd 100644 --- a/src/main/java/net/runelite/deob/attributes/Attributes.java +++ b/src/main/java/net/runelite/deob/attributes/Attributes.java @@ -33,11 +33,9 @@ public class Attributes load(); } - public Attributes(Method m) throws IOException + public Attributes(Method m) { method = m; - - load(); } public Attributes(Code c) throws IOException @@ -82,7 +80,7 @@ public class Attributes return getClassFile().getStream(); } - private void load() throws IOException + public void load() throws IOException { DataInputStream is = getStream(); @@ -97,6 +95,7 @@ public class Attributes { Constructor con = type.getAttributeClass().getConstructor(new Class[] { Attributes.class }); Attribute attr = con.newInstance(this); + attr.load(); if (type != AttributeType.UNKNOWN) attributes.add(attr); diff --git a/src/main/java/net/runelite/deob/attributes/Code.java b/src/main/java/net/runelite/deob/attributes/Code.java index db94a29fd0..13d09f5104 100644 --- a/src/main/java/net/runelite/deob/attributes/Code.java +++ b/src/main/java/net/runelite/deob/attributes/Code.java @@ -17,16 +17,23 @@ public class Code extends Attribute private Exceptions exceptions; private Attributes attributes; - public Code(Attributes attributes) throws IOException + public Code(Attributes attributes) { super(attributes, AttributeType.CODE); - - DataInputStream is = attributes.getStream(); + } + + @Override + public void load() throws IOException + { + super.load(); + + DataInputStream is = this.getAttributes().getStream(); maxStack = is.readUnsignedShort(); is.skip(2); // max locals instructions = new Instructions(this); + instructions.load(); exceptions = new Exceptions(this); this.attributes = new Attributes(this); @@ -95,6 +102,11 @@ public class Code extends Attribute { return instructions; } + + public void setInstructions(Instructions instructions) + { + this.instructions = instructions; + } public void buildInstructionGraph() { diff --git a/src/main/java/net/runelite/deob/attributes/ConstantValue.java b/src/main/java/net/runelite/deob/attributes/ConstantValue.java index 97222f2df2..7d76506a5b 100644 --- a/src/main/java/net/runelite/deob/attributes/ConstantValue.java +++ b/src/main/java/net/runelite/deob/attributes/ConstantValue.java @@ -10,20 +10,26 @@ public class ConstantValue extends Attribute { private PoolEntry value; - public ConstantValue(Attributes attributes) throws IOException + public ConstantValue(Attributes attributes) { super(attributes, AttributeType.CONSTANT_VALUE); - - DataInputStream is = attributes.getStream(); - value = this.getAttributes().getClassFile().getPool().getEntry(is.readUnsignedShort()); } public ConstantValue(Attributes attributes, PoolEntry value) { - super(attributes, AttributeType.CONSTANT_VALUE, -1); + super(attributes, AttributeType.CONSTANT_VALUE); this.value = value; } + + @Override + public void load() throws IOException + { + super.load(); + + DataInputStream is = this.getAttributes().getStream(); + value = this.getAttributes().getClassFile().getPool().getEntry(is.readUnsignedShort()); + } public PoolEntry getValue() { diff --git a/src/main/java/net/runelite/deob/attributes/Exceptions.java b/src/main/java/net/runelite/deob/attributes/Exceptions.java index d5c2cdbccc..abb7cebb35 100644 --- a/src/main/java/net/runelite/deob/attributes/Exceptions.java +++ b/src/main/java/net/runelite/deob/attributes/Exceptions.java @@ -13,16 +13,22 @@ public class Exceptions extends Attribute { private List classes = new ArrayList<>(); - public Exceptions(Attributes attributes) throws IOException + public Exceptions(Attributes attributes) { super(attributes, AttributeType.EXCEPTIONS); + } + + @Override + public void load() throws IOException + { + super.load(); - DataInputStream is = attributes.getStream(); + DataInputStream is = this.getAttributes().getStream(); int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) { - Class clazz = attributes.getClassFile().getPool().getClass(is.readUnsignedShort()); + Class clazz = this.getAttributes().getClassFile().getPool().getClass(is.readUnsignedShort()); classes.add(clazz); } } diff --git a/src/main/java/net/runelite/deob/attributes/Unknown.java b/src/main/java/net/runelite/deob/attributes/Unknown.java index 632e5353b7..a790c45481 100644 --- a/src/main/java/net/runelite/deob/attributes/Unknown.java +++ b/src/main/java/net/runelite/deob/attributes/Unknown.java @@ -8,12 +8,18 @@ public class Unknown extends Attribute { private byte[] data; - public Unknown(Attributes attributes) throws IOException + public Unknown(Attributes attributes) { super(attributes, AttributeType.UNKNOWN); + } + + @Override + public void load() throws IOException + { + super.load(); int len = this.getLength(); - DataInputStream is = attributes.getStream(); + DataInputStream is = this.getAttributes().getStream(); data = new byte[len]; diff --git a/src/main/java/net/runelite/deob/attributes/code/Instructions.java b/src/main/java/net/runelite/deob/attributes/code/Instructions.java index a5febcf75b..5c410c3a39 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Instructions.java +++ b/src/main/java/net/runelite/deob/attributes/code/Instructions.java @@ -21,9 +21,13 @@ public class Instructions private List instructions = new ArrayList<>(); private List blocks = new ArrayList<>(); - public Instructions(Code code) throws IOException + public Instructions(Code code) { this.code = code; + } + + public void load() throws IOException + { DataInputStream is = code.getAttributes().getStream(); int length = is.readInt(); diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java b/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java index f9c2d92f40..0e16aee782 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java @@ -7,11 +7,10 @@ import net.runelite.deob.attributes.code.instruction.types.ReturnInstruction; import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; -import java.io.IOException; public class VReturn extends Instruction implements ReturnInstruction { - public VReturn(Instructions instructions, InstructionType type, int pc) throws IOException + public VReturn(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } diff --git a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java b/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java index 21eede3495..29ebf63952 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java +++ b/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java @@ -11,15 +11,29 @@ import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.instruction.types.FieldInstruction; import net.runelite.deob.pool.NameAndType; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import net.runelite.deob.attributes.Attributes; +import net.runelite.deob.attributes.code.InstructionType; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instructions.PutStatic; +import net.runelite.deob.attributes.code.instructions.VReturn; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.execution.StackContext; +import net.runelite.deob.signature.Signature; import org.apache.commons.collections4.map.MultiValueMap; public class FieldMover implements Deobfuscator { private static final String mainClass = "client"; + private Execution execution; private ClassGroup group; private MultiValueMap fields = new MultiValueMap<>(); + private Map clinits = new HashMap<>(); private void findUses() { @@ -48,14 +62,22 @@ public class FieldMover implements Deobfuscator if (!field.isStatic()) continue; - if (fields.containsKey(field)) + if (m.getName().equals("")) { - Collection col = fields.getCollection(field); - if (!col.contains(cf)) - fields.put(field, cf); + if (fi instanceof PutStatic) + clinits.put(field, (PutStatic) fi); } else - fields.put(field, cf); + { + if (fields.containsKey(field)) + { + Collection col = fields.getCollection(field); + if (!col.contains(cf)) + fields.put(field, cf); + } + else + fields.put(field, cf); + } } } } @@ -92,13 +114,12 @@ public class FieldMover implements Deobfuscator if (list.size() == 1) return list.get(0); -// ClassFile cf = getBase(list.get(0), list.get(1)); -// -// for (int i = 2; i < list.size(); ++i) -// cf = getBase(cf, list.get(i)); -// -// return cf; - return null; // to do this, would have to move static initializer + ClassFile cf = getBase(list.get(0), list.get(1)); + + for (int i = 2; i < list.size(); ++i) + cf = getBase(cf, list.get(i)); + + return cf; } private int moveFields() @@ -111,9 +132,8 @@ public class FieldMover implements Deobfuscator ClassFile to = findCommonBase(cfs); if (to == null) - continue; // no common base, move to entry class - //to = group.findClass(mainClass); + to = group.findClass(mainClass); assert to != null; @@ -154,12 +174,77 @@ public class FieldMover implements Deobfuscator field.getFields().getFields().remove(field); to.getFields().getFields().add(field); field.setFields(to.getFields()); + + // move initializer + PutStatic setField = clinits.get(field); + if (setField == null) + return; // no initializer + + Method toClinit = to.findMethod(""); + if (toClinit == null) + { + // make clinit + + Signature sig = new Signature("()V"); + toClinit = new Method(to.getMethods(), "", sig); + + Attributes attributes = toClinit.getAttributes(); + Code code = new Code(attributes); + + attributes.addAttribute(code); + + // make instructions + Instructions instructions = new Instructions(code); + code.setInstructions(instructions); + + instructions.getInstructions().add(new VReturn(instructions, InstructionType.RETURN, 0)); // add return + } + + moveInitializer(setField, toClinit); + } + + private void moveInitializer(PutStatic setInstruction, Method to) + { + // find instruction in execution and remove it + InstructionContext setCtx = null; + List ctxs = null; + for (Frame frame : execution.processedFrames) + for (InstructionContext ctx : frame.getInstructions()) + { + if (ctx.getInstruction() != setInstruction) + continue; + + setCtx = ctx; + + // get instructions before recursive stack removal + //List oldIns = new ArrayList<>(frame.getMethod().getCode().getInstructions().getInstructions()); + + ctxs = ctx.removeStack(0); //remove + + //List newIns = new ArrayList<>(frame.getMethod().getCode().getInstructions().getInstructions()); + + //changedIns = CollectionUtils.disjunction(oldIns, newIns); + break; + } + + if (setCtx == null) + { + System.err.println("Unable to locate context for putstatic when moving field initializer"); + return; + } + + // insert instructions into method } @Override public void run(ClassGroup group) { group.buildClassGraph(); + + execution = new Execution(group); + execution.populateInitialMethods(); + execution.run(); + this.group = group; findUses(); int count = moveFields(); diff --git a/src/main/java/net/runelite/deob/execution/InstructionContext.java b/src/main/java/net/runelite/deob/execution/InstructionContext.java index ec1069b20d..efd7dd50a3 100644 --- a/src/main/java/net/runelite/deob/execution/InstructionContext.java +++ b/src/main/java/net/runelite/deob/execution/InstructionContext.java @@ -75,15 +75,14 @@ public class InstructionContext return invokes; } - public void removeStack(int idx) + public List removeStack(int idx) { // idx 0 is top of the stack, 1 is one under // stack contexts are added to 'pops' in the order that they are popped from the stack, - // so just remove at index idx - StackContext ctx = pops.remove(idx); + StackContext ctx = pops.get(idx); // start recursively removing - ctx.removeStack(); + return ctx.removeStack(); } @Override diff --git a/src/main/java/net/runelite/deob/execution/StackContext.java b/src/main/java/net/runelite/deob/execution/StackContext.java index 72f14e52c7..7f68b33d39 100644 --- a/src/main/java/net/runelite/deob/execution/StackContext.java +++ b/src/main/java/net/runelite/deob/execution/StackContext.java @@ -1,5 +1,8 @@ package net.runelite.deob.execution; +import java.util.ArrayList; +import java.util.List; + public class StackContext { public InstructionContext pushed; // instruction which pushed this @@ -45,16 +48,22 @@ public class StackContext } // remove this object from the stack - public void removeStack() + public List removeStack() { + List list = new ArrayList<>(); + + list.add(this); + // remove the instruction which pushed this if (!pushed.getInstruction().removeStack()) // dup will return false as the other objects on the stack below this are necessary // for the other branch. - return; + return list; // remove from the stack things this instruction read for (StackContext ctx : pushed.getPops()) - ctx.removeStack(); + list.addAll(ctx.removeStack()); + + return list; } }