From 5ca2e373f5b7a6a317839d28fdd2ab8641e07daf Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 13 Dec 2015 12:39:48 -0500 Subject: [PATCH] Test seems promising --- .../deob/attributes/code/Instruction.java | 2 +- .../instruction/types/InvokeInstruction.java | 2 +- .../types/MappableInstruction.java | 8 ++ .../types/SetFieldInstruction.java | 2 +- .../attributes/code/instructions/Goto.java | 6 + .../deob/attributes/code/instructions/If.java | 28 ++++- .../attributes/code/instructions/If0.java | 23 +++- .../code/instructions/InvokeInterface.java | 7 ++ .../code/instructions/InvokeSpecial.java | 7 ++ .../code/instructions/InvokeStatic.java | 7 ++ .../code/instructions/InvokeVirtual.java | 7 ++ .../code/instructions/PutField.java | 9 ++ .../code/instructions/PutStatic.java | 9 ++ .../net/runelite/deob/execution/Frame.java | 14 +++ .../deob/execution/InstructionContext.java | 5 + .../deob/deobfuscators/rename/MapTest.java | 117 ++++++++++++++++++ 16 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 src/main/java/net/runelite/deob/attributes/code/instruction/types/MappableInstruction.java create mode 100644 src/test/java/net/runelite/deob/deobfuscators/rename/MapTest.java diff --git a/src/main/java/net/runelite/deob/attributes/code/Instruction.java b/src/main/java/net/runelite/deob/attributes/code/Instruction.java index 974d0ca6c0..bbc25b6295 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Instruction.java +++ b/src/main/java/net/runelite/deob/attributes/code/Instruction.java @@ -32,7 +32,7 @@ public abstract class Instruction implements Cloneable public String toString() { Method m = this.getInstructions().getCode().getAttributes().getMethod(); - return super.toString() + " in " + m + " at pc " + this.getPc(); + return super.toString() + " in " + m + " at pc 0x" + Integer.toHexString(this.getPc()); } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instruction/types/InvokeInstruction.java b/src/main/java/net/runelite/deob/attributes/code/instruction/types/InvokeInstruction.java index e822222d43..ac71c98af1 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instruction/types/InvokeInstruction.java +++ b/src/main/java/net/runelite/deob/attributes/code/instruction/types/InvokeInstruction.java @@ -5,7 +5,7 @@ import java.util.List; import net.runelite.deob.Method; import net.runelite.deob.pool.PoolEntry; -public interface InvokeInstruction +public interface InvokeInstruction extends MappableInstruction { public void removeParameter(int idx); diff --git a/src/main/java/net/runelite/deob/attributes/code/instruction/types/MappableInstruction.java b/src/main/java/net/runelite/deob/attributes/code/instruction/types/MappableInstruction.java new file mode 100644 index 0000000000..b07377d78c --- /dev/null +++ b/src/main/java/net/runelite/deob/attributes/code/instruction/types/MappableInstruction.java @@ -0,0 +1,8 @@ +package net.runelite.deob.attributes.code.instruction.types; + +import net.runelite.deob.execution.InstructionContext; + +public interface MappableInstruction +{ + void map(InstructionContext ctx, InstructionContext other); +} diff --git a/src/main/java/net/runelite/deob/attributes/code/instruction/types/SetFieldInstruction.java b/src/main/java/net/runelite/deob/attributes/code/instruction/types/SetFieldInstruction.java index 49a4707033..d3508b52ad 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instruction/types/SetFieldInstruction.java +++ b/src/main/java/net/runelite/deob/attributes/code/instruction/types/SetFieldInstruction.java @@ -1,5 +1,5 @@ package net.runelite.deob.attributes.code.instruction.types; -public interface SetFieldInstruction extends FieldInstruction +public interface SetFieldInstruction extends FieldInstruction, MappableInstruction { } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Goto.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Goto.java index 4f7b60fd6a..d16c0a61e0 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Goto.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Goto.java @@ -22,6 +22,12 @@ public class Goto extends Instruction implements JumpingInstruction { super(instructions, type, pc); } + + @Override + public String toString() + { + return "goto " + to + " (at pc " + (this.getPc() + offset) + ")"; + } public Goto(Instructions instructions, Instruction to) { diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/If.java b/src/main/java/net/runelite/deob/attributes/code/instructions/If.java index 0e6ab0dd30..3453bccb09 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/If.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/If.java @@ -15,8 +15,9 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.List; +import net.runelite.deob.attributes.code.instruction.types.MappableInstruction; -public class If extends Instruction implements JumpingInstruction, ComparisonInstruction +public abstract class If extends Instruction implements JumpingInstruction, ComparisonInstruction, MappableInstruction { private Instruction to; private short offset; @@ -93,4 +94,29 @@ public class If extends Instruction implements JumpingInstruction, ComparisonIns { return Arrays.asList(to); } + + @Override + public final/*XXX tmp*/ void map(InstructionContext ctx, InstructionContext other) + { + InstructionContext oneLhs = ctx.getPops().get(0).getPushed().resolve(ctx.getPops().get(0)), + oneRhs = ctx.getPops().get(1).getPushed().resolve(ctx.getPops().get(1)), + + twoLhs = other.getPops().get(0).getPushed().resolve(other.getPops().get(0)), + twoRhs = other.getPops().get(1).getPushed().resolve(other.getPops().get(1)); + + assert ctx.getInstruction().getClass().equals(other.getInstruction().getClass()); + + Frame branch1 = ctx.getBranches().get(0), + branch2 = other.getBranches().get(0); + + assert branch1.other == null; + assert branch2.other == null; + + branch1.other = branch2; + branch2.other = branch1; + + // we can map these if they are getfield instructions? + + // + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/If0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/If0.java index 330ce4e776..d63bee10d0 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/If0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/If0.java @@ -15,8 +15,9 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.List; +import net.runelite.deob.attributes.code.instruction.types.MappableInstruction; -public class If0 extends Instruction implements JumpingInstruction, ComparisonInstruction +public abstract class If0 extends Instruction implements JumpingInstruction, ComparisonInstruction, MappableInstruction { private Instruction to; private short offset; @@ -94,4 +95,24 @@ public class If0 extends Instruction implements JumpingInstruction, ComparisonIn { return Arrays.asList(to); } + + @Override + public final/*XXX tmp*/ void map(InstructionContext ctx, InstructionContext other) + { + InstructionContext one = ctx.getPops().get(0).getPushed().resolve(ctx.getPops().get(0)), + two = other.getPops().get(0).getPushed().resolve(other.getPops().get(0)); + + // we can map these if they are getfield instructions? + + assert ctx.getInstruction().getClass().equals(other.getInstruction().getClass()); + + Frame branch1 = ctx.getBranches().get(0), + branch2 = other.getBranches().get(0); + + assert branch1.other == null; + assert branch2.other == null; + + branch1.other = branch2; + branch2.other = branch1; + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeInterface.java b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeInterface.java index ebad6e4b2b..a5e3192942 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeInterface.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeInterface.java @@ -157,4 +157,11 @@ public class InvokeInterface extends Instruction implements InvokeInstruction if (myMethods != null && !myMethods.isEmpty()) method = myMethods.get(0).getPoolInterfaceMethod(); // is this right? } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + List myMethods = this.getMethods(), + otherMethods = ((InvokeInterface) other.getInstruction()).getMethods(); + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeSpecial.java b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeSpecial.java index ad3a161ea6..a51b15742a 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeSpecial.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/InvokeSpecial.java @@ -150,4 +150,11 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction if (myMethods != null && !myMethods.isEmpty()) method = myMethods.get(0).getPoolMethod(); } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + List myMethods = this.getMethods(), + otherMethods = ((InvokeSpecial) other.getInstruction()).getMethods(); + } } 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 ee1080a6e2..e51741d05a 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 @@ -160,4 +160,11 @@ public class InvokeStatic extends Instruction implements InvokeInstruction if (myMethods != null && !myMethods.isEmpty()) method = myMethods.get(0).getPoolMethod(); } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + List myMethods = this.getMethods(), + otherMethods = ((InvokeStatic) other.getInstruction()).getMethods(); + } } 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 a8784f2352..c64444ee75 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 @@ -161,4 +161,11 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction if (myMethods != null && !myMethods.isEmpty()) method = myMethods.get(0).getPoolMethod(); // is this right? } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + List myMethods = this.getMethods(), + otherMethods = ((InvokeVirtual) other.getInstruction()).getMethods(); + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/PutField.java b/src/main/java/net/runelite/deob/attributes/code/instructions/PutField.java index da534bebe2..e8b5de8966 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/PutField.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/PutField.java @@ -94,4 +94,13 @@ public class PutField extends Instruction implements SetFieldInstruction if (myField != null) field = myField.getPoolField(); } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + net.runelite.deob.Field myField = this.getMyField(), + otherField = ((PutField) other.getInstruction()).getMyField(); + + System.out.println("MAPPING " + myField + " -> " + otherField); + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/PutStatic.java b/src/main/java/net/runelite/deob/attributes/code/instructions/PutStatic.java index c3d316b60b..e9c2aa3ade 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/PutStatic.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/PutStatic.java @@ -93,4 +93,13 @@ public class PutStatic extends Instruction implements SetFieldInstruction if (myField != null) field = myField.getPoolField(); } + + @Override + public void map(InstructionContext ctx, InstructionContext other) + { + net.runelite.deob.Field myField = this.getMyField(), + otherField = ((PutStatic) other.getInstruction()).getMyField(); + + System.out.println("MAPPING " + myField + " -> " + otherField); + } } diff --git a/src/main/java/net/runelite/deob/execution/Frame.java b/src/main/java/net/runelite/deob/execution/Frame.java index 4ef7f6be82..be61168d1b 100644 --- a/src/main/java/net/runelite/deob/execution/Frame.java +++ b/src/main/java/net/runelite/deob/execution/Frame.java @@ -11,6 +11,7 @@ import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.Instructions; import net.runelite.deob.pool.NameAndType; import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction; +import net.runelite.deob.attributes.code.instruction.types.MappableInstruction; import net.runelite.deob.attributes.code.instruction.types.ReturnInstruction; import net.runelite.deob.attributes.code.instruction.types.SetFieldInstruction; import net.runelite.deob.attributes.code.instructions.AThrow; @@ -28,6 +29,7 @@ public class Frame private MethodContext ctx; protected Method nonStatic; // next non static method up the stack private Frame caller; + public Frame other; // in the other execution for mapping public Frame(Execution execution, Method method) { @@ -44,6 +46,12 @@ public class Frame ctx = new MethodContext(execution); nonStatic = method; } + + @Override + public String toString() + { + return "Frame{" + "cur=" + cur + '}'; + } public void initialize() { @@ -219,6 +227,12 @@ public class Frame { /* jump */ } + + if (oldCur instanceof MappableInstruction) + { + execution.paused = true; + return; + } } } diff --git a/src/main/java/net/runelite/deob/execution/InstructionContext.java b/src/main/java/net/runelite/deob/execution/InstructionContext.java index 480848e327..7089ddb991 100644 --- a/src/main/java/net/runelite/deob/execution/InstructionContext.java +++ b/src/main/java/net/runelite/deob/execution/InstructionContext.java @@ -98,6 +98,11 @@ public class InstructionContext { return invokes; } + + public List getBranches() + { + return branches; + } public List removeStack(int idx) { diff --git a/src/test/java/net/runelite/deob/deobfuscators/rename/MapTest.java b/src/test/java/net/runelite/deob/deobfuscators/rename/MapTest.java new file mode 100644 index 0000000000..5fb25c7fa8 --- /dev/null +++ b/src/test/java/net/runelite/deob/deobfuscators/rename/MapTest.java @@ -0,0 +1,117 @@ +package net.runelite.deob.deobfuscators.rename; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.Method; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.instruction.types.MappableInstruction; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.util.JarUtil; +import org.junit.Test; + +public class MapTest +{ + @Test + public void main() throws IOException + { + ClassGroup group1 = JarUtil.loadJar(new File("d:/rs/07/adamin1.jar")); + ClassGroup group2 = JarUtil.loadJar(new File("d:/rs/07/adamin2.jar")); + + Method m1 = group1.findClass("class99").findMethod("method2220"); + Execution e = new Execution(group1); + Frame frame = new Frame(e, m1); + frame.initialize(); + e.frames.add(frame); + + Method m2 = group2.findClass("class99").findMethod("method2149"); + Execution e2 = new Execution(group2); + Frame frame2 = new Frame(e2, m2); + frame2.initialize(); + e2.frames.add(frame2); + + frame.other = frame2; + frame2.other = frame; + + List l1 = m1.getCode().getInstructions().getInstructions().stream().filter(i -> i instanceof MappableInstruction).collect(Collectors.toList()); + List l2 = m2.getCode().getInstructions().getInstructions().stream().filter(i -> i instanceof MappableInstruction).collect(Collectors.toList()); + + while (!e.frames.isEmpty()) + { + assert e.frames.size() == e2.frames.size(); + Frame f1 = e.frames.get(0), f2 = e2.frames.get(0); + + assert f1.other == f2; + assert f2.other == f1; + + assert f1.isExecuting() == f2.isExecuting(); + + // on if it is duped then jumped, + if (!f1.isExecuting()) + { + assert e.frames.get(0) == f1; + assert e2.frames.get(0) == f2; + + e.frames.remove(0); + e2.frames.remove(0); + continue; + } + + // step frame + f1.execute(); + f2.execute(); + + // get what each frame is paused/exited on + InstructionContext p1 = f1.getInstructions().get(f1.getInstructions().size() - 1); + InstructionContext p2 = f2.getInstructions().get(f2.getInstructions().size() - 1); + + if (!f1.isExecuting() || !f2.isExecuting()) + { + for (Frame branch : p1.getBranches()) + { + e.frames.remove(branch); + } + for (Frame branch : p2.getBranches()) + { + e2.frames.remove(branch); + } + + // System.out.println("Something exited " + f1 + " " + f2); + + assert e.frames.get(0) == f1; + assert e2.frames.get(0) == f2; + + e.frames.remove(0); + e2.frames.remove(0); + continue; + } + + // frames can stop executing if they've determined that they've executed + // the ins before, and it won't necessarily be at the same time? + + assert e.paused; + assert e2.paused; + + //System.out.println(p1.getInstruction() + " <-> " + p2.getInstruction()); + + assert p1.getInstruction().getInstructions().getCode().getAttributes().getMethod() == m1; + assert p2.getInstruction().getInstructions().getCode().getAttributes().getMethod() == m2; + + assert p1.getInstruction() instanceof MappableInstruction; + assert p2.getInstruction() instanceof MappableInstruction; + + assert p1.getInstruction().getClass().equals(p2.getInstruction().getClass()); + + MappableInstruction mi1 = (MappableInstruction) p1.getInstruction(); + + mi1.map(p1, p2); + + e.paused = e2.paused = false; + } + } +}