From 9b2b5fdecff3d821d54c468f2e7733fafff75570 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 5 Dec 2015 18:42:16 -0500 Subject: [PATCH] hn --- src/main/java/net/runelite/deob/Deob.java | 118 ++++++------- .../attributes/code/instructions/AAStore.java | 4 +- .../code/instructions/InvokeStatic.java | 15 +- .../code/instructions/InvokeVirtual.java | 6 + .../code/instructions/NewArray.java | 5 + .../deob/deobfuscators/UnusedFields.java | 22 +-- .../deob/deobfuscators/rename/Rename2.java | 47 +++-- .../deob/deobfuscators/rename/graph/Edge.java | 162 ++++++++++++++++-- .../java/net/runelite/deob/pool/Class.java | 6 + .../java/net/runelite/deob/pool/Method.java | 6 + .../net/runelite/deob/pool/NameAndType.java | 9 + 11 files changed, 278 insertions(+), 122 deletions(-) diff --git a/src/main/java/net/runelite/deob/Deob.java b/src/main/java/net/runelite/deob/Deob.java index c5e17f20b5..7aa05153e1 100644 --- a/src/main/java/net/runelite/deob/Deob.java +++ b/src/main/java/net/runelite/deob/Deob.java @@ -31,67 +31,67 @@ public class Deob ClassGroup group = JarUtil.loadJar(new File(args[0])); - run(group, new RenameUnique()); - - // remove except RuntimeException - run(group, new RuntimeExceptions()); - - // remove unused methods - run(group, new UnreachedCode()); - run(group, new UnusedMethods()); - - // remove illegal state exceptions, frees up some parameters - run(group, new IllegalStateExceptions()); - - // remove constant logically dead parameters - run(group, new ConstantParameter()); - - // remove unhit blocks - run(group, new UnreachedCode()); - run(group, new UnusedMethods()); - - // remove unused parameters - run(group, new UnusedParameters()); - +// run(group, new RenameUnique()); +// +// // remove except RuntimeException +// run(group, new RuntimeExceptions()); +// +// // remove unused methods +// run(group, new UnreachedCode()); +// run(group, new UnusedMethods()); +// +// // remove illegal state exceptions, frees up some parameters +// run(group, new IllegalStateExceptions()); +// +// // remove constant logically dead parameters +// run(group, new ConstantParameter()); +// +// // remove unhit blocks +// run(group, new UnreachedCode()); +// run(group, new UnusedMethods()); +// +// // remove unused parameters +// run(group, new UnusedParameters()); +// // remove unused fields run(group, new UnusedFields()); - - // remove unused methods, again? - run(group, new UnusedMethods()); - -// run(group, new MethodInliner()); -// run(group, new UnusedMethods()); // inliner might leave unused methods - -// // broken because rename was removed -// //run(group, new MethodMover()); - - run(group, new FieldInliner()); - -// // XXX this is broken because when moving clinit around, some fields can depend on other fields -// // (like multianewarray) -// //new FieldMover().run(group); - - 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(); +// +// // remove unused methods, again? +// run(group, new UnusedMethods()); +// +//// run(group, new MethodInliner()); +//// run(group, new UnusedMethods()); // inliner might leave unused methods +// +//// // broken because rename was removed +//// //run(group, new MethodMover()); +// +// run(group, new FieldInliner()); +// +//// // XXX this is broken because when moving clinit around, some fields can depend on other fields +//// // (like multianewarray) +//// //new FieldMover().run(group); +// +// 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(); // eval constant fields (only set once to a constant in ctor) maybe just inline them diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/AAStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/AAStore.java index 9e515b7f45..2f88e5f591 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/AAStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/AAStore.java @@ -26,9 +26,7 @@ public class AAStore extends Instruction implements ArrayStore StackContext index = stack.pop(); StackContext array = stack.pop(); - ins.pop(value); - ins.pop(index); - ins.pop(array); + ins.pop(value, index, array); frame.addInstructionContext(ins); } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeStatic.java b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeStatic.java index 84346341da..cc5dc7c11d 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeStatic.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeStatic.java @@ -41,6 +41,12 @@ public class InvokeStatic extends Instruction implements InvokeInstruction this.method = method; } + @Override + public String toString() + { + return "invokestatic " + method + " in " + this.getInstructions().getCode().getAttributes().getMethod(); + } + @Override public void load(DataInputStream is) throws IOException { @@ -96,15 +102,6 @@ public class InvokeStatic extends Instruction implements InvokeInstruction // add possible method call to execution Execution execution = frame.getExecution(); Frame f = execution.invoke(ins, method); - - if (f != null) - { - assert f.getMethod() == method; - //assert f.lastField == frame.lastField; - //assert f.staticReturn == frame; - - //frame.stop(); - } } frame.addInstructionContext(ins); diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeVirtual.java b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeVirtual.java index d2c1ca1bf1..c75b3e3278 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeVirtual.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeVirtual.java @@ -34,6 +34,12 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction super(instructions, type, pc); } + @Override + public String toString() + { + return "invokevirtual " + method + " in " + this.getInstructions().getCode().getAttributes().getMethod(); + } + @Override public void load(DataInputStream is) throws IOException { diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/NewArray.java b/src/main/java/net/runelite/deob/attributes/code/instructions/NewArray.java index 90270616f0..77b522b7c5 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/NewArray.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/NewArray.java @@ -21,6 +21,11 @@ public class NewArray extends Instruction { super(instructions, type, pc); } + + public int getArrayType() + { + return type; + } @Override public void load(DataInputStream is) throws IOException diff --git a/src/main/java/net/runelite/deob/deobfuscators/UnusedFields.java b/src/main/java/net/runelite/deob/deobfuscators/UnusedFields.java index 3e9a4afcf7..999ebdc55c 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/UnusedFields.java +++ b/src/main/java/net/runelite/deob/deobfuscators/UnusedFields.java @@ -30,27 +30,19 @@ public class UnusedFields implements Deobfuscator if (ins instanceof FieldInstruction) { FieldInstruction fi = (FieldInstruction) ins; - net.runelite.deob.pool.Field ff = fi.getField(); - // pool to Field - ClassFile clazz = group.findClass(ff.getClassEntry().getName()); - if (clazz == null) + if (fi.getMyField() != field) continue; - - Field f = clazz.findFieldDeep(ff.getNameAndType()); - - if (field == f) - { - if (ins instanceof GetFieldInstruction) - ++get; - if (ins instanceof SetFieldInstruction) - ++set; - } + + if (ins instanceof GetFieldInstruction) + ++get; + if (ins instanceof SetFieldInstruction) + ++set; } } } - if (get == 0 && set == 0) + if (get == 0) return true; return false; diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/Rename2.java b/src/main/java/net/runelite/deob/deobfuscators/rename/Rename2.java index 86e0095498..efbc712544 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/Rename2.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/Rename2.java @@ -246,27 +246,20 @@ public class Rename2 assert s.getGraph() != other.getGraph(); - boolean b =false; - if (s.toString().equals("Vertex{object=B[] class118.field1980}") - && other.toString().equals("Vertex{object=B[] class118.field1986}")) - { - b=true; - } - for (Edge e : s.getEdges()) { assert e.getFrom() == s; + boolean b = false; + if (e.toString().equals("Edge{from=Vertex{object=client.init()V}, to=Vertex{object=static Ljava/lang/String;[] class14.field209}, type=SETFIELD}")) + { + b = true; + } + if (e.getTo().getOther() != null) continue; // skip solved edges Vertex v = e.getTo(); // end of edge in g1 - - boolean b2 = false; - if (b && v.toString().equals("Vertex{object=class118.method2566()B}")) - { - b2 = true; - } List l = new ArrayList<>(); for (Edge e2 : other.getEdges()) @@ -289,6 +282,11 @@ public class Rename2 continue; } + if (b) + { + int i = 5; + } + if (!e.couldBeEqual(e2)) { // System.out.println(e + " != " + e2); @@ -397,13 +395,14 @@ public class Rename2 System.out.println("methods " +g1.solved(VertexType.METHOD)); System.out.println("f " +g1.solved(VertexType.FIELD)); - Vertex stored = null; + List unsolved = new ArrayList<>(); + //Vertex stored = null; for (Vertex v : g1.getVerticies()) { if (v.getOther() == null) continue; - if (v.getObject() instanceof Method) continue; + //if (v.getObject() instanceof Method) continue; //assert stored == null; //stored = v; @@ -412,10 +411,19 @@ public class Rename2 { if (e.getTo().getOther() == null) { - System.out.println("Edge " + e + " on vertex " + v + " is unsolved"); + unsolved.add(e); + + if (e.getType() == EdgeType.SETFIELD) + System.out.println("Edge " + e + " is unsolved"); } } } + for (EdgeType t : EdgeType.values()) + { + long count = unsolved.stream().filter(e -> e.getType() == t).count(); + if (count >0) + System.out.println(t + " " + count); + } // NameMappings col = buildCollisionMap(one, two); // rename(col, two); @@ -430,9 +438,10 @@ public class Rename2 // for (Vertex v : g1.getVerticies()) // { -// if (v.getOther() != null) -// System.out.println(v.getObject() + " -> " + v.getOther().getOther()); -// else +//// if (v.getOther() != null) +//// System.out.println(v.getObject() + " -> " + v.getOther().getOther()); +//// else +// if (v.getObject() instanceof Field) // System.out.println(v.getObject() + " -> unk"); // } diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/graph/Edge.java b/src/main/java/net/runelite/deob/deobfuscators/rename/graph/Edge.java index 000092e517..aade7a5920 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/graph/Edge.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/graph/Edge.java @@ -1,10 +1,21 @@ package net.runelite.deob.deobfuscators.rename.graph; import java.util.Arrays; +import java.util.List; import java.util.Objects; +import net.runelite.deob.Field; +import net.runelite.deob.Method; +import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.instruction.types.DupInstruction; +import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction; +import net.runelite.deob.attributes.code.instruction.types.LVTInstruction; +import net.runelite.deob.attributes.code.instruction.types.SetFieldInstruction; +import net.runelite.deob.attributes.code.instructions.InvokeStatic; +import net.runelite.deob.attributes.code.instructions.NewArray; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.StackContext; +import net.runelite.deob.execution.VariableContext; +import net.runelite.deob.execution.Variables; public class Edge { @@ -105,9 +116,9 @@ public class Edge if (this.type != other.type) return false; - if (this.type == EdgeType.SETFIELD) + if (this.type == EdgeType.SETFIELD)// || this.type == EdgeType.SETFIELD_FROM) { - if (!compareSetField(other.getIns())) + if (!compareSetField((Field) this.getTo().getObject(), (Field) other.getTo().getObject(), other.getIns())) return false; } // if (this.weight != other.weight) @@ -115,30 +126,147 @@ public class Edge return true; } - - private InstructionContext handleDup(InstructionContext i, StackContext sctx) + + private InstructionContext resolve( + InstructionContext ctx, + StackContext from // pushed from ctx + ) { - DupInstruction d = (DupInstruction) i.getInstruction(); - return d.getOriginal(sctx).getPushed(); + if (ctx.getInstruction() instanceof SetFieldInstruction) + { + StackContext s = ctx.getPops().get(0); + return resolve(s.getPushed(), s); + } + + if (ctx.getInstruction() instanceof DupInstruction) + { + DupInstruction d = (DupInstruction) ctx.getInstruction(); + StackContext s = d.getOriginal(from); + return resolve(s.getPushed(), s); + } + + if (ctx.getInstruction() instanceof LVTInstruction) + { + LVTInstruction lvt = (LVTInstruction) ctx.getInstruction(); + Variables variables = ctx.getVariables(); + + if (lvt.store()) + { + StackContext s = ctx.getPops().get(0); // is this right? + return resolve(s.getPushed(), s); + } + else + { + VariableContext vctx = variables.get(lvt.getVariableIndex()); // variable being loaded + assert vctx != null; + + InstructionContext storedCtx = vctx.getInstructionWhichStored(); + if (storedCtx == null) + return ctx; // parameter? + + return resolve(storedCtx, null); + } + } + + return ctx; } - private boolean compareSetField(InstructionContext other) +// private static final String[][] map = { +// {"field1989", "field2042"}, +// {"field164", "field2156"}, +// {"field2904", "field2881"}, +// {"field296", "field287"}, +// {"field297", "field425"}, +// {"field416", "field420"}, +// {"field329", "field331"}, +// {"field2203", "field2216"}, +// {"field2202", "field2222"}, +// {"field2100", "field2109"}, +// }; +// +// private boolean isEqual(SetFieldInstruction sf1, SetFieldInstruction sf2) +// { +// for (int i = 0; i < map.length; ++i) +// { +// if (sf1.getMyField() != null && sf1.getMyField().getName().equals(map[i][0]) && +// sf2.getMyField() != null && sf2.getMyField().getName().equals(map[i][1])) +// return true; +// } +// return false; +// } + + private boolean compareSetField(Field field1, Field field2, InstructionContext other) { - InstructionContext thisp = ins.getPops().get(0).getPushed(), - otherp = other.getPops().get(0).getPushed(); - - if (thisp.getInstruction() instanceof DupInstruction) + InstructionContext thisp = resolve(ins.getPops().get(0).getPushed(), ins.getPops().get(0)), + otherp = resolve(other.getPops().get(0).getPushed(), other.getPops().get(0)); + + return couldBeEqual(field1, field2, thisp, otherp); + } + + private boolean couldBeEqual(Field field1, Field field2, InstructionContext one, InstructionContext two) + { + if (field2.getName().equals("field209")) { - thisp = handleDup(thisp, ins.getPops().get(0)); + int i =5; } - if (otherp.getInstruction() instanceof DupInstruction) + Instruction i1 = one.getInstruction(), i2 = two.getInstruction(); + + if (i1 instanceof LVTInstruction && i2 instanceof LVTInstruction) { - otherp = handleDup(otherp, other.getPops().get(0)); + LVTInstruction l1 = (LVTInstruction) i1, l2 = (LVTInstruction) i2; + + assert !l1.store(); + assert !l2.store(); + + VariableContext v1 = one.getVariables().get(l1.getVariableIndex()), + v2 = two.getVariables().get(l2.getVariableIndex()); + + assert v1.getInstructionWhichStored() == null; + assert v2.getInstructionWhichStored() == null; + + return v1.getType().equals(v2.getType()); } - Class[] c1 = thisp.getInstruction().getClass().getInterfaces(), - c2 = otherp.getInstruction().getClass().getInterfaces(); + if (i1 instanceof NewArray && i2 instanceof NewArray) + { + NewArray a1 = (NewArray) i1, a2 = (NewArray) i2; + return a1.getArrayType() == a2.getArrayType(); + } - return Arrays.equals(c1, c2); + // XXX check for invokestatic vs. + if (i1 instanceof InvokeInstruction && i2 instanceof InvokeInstruction) + { + InvokeInstruction ii1 = (InvokeInstruction) i1, ii2 = (InvokeInstruction) i2; + + List methods1 = ii1.getMethods(), methods2 = ii2.getMethods(); + + if (methods1.size() != methods2.size()) + { + return false; + } + + if (methods1.isEmpty()) + { + // compare pool Method + return ii1.getMethod().equals(ii2.getMethod()); + } + + Method m1 = methods1.get(0), m2 = methods2.get(0); + + if (!m1.getDescriptor().equals(m2.getDescriptor())) + return false; + } + else if (i1 instanceof InvokeStatic || i2 instanceof InvokeStatic) + { + return true; + //int i = 5; + } + + if (!i1.getClass().equals(i2.getClass())) + { + return false; + } + + return true; } } diff --git a/src/main/java/net/runelite/deob/pool/Class.java b/src/main/java/net/runelite/deob/pool/Class.java index 12c405fed4..6cf2b25b4a 100644 --- a/src/main/java/net/runelite/deob/pool/Class.java +++ b/src/main/java/net/runelite/deob/pool/Class.java @@ -47,6 +47,12 @@ public class Class extends PoolEntry { index = pool.makeUTF8(name); } + + @Override + public java.lang.String toString() + { + return name; + } @Override public boolean equals(Object other) diff --git a/src/main/java/net/runelite/deob/pool/Method.java b/src/main/java/net/runelite/deob/pool/Method.java index 6b68b89d79..64b34cc392 100644 --- a/src/main/java/net/runelite/deob/pool/Method.java +++ b/src/main/java/net/runelite/deob/pool/Method.java @@ -28,6 +28,12 @@ public class Method extends PoolEntry classIndex = is.readUnsignedShort(); natIndex = is.readUnsignedShort(); } + + @Override + public java.lang.String toString() + { + return clazz + "." + nat; + } @Override public void resolve(ConstantPool pool) diff --git a/src/main/java/net/runelite/deob/pool/NameAndType.java b/src/main/java/net/runelite/deob/pool/NameAndType.java index 75a7ed6661..7c4828c1f7 100644 --- a/src/main/java/net/runelite/deob/pool/NameAndType.java +++ b/src/main/java/net/runelite/deob/pool/NameAndType.java @@ -63,6 +63,15 @@ public class NameAndType extends PoolEntry else descriptorIndex = pool.makeUTF8(type.getFullType()); } + + @Override + public java.lang.String toString() + { + if (type != null) + return name + " " + type; + else + return name + signature; + } @Override public boolean equals(Object other)