From cbdf4064340c10331038a7f1cbf39c6e70b7e2a5 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 24 Mar 2016 17:18:08 -0400 Subject: [PATCH] Remove jump graph, isn't used except for some integrity checks, but it makes stuff overly complex. --- .../net/runelite/asm/attributes/Code.java | 2 - .../asm/attributes/code/Instruction.java | 68 +-- .../asm/attributes/code/Instructions.java | 38 +- .../instruction/types/JumpingInstruction.java | 2 - .../attributes/code/instructions/Goto.java | 6 - .../attributes/code/instructions/GotoW.java | 6 - .../asm/attributes/code/instructions/If.java | 7 - .../asm/attributes/code/instructions/If0.java | 6 - .../code/instructions/LookupSwitch.java | 9 - .../code/instructions/TableSwitch.java | 8 - src/main/java/net/runelite/deob/Deob.java | 39 +- .../deob/deobfuscators/ConstantParameter.java | 13 +- .../deob/deobfuscators/FieldInliner.java | 27 +- .../deob/deobfuscators/FieldMover.java | 339 --------------- .../deobfuscators/IllegalStateExceptions.java | 15 +- .../deob/deobfuscators/MethodInliner.java | 404 ------------------ .../deob/deobfuscators/UnreachedCode.java | 4 - 17 files changed, 38 insertions(+), 955 deletions(-) delete mode 100644 src/main/java/net/runelite/deob/deobfuscators/FieldMover.java delete mode 100644 src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java diff --git a/src/main/java/net/runelite/asm/attributes/Code.java b/src/main/java/net/runelite/asm/attributes/Code.java index 34af91d24e..cad791d4f6 100644 --- a/src/main/java/net/runelite/asm/attributes/Code.java +++ b/src/main/java/net/runelite/asm/attributes/Code.java @@ -41,8 +41,6 @@ public class Code extends Attribute this.attributes = new Attributes(this); this.attributes.load(is); - - instructions.buildJumpGraph(); } @Override diff --git a/src/main/java/net/runelite/asm/attributes/code/Instruction.java b/src/main/java/net/runelite/asm/attributes/code/Instruction.java index 9aecf0de5e..e3e300edb3 100644 --- a/src/main/java/net/runelite/asm/attributes/code/Instruction.java +++ b/src/main/java/net/runelite/asm/attributes/code/Instruction.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import net.runelite.asm.Method; +import net.runelite.asm.attributes.code.instruction.types.JumpingInstruction; public abstract class Instruction implements Cloneable { @@ -18,9 +19,6 @@ public abstract class Instruction implements Cloneable private int pc; // offset into method this instructions resides at protected int length = 1; // length of this instruction - public List jump = new ArrayList<>(), // instructions which this instruction jumps to - from = new ArrayList<>(); // instructions which jump to this instruction - public Instruction(Instructions instructions, InstructionType type, int pc) { this.instructions = instructions; @@ -48,9 +46,6 @@ public abstract class Instruction implements Cloneable throw new RuntimeException(); } - i.from = new ArrayList<>(); - i.jump = new ArrayList<>(); - return i; } @@ -60,10 +55,6 @@ public abstract class Instruction implements Cloneable protected void remove() { - for (Instruction i : jump) - i.from.remove(this); - jump.clear(); - Exceptions exceptions = instructions.getCode().getExceptions(); for (Exception e : exceptions.getExceptions()) { @@ -71,8 +62,12 @@ public abstract class Instruction implements Cloneable assert this != e.getEnd(); assert this != e.getHandler(); } - - assert from.isEmpty(); // because this is empty no jumping instructions point here + + // XXX unreached code deob relies on being able to remove instructions that other ins jump to, + // if those other ins are also unreached. + //for (Instruction i : instructions.getInstructions()) + // if (i instanceof JumpingInstruction) + // assert ((JumpingInstruction) i).getJumps().contains(this) == false; } public void replace(Instruction other) @@ -83,35 +78,12 @@ public abstract class Instruction implements Cloneable assert ins.contains(this); assert !ins.contains(other); - // XXX instructions which hold references to instructions ! + // is this really the right place for this? for (Instruction i : ins) { i.replace(this, other); } - // update instructions which jump here to jump to the new instruction - for (Instruction i : from) - { - assert i.jump.contains(this); - assert !i.jump.contains(other); - - i.jump.remove(this); - i.jump.add(other); - } - from.clear(); - - // move jumps over - for (Instruction i : jump) - { - assert i.from.contains(this); - assert !i.from.contains(other); - - i.from.remove(this); - i.from.add(other); - } - other.jump = new ArrayList<>(this.jump); - jump.clear(); - Exceptions exceptions = instructions.getCode().getExceptions(); for (Exception e : exceptions.getExceptions()) { @@ -141,17 +113,6 @@ public abstract class Instruction implements Cloneable i.replace(this, next); } - for (Instruction i : from) - { - assert i.jump.contains(this); - - i.jump.remove(this); - - i.jump.add(next); - next.from.add(i); - } - from.clear(); - for (Exception e : instructions.getCode().getExceptions().getExceptions()) e.replace(this, next); @@ -220,19 +181,6 @@ public abstract class Instruction implements Cloneable return type.getName() + " at pc " + frame.getPc() + " in " + frame.getMethod().getName() + " " + frame.getMethod().getDescriptor() + " class " + frame.getMethod().getCode().getAttributes().getClassFile().getName(); } - protected void addJump(Instruction to) - { - assert to != null; - assert to != this; - - assert this.jump.contains(to) == to.from.contains(this); - if (this.jump.contains(to)) - return; // switch statements can jump to the same place multiple times - - this.jump.add(to); - to.from.add(this); - } - public abstract void execute(Frame e); /* does this terminate a block? */ diff --git a/src/main/java/net/runelite/asm/attributes/code/Instructions.java b/src/main/java/net/runelite/asm/attributes/code/Instructions.java index 8c667252b8..80b492ae33 100644 --- a/src/main/java/net/runelite/asm/attributes/code/Instructions.java +++ b/src/main/java/net/runelite/asm/attributes/code/Instructions.java @@ -85,8 +85,6 @@ public class Instructions this.regeneratePool(); // translate instructions to specific - this.buildJumpGraph(); - for (Instruction i : new ArrayList<>(instructions)) { Instruction specific = i.makeSpecific(); @@ -121,26 +119,6 @@ public class Instructions out.write(ba); } - public void clearJumpGraph() - { - for (Instruction i : instructions) - { - i.jump.clear(); - i.from.clear(); - } - } - - public void buildJumpGraph() - { - clearJumpGraph(); - - assert new HashSet<>(instructions).size() == instructions.size(); - - for (Instruction i : instructions) - if (i instanceof JumpingInstruction) - ((JumpingInstruction) i).buildJumpGraph(); - } - public Code getCode() { return code; @@ -180,21 +158,9 @@ public class Instructions instructions.remove(oldi); oldi.setInstructions(null); instructions.add(i, newi); - - for (Instruction ins : oldi.from) - { - assert ins.getInstructions() == this; - assert this.getInstructions().contains(ins); - assert ins.jump.contains(oldi); - - ins.jump.remove(oldi); - - ins.jump.add(newi); - newi.from.add(ins); - + + for (Instruction ins : instructions) ins.replace(oldi, newi); - } - oldi.from.clear(); for (net.runelite.asm.attributes.code.Exception e : code.getExceptions().getExceptions()) e.replace(oldi, newi); diff --git a/src/main/java/net/runelite/asm/attributes/code/instruction/types/JumpingInstruction.java b/src/main/java/net/runelite/asm/attributes/code/instruction/types/JumpingInstruction.java index 183fa1ad60..e40080076a 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instruction/types/JumpingInstruction.java +++ b/src/main/java/net/runelite/asm/attributes/code/instruction/types/JumpingInstruction.java @@ -5,7 +5,5 @@ import java.util.List; public interface JumpingInstruction { - public void buildJumpGraph(); - List getJumps(); } diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/Goto.java b/src/main/java/net/runelite/asm/attributes/code/instructions/Goto.java index ef5d687290..4062577379 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/Goto.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/Goto.java @@ -64,12 +64,6 @@ public class Goto extends Instruction implements JumpingInstruction out.writeShort(offset); } - - @Override - public void buildJumpGraph() - { - this.addJump(to); - } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/GotoW.java b/src/main/java/net/runelite/asm/attributes/code/instructions/GotoW.java index 53a4f4cf97..cf793ab137 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/GotoW.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/GotoW.java @@ -42,12 +42,6 @@ public class GotoW extends Instruction implements JumpingInstruction super.write(out); out.writeInt(to.getPc() - this.getPc()); } - - @Override - public void buildJumpGraph() - { - this.addJump(to); - } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/If.java b/src/main/java/net/runelite/asm/attributes/code/instructions/If.java index 83b511e695..d1636dc178 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/If.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/If.java @@ -23,7 +23,6 @@ import net.runelite.asm.attributes.code.instruction.types.PushConstantInstructio import net.runelite.deob.deobfuscators.rename.MappingExecutorUtil; import net.runelite.deob.deobfuscators.rename.PacketHandler; import net.runelite.deob.deobfuscators.rename.ParallelExecutorMapping; -import net.runelite.asm.execution.Execution; public abstract class If extends Instruction implements JumpingInstruction, ComparisonInstruction, MappableInstruction { @@ -71,12 +70,6 @@ public abstract class If extends Instruction implements JumpingInstruction, Comp super.write(out); out.writeShort(to.getPc() - this.getPc()); } - - @Override - public void buildJumpGraph() - { - this.addJump(to); - } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/If0.java b/src/main/java/net/runelite/asm/attributes/code/instructions/If0.java index 5729ca2b6e..302ea7381d 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/If0.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/If0.java @@ -63,12 +63,6 @@ public abstract class If0 extends Instruction implements JumpingInstruction, Com out.writeShort(to.getPc() - this.getPc()); } - @Override - public void buildJumpGraph() - { - this.addJump(to); - } - @Override public void execute(Frame frame) { diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/LookupSwitch.java b/src/main/java/net/runelite/asm/attributes/code/instructions/LookupSwitch.java index 9f15f4ec99..3db9cdb795 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/LookupSwitch.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/LookupSwitch.java @@ -13,7 +13,6 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -101,14 +100,6 @@ public class LookupSwitch extends Instruction implements JumpingInstruction } } - @Override - public void buildJumpGraph() - { - for (Instruction i : branchi) - this.addJump(i); - this.addJump(defi); - } - @Override public void execute(Frame frame) { diff --git a/src/main/java/net/runelite/asm/attributes/code/instructions/TableSwitch.java b/src/main/java/net/runelite/asm/attributes/code/instructions/TableSwitch.java index 82a7980a9d..0ee269bbcb 100644 --- a/src/main/java/net/runelite/asm/attributes/code/instructions/TableSwitch.java +++ b/src/main/java/net/runelite/asm/attributes/code/instructions/TableSwitch.java @@ -97,14 +97,6 @@ public class TableSwitch extends Instruction implements JumpingInstruction out.writeInt(i.getPc() - this.getPc()); } - @Override - public void buildJumpGraph() - { - for (Instruction i : branchi) - this.addJump(i); - this.addJump(defi); - } - @Override public void execute(Frame frame) { diff --git a/src/main/java/net/runelite/deob/Deob.java b/src/main/java/net/runelite/deob/Deob.java index a881405a0d..e03cd6f1af 100644 --- a/src/main/java/net/runelite/deob/Deob.java +++ b/src/main/java/net/runelite/deob/Deob.java @@ -6,7 +6,6 @@ import java.io.IOException; import net.runelite.deob.deobfuscators.ConstantParameter; import net.runelite.deob.deobfuscators.FieldInliner; import net.runelite.deob.deobfuscators.IllegalStateExceptions; -import net.runelite.deob.deobfuscators.MethodInliner; import net.runelite.deob.deobfuscators.RenameUnique; import net.runelite.deob.deobfuscators.RuntimeExceptions; import net.runelite.deob.deobfuscators.UnreachedCode; @@ -73,25 +72,25 @@ public class Deob run(group, new UnusedClass()); - ModArith mod = new ModArith(); - mod.run(group); - - int last = -1, cur; - while ((cur = mod.runOnce()) > 0) - { - new MultiplicationDeobfuscator().run(group); - - new MultiplyOneDeobfuscator().run(group); - - new MultiplyZeroDeobfuscator().run(group); - - if (last == cur) - break; - - last = cur; - } - - mod.annotateEncryption(); +// ModArith mod = new ModArith(); +// mod.run(group); +// +// int last = -1, cur; +// while ((cur = mod.runOnce()) > 0) +// { +// new MultiplicationDeobfuscator().run(group); +// +// new MultiplyOneDeobfuscator().run(group); +// +// new MultiplyZeroDeobfuscator().run(group); +// +// if (last == cur) +// break; +// +// last = cur; +// } +// +// mod.annotateEncryption(); JarUtil.saveJar(group, new File(args[1])); diff --git a/src/main/java/net/runelite/deob/deobfuscators/ConstantParameter.java b/src/main/java/net/runelite/deob/deobfuscators/ConstantParameter.java index 1f0edb4755..b3e90a1797 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/ConstantParameter.java +++ b/src/main/java/net/runelite/deob/deobfuscators/ConstantParameter.java @@ -459,7 +459,6 @@ public class ConstantParameter implements Deobfuscator continue; // ins already removed? Instructions instructions = ins.getInstructions(); - instructions.buildJumpGraph(); // remove the if if (ctx.getInstruction() instanceof If) @@ -489,14 +488,8 @@ public class ConstantParameter implements Deobfuscator assert instructions.getInstructions().contains(to); // move things that jump here to instead jump to 'to' - for (Instruction fromI : ins.from) - { - assert fromI.jump.contains(ins); - - fromI.jump.remove(ins); - fromI.replace(ins, to); - } - ins.from.clear(); + for (Instruction i : instructions.getInstructions()) + i.replace(ins, to); instructions.remove(ins); @@ -505,8 +498,6 @@ public class ConstantParameter implements Deobfuscator if (branch) { Goto gotoins = new Goto(instructions, to); - to.from.add(gotoins); - gotoins.jump.add(to); // insert goto instructions.getInstructions().add(idx, gotoins); diff --git a/src/main/java/net/runelite/deob/deobfuscators/FieldInliner.java b/src/main/java/net/runelite/deob/deobfuscators/FieldInliner.java index 260f2a067b..295d62a5fe 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/FieldInliner.java +++ b/src/main/java/net/runelite/deob/deobfuscators/FieldInliner.java @@ -101,22 +101,12 @@ public class FieldInliner implements Deobfuscator // nop NOP nop1 = new NOP(instructions), nop2 = new NOP(instructions); - - for (Instruction i : prev.from) - { - i.jump.remove(prev); - i.jump.add(nop1); + + for (Instruction i : instructions.getInstructions()) i.replace(prev, nop1); - } - prev.from.clear(); - - for (Instruction i : ins.from) - { - i.jump.remove(ins); - i.jump.add(nop1); + + for (Instruction i : instructions.getInstructions()) i.replace(ins, nop1); - } - ins.from.clear(); boolean b = instructions.getInstructions().remove(prev); assert b; @@ -144,8 +134,6 @@ public class FieldInliner implements Deobfuscator // remove fin, add push constant Instruction i = (Instruction) fin; - i.getInstructions().buildJumpGraph(); - Instruction pushIns = new LDC_W(i.getInstructions(), value.getValue()); List instructions = i.getInstructions().getInstructions(); @@ -154,13 +142,8 @@ public class FieldInliner implements Deobfuscator assert idx != -1; // move jumps to i to pushIns - for (Instruction i2 : i.from) - { - i2.jump.remove(i); - i2.jump.add(pushIns); + for (Instruction i2 : instructions) i2.replace(i, pushIns); - } - i.from.clear(); i.getInstructions().remove(i); instructions.add(idx, pushIns); diff --git a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java b/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java deleted file mode 100644 index 532256538d..0000000000 --- a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java +++ /dev/null @@ -1,339 +0,0 @@ -package net.runelite.deob.deobfuscators; - -import java.util.ArrayList; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.Deobfuscator; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.instruction.types.FieldInstruction; -import net.runelite.asm.pool.NameAndType; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import net.runelite.asm.attributes.Attributes; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.Goto; -import net.runelite.asm.attributes.code.instructions.PutStatic; -import net.runelite.asm.attributes.code.instructions.VReturn; -import net.runelite.asm.execution.Execution; -import net.runelite.asm.execution.Frame; -import net.runelite.asm.execution.InstructionContext; -import net.runelite.asm.execution.StackContext; -import net.runelite.asm.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() - { - fields.clear(); - - for (ClassFile cf : group.getClasses()) - { - for (Method m : cf.getMethods().getMethods()) - { - Code code = m.getCode(); - - if (code == null) - continue; - - for (Instruction i : code.getInstructions().getInstructions()) - { - if (!(i instanceof FieldInstruction)) - continue; - - FieldInstruction fi = (FieldInstruction) i; - Field field = fi.getMyField(); - - if (field == null) - continue; - - if (!field.isStatic()) - continue; - - if (m.getName().equals("")) - { - if (fi instanceof PutStatic) - clinits.put(field, (PutStatic) fi); - } - else if (!m.isStatic()) // I think non static methods are always right? - { - if (fields.containsKey(field)) - { - Collection col = fields.getCollection(field); - if (!col.contains(cf)) - fields.put(field, cf); - } - else - fields.put(field, cf); - } - } - } - } - } - - private boolean isDowncastable(ClassFile from, ClassFile to) - { - while (from != null && from != to) - { - from = from.getParent(); - } - - return from != null; - } - - private ClassFile getBase(ClassFile one, ClassFile two) - { - if (one == two) - return one; - - if (isDowncastable(one, two)) - return two; - - if (isDowncastable(two, one)) - return one; - - return null; - } - - private ClassFile findCommonBase(Collection classes) - { - List list = new ArrayList<>(classes); - - 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; - } - - private int moveFields() - { - int count = 0; - - for (Field field : fields.keySet()) - { - Collection cfs = fields.getCollection(field); - - ClassFile to = findCommonBase(cfs); - if (to == null) - // no common base, move to entry class - to = group.findClass(mainClass); - - assert to != null; - - if (field.getFields().getClassFile() == to) - continue; - - moveField(field, to); - ++count; - } - - return count; - } - - private void moveField(Field field, ClassFile to) - { - assert field.getFields().getClassFile() != to; - - net.runelite.asm.pool.Field newField = new net.runelite.asm.pool.Field( - new net.runelite.asm.pool.Class(to.getName()), - new NameAndType(field.getName(), field.getType()) - ); - - // move on instructions - for (ClassFile cf : group.getClasses()) - { - for (Method m : cf.getMethods().getMethods()) - { - Code code = m.getCode(); - - if (code == null) - continue; - - //code.getInstructions().renameField(field, newField); - } - } - - // move the field - 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 - - to.getMethods().getMethods().add(toClinit); - } - - moveInitializer(setField, toClinit); - } - - private void moveInitializer(PutStatic setInstruction, Method to) - { - // find instruction in execution and remove it - InstructionContext setCtx = null; - Frame frame = null; - List ctxs = null; - for (Frame f : execution.processedFrames) - for (InstructionContext ctx : f.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 - frame = f; - - //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 - - // convert stack info to instruction ctx - List ictxs = getContexts(setCtx); - - // order instructions based on the order they execute in the frame - Map orderedIns = new TreeMap<>(); - for (InstructionContext i : ictxs) - { - assert frame.getInstructions().indexOf(i) != -1; - orderedIns.put(frame.getInstructions().indexOf(i), i.getInstruction()); - } - - to.getCode().getInstructions().buildJumpGraph(); - frame.getMethod().getCode().getInstructions().buildJumpGraph(); - - for (Instruction i : orderedIns.values()) - { - moveJumps(i); - i.getInstructions().remove(i); - - i.setInstructions(to.getCode().getInstructions()); - } - - // insert instructions into method - to.getCode().getInstructions().getInstructions().addAll(0, orderedIns.values()); - } - - private void moveJumps(Instruction i) - { - List list = i.getInstructions().getInstructions(); - - int idx = list.indexOf(i); - - Instruction next = list.get(idx + 1); - - for (Instruction i2 : i.from) - { - i2.jump.remove(i); - - i2.replace(i, next); - - next.from.add(i2); - i2.jump.add(next); - } - i.from.clear(); - } - - private void getContexts(List list, InstructionContext ctx) - { - assert !(ctx.getInstruction() instanceof Goto); - - if (list.contains(ctx)) - return; - - list.add(ctx); - - for (StackContext s : ctx.getPops()) - { - assert s.getPopped() == ctx; - - getContexts(list, s.getPushed()); - } - - for (StackContext s : ctx.getPushes()) - { - assert s.getPushed() == ctx; - - for (InstructionContext i : s.getPopped()) - getContexts(list, i); - } - } - - // get instruction contexts for stack contexts - private List getContexts(InstructionContext ctx) - { - List list = new ArrayList<>(); - getContexts(list, ctx); - return list; - } - - @Override - public void run(ClassGroup group) - { - group.buildClassGraph(); - - execution = new Execution(group); - execution.populateInitialMethods(); - execution.run(); - - this.group = group; - findUses(); - int count = moveFields(); - - System.out.println("Moved " + count + " fields"); - } - -} diff --git a/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java b/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java index 1814215e45..18b7d16d86 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java +++ b/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java @@ -35,7 +35,6 @@ public class IllegalStateExceptions implements Deobfuscator continue; Instructions instructions = c.getInstructions(); - instructions.buildJumpGraph(); List ilist = instructions.getInstructions(); for (int i = 0; i < ilist.size(); ++i) @@ -78,17 +77,9 @@ public class IllegalStateExceptions implements Deobfuscator while (!(ins instanceof AThrow)) { // modify instructions which jump to here to instead jump to 'to' - - for (Instruction from : ins.from) - { - from.jump.remove(ins); - //ins.from.remove(from); - + + for (Instruction from : ilist) from.replace(ins, to); - - from.jump.add(to); - } - ins.from.clear(); instructions.remove(ins); ins = ilist.get(i); // don't need to ++i because @@ -100,8 +91,6 @@ public class IllegalStateExceptions implements Deobfuscator // insert goto assert ilist.contains(to); Goto g = new Goto(instructions, to); - g.jump.add(to); - to.from.add(g); ilist.add(i, g); ++count; diff --git a/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java b/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java deleted file mode 100644 index 39169bac7f..0000000000 --- a/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java +++ /dev/null @@ -1,404 +0,0 @@ -package net.runelite.deob.deobfuscators; - -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.Deobfuscator; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; -import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction; -import net.runelite.asm.attributes.code.instructions.AStore; -import net.runelite.asm.attributes.code.instructions.DStore; -import net.runelite.asm.attributes.code.instructions.FStore; -import net.runelite.asm.attributes.code.instructions.Goto; -import net.runelite.asm.attributes.code.instructions.IStore; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.LStore; -import net.runelite.asm.attributes.code.instructions.NOP; -import net.runelite.asm.signature.Signature; -import net.runelite.asm.signature.Type; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import net.runelite.asm.attributes.code.Exceptions; -import net.runelite.asm.attributes.code.instruction.types.JumpingInstruction; -import net.runelite.asm.attributes.code.instructions.If; - -public class MethodInliner implements Deobfuscator -{ - private Map calls = new HashMap<>(); - //private Set removeMethods = new HashSet<>(); - - private void countCalls(Method m) - { - Code code = m.getCode(); - if (code == null) - return; - - Instructions ins = code.getInstructions(); - - for (Instruction i : ins.getInstructions()) - { - // can only inline static method calls - if (!(i instanceof InvokeStatic)) - continue; - - List invokedMethods = ((InvokeInstruction) i).getMethods(); - if (invokedMethods.isEmpty()) - continue; // not our method - - assert invokedMethods.size() == 1; - Method invokedMethod = invokedMethods.get(0); - - Integer count = calls.get(invokedMethod); - if (count == null) - calls.put(invokedMethod, 1); - else - calls.put(invokedMethod, count + 1); - } - } - - private int processMethod(Method m) - { - int inlineCount = 0; - Code code = m.getCode(); - if (code == null) - return inlineCount; - - Instructions ins = code.getInstructions(); - - for (Instruction i : ins.getInstructions()) - { - assert i.getInstructions() == ins; - // can only inline static method calls - if (!(i instanceof InvokeStatic)) - continue; - - List invokedMethods = ((InvokeInstruction) i).getMethods(); - if (invokedMethods.isEmpty()) - continue; // not our method - - Method invokedMethod = invokedMethods.get(0); - Integer count = calls.get(invokedMethod); - - // this can't inline functions with exception handlers because throwing exceptions clears the stack - if (count == null - || !invokedMethod.getCode().getExceptions().getExceptions().isEmpty() - || invokedMethod.getCode().getInstructions().getInstructions().size() > 30) // XXX magic - continue; -// if (count == null || count != 1) -// continue; // only inline methods called once - - if (m == invokedMethod) - continue; // recursive method - - int invokeIdx = ins.getInstructions().indexOf(i); - assert invokeIdx != -1; - assert ins.getInstructions().get(invokeIdx).getInstructions() == ins; - - int lvtIndex = code.getMaxLocals(), - theirLocals = invokedMethod.getCode().getMaxLocals(); - - if (lvtIndex + theirLocals > 127) - continue; - - if (invokedMethod.isSynchronized()) - continue; - - // assign variables on stack to lvt - Signature descriptor = invokedMethod.getDescriptor(); - - Map lvtIndexes = new HashMap<>(); - for (int j = 0, idx = 0; j < descriptor.size(); ++j) - { - lvtIndexes.put(j, idx); - idx += descriptor.getTypeOfArg(j).getSlots(); - } - - Instruction firstParamStore = null; - - for (int j = descriptor.size() - 1; j >= 0; --j) - { - Type type = descriptor.getTypeOfArg(j); - int paramLvtIndex = lvtIndexes.get(j); - - // insert instruction to store top of stack in lvt - - Instruction storeIns = null; - if (type.getArrayDims() == 0) - { - switch (type.getType()) - { - case "B": - case "Z": - case "C": - case "S": - case "I": - storeIns = new IStore(ins, lvtIndex + paramLvtIndex); - break; - case "J": - storeIns = new LStore(ins, lvtIndex + paramLvtIndex); - break; - case "F": - storeIns = new FStore(ins, lvtIndex + paramLvtIndex); - break; - case "D": - storeIns = new DStore(ins, lvtIndex + paramLvtIndex); - break; - } - } - - if (type.getArrayDims() != 0 || type.getType().startsWith("L")) - { - assert storeIns == null; - storeIns = new AStore(ins, lvtIndex + paramLvtIndex); - } - assert storeIns != null; - - // insert storeIns before invoke instruction - ins.getInstructions().add(invokeIdx++, storeIns); - - if (firstParamStore == null) - firstParamStore = storeIns; - } - - int maxStack = code.getMaxStack() + invokedMethod.getCode().getMaxStack(); // not really right but ok - code.setMaxStack(maxStack); - - inline(m, i, invokedMethod, lvtIndex, firstParamStore); - ++inlineCount; - break; - } - - return inlineCount; - } - - private void inline(Method method, Instruction invokeIns, Method invokeMethod, int lvtBase, Instruction firstParamStore) - { - Code methodCode = method.getCode(), - invokeMethodCode = invokeMethod.getCode(); - Instructions methodInstructions = methodCode.getInstructions(), - invokeMethodInstructions = invokeMethodCode.getInstructions(); - - int idx = methodInstructions.getInstructions().indexOf(invokeIns); // index of invoke ins, before removal - assert invokeIns.getInstructions() == methodInstructions; - assert idx != -1; - - Instruction nextInstruction = methodInstructions.getInstructions().get(idx + 1); - - // move stuff which jumps to invokeIns to firstParamStore. If there are no arguments that are stored, - // firstParamStore is null, and so create a nop instruction. - - if (firstParamStore == null) - { - Instruction nop = new NOP(methodInstructions); - methodInstructions.getInstructions().add(idx + 1, nop); - ++idx; - - firstParamStore = nop; - } - - methodInstructions.buildJumpGraph(); - invokeMethodInstructions.buildJumpGraph(); - - for (Instruction fromI : invokeIns.from) - { - assert fromI.jump.contains(invokeIns); - - fromI.jump.remove(invokeIns); - fromI.replace(invokeIns, firstParamStore); - - fromI.jump.add(firstParamStore); - firstParamStore.from.add(fromI); - } - invokeIns.from.clear(); - - for (net.runelite.asm.attributes.code.Exception e : invokeMethodCode.getExceptions().getExceptions()) - e.replace(invokeIns, firstParamStore); - - methodInstructions.remove(invokeIns); - - Map insMap = new HashMap<>(); - for (Instruction i : invokeMethodInstructions.getInstructions()) - { - Instruction i2 = i.clone(); - i2.setInstructions(null); - insMap.put(i, i2); - } - - for (Instruction i : insMap.values()) - { - for (Entry e : insMap.entrySet()) - { - i.replace(e.getKey(), e.getValue()); - } - } - - for (Instruction i : insMap.values()) - { - if (i instanceof JumpingInstruction) - { - JumpingInstruction j = (JumpingInstruction) i; - for (Instruction i2 : j.getJumps()) - { - assert insMap.values().contains(i2); - assert i2.getInstructions() == null; - } - } - } - - Exceptions fromExceptions = invokeMethod.getCode().getExceptions(); - Exceptions toExceptions = method.getCode().getExceptions(); - - for (net.runelite.asm.attributes.code.Exception e : fromExceptions.getExceptions()) - { - e = e.clone(); - e.setExceptions(toExceptions); - - for (Entry en : insMap.entrySet()) - { - e.replace(en.getKey(), en.getValue()); - } - - toExceptions.add(e); - } - - for (Instruction i : invokeMethodInstructions.getInstructions()) - { - Instruction orig = i; - i = insMap.get(i); - // copy instructions over. - - if (i instanceof ReturnInstruction) - { - // XXX I am assuming that this function leaves the stack in a clean state? - - // instead of return, jump to next instruction after the invoke - Instruction oldI = i; - assert oldI.getInstructions() == null; - - i = new Goto(methodInstructions, nextInstruction); - - assert nextInstruction.getInstructions() == methodInstructions; - assert methodInstructions.getInstructions().contains(nextInstruction); - - for (Instruction i2 : insMap.values()) - i2.replace(oldI, i); - - for (net.runelite.asm.attributes.code.Exception e : toExceptions.getExceptions()) - e.replace(oldI, i); - - insMap.put(orig, i); - } - - if (i instanceof LVTInstruction) - { - LVTInstruction lvt = (LVTInstruction) i; - // offset lvt index - int newIndex = lvtBase + lvt.getVariableIndex(); - - Instruction oldI = i; - i = lvt.setVariableIndex(newIndex); - - assert oldI == i; -// if (oldI != i) -// { -// for (Instruction i2 : insMap.values()) -// i2.replace(oldI, i); -// -// for (net.runelite.deob.attributes.code.Exception e : toExceptions.getExceptions()) -// e.replace(oldI, i); -// -// insMap.put(orig, i); -// } - } - - - i.setInstructions(methodInstructions); - assert !methodInstructions.getInstructions().contains(i); - methodInstructions.getInstructions().add(idx++, i); - } - - this.checkJumpGraph(methodInstructions); - } - - private void checkJumpGraph(Instructions ins) - { - ins.buildJumpGraph(); - - assert new HashSet<>(ins.getInstructions()).size() == ins.getInstructions().size(); - - for (Instruction i : ins.getInstructions()) - { - for (Instruction i2 : i.jump) - { - assert i2.getInstructions() == ins; - assert ins.getInstructions().contains(i2); - - assert i2.from.contains(i); - } - - for (Instruction i2 : i.from) - { - assert i2.getInstructions() == ins; - assert ins.getInstructions().contains(i2); - - assert i2.jump.contains(i); - } - - if (i instanceof JumpingInstruction) - { - JumpingInstruction j = (JumpingInstruction) i; - assert j.getJumps().size() == i.jump.size(); - } - } - } - - @Override - public void run(ClassGroup group) - { - int total = 0; - int i; - do - { - i = pass(group); - total += i; - } - while (i > 0); - - System.out.println("[TOTAL] Inlined " + total + " methods"); - } - - private int pass(ClassGroup group) - { - group.buildClassGraph(); - int count = 0; - - calls.clear(); - - for (ClassFile cf : group.getClasses()) - { - for (Method m : cf.getMethods().getMethods()) - { - countCalls(m); - } - } - - for (ClassFile cf : group.getClasses()) - { - for (Method m : cf.getMethods().getMethods()) - { - count += processMethod(m); - } - } - - System.out.println("Inlined " + count + " methods"); - return count; - } - -} diff --git a/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java b/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java index f05735c573..5897dbff5f 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java +++ b/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java @@ -27,10 +27,6 @@ public class UnreachedCode implements Deobfuscator if (!execution.executed.contains(i)) { - for (Instruction i2 : i.from) - i2.jump.remove(i); - i.from.clear(); // if this is never executed, anything that jumps here ia also never executed? - // if this is an exception handler, the exception handler is never used... for (net.runelite.asm.attributes.code.Exception e : new ArrayList<>(m.getCode().getExceptions().getExceptions())) {