From 98a24c954b13aac027ce8a8cff32a4470c3821ea Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 22 Nov 2015 09:04:10 -0600 Subject: [PATCH] Import runeloader inject system --- pom.xml | 15 +- .../deob/inject/AddFieldInstruction.java | 7 + .../deob/inject/AddInterfaceInstruction.java | 29 ++++ .../deob/inject/AddMethodInstruction.java | 37 +++++ .../deob/inject/GetterInjectInstruction.java | 149 ++++++++++++++++++ .../deob/inject/InjectionModscript.java | 60 +++++++ .../deob/inject/InstructionDeserializer.java | 57 +++++++ .../deob/inject/MethodModInstruction.java | 64 ++++++++ .../deob/inject/SuperChangeInstruction.java | 29 ++++ .../TableJumpInstruction$TableJump.java | 16 ++ .../deob/inject/TableJumpInstruction.java | 105 ++++++++++++ 11 files changed, 558 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/runelite/deob/inject/AddFieldInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/AddInterfaceInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/AddMethodInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/GetterInjectInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/InjectionModscript.java create mode 100644 src/main/java/net/runelite/deob/inject/InstructionDeserializer.java create mode 100644 src/main/java/net/runelite/deob/inject/MethodModInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/SuperChangeInstruction.java create mode 100644 src/main/java/net/runelite/deob/inject/TableJumpInstruction$TableJump.java create mode 100644 src/main/java/net/runelite/deob/inject/TableJumpInstruction.java diff --git a/pom.xml b/pom.xml index efb5165e6e..985ec73a4d 100644 --- a/pom.xml +++ b/pom.xml @@ -24,21 +24,16 @@ commons-compress 1.10 - com.google.code.gson gson 2.4 - + + org.ow2.asm + asm-all + 5.0.4 + org.slf4j diff --git a/src/main/java/net/runelite/deob/inject/AddFieldInstruction.java b/src/main/java/net/runelite/deob/inject/AddFieldInstruction.java new file mode 100644 index 0000000000..79d7eca2fb --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/AddFieldInstruction.java @@ -0,0 +1,7 @@ +package net.runelite.deob.inject; + +public class AddFieldInstruction { + public static String owner; + public static String name; + public static String desc; +} diff --git a/src/main/java/net/runelite/deob/inject/AddInterfaceInstruction.java b/src/main/java/net/runelite/deob/inject/AddInterfaceInstruction.java new file mode 100644 index 0000000000..376f7ea799 --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/AddInterfaceInstruction.java @@ -0,0 +1,29 @@ +package net.runelite.deob.inject; + +import org.objectweb.asm.tree.ClassNode; + +public class AddInterfaceInstruction { + private final String clientClass; + private final String interfaceClass; + + public AddInterfaceInstruction(String var1, String var2) { + this.clientClass = var1; + this.interfaceClass = var2; + } + + public String getClientClass() { + return this.clientClass; + } + + public String getInterfaceClass() { + return this.interfaceClass; + } + + public boolean valid(ClassNode var1) { + return var1.name.equalsIgnoreCase(this.clientClass); + } + + public void inject(ClassNode var1) { + var1.interfaces.add(this.interfaceClass); + } +} diff --git a/src/main/java/net/runelite/deob/inject/AddMethodInstruction.java b/src/main/java/net/runelite/deob/inject/AddMethodInstruction.java new file mode 100644 index 0000000000..e356158a13 --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/AddMethodInstruction.java @@ -0,0 +1,37 @@ +package net.runelite.deob.inject; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +public class AddMethodInstruction { + private final String clientClass; + private final String methodName; + private final String methodDesc; + private final AbstractInsnNode[] instructions; + + public AddMethodInstruction(String var1, String var2, String var3, AbstractInsnNode[] var4) { + this.clientClass = var1; + this.methodName = var2; + this.methodDesc = var3; + this.instructions = var4; + } + + public boolean valid(ClassNode var1) { + return var1.name.equalsIgnoreCase(this.clientClass); + } + + public void inject(ClassNode var1) { + MethodNode var2 = new MethodNode(1, this.methodName, this.methodDesc, (String)null, (String[])null); + AbstractInsnNode[] var6 = this.instructions; + int var5 = this.instructions.length; + + for(int var4 = 0; var4 < var5; ++var4) { + AbstractInsnNode var3 = var6[var4]; + var2.instructions.add(var3); + } + + var2.visitMaxs(0, 0); + var1.methods.add(var2); + } +} diff --git a/src/main/java/net/runelite/deob/inject/GetterInjectInstruction.java b/src/main/java/net/runelite/deob/inject/GetterInjectInstruction.java new file mode 100644 index 0000000000..923f494b7e --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/GetterInjectInstruction.java @@ -0,0 +1,149 @@ +package net.runelite.deob.inject; + +import java.util.Iterator; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class GetterInjectInstruction { + private final String className; + private final String getterMethodDesc; + private final String getterName; + private final String getterClassName; + private final String getterFieldName; + private final Integer multiplier; + private final boolean staticField; + + public GetterInjectInstruction(String var1, String var2, String var3, String var4, String var5, Integer var6, boolean var7) { + this.className = var1; + this.getterMethodDesc = "()" + var3; + this.getterName = var2; + this.getterClassName = var4; + this.getterFieldName = var5; + this.multiplier = var6; + this.staticField = var7; + } + + public String getClassName() { + return this.className; + } + + public String getGetterMethodDesc() { + return this.getterMethodDesc; + } + + public String getGetterName() { + return this.getterName; + } + + public String getGetterClassName() { + return this.getterClassName; + } + + public String getGetterFieldName() { + return this.getterFieldName; + } + + public Integer getMultiplier() { + return this.multiplier; + } + + public boolean isStaticField() { + return this.staticField; + } +// +// public boolean valid(ClassNode var1) { +// return var1.name.equalsIgnoreCase(this.className); +// } +// +// private FieldNode get(qelKbskphK[] var1) { +// qelKbskphK[] var5 = var1; +// int var4 = var1.length; +// +// for(int var3 = 0; var3 < var4; ++var3) { +// qelKbskphK var2 = var5[var3]; +// ClassNode var6 = var2.KxdZMCzVTn(); +// if(var6.name.equalsIgnoreCase(this.getterClassName)) { +// Iterator var8 = var6.fields.iterator(); +// +// while(var8.hasNext()) { +// FieldNode var7 = (FieldNode)var8.next(); +// if(var7.name.equalsIgnoreCase(this.getterFieldName)) { +// return var7; +// } +// } +// } +// } +// +// return null; +// } +// +// public void inject(ClassNode var1, qelKbskphK[] var2) { +// String var3 = this.getGetterMethodDesc().substring(2); +// MethodNode var4 = new MethodNode(1, this.getGetterName(), this.getGetterMethodDesc(), (String)null, (String[])null); +// if(!this.isStaticField()) { +// var4.instructions.add(new VarInsnNode(25, 0)); +// } +// +// int var5 = this.isStaticField()?178:180; +// var4.instructions.add(new FieldInsnNode(var5, this.getterClassName, this.getterFieldName, this.get(var2).desc)); +// if(this.getMultiplier() != null) { +// var4.instructions.add(new LdcInsnNode(this.getMultiplier())); +// var4.instructions.add(new InsnNode(104)); +// } +// +// var4.instructions.add(new InsnNode(getReturn(Type.getReturnType(var3).getSort()))); +// var1.methods.add(var4); +// } +// +// public static int getReturn(int var0) { +// return var0 == 0?177:(var0 >= 1 && var0 <= 5?172:(var0 == 6?174:(var0 == 7?173:(var0 == 8?175:176)))); +// } +// +// private int getReturnOpcode(String var1) { +// var1 = var1.substring(var1.indexOf(")") + 1); +// if(var1.length() > 1) { +// return 176; +// } else { +// char var2 = var1.charAt(0); +// switch(var2) { +// case 'B': +// case 'C': +// case 'I': +// case 'S': +// case 'Z': +// return 172; +// case 'D': +// return 175; +// case 'E': +// case 'G': +// case 'H': +// case 'K': +// case 'L': +// case 'M': +// case 'N': +// case 'O': +// case 'P': +// case 'Q': +// case 'R': +// case 'T': +// case 'U': +// case 'V': +// case 'W': +// case 'X': +// case 'Y': +// default: +// throw new RuntimeException("bad_return"); +// case 'F': +// return 174; +// case 'J': +// return 173; +// } +// } +// } +} diff --git a/src/main/java/net/runelite/deob/inject/InjectionModscript.java b/src/main/java/net/runelite/deob/inject/InjectionModscript.java new file mode 100644 index 0000000000..e1694f5e00 --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/InjectionModscript.java @@ -0,0 +1,60 @@ +package net.runelite.deob.inject; + +import com.google.common.io.Files; +import com.google.gson.GsonBuilder; +import com.runeloader.RuneLoader; +import com.runeloader.api.inject.InstructionDeserializer; +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import org.objectweb.asm.tree.AbstractInsnNode; + +public class InjectionModscript { + private List getterInjects = new LinkedList(); + private List superChangeInjects = new LinkedList(); + private List addInterfaceInjects = new LinkedList(); + private List methodMods = new LinkedList(); + private List addMethods = new LinkedList(); + private List newMethodMods = new LinkedList(); + + public void save() { + byte[] var1 = (new GsonBuilder()).setPrettyPrinting().create().toJson(this).getBytes(); + + try { + Files.write(var1, new File("injection.json")); + } catch (IOException var3) { + var3.printStackTrace(); + } + + } + + public static InjectionModscript load(File var0) throws IOException { + byte[] var1 = Files.toByteArray(var0); + return (InjectionModscript)(new GsonBuilder()).registerTypeAdapter(AbstractInsnNode.class, new InstructionDeserializer()).create().fromJson((new String(var1)).replaceAll("runecore", "runeloader"), InjectionModscript.class); + } + + public List getGetterInjects() { + return this.getterInjects; + } + + public List getSuperChangeInjects() { + return this.superChangeInjects; + } + + public List getAddInterfaceInjects() { + return this.addInterfaceInjects; + } + + public List getMethodMods() { + return this.methodMods; + } + + public List getAddMethods() { + return this.addMethods; + } + + public List getNewMethodMods() { + return this.newMethodMods; + } +} diff --git a/src/main/java/net/runelite/deob/inject/InstructionDeserializer.java b/src/main/java/net/runelite/deob/inject/InstructionDeserializer.java new file mode 100644 index 0000000000..7d8ff3f03a --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/InstructionDeserializer.java @@ -0,0 +1,57 @@ +package net.runelite.deob.inject; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.lang.reflect.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class InstructionDeserializer implements JsonDeserializer { + public AbstractInsnNode deserialize(JsonElement var1, Type var2, JsonDeserializationContext var3) { + JsonObject var4 = (JsonObject)var1; + int var5 = var4.get("opcode").getAsInt(); + if(var5 != 21 && var5 != 25 && var5 != 58 && var5 != 54 && var5 != 22) { + String var7; + String var8; + String var10; + if(var5 != 184 && var5 != 182 && var5 != 183) { + if(var5 == 18) { + try { + return new LdcInsnNode(Integer.valueOf(var4.get("cst").getAsInt())); + } catch (Exception var9) { + return new LdcInsnNode(var4.get("cst").getAsString()); + } + } else if(var5 == 187) { + return new TypeInsnNode(var5, var4.get("desc").getAsString()); + } else if(var5 != 16 && var5 != 17) { + if(var5 != 179 && var5 != 178 && var5 != 180 && var5 != 181) { + return new InsnNode(var5); + } else { + var10 = var4.get("owner").getAsString(); + var7 = var4.get("name").getAsString(); + var8 = var4.get("desc").getAsString(); + return new FieldInsnNode(var5, var10, var7, var8); + } + } else { + return new IntInsnNode(var5, var4.get("operand").getAsInt()); + } + } else { + var10 = var4.get("owner").getAsString(); + var7 = var4.get("name").getAsString(); + var8 = var4.get("desc").getAsString(); + return new MethodInsnNode(var5, var10, var7, var8); + } + } else { + int var6 = var4.get("var").getAsInt(); + return new VarInsnNode(var5, var6); + } + } +} diff --git a/src/main/java/net/runelite/deob/inject/MethodModInstruction.java b/src/main/java/net/runelite/deob/inject/MethodModInstruction.java new file mode 100644 index 0000000000..a2a0edc658 --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/MethodModInstruction.java @@ -0,0 +1,64 @@ +package net.runelite.deob.inject; + +import java.util.Iterator; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; + +public class MethodModInstruction { + private final int startIndex; + private final AbstractInsnNode[] nodes; + public final String owner; + public final String method; + public final String desc; + + public MethodModInstruction(int var1, AbstractInsnNode[] var2, String var3, String var4, String var5) { + this.startIndex = var1; + this.nodes = var2; + this.owner = var3; + this.method = var4; + this.desc = var5; + } + + public boolean valid(ClassNode var1) { + return var1.name.equalsIgnoreCase(this.owner); + } + + public void inject(ClassNode var1) { + Iterator var3 = var1.methods.iterator(); + + while(true) { + MethodNode var2; + do { + do { + if(!var3.hasNext()) { + return; + } + + var2 = (MethodNode)var3.next(); + } while(!var2.name.equalsIgnoreCase(this.method)); + } while(!var2.desc.equalsIgnoreCase(this.desc)); + + InsnList var4 = var2.instructions; + + try { + AbstractInsnNode var5 = var4.get(this.startIndex); + AbstractInsnNode var6 = null; + + for(int var7 = 0; var7 < this.nodes.length; ++var7) { + if(var6 == null) { + var4.insertBefore(var5, this.nodes[var7]); + } else { + var4.insert(var6, this.nodes[var7]); + } + + var6 = this.nodes[var7]; + } + } catch (Exception var8) { + System.err.println("Failed on " + this.startIndex + " @ " + this.owner + "." + this.method + " " + this.desc); + var8.printStackTrace(); + } + } + } +} diff --git a/src/main/java/net/runelite/deob/inject/SuperChangeInstruction.java b/src/main/java/net/runelite/deob/inject/SuperChangeInstruction.java new file mode 100644 index 0000000000..76754bd9fe --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/SuperChangeInstruction.java @@ -0,0 +1,29 @@ +package net.runelite.deob.inject; + +import org.objectweb.asm.tree.ClassNode; + +public class SuperChangeInstruction { + private final String clientName; + private final String superName; + + public SuperChangeInstruction(String var1, String var2) { + this.clientName = var1; + this.superName = var2; + } + + public String getClientName() { + return this.clientName; + } + + public String getSuperName() { + return this.superName; + } + + public boolean valid(ClassNode var1) { + return var1.name.equalsIgnoreCase(this.clientName); + } + + public void inject(ClassNode var1) { + var1.superName = this.superName; + } +} diff --git a/src/main/java/net/runelite/deob/inject/TableJumpInstruction$TableJump.java b/src/main/java/net/runelite/deob/inject/TableJumpInstruction$TableJump.java new file mode 100644 index 0000000000..96dcea7c8a --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/TableJumpInstruction$TableJump.java @@ -0,0 +1,16 @@ +package net.runelite.deob.inject; + +import org.objectweb.asm.Label; + +public class TableJumpInstruction$TableJump { + public Label label; + public final int instructionIndex; + public final int labelArrayIndex; + public final int opcode; + + public TableJumpInstruction$TableJump(int var1, int var2, int var3) { + this.instructionIndex = var1; + this.opcode = var3; + this.labelArrayIndex = var2; + } +} diff --git a/src/main/java/net/runelite/deob/inject/TableJumpInstruction.java b/src/main/java/net/runelite/deob/inject/TableJumpInstruction.java new file mode 100644 index 0000000000..bd4289c5b4 --- /dev/null +++ b/src/main/java/net/runelite/deob/inject/TableJumpInstruction.java @@ -0,0 +1,105 @@ +package net.runelite.deob.inject; + +import java.util.Iterator; +import org.objectweb.asm.Label; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; + +public class TableJumpInstruction { + private final TableJumpInstruction$TableJump[] tableJumps; + private final int[] labels; + private final int start; + private final AbstractInsnNode[] instructions; + private final String owner; + private final String name; + private final String desc; + + public TableJumpInstruction(TableJumpInstruction$TableJump[] var1, AbstractInsnNode[] var2, int[] var3, int var4, String var5, String var6, String var7) { + this.tableJumps = var1; + this.instructions = var2; + this.labels = var3; + this.owner = var5; + this.name = var6; + this.desc = var7; + this.start = var4; + } + + public boolean valid(ClassNode var1) { + return var1.name.equalsIgnoreCase(this.owner); + } + + public void inject(ClassNode var1) { + Iterator var3 = var1.methods.iterator(); + + MethodNode var2; + do { + if(!var3.hasNext()) { + return; + } + + var2 = (MethodNode)var3.next(); + } while(!var2.name.equalsIgnoreCase(this.name) || !var2.desc.equalsIgnoreCase(this.desc)); + + this.insert(var2); + } + + private void insert(MethodNode var1) { + AbstractInsnNode[] var2 = new AbstractInsnNode[this.instructions.length]; + Label[] var3 = new Label[this.labels.length]; + InsnList var4 = var1.instructions; + + int var5; + for(var5 = 0; var5 < this.labels.length; ++var5) { + int var6 = this.labels[var5]; + if(var6 == -1) { + var3[var5] = new Label(); + } else { + JumpInsnNode var7 = (JumpInsnNode)var4.get(var6); + var3[var5] = var7.label.getLabel(); + } + } + + for(var5 = 0; var5 < this.instructions.length; ++var5) { + Object var11 = this.instructions[var5]; + if(var11 == null) { + TableJumpInstruction$TableJump var12 = this.getJump(var5); + LabelNode var8 = new LabelNode(var3[var12.labelArrayIndex]); + if(var12.opcode != 9000) { + var11 = new JumpInsnNode(var12.opcode, var8); + } else { + var11 = var8; + } + } + + var2[var5] = (AbstractInsnNode)var11; + } + + AbstractInsnNode var10 = var4.get(this.start); + AbstractInsnNode[] var9 = var2; + int var15 = var2.length; + + for(int var13 = 0; var13 < var15; ++var13) { + AbstractInsnNode var14 = var9[var13]; + var4.insertBefore(var10, var14); + } + + } + + private TableJumpInstruction$TableJump getJump(int var1) { + TableJumpInstruction$TableJump[] var5 = this.tableJumps; + int var4 = this.tableJumps.length; + + for(int var3 = 0; var3 < var4; ++var3) { + TableJumpInstruction$TableJump var2 = var5[var3]; + if(var2.instructionIndex == var1) { + return var2; + } + } + + return null; + } +}