diff --git a/pom.xml b/pom.xml index bc0a1b08cd..dfb330e6d2 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,12 @@ guava 18.0 + + junit + junit + 4.12 + test + 1.7 diff --git a/src/main/java/net/runelite/deob/ClassFile.java b/src/main/java/net/runelite/deob/ClassFile.java index e89016c4e8..3320f250e8 100644 --- a/src/main/java/net/runelite/deob/ClassFile.java +++ b/src/main/java/net/runelite/deob/ClassFile.java @@ -16,7 +16,6 @@ public class ClassFile private static final int MAGIC = 0xcafebabe; private ClassGroup group; - private DataInputStream is; private ClassFile parent; // super class private List children = new ArrayList<>(); // classes which inherit from this @@ -35,7 +34,6 @@ public class ClassFile public ClassFile(ClassGroup group, DataInputStream is) throws IOException { this.group = group; - this.is = is; int magic = is.readInt(); if (magic != MAGIC) @@ -50,12 +48,22 @@ public class ClassFile name = pool.getClass(is.readUnsignedShort()); super_class = pool.getClass(is.readUnsignedShort()); + interfaces = new Interfaces(this, is); + + fields = new Fields(this, is); + + methods = new Methods(this, is); + + attributes = new Attributes(this, is); + } + + public ClassFile(ClassGroup group) + { + this.group = group; + interfaces = new Interfaces(this); - fields = new Fields(this); - methods = new Methods(this); - attributes = new Attributes(this); } @@ -93,12 +101,7 @@ public class ClassFile { return group; } - - public DataInputStream getStream() - { - return is; - } - + public ConstantPool getPool() { return pool; @@ -129,6 +132,16 @@ public class ClassFile this.name = new Class(name); } + public String getSuperName() + { + return super_class.getName(); + } + + public void setSuperName(String name) + { + super_class = new Class(name); + } + public Class getParentClass() { return this.super_class; @@ -148,6 +161,11 @@ public class ClassFile { return children; } + + public Field findField(String name) + { + return fields.findField(name); + } public Field findFieldDeep(NameAndType nat) { diff --git a/src/main/java/net/runelite/deob/ClassGroup.java b/src/main/java/net/runelite/deob/ClassGroup.java index f0d5cac302..c775db277f 100644 --- a/src/main/java/net/runelite/deob/ClassGroup.java +++ b/src/main/java/net/runelite/deob/ClassGroup.java @@ -20,6 +20,11 @@ public class ClassGroup return cf; } + public void addClass(ClassFile cf) + { + classes.add(cf); + } + public void removeClass(ClassFile cf) { classes.remove(cf); diff --git a/src/main/java/net/runelite/deob/ConstantPool.java b/src/main/java/net/runelite/deob/ConstantPool.java index 8193237f25..8dae509745 100644 --- a/src/main/java/net/runelite/deob/ConstantPool.java +++ b/src/main/java/net/runelite/deob/ConstantPool.java @@ -38,8 +38,8 @@ public class ConstantPool try { - Constructor con = type.getPoolClass().getConstructor(new Class[] { ConstantPool.class }); - PoolEntry entry = con.newInstance(this); + Constructor con = type.getPoolClass().getConstructor(new Class[] { ConstantPool.class, DataInputStream.class }); + PoolEntry entry = con.newInstance(this, is); entry.id = i; entries.add(entry); diff --git a/src/main/java/net/runelite/deob/Deob.java b/src/main/java/net/runelite/deob/Deob.java index 3995fdcab4..c6cc59b132 100644 --- a/src/main/java/net/runelite/deob/Deob.java +++ b/src/main/java/net/runelite/deob/Deob.java @@ -25,13 +25,11 @@ import net.runelite.deob.deobfuscators.UnusedClass; import net.runelite.deob.deobfuscators.UnusedFields; import net.runelite.deob.deobfuscators.UnusedMethods; import net.runelite.deob.deobfuscators.UnusedParameters; - -//move static methods -//move static fields -//math deob -//remove dead classes -//inline constant fields -//compare old and new +import net.runelite.deob.deobfuscators.arithmetic.ModArith; +import net.runelite.deob.deobfuscators.arithmetic.MultiplicationDeobfuscator; +import net.runelite.deob.deobfuscators.arithmetic.MultiplyOneDeobfuscator; +import net.runelite.deob.deobfuscators.arithmetic.MultiplyZeroDeobfuscator; +import net.runelite.deob.execution.Execution; public class Deob { @@ -40,81 +38,70 @@ public class Deob long start = System.currentTimeMillis(); ClassGroup group = loadJar(args[0]); - long bstart, bdur; -// bstart = System.currentTimeMillis(); -// new RenameUnique().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("rename unique took " + bdur/1000L + " seconds"); + //run(group, new RenameUnique()); // // remove except RuntimeException -// bstart = System.currentTimeMillis(); -// new RuntimeExceptions().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("runtime exception took " + bdur/1000L + " seconds"); +// run(group, new RuntimeExceptions()); // // // remove unused methods -// bstart = System.currentTimeMillis(); -// new UnusedMethods().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("unused methods took " + bdur/1000L + " seconds"); +// run(group, new UnusedMethods()); // -// new UnreachedCode().run(group); +// run(group, new UnreachedCode()); // // // remove illegal state exceptions, frees up some parameters -// bstart = System.currentTimeMillis(); -// new IllegalStateExceptions().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("illegal state exception took " + bdur/1000L + " seconds"); +// run(group, new IllegalStateExceptions()); // // // remove constant logically dead parameters -// bstart = System.currentTimeMillis(); -// new ConstantParameter().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("constant param took " + bdur/1000L + " seconds"); +// run(group, new ConstantParameter()); // // // remove unhit blocks -// bstart = System.currentTimeMillis(); -// new UnreachedCode().run(group); -// //new UnusedBlocks().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("unused blocks took " + bdur/1000L + " seconds"); +// run(group, new UnreachedCode()); // // // remove unused parameters -// bstart = System.currentTimeMillis(); -// new UnusedParameters().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("unused params took " + bdur/1000L + " seconds"); +// run(group, new UnusedParameters()); // // // remove jump obfuscation // //new Jumps().run(group); // // // remove unused fields -// bstart = System.currentTimeMillis(); -// new UnusedFields().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("unused fields took " + bdur/1000L + " seconds"); +// run(group, new UnusedFields()); // // // remove unused methods, again? -// bstart = System.currentTimeMillis(); -// new UnusedMethods().run(group); -// bdur = System.currentTimeMillis() - bstart; -// System.out.println("unused methods took " + bdur/1000L + " seconds"); - - - new MethodInliner().run(group); +// run(group, new UnusedMethods()); // -// new MethodMover().run(group); +// run(group, new MethodInliner()); +// +// run(group, new MethodMover()); // -// new FieldInliner().run(group); +// 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); - // XXX this is broken because when moving clinit around, some fields can depend on other fields - // (like multianewarray) - //new FieldMover().run(group); - - //new UnusedClass().run(group); - -// new ModularArithmeticDeobfuscation().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) + { + System.out.println("break"); + break; + } + + last = cur; + } saveJar(group, args[1]); @@ -165,4 +152,20 @@ public class Deob jout.close(); } + + private static void run(ClassGroup group, Deobfuscator deob) + { + long bstart, bdur; + + bstart = System.currentTimeMillis(); + deob.run(group); + bdur = System.currentTimeMillis() - bstart; + + System.out.println(deob.getClass().getName() + " took " + (bdur / 1000L) + " seconds"); + + // check code is still correct + Execution execution = new Execution(group); + execution.populateInitialMethods(); + execution.run(); + } } \ No newline at end of file diff --git a/src/main/java/net/runelite/deob/Field.java b/src/main/java/net/runelite/deob/Field.java index 07e883acd8..05bb4aeff5 100644 --- a/src/main/java/net/runelite/deob/Field.java +++ b/src/main/java/net/runelite/deob/Field.java @@ -8,6 +8,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Objects; +import net.runelite.deob.pool.NameAndType; public class Field { @@ -28,16 +30,24 @@ public class Field private Type type; private Attributes attributes; - Field(Fields fields) throws IOException + Field(Fields fields, DataInputStream is) throws IOException { this.fields = fields; - DataInputStream is = fields.getClassFile().getStream(); ConstantPool pool = fields.getClassFile().getPool(); accessFlags = is.readShort(); name = pool.getUTF8(is.readUnsignedShort()); type = new Type(pool.getUTF8(is.readUnsignedShort())); + attributes = new Attributes(this, is); + } + + public Field(Fields fields, String name, Type type) + { + this.fields = fields; + this.name = name; + this.type = type; + attributes = new Attributes(this); } @@ -70,6 +80,11 @@ public class Field { return (accessFlags & ACC_STATIC) != 0; } + + public void setStatic() + { + accessFlags |= ACC_STATIC; + } public String getName() { @@ -95,4 +110,18 @@ public class Field { return attributes; } + + public net.runelite.deob.pool.Field getPoolField() + { + return new net.runelite.deob.pool.Field( + new net.runelite.deob.pool.Class(this.getFields().getClassFile().getName()), + new NameAndType(this.getName(), this.getType()) + ); + } + + @Override + public int hashCode() + { + return name.hashCode(); + } } \ No newline at end of file diff --git a/src/main/java/net/runelite/deob/Fields.java b/src/main/java/net/runelite/deob/Fields.java index 293bc7fa1b..d363dabfc9 100644 --- a/src/main/java/net/runelite/deob/Fields.java +++ b/src/main/java/net/runelite/deob/Fields.java @@ -14,16 +14,19 @@ public class Fields private List fields = new ArrayList<>(); - Fields(ClassFile c) throws IOException + Fields(ClassFile c, DataInputStream is) throws IOException { classFile = c; - DataInputStream is = c.getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) - fields.add(new Field(this)); + fields.add(new Field(this, is)); + } + + Fields(ClassFile c) + { + classFile = c; } public void write(DataOutputStream out) throws IOException @@ -37,6 +40,11 @@ public class Fields { return classFile; } + + public void addField(Field field) + { + fields.add(field); + } public List getFields() { @@ -50,4 +58,12 @@ public class Fields return f; return null; } + + public Field findField(String name) + { + for (Field f : fields) + if (f.getName().equals(name)) + return f; + return null; + } } diff --git a/src/main/java/net/runelite/deob/Interfaces.java b/src/main/java/net/runelite/deob/Interfaces.java index df3fbd1d66..f8a877721e 100644 --- a/src/main/java/net/runelite/deob/Interfaces.java +++ b/src/main/java/net/runelite/deob/Interfaces.java @@ -14,18 +14,21 @@ public class Interfaces private List interfaces = new ArrayList(); - Interfaces(ClassFile c) throws IOException + Interfaces(ClassFile c, DataInputStream is) throws IOException { classFile = c; - DataInputStream is = c.getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) interfaces.add(c.getPool().getClass(is.readUnsignedShort())); } + Interfaces(ClassFile c) + { + classFile = c; + } + public List getInterfaces() { return interfaces; diff --git a/src/main/java/net/runelite/deob/Method.java b/src/main/java/net/runelite/deob/Method.java index a51508935c..77a2833c83 100644 --- a/src/main/java/net/runelite/deob/Method.java +++ b/src/main/java/net/runelite/deob/Method.java @@ -27,18 +27,17 @@ public class Method public Signature arguments; private Attributes attributes; - Method(Methods methods) throws IOException + Method(Methods methods, DataInputStream is) throws IOException { this.methods = methods; - DataInputStream is = methods.getClassFile().getStream(); ConstantPool pool = methods.getClassFile().getPool(); accessFlags = is.readShort(); name = pool.getUTF8(is.readUnsignedShort()); arguments = new Signature(pool.getUTF8(is.readUnsignedShort())); attributes = new Attributes(this); - attributes.load(); + attributes.load(is); } public Method(Methods methods, String name, Signature signature) @@ -76,6 +75,11 @@ public class Method return attributes; } + public void setAttributes(Attributes a) + { + this.attributes = a; + } + public String getName() { return name; @@ -101,6 +105,11 @@ public class Method return (accessFlags & ACC_STATIC) != 0; } + public void setStatic() + { + accessFlags |= ACC_STATIC; + } + public boolean isSynchronized() { return (accessFlags & ACC_SYNCHRONIZED) != 0; @@ -136,5 +145,13 @@ public class Method } return list; - } + } + + public net.runelite.deob.pool.Method getPoolMethod() + { + return new net.runelite.deob.pool.Method( + new net.runelite.deob.pool.Class(this.getMethods().getClassFile().getName()), + new NameAndType(this.getName(), this.getDescriptor()) + ); + } } diff --git a/src/main/java/net/runelite/deob/Methods.java b/src/main/java/net/runelite/deob/Methods.java index 4bb6dceab3..dac43dc9f5 100644 --- a/src/main/java/net/runelite/deob/Methods.java +++ b/src/main/java/net/runelite/deob/Methods.java @@ -15,16 +15,19 @@ public class Methods private List methods = new ArrayList<>(); - Methods(ClassFile cf) throws IOException + Methods(ClassFile cf, DataInputStream is) throws IOException { classFile = cf; - DataInputStream is = cf.getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) - methods.add(new Method(this)); + methods.add(new Method(this, is)); + } + + Methods(ClassFile cf) + { + classFile = cf; } public void write(DataOutputStream out) throws IOException @@ -34,6 +37,11 @@ public class Methods m.write(out); } + public void addMethod(Method m) + { + methods.add(m); + } + public void removeMethod(Method m) { methods.remove(m); diff --git a/src/main/java/net/runelite/deob/attributes/Attribute.java b/src/main/java/net/runelite/deob/attributes/Attribute.java index c92378223f..46980a5fb4 100644 --- a/src/main/java/net/runelite/deob/attributes/Attribute.java +++ b/src/main/java/net/runelite/deob/attributes/Attribute.java @@ -17,14 +17,13 @@ public abstract class Attribute this.type = type; } - public final void load() throws IOException + public final void load(DataInputStream is) throws IOException { - DataInputStream is = attributes.getStream(); this.length = is.readInt(); - this.loadAttribute(); + this.loadAttribute(is); } - public abstract void loadAttribute() throws IOException; + public abstract void loadAttribute(DataInputStream is) throws IOException; public final void write(DataOutputStream out) throws IOException { diff --git a/src/main/java/net/runelite/deob/attributes/Attributes.java b/src/main/java/net/runelite/deob/attributes/Attributes.java index e91300e2e5..b76cf0d24c 100644 --- a/src/main/java/net/runelite/deob/attributes/Attributes.java +++ b/src/main/java/net/runelite/deob/attributes/Attributes.java @@ -19,18 +19,28 @@ public class Attributes private List attributes = new ArrayList<>(); - public Attributes(ClassFile cf) throws IOException + public Attributes(ClassFile cf, DataInputStream is) throws IOException { classFile = cf; - load(); + load(is); + } + + public Attributes(ClassFile cf) + { + classFile = cf; } - public Attributes(Field f) throws IOException + public Attributes(Field f, DataInputStream is) throws IOException { field = f; - load(); + load(is); + } + + public Attributes(Field f) + { + field = f; } public Attributes(Method m) @@ -73,15 +83,8 @@ public class Attributes return null; } - public DataInputStream getStream() + public void load(DataInputStream is) throws IOException { - return getClassFile().getStream(); - } - - public void load() throws IOException - { - DataInputStream is = getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) @@ -93,7 +96,7 @@ public class Attributes { Constructor con = type.getAttributeClass().getConstructor(new Class[] { Attributes.class }); Attribute attr = con.newInstance(this); - attr.load(); + attr.load(is); if (type != AttributeType.UNKNOWN) attributes.add(attr); diff --git a/src/main/java/net/runelite/deob/attributes/Code.java b/src/main/java/net/runelite/deob/attributes/Code.java index edacb393de..4ac3ccdc2e 100644 --- a/src/main/java/net/runelite/deob/attributes/Code.java +++ b/src/main/java/net/runelite/deob/attributes/Code.java @@ -23,24 +23,23 @@ public class Code extends Attribute exceptions = new Exceptions(this); this.attributes = new Attributes(this); + instructions = new Instructions(this); } @Override - public void loadAttribute() throws IOException + public void loadAttribute(DataInputStream is) throws IOException { - DataInputStream is = this.getAttributes().getStream(); - maxStack = is.readUnsignedShort(); is.skip(2); // max locals instructions = new Instructions(this); - instructions.load(); + instructions.load(is); exceptions = new Exceptions(this); - exceptions.load(); + exceptions.load(is); this.attributes = new Attributes(this); - this.attributes.load(); + this.attributes.load(is); instructions.buildBlocks(); instructions.buildJumpGraph(); diff --git a/src/main/java/net/runelite/deob/attributes/ConstantValue.java b/src/main/java/net/runelite/deob/attributes/ConstantValue.java index 56e61c077a..44f8d92af3 100644 --- a/src/main/java/net/runelite/deob/attributes/ConstantValue.java +++ b/src/main/java/net/runelite/deob/attributes/ConstantValue.java @@ -23,9 +23,8 @@ public class ConstantValue extends Attribute } @Override - public void loadAttribute() throws IOException + public void loadAttribute(DataInputStream is) throws IOException { - DataInputStream is = this.getAttributes().getStream(); value = this.getAttributes().getClassFile().getPool().getEntry(is.readUnsignedShort()); } diff --git a/src/main/java/net/runelite/deob/attributes/Exceptions.java b/src/main/java/net/runelite/deob/attributes/Exceptions.java index d3542e8f84..adfa20444d 100644 --- a/src/main/java/net/runelite/deob/attributes/Exceptions.java +++ b/src/main/java/net/runelite/deob/attributes/Exceptions.java @@ -19,10 +19,8 @@ public class Exceptions extends Attribute } @Override - public void loadAttribute() throws IOException + public void loadAttribute(DataInputStream is) throws IOException { - DataInputStream is = this.getAttributes().getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) { diff --git a/src/main/java/net/runelite/deob/attributes/Unknown.java b/src/main/java/net/runelite/deob/attributes/Unknown.java index a37270b02d..74fc97ebb3 100644 --- a/src/main/java/net/runelite/deob/attributes/Unknown.java +++ b/src/main/java/net/runelite/deob/attributes/Unknown.java @@ -14,10 +14,9 @@ public class Unknown extends Attribute } @Override - public void loadAttribute() throws IOException + public void loadAttribute(DataInputStream is) throws IOException { int len = this.getLength(); - DataInputStream is = this.getAttributes().getStream(); data = new byte[len]; diff --git a/src/main/java/net/runelite/deob/attributes/code/Exception.java b/src/main/java/net/runelite/deob/attributes/code/Exception.java index 6ad9e1b32c..d7257deb03 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Exception.java +++ b/src/main/java/net/runelite/deob/attributes/code/Exception.java @@ -15,11 +15,10 @@ public class Exception private Instruction start, end, handler; private Class catchType; - public Exception(Exceptions exceptions) throws IOException + public Exception(Exceptions exceptions, DataInputStream is) throws IOException { this.exceptions = exceptions; - DataInputStream is = exceptions.getCode().getAttributes().getStream(); ConstantPool pool = exceptions.getCode().getAttributes().getClassFile().getPool(); int startPc = is.readUnsignedShort(); diff --git a/src/main/java/net/runelite/deob/attributes/code/Exceptions.java b/src/main/java/net/runelite/deob/attributes/code/Exceptions.java index e9de6f3c31..ea2a19f0e2 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Exceptions.java +++ b/src/main/java/net/runelite/deob/attributes/code/Exceptions.java @@ -19,14 +19,12 @@ public class Exceptions this.code = code; } - public void load() throws IOException + public void load(DataInputStream is) throws IOException { - DataInputStream is = code.getAttributes().getStream(); - int count = is.readUnsignedShort(); for (int i = 0; i < count; ++i) - exceptions.add(new Exception(this)); + exceptions.add(new Exception(this, is)); } public void add(Exception e) 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 2027330f47..dbd93a8736 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Instruction.java +++ b/src/main/java/net/runelite/deob/attributes/code/Instruction.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code; +import java.io.DataInputStream; import net.runelite.deob.ClassFile; import net.runelite.deob.ConstantPool; import net.runelite.deob.Field; @@ -31,6 +32,10 @@ public abstract class Instruction this.pc = pc; } + public void load(DataInputStream is) throws IOException + { + } + protected void remove() { assert block == null; @@ -128,6 +133,9 @@ public abstract class Instruction } from.clear(); + for (Exception e : instructions.getCode().getExceptions().getExceptions()) + e.replace(this, next); + this.getInstructions().remove(this); // calls remove() return true; @@ -225,4 +233,14 @@ public abstract class Instruction public void renameMethod(Method oldMethod, net.runelite.deob.pool.Method newMethod) { } + + public Instruction makeGeneric() + { + return this; + } + + public Instruction makeSpecific() + { + return this; + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/Instructions.java b/src/main/java/net/runelite/deob/attributes/code/Instructions.java index f0803d1b1c..2125c9c1a3 100644 --- a/src/main/java/net/runelite/deob/attributes/code/Instructions.java +++ b/src/main/java/net/runelite/deob/attributes/code/Instructions.java @@ -26,10 +26,8 @@ public class Instructions this.code = code; } - public void load() throws IOException + public void load(DataInputStream is) throws IOException { - DataInputStream is = code.getAttributes().getStream(); - int length = is.readInt(); int pc; @@ -43,8 +41,15 @@ public class Instructions { Constructor con = type.getInstructionClass().getConstructor(Instructions.class, InstructionType.class, int.class); Instruction ins = con.newInstance(this, type, pc); + ins.load(is); + + Instruction genericIns = ins.makeGeneric(); + if (genericIns != ins) + { + genericIns.setPc(ins.getPc()); + } - instructions.add(ins); + instructions.add(genericIns); int len = ins.getLength(); pc += len; @@ -66,6 +71,11 @@ public class Instructions return instructions; } + public void addInstruction(Instruction i) + { + instructions.add(i); + } + public List getBlocks() { return blocks; @@ -73,6 +83,15 @@ public class Instructions public void remove(Instruction ins) { +// for (Instruction i : instructions) +// { +// if (i instanceof JumpingInstruction) +// { +// JumpingInstruction j = (JumpingInstruction) i; +// assert !j.getJumps().contains(ins); +// } +// } + ins.remove(); instructions.remove(ins); } @@ -168,6 +187,16 @@ public class Instructions public void write(DataOutputStream out) throws IOException { + // trnaslate instructions to specific + for (Instruction i : new ArrayList<>(instructions)) + { + Instruction specific = i.makeSpecific(); + if (i != specific) + { + replace(i, specific); + } + } + // generate pool indexes for (Instruction i : new ArrayList<>(instructions)) i.prime(); @@ -241,4 +270,33 @@ public class Instructions for (Instruction i : instructions) i.renameMethod(oldMethod, newMethod); } + + public void replace(Instruction oldi, Instruction newi) + { + assert oldi != newi; + + assert oldi.getInstructions() == this; + assert newi.getInstructions() == this; + + assert instructions.contains(oldi); + assert !instructions.contains(newi); + + int i = instructions.indexOf(oldi); + instructions.remove(oldi); + instructions.add(i, newi); + + for (Instruction ins : oldi.from) + { + assert ins.jump.contains(oldi); + + ins.jump.remove(oldi); + ins.jump.add(newi); + + ins.replace(oldi, newi); + } + oldi.from.clear(); + + for (net.runelite.deob.attributes.code.Exception e : code.getExceptions().getExceptions()) + e.replace(oldi, newi); + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instruction/types/DupInstruction.java b/src/main/java/net/runelite/deob/attributes/code/instruction/types/DupInstruction.java new file mode 100644 index 0000000000..b9fd1a5c83 --- /dev/null +++ b/src/main/java/net/runelite/deob/attributes/code/instruction/types/DupInstruction.java @@ -0,0 +1,10 @@ +package net.runelite.deob.attributes.code.instruction.types; + +import net.runelite.deob.execution.StackContext; + +public interface DupInstruction +{ + public StackContext getOriginal(StackContext sctx); + + public StackContext getOtherBranch(StackContext sctx); +} diff --git a/src/main/java/net/runelite/deob/attributes/code/instruction/types/PushConstantInstruction.java b/src/main/java/net/runelite/deob/attributes/code/instruction/types/PushConstantInstruction.java index 7aeda1f371..de451ab1fe 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instruction/types/PushConstantInstruction.java +++ b/src/main/java/net/runelite/deob/attributes/code/instruction/types/PushConstantInstruction.java @@ -1,10 +1,11 @@ package net.runelite.deob.attributes.code.instruction.types; +import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.pool.PoolEntry; public interface PushConstantInstruction { public PoolEntry getConstant(); - public void setConstant(PoolEntry entry); + public Instruction setConstant(PoolEntry entry); } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/ALoad.java b/src/main/java/net/runelite/deob/attributes/code/instructions/ALoad.java index 19d09f8bda..2d606f6275 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/ALoad.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/ALoad.java @@ -19,6 +19,7 @@ import java.io.IOException; public class ALoad extends Instruction implements LVTInstruction, WideInstruction { private int index; + private boolean wide; public ALoad(Instructions instructions, int index) { @@ -30,19 +31,27 @@ public class ALoad extends Instruction implements LVTInstruction, WideInstructio public ALoad(Instructions instructions, InstructionType type, int pc) throws IOException { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - length += 1; } public ALoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - length += 2; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + length += 2; + } + else + { + index = is.readByte(); + length += 1; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/ANewArray.java b/src/main/java/net/runelite/deob/attributes/code/instructions/ANewArray.java index 2258188730..0e47651364 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/ANewArray.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/ANewArray.java @@ -19,11 +19,14 @@ public class ANewArray extends Instruction { private Class clazz; - public ANewArray(Instructions instructions, InstructionType type, int pc) throws IOException + public ANewArray(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { clazz = this.getPool().getClass(is.readUnsignedShort()); length += 2; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/AStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/AStore.java index bc60499d24..b189381d3f 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/AStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/AStore.java @@ -27,11 +27,14 @@ public class AStore extends Instruction implements LVTInstruction, WideInstructi ++length; } - public AStore(Instructions instructions, InstructionType type, int pc) throws IOException + public AStore(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { index = is.readByte(); length += 1; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/BiPush.java b/src/main/java/net/runelite/deob/attributes/code/instructions/BiPush.java index cb341e2bff..6404d7a48d 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/BiPush.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/BiPush.java @@ -18,11 +18,14 @@ public class BiPush extends Instruction implements PushConstantInstruction { private byte b; - public BiPush(Instructions instructions, InstructionType type, int pc) throws IOException + public BiPush(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { b = is.readByte(); length += 1; } @@ -55,7 +58,7 @@ public class BiPush extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/CheckCast.java b/src/main/java/net/runelite/deob/attributes/code/instructions/CheckCast.java index 8c424f5ea0..33a8cc9812 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/CheckCast.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/CheckCast.java @@ -19,11 +19,14 @@ public class CheckCast extends Instruction { private Class clazz; - public CheckCast(Instructions instructions, InstructionType type, int pc) throws IOException + public CheckCast(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { clazz = this.getPool().getClass(is.readUnsignedShort()); length += 2; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_0.java index 124752f07b..8075194ae9 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_0.java @@ -40,7 +40,7 @@ public class DConst_0 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_1.java index 6404d7df51..5957255930 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/DConst_1.java @@ -40,7 +40,7 @@ public class DConst_1 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/DLoad.java b/src/main/java/net/runelite/deob/attributes/code/instructions/DLoad.java index 7968b6f7dc..ae1c069026 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/DLoad.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/DLoad.java @@ -20,6 +20,7 @@ import java.io.IOException; public class DLoad extends Instruction implements LVTInstruction, WideInstruction { private int index; + private boolean wide; public DLoad(Instructions instructions, int index) { @@ -28,22 +29,30 @@ public class DLoad extends Instruction implements LVTInstruction, WideInstructio ++length; } - public DLoad(Instructions instructions, InstructionType type, int pc) throws IOException + public DLoad(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - length += 1; } - public DLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException + public DLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - length += 2; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + length += 2; + } + else + { + index = is.readByte(); + length += 1; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/DStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/DStore.java index a42a618723..7696fbbcdc 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/DStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/DStore.java @@ -27,11 +27,14 @@ public class DStore extends Instruction implements LVTInstruction, WideInstructi ++length; } - public DStore(Instructions instructions, InstructionType type, int pc) throws IOException + public DStore(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { index = is.readByte(); length += 1; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup.java index 5c1743fae3..f24a9803c9 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup.java @@ -1,5 +1,7 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; +import java.util.List; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -7,10 +9,9 @@ import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup extends Instruction +public class Dup extends Instruction implements DupInstruction { public Dup(Instructions instructions, InstructionType type, int pc) throws IOException { @@ -55,4 +56,29 @@ public class Dup extends Instruction // an unused new/invokesepcial return false; } + + @Override + public StackContext getOriginal(StackContext sctx) + { + // ctx = stack pushed by this instruction, return stack popped by this instruction + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + assert ctx.getPushes().contains(sctx); + return ctx.getPops().get(0); + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + + List pushes = ctx.getPushes(); + assert pushes.contains(sctx); + + int idx = pushes.indexOf(sctx); + assert idx == 0 || idx == 1; + + return pushes.get(~idx & 1); + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2.java index 7a0698ed8a..348e361a30 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -8,10 +9,9 @@ import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; import net.runelite.deob.execution.Type; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup2 extends Instruction +public class Dup2 extends Instruction implements DupInstruction { public Dup2(Instructions instructions, InstructionType type, int pc) throws IOException { @@ -67,4 +67,16 @@ public class Dup2 extends Instruction { throw new UnsupportedOperationException(); } + + @Override + public StackContext getOriginal(StackContext ctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X1.java index b7dbfaacf9..0f0f13afc7 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X1.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -8,10 +9,9 @@ import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; import net.runelite.deob.execution.Type; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup2_X1 extends Instruction +public class Dup2_X1 extends Instruction implements DupInstruction { public Dup2_X1(Instructions instructions, InstructionType type, int pc) throws IOException { @@ -74,4 +74,16 @@ public class Dup2_X1 extends Instruction { throw new UnsupportedOperationException(); } + + @Override + public StackContext getOriginal(StackContext ctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X2.java index 367e86885f..e4ca17c5ef 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup2_X2.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -8,10 +9,9 @@ import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; import net.runelite.deob.execution.Type; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup2_X2 extends Instruction +public class Dup2_X2 extends Instruction implements DupInstruction { public Dup2_X2(Instructions instructions, InstructionType type, int pc) throws IOException { @@ -87,4 +87,16 @@ public class Dup2_X2 extends Instruction { throw new UnsupportedOperationException(); } + + @Override + public StackContext getOriginal(StackContext ctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X1.java index 173f138e5b..4e0ce8ded2 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X1.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -7,15 +8,19 @@ import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup_X1 extends Instruction +public class Dup_X1 extends Instruction implements DupInstruction { - public Dup_X1(Instructions instructions, InstructionType type, int pc) throws IOException + public Dup_X1(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } + + public Dup_X1(Instructions instructions) + { + super(instructions, InstructionType.DUP_X1, -1); + } @Override public void execute(Frame frame) @@ -51,4 +56,58 @@ public class Dup_X1 extends Instruction { throw new UnsupportedOperationException(); } + + @Override + public StackContext getOriginal(StackContext sctx) + { + // ctx = stack pushed by this instruction, return stack popped by this instruction + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + + assert ctx.getPushes().contains(sctx); + int pushedIndex = ctx.getPushes().indexOf(sctx); + int poppedIndex; + + // 2 1 -> 1 2 1 + // index 0 is 0, index 1 is 1, index 2 is 2 + + switch (pushedIndex) + { + case 0: + case 2: + poppedIndex = 0; + break; + case 1: + poppedIndex = 1; + break; + default: + throw new IllegalStateException(); + } + + // get popped ctx + return ctx.getPops().get(poppedIndex); + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + // sctx = stack pushed by this instruction, return the other branch + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + + assert ctx.getPushes().contains(sctx); + int pushedIndex = ctx.getPushes().indexOf(sctx); + + // 2 1 -> 1 2 1 + + // if pushed index is 0 or 2, return other, if 1 there is no other side + assert pushedIndex >= 0 && pushedIndex <= 2; + + if (pushedIndex == 0) + return ctx.getPushes().get(2); + else if (pushedIndex == 2) + return ctx.getPushes().get(0); + + return null; + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X2.java index 55412a94a2..8c300c0c74 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Dup_X2.java @@ -1,5 +1,6 @@ package net.runelite.deob.attributes.code.instructions; +import java.io.IOException; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; @@ -8,10 +9,9 @@ import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; import net.runelite.deob.execution.StackContext; import net.runelite.deob.execution.Type; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; -import java.io.IOException; - -public class Dup_X2 extends Instruction +public class Dup_X2 extends Instruction implements DupInstruction { public Dup_X2(Instructions instructions, InstructionType type, int pc) throws IOException { @@ -65,4 +65,53 @@ public class Dup_X2 extends Instruction { throw new UnsupportedOperationException(); } + + @Override + public StackContext getOriginal(StackContext sctx) + { + // 3 2 1 -> 1 3 2 1 + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + + assert ctx.getPushes().contains(sctx); + int pushedIndex = ctx.getPushes().indexOf(sctx); + int poppedIndex; + + switch (pushedIndex) + { + case 0: + case 3: + poppedIndex = 0; + break; + case 1: + poppedIndex = 2; + break; + case 2: + poppedIndex = 1; + default: + throw new IllegalStateException(); + } + + return ctx.getPops().get(poppedIndex); + } + + @Override + public StackContext getOtherBranch(StackContext sctx) + { + // sctx = stack pushed by this instruction, return the other branch + InstructionContext ctx = sctx.getPushed(); + assert ctx.getInstruction() == this; + + assert ctx.getPushes().contains(sctx); + int pushedIndex = ctx.getPushes().indexOf(sctx); + + // 3 2 1 -> 1 3 2 1 + + if (pushedIndex == 0) + return ctx.getPushes().get(3); + else if (pushedIndex == 3) + return ctx.getPushes().get(0); + + return null; + } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_0.java index afe0edde87..4ce94c86d3 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_0.java @@ -40,7 +40,7 @@ public class FConst_0 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_1.java index 6045c2a192..4f8837cd38 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_1.java @@ -40,7 +40,7 @@ public class FConst_1 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_2.java index e342d96609..ff5f51ca4e 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/FConst_2.java @@ -40,7 +40,7 @@ public class FConst_2 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/FLoad.java b/src/main/java/net/runelite/deob/attributes/code/instructions/FLoad.java index cda5057067..f6022d2464 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/FLoad.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/FLoad.java @@ -20,6 +20,7 @@ import java.io.IOException; public class FLoad extends Instruction implements LVTInstruction, WideInstruction { private int index; + private boolean wide; public FLoad(Instructions instructions, int index) { @@ -28,22 +29,30 @@ public class FLoad extends Instruction implements LVTInstruction, WideInstructio ++length; } - public FLoad(Instructions instructions, InstructionType type, int pc) throws IOException + public FLoad(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - length += 1; } - public FLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException + public FLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - length += 2; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + length += 2; + } + else + { + index = is.readByte(); + length += 1; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/FStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/FStore.java index 53f08a4966..6bbb78c365 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/FStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/FStore.java @@ -27,11 +27,14 @@ public class FStore extends Instruction implements LVTInstruction, WideInstructi ++length; } - public FStore(Instructions instructions, InstructionType type, int pc) throws IOException + public FStore(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { index = is.readByte(); length += 1; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java b/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java index 252f3aa2c4..318645a9ad 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java @@ -17,16 +17,21 @@ import net.runelite.deob.pool.NameAndType; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; +import net.runelite.deob.deobfuscators.arithmetic.Pair; public class GetField extends Instruction implements GetFieldInstruction { private Field field; - public GetField(Instructions instructions, InstructionType type, int pc) throws IOException + public GetField(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { field = this.getPool().getField(is.readUnsignedShort()); length += 2; } @@ -88,15 +93,7 @@ public class GetField extends Instruction implements GetFieldInstruction @Override public void renameField(net.runelite.deob.Field f, Field newField) { - Class clazz = field.getClassEntry(); - NameAndType nat = field.getNameAndType(); - - ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); - if (cf == null) - return; - - net.runelite.deob.Field f2 = cf.findFieldDeep(nat); - assert f2 != null; + net.runelite.deob.Field f2 = getMyField(); if (f2 == f) field = newField; diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/GetStatic.java b/src/main/java/net/runelite/deob/attributes/code/instructions/GetStatic.java index eb2227b01e..7299357251 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/GetStatic.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/GetStatic.java @@ -17,16 +17,28 @@ import net.runelite.deob.pool.NameAndType; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; +import net.runelite.deob.deobfuscators.arithmetic.Pair; public class GetStatic extends Instruction implements GetFieldInstruction { private Field field; - public GetStatic(Instructions instructions, InstructionType type, int pc) throws IOException + public GetStatic(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + public GetStatic(Instructions instructions, Field field) + { + super(instructions, InstructionType.GETSTATIC, -1); + + this.field = field; + } + + @Override + public void load(DataInputStream is) throws IOException + { field = this.getPool().getField(is.readUnsignedShort()); length += 2; } @@ -44,7 +56,7 @@ public class GetStatic extends Instruction implements GetFieldInstruction InstructionContext ins = new InstructionContext(this, frame); Stack stack = frame.getStack(); - StackContext ctx = new StackContext(ins, new Type(field.getNameAndType().getDescriptorType()).toStackType()); + StackContext ctx = new StackContext(ins, new Type(field.getNameAndType().getDescriptorType()).toStackType()); stack.push(ctx); ins.push(ctx); @@ -85,15 +97,7 @@ public class GetStatic extends Instruction implements GetFieldInstruction @Override public void renameField(net.runelite.deob.Field f, Field newField) { - Class clazz = field.getClassEntry(); - NameAndType nat = field.getNameAndType(); - - ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); - if (cf == null) - return; - - net.runelite.deob.Field f2 = cf.findFieldDeep(nat); - assert f2 != null; + net.runelite.deob.Field f2 = getMyField(); if (f2 == f) { 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 38ddc9d37d..4f7b60fd6a 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 @@ -18,13 +18,9 @@ public class Goto extends Instruction implements JumpingInstruction private Instruction to; private short offset; - public Goto(Instructions instructions, InstructionType type, int pc) throws IOException + public Goto(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - offset = is.readShort(); - length += 2; } public Goto(Instructions instructions, Instruction to) @@ -34,6 +30,13 @@ public class Goto extends Instruction implements JumpingInstruction length += 2; } + @Override + public void load(DataInputStream is) throws IOException + { + offset = is.readShort(); + length += 2; + } + @Override public void resolve() { diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/GotoW.java b/src/main/java/net/runelite/deob/attributes/code/instructions/GotoW.java index 67263ae0ca..123bed2413 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/GotoW.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/GotoW.java @@ -18,11 +18,14 @@ public class GotoW extends Instruction implements JumpingInstruction private Instruction to; private int offset; - public GotoW(Instructions instructions, InstructionType type, int pc) throws IOException + public GotoW(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { offset = is.readInt(); length += 4; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IAdd.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IAdd.java index 286ff4e5c3..053a76de47 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IAdd.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IAdd.java @@ -3,6 +3,9 @@ package net.runelite.deob.attributes.code.instructions; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.deobfuscators.arithmetic.DMath; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; @@ -14,6 +17,11 @@ public class IAdd extends Instruction { super(instructions, type, pc); } + + public IAdd(Instructions instructions) + { + super(instructions, InstructionType.IADD, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_0.java index 268701a82f..5a2e50663b 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_0.java @@ -18,6 +18,11 @@ public class IConst_0 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_0(Instructions instructions) + { + super(instructions, InstructionType.ICONST_0, 0); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_0 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_1.java index ffaa661d0d..57ee54e0ec 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_1.java @@ -18,6 +18,11 @@ public class IConst_1 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_1(Instructions instructions) + { + super(instructions, InstructionType.ICONST_1, 0); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_1 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_2.java index 29b5bea5d2..38ba4721da 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_2.java @@ -18,6 +18,11 @@ public class IConst_2 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_2(Instructions instructions) + { + super(instructions, InstructionType.ICONST_2, -1); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_2 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_3.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_3.java index fb4b1d6464..80f4e35955 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_3.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_3.java @@ -18,6 +18,11 @@ public class IConst_3 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_3(Instructions instructions) + { + super(instructions, InstructionType.ICONST_3, -1); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_3 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_4.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_4.java index f548584ac9..815c0736e4 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_4.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_4.java @@ -18,6 +18,11 @@ public class IConst_4 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_4(Instructions instructions) + { + super(instructions, InstructionType.ICONST_4, 0); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_4 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_5.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_5.java index 75d62b9fe8..416473bd8f 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_5.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_5.java @@ -18,6 +18,11 @@ public class IConst_5 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_5(Instructions instructions) + { + super(instructions, InstructionType.ICONST_5, 0); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_5 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_M1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_M1.java index 8045437289..bfbe243c6b 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_M1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IConst_M1.java @@ -18,6 +18,11 @@ public class IConst_M1 extends Instruction implements PushConstantInstruction { super(instructions, type, pc); } + + public IConst_M1(Instructions instructions) + { + super(instructions, InstructionType.ICONST_M1, 0); + } @Override public void execute(Frame frame) @@ -40,8 +45,14 @@ public class IConst_M1 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return new LDC_W(this.getInstructions(), entry); + } + + @Override + public Instruction makeGeneric() + { + return new LDC_W(this.getInstructions(), getConstant()); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IDiv.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IDiv.java index 37c001f8eb..4d39142f3f 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IDiv.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IDiv.java @@ -14,6 +14,11 @@ public class IDiv extends Instruction { super(instructions, type, pc); } + + public IDiv(Instructions instructions) + { + super(instructions, InstructionType.IDIV, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IInc.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IInc.java index 0ab042b8af..5e94c1497a 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IInc.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IInc.java @@ -19,25 +19,34 @@ public class IInc extends Instruction implements LVTInstruction, WideInstruction { private short index; private short inc; + private boolean wide; - public IInc(Instructions instructions, InstructionType type, int pc) throws IOException + public IInc(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - inc = is.readByte(); - length += 2; } - public IInc(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException + public IInc(Instructions instructions, InstructionType type, Instruction instruction, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - inc = is.readShort(); - length += 4; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + inc = is.readShort(); + length += 4; + } + else + { + index = is.readByte(); + inc = is.readByte(); + length += 2; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/ILoad.java b/src/main/java/net/runelite/deob/attributes/code/instructions/ILoad.java index 74cae101bf..88dd26a874 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/ILoad.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/ILoad.java @@ -20,30 +20,39 @@ import java.io.IOException; public class ILoad extends Instruction implements LVTInstruction, WideInstruction { private int index; + private boolean wide; public ILoad(Instructions instructions, int index) { - super(instructions, InstructionType.ILOAD, 0); + super(instructions, InstructionType.ILOAD, -1); this.index = index; ++length; } - public ILoad(Instructions instructions, InstructionType type, int pc) throws IOException + public ILoad(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - length += 1; } - public ILoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException + public ILoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - length += 2; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + length += 2; + } + else + { + index = is.readByte(); + length += 1; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IMul.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IMul.java index c1688b0c9c..73e6f27e58 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IMul.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IMul.java @@ -3,6 +3,10 @@ package net.runelite.deob.attributes.code.instructions; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.deobfuscators.arithmetic.DMath; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; +import net.runelite.deob.execution.Execution; import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; @@ -14,6 +18,11 @@ public class IMul extends Instruction { super(instructions, type, pc); } + + public IMul(Instructions instructions) + { + super(instructions, InstructionType.IMUL, 0); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore.java index df295480f0..3283bbabeb 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore.java @@ -23,29 +23,23 @@ public class IStore extends Instruction implements LVTInstruction, WideInstructi public IStore(Instructions instructions, int index) { - super(instructions, InstructionType.ISTORE, 0); + super(instructions, InstructionType.ISTORE, -1); this.index = index; ++length; } - public IStore(Instructions instructions, InstructionType type, int pc) throws IOException + public IStore(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { index = is.readByte(); length += 1; } -// public IStore(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException -// { -// super(instructions, type, pc); -// -// DataInputStream is = instructions.getCode().getAttributes().getStream(); -// index = is.readShort(); -// length += 2; -// } - @Override public void write(DataOutputStream out) throws IOException { diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_0.java index 7b006d99a8..7bb7db6de1 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_0.java @@ -16,10 +16,15 @@ import java.io.IOException; public class IStore_0 extends Instruction implements LVTInstruction { - public IStore_0(Instructions instructions, InstructionType type, int pc) throws IOException + public IStore_0(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } + + public IStore_0(Instructions instructions) + { + super(instructions, InstructionType.ISTORE_0, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_1.java index 1479303179..5ec09ec4c7 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_1.java @@ -16,10 +16,15 @@ import java.io.IOException; public class IStore_1 extends Instruction implements LVTInstruction { - public IStore_1(Instructions instructions, InstructionType type, int pc) throws IOException + public IStore_1(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } + + public IStore_1(Instructions instructions) + { + super(instructions, InstructionType.ISTORE_1, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_2.java b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_2.java index 446174772d..cb9fe29e77 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_2.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/IStore_2.java @@ -16,10 +16,15 @@ import java.io.IOException; public class IStore_2 extends Instruction implements LVTInstruction { - public IStore_2(Instructions instructions, InstructionType type, int pc) throws IOException + public IStore_2(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } + + public IStore_2(Instructions instructions) + { + super(instructions, InstructionType.ISTORE_2, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/ISub.java b/src/main/java/net/runelite/deob/attributes/code/instructions/ISub.java index 2b8519d509..c1e2b73ceb 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/ISub.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/ISub.java @@ -3,6 +3,8 @@ package net.runelite.deob.attributes.code.instructions; import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.InstructionType; import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.Stack; 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 33dea6a988..c7e31b8b75 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 @@ -21,11 +21,24 @@ public class If extends Instruction implements JumpingInstruction, ComparisonIns private Instruction to; private short offset; - public If(Instructions instructions, InstructionType type, int pc) throws IOException + public If(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + public If(Instructions instructions, Instruction to) + { + super(instructions, InstructionType.IF_ICMPNE, -1); + + assert this != to; + assert to.getInstructions() == this.getInstructions(); + + this.to = to; + } + + @Override + public void load(DataInputStream is) throws IOException + { offset = is.readShort(); length += 2; } 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 a0d1a538e7..76ff52e671 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 @@ -21,11 +21,24 @@ public class If0 extends Instruction implements JumpingInstruction, ComparisonIn private Instruction to; private short offset; - public If0(Instructions instructions, InstructionType type, int pc) throws IOException + public If0(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + public If0(Instructions instructions, Instruction to) + { + super(instructions, InstructionType.IFEQ, -1); + + assert this != to; + assert to.getInstructions() == this.getInstructions(); + + this.to = to; + } + + @Override + public void load(DataInputStream is) throws IOException + { offset = is.readShort(); length += 2; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/InstanceOf.java b/src/main/java/net/runelite/deob/attributes/code/instructions/InstanceOf.java index c73ec2c0e1..76fdbd900e 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/InstanceOf.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/InstanceOf.java @@ -18,11 +18,14 @@ public class InstanceOf extends Instruction { private Class clazz; - public InstanceOf(Instructions instructions, InstructionType type, int pc) throws IOException + public InstanceOf(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { clazz = this.getPool().getClass(is.readUnsignedShort()); length += 2; } 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 316a96b001..e926446534 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 @@ -30,11 +30,14 @@ public class InvokeInterface extends Instruction implements InvokeInstruction private InterfaceMethod method; private int count; - public InvokeInterface(Instructions instructions, InstructionType type, int pc) throws IOException + public InvokeInterface(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { method = this.getPool().getInterfaceMethod(is.readUnsignedShort()); count = is.readUnsignedByte(); is.skip(1); 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 4620440f14..8df3eceeb4 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 @@ -28,11 +28,14 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction { private Method method; - public InvokeSpecial(Instructions instructions, InstructionType type, int pc) throws IOException + public InvokeSpecial(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { method = this.getPool().getMethod(is.readUnsignedShort()); length += 2; } 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 6c3b057f73..d3bc166584 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 @@ -28,11 +28,21 @@ public class InvokeStatic extends Instruction implements InvokeInstruction { private Method method; - public InvokeStatic(Instructions instructions, InstructionType type, int pc) throws IOException + public InvokeStatic(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + public InvokeStatic(Instructions instructions, Method method) + { + super(instructions, InstructionType.INVOKESTATIC, -1); + + this.method = method; + } + + @Override + public void load(DataInputStream is) throws IOException + { method = this.getPool().getMethod(is.readUnsignedShort()); length += 2; } 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 8a33320d8e..c374548e57 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 @@ -28,11 +28,14 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction { private Method method; - public InvokeVirtual(Instructions instructions, InstructionType type, int pc) throws IOException + public InvokeVirtual(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { method = this.getPool().getMethod(is.readUnsignedShort()); length += 2; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_0.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_0.java index 7d55b1b7a1..2838b7690c 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_0.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_0.java @@ -40,7 +40,7 @@ public class LConst_0 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_1.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_1.java index 978d77f736..96823a9350 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_1.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LConst_1.java @@ -40,7 +40,7 @@ public class LConst_1 extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LDC2_W.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LDC2_W.java index 2a6425eba9..f770a6a6c5 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LDC2_W.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LDC2_W.java @@ -18,11 +18,14 @@ public class LDC2_W extends Instruction implements PushConstantInstruction { private PoolEntry value; - public LDC2_W(Instructions instructions, InstructionType type, int pc) throws IOException + public LDC2_W(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { value = this.getPool().getEntry(is.readUnsignedShort()); length += 2; } @@ -55,8 +58,9 @@ public class LDC2_W extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { value = entry; + return this; } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LDC_W.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LDC_W.java index a80c87e2c7..8064b069f5 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LDC_W.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LDC_W.java @@ -18,11 +18,31 @@ public class LDC_W extends Instruction implements PushConstantInstruction { private PoolEntry value; - public LDC_W(Instructions instructions, InstructionType type, int pc) throws IOException + public LDC_W(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + + assert type == InstructionType.LDC_W || type == InstructionType.LDC; + } + + public LDC_W(Instructions instructions, PoolEntry value) + { + super(instructions, InstructionType.LDC_W, 0); + + this.value = value; + length += 2; + } + + public LDC_W(Instructions instructions, int value) + { + this(instructions, new net.runelite.deob.pool.Integer(value)); + } + + @Override + public void load(DataInputStream is) throws IOException + { + InstructionType type = this.getType(); + assert type == InstructionType.LDC_W || type == InstructionType.LDC; if (type == InstructionType.LDC_W) @@ -37,14 +57,6 @@ public class LDC_W extends Instruction implements PushConstantInstruction } } - public LDC_W(Instructions instructions, PoolEntry value) - { - super(instructions, InstructionType.LDC_W, 0); - - this.value = value; - length += 2; - } - @Override public void prime() { @@ -105,8 +117,45 @@ public class LDC_W extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { value = entry; + return this; + } + + @Override + public Instruction makeSpecific() + { + switch (value.getType()) + { + case INTEGER: + { + int i = (int) value.getObject(); + switch (i) + { + case -1: + return new IConst_M1(this.getInstructions()); + case 0: + return new IConst_0(this.getInstructions()); + case 1: + return new IConst_1(this.getInstructions()); + case 2: + return new IConst_2(this.getInstructions()); + case 3: + return new IConst_3(this.getInstructions()); + case 4: + return new IConst_4(this.getInstructions()); + case 5: + return new IConst_5(this.getInstructions()); + } + } + } + + return super.makeSpecific(); + } + + public int getConstantAsInt() + { + return (int) value.getObject(); } } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LLoad.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LLoad.java index 85965b2b49..2fc0129555 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LLoad.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LLoad.java @@ -20,6 +20,7 @@ import java.io.IOException; public class LLoad extends Instruction implements LVTInstruction, WideInstruction { private int index; + private boolean wide; public LLoad(Instructions instructions, int index) { @@ -28,22 +29,30 @@ public class LLoad extends Instruction implements LVTInstruction, WideInstructio ++length; } - public LLoad(Instructions instructions, InstructionType type, int pc) throws IOException + public LLoad(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readByte(); - length += 1; } - public LLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) throws IOException + public LLoad(Instructions instructions, InstructionType type, Instruction instruction, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - index = is.readShort(); - length += 2; + wide = true; + } + + @Override + public void load(DataInputStream is) throws IOException + { + if (wide) + { + index = is.readShort(); + length += 2; + } + else + { + index = is.readByte(); + length += 1; + } } @Override diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LStore.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LStore.java index 7f519055e2..7a04bf927c 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LStore.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LStore.java @@ -28,11 +28,14 @@ public class LStore extends Instruction implements LVTInstruction, WideInstructi ++length; } - public LStore(Instructions instructions, InstructionType type, int pc) throws IOException + public LStore(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { index = is.readByte(); length += 1; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/LookupSwitch.java b/src/main/java/net/runelite/deob/attributes/code/instructions/LookupSwitch.java index c1923d7d67..cf499f1086 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/LookupSwitch.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/LookupSwitch.java @@ -26,12 +26,15 @@ public class LookupSwitch extends Instruction implements JumpingInstruction private int[] match; private int[] branch; - public LookupSwitch(Instructions instructions, InstructionType type, int pc) throws IOException + public LookupSwitch(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - + } + + @Override + public void load(DataInputStream is) throws IOException + { + int pc = this.getPc(); int tableSkip = 4 - (pc + 1) % 4; if (tableSkip == 4) tableSkip = 0; if (tableSkip > 0) is.skip(tableSkip); diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/MultiANewArray.java b/src/main/java/net/runelite/deob/attributes/code/instructions/MultiANewArray.java index 37f3a9a773..a29de34494 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/MultiANewArray.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/MultiANewArray.java @@ -23,8 +23,11 @@ public class MultiANewArray extends Instruction public MultiANewArray(Instructions instructions, InstructionType type, int pc) throws IOException { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { clazz = this.getPool().getClass(is.readUnsignedShort()); dimensions = is.readUnsignedByte(); length += 3; diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/NOP.java b/src/main/java/net/runelite/deob/attributes/code/instructions/NOP.java index 9acc5b6211..4ec6d0c69a 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/NOP.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/NOP.java @@ -10,7 +10,7 @@ import java.io.IOException; public class NOP extends Instruction { - public NOP(Instructions instructions, InstructionType type, int pc) throws IOException + public NOP(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/New.java b/src/main/java/net/runelite/deob/attributes/code/instructions/New.java index b972ab959f..a3af1181eb 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/New.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/New.java @@ -19,11 +19,14 @@ public class New extends Instruction { private Class clazz; - public New(Instructions instructions, InstructionType type, int pc) throws IOException + public New(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { clazz = this.getPool().getClass(is.readUnsignedShort()); length += 2; } 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 153d07822b..90270616f0 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 @@ -17,11 +17,14 @@ public class NewArray extends Instruction { private int type; - public NewArray(Instructions instructions, InstructionType type, int pc) throws IOException + public NewArray(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { this.type = is.readUnsignedByte(); length += 1; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Pop.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Pop.java index 03ede0dc36..44420a5bcf 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Pop.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Pop.java @@ -7,14 +7,18 @@ import net.runelite.deob.execution.Frame; import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.StackContext; -import java.io.IOException; public class Pop extends Instruction { - public Pop(Instructions instructions, InstructionType type, int pc) throws IOException + public Pop(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); } + + public Pop(Instructions instructions) + { + super(instructions, InstructionType.POP, -1); + } @Override public void execute(Frame frame) 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 fb89440883..1b4664e3d5 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 @@ -16,6 +16,8 @@ import net.runelite.deob.pool.NameAndType; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; +import net.runelite.deob.deobfuscators.arithmetic.Pair; public class PutField extends Instruction implements SetFieldInstruction { @@ -24,8 +26,11 @@ public class PutField extends Instruction implements SetFieldInstruction public PutField(Instructions instructions, InstructionType type, int pc) throws IOException { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { field = this.getPool().getField(is.readUnsignedShort()); length += 2; } 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 b49c30e1f4..ce1d31b2f7 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 @@ -24,8 +24,11 @@ public class PutStatic extends Instruction implements SetFieldInstruction public PutStatic(Instructions instructions, InstructionType type, int pc) throws IOException { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { field = this.getPool().getField(is.readUnsignedShort()); length += 2; } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/SiPush.java b/src/main/java/net/runelite/deob/attributes/code/instructions/SiPush.java index daa4055694..0cad63a64c 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/SiPush.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/SiPush.java @@ -18,11 +18,14 @@ public class SiPush extends Instruction implements PushConstantInstruction { private short s; - public SiPush(Instructions instructions, InstructionType type, int pc) throws IOException + public SiPush(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); + } + + @Override + public void load(DataInputStream is) throws IOException + { s = is.readShort(); length += 2; } @@ -55,7 +58,7 @@ public class SiPush extends Instruction implements PushConstantInstruction } @Override - public void setConstant(PoolEntry entry) + public Instruction setConstant(PoolEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/TableSwitch.java b/src/main/java/net/runelite/deob/attributes/code/instructions/TableSwitch.java index 2e097b6cb8..cc88def589 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/TableSwitch.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/TableSwitch.java @@ -25,12 +25,15 @@ public class TableSwitch extends Instruction implements JumpingInstruction private int high; private int[] jumps; - public TableSwitch(Instructions instructions, InstructionType type, int pc) throws IOException + public TableSwitch(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - + } + + @Override + public void load(DataInputStream is) throws IOException + { + int pc = this.getPc(); int tableSkip = 4 - (pc + 1) % 4; if (tableSkip == 4) tableSkip = 0; if (tableSkip > 0) is.skip(tableSkip); diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java b/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java index 0e16aee782..952f3504e1 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/VReturn.java @@ -14,6 +14,11 @@ public class VReturn extends Instruction implements ReturnInstruction { super(instructions, type, pc); } + + public VReturn(Instructions instructions) + { + super(instructions, InstructionType.RETURN, -1); + } @Override public void execute(Frame frame) diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Wide.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Wide.java index c9f42abcce..4e83058175 100644 --- a/src/main/java/net/runelite/deob/attributes/code/instructions/Wide.java +++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Wide.java @@ -17,19 +17,22 @@ public class Wide extends Instruction implements LVTInstruction { private Instruction ins; - public Wide(Instructions instructions, InstructionType type, int pc) throws IOException + public Wide(Instructions instructions, InstructionType type, int pc) { super(instructions, type, pc); - - DataInputStream is = instructions.getCode().getAttributes().getStream(); - + } + + @Override + public void load(DataInputStream is) throws IOException + { byte opcode = is.readByte(); // this byte is already in the length of the new instruction (length is initialized to 1) InstructionType op = InstructionType.findInstructionFromCode(opcode); try { Constructor con = op.getInstructionClass().getConstructor(Instructions.class, InstructionType.class, Instruction.class, int.class); - ins = con.newInstance(instructions, op, this, pc); + ins = con.newInstance(this.getInstructions(), op, this, this.getPc()); + ins.load(is); length += ins.getLength(); } catch (Exception ex) diff --git a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java b/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java index bafd0add4b..75ddd98117 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java +++ b/src/main/java/net/runelite/deob/deobfuscators/FieldMover.java @@ -307,7 +307,8 @@ public class FieldMover implements Deobfuscator { assert s.getPushed() == ctx; - getContexts(list, s.getPopped()); + for (InstructionContext i : s.getPopped()) + getContexts(list, i); } } diff --git a/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java b/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java index cdff714ad5..b021725e40 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java +++ b/src/main/java/net/runelite/deob/deobfuscators/IllegalStateExceptions.java @@ -39,6 +39,7 @@ public class IllegalStateExceptions implements Deobfuscator Instructions instructions = c.getInstructions(); instructions.clearBlockGraph(); + instructions.buildJumpGraph(); List ilist = instructions.getInstructions(); for (int i = 0; i < ilist.size(); ++i) @@ -109,7 +110,11 @@ public class IllegalStateExceptions implements Deobfuscator instructions.remove(ins); // insert goto - ilist.add(i, new Goto(instructions, to)); + assert ilist.contains(to); + Goto g = new Goto(instructions, to); + g.jump.add(to); + to.from.add(g); + ilist.add(i, g); ++count; break; @@ -121,17 +126,20 @@ public class IllegalStateExceptions implements Deobfuscator @Override public void run(ClassGroup group) - { + { + group.buildClassGraph(); Execution execution = new Execution(group); execution.populateInitialMethods(); execution.run(); - + int count = 0; int passes = 0; int i; do { i = checkOnce(execution, group); + + System.out.println("ise removal pass " + passes + " removed " + i); count += i; ++passes; diff --git a/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java b/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java index 37e946ce68..ec965f7f36 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java +++ b/src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java @@ -203,7 +203,7 @@ public class MethodInliner implements Deobfuscator fromI.jump.remove(invokeIns); fromI.replace(invokeIns, firstParamStore); - + fromI.jump.add(firstParamStore); firstParamStore.from.add(fromI); } @@ -225,8 +225,14 @@ public class MethodInliner implements Deobfuscator // instead of return, jump to next instruction after the invoke Instruction oldI = i; i = new Goto(methodInstructions, nextInstruction); + assert methodInstructions.getInstructions().contains(nextInstruction); - i.jump.addAll(oldI.jump); + assert oldI != nextInstruction; + i.jump.add(nextInstruction); + nextInstruction.from.add(i); + + assert oldI.jump.isEmpty(); + //i.jump.addAll(oldI.jump); i.from.addAll(oldI.from); for (Instruction i2 : oldI.from) @@ -249,7 +255,8 @@ public class MethodInliner implements Deobfuscator if (oldI != i) { - i.jump.addAll(oldI.jump); + assert oldI.jump.isEmpty(); + //i.jump.addAll(oldI.jump); i.from.addAll(oldI.from); for (Instruction i2 : oldI.from) diff --git a/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java b/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java deleted file mode 100644 index f644ae9f7e..0000000000 --- a/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java +++ /dev/null @@ -1,821 +0,0 @@ -package net.runelite.deob.deobfuscators; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import net.runelite.deob.ClassFile; -import net.runelite.deob.ClassGroup; -import net.runelite.deob.Deobfuscator; -import net.runelite.deob.Field; -import net.runelite.deob.attributes.code.Instruction; -import net.runelite.deob.attributes.code.instruction.types.FieldInstruction; -import net.runelite.deob.attributes.code.instruction.types.GetFieldInstruction; -import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; -import net.runelite.deob.attributes.code.instruction.types.SetFieldInstruction; -import net.runelite.deob.attributes.code.instructions.IMul; -import net.runelite.deob.execution.Execution; -import net.runelite.deob.execution.Frame; -import net.runelite.deob.execution.InstructionContext; -import net.runelite.deob.execution.StackContext; - -public class ModularArithmeticDeobfuscation implements Deobfuscator -{ - private Set obfuscatedFields; // reliability of these sucks - - static class Magic - { - Field field; - int getter, setter; - boolean unknownGetter, unknownSetter; - } - - static class Magics - { - Map magic = new HashMap<>(); - - Magic getMagic(Field field) - { - Magic m = magic.get(field); - if (m != null) - return m; - - m = new Magic(); - m.field = field; - magic.put(field, m); - return m; - } - - void pass1() - { - int good = 0, bad = 0, calculated = 0, mismatch = 0; - for (Magic m : new ArrayList<>(magic.values())) - if (m.getter == 0 && m.setter == 0) - { - magic.remove(m.field); - ++bad; - } - else if (m.getter == 0) - { - m.unknownGetter = false; - m.getter = modInverse(m.setter); - ++calculated; - } - else if (m.setter == 0) - { - m.unknownSetter = false; - m.setter = modInverse(m.getter); - ++calculated; - } - else if (m.getter != modInverse(m.setter) || m.setter != modInverse(m.getter)) - { - magic.remove(m.field); - ++mismatch; - } - else - { - ++good; - } - - System.out.println("Pass 1: Bad: " + bad + ", good: " + good + ", calculated " + calculated + ", mismatch: " + mismatch); - } - - void pass2() - { - int found = 0; - for (Magic m : new ArrayList<>(magic.values())) - { - if (!m.unknownGetter && !m.unknownSetter && (m.setter != 0 || m.getter != 0)) - { - ++found; - } - } - System.out.println("Pass 2: Calculated " + found); - } - - void merge(Magics other) - { - int merged = 0; - for (Magic m : other.magic.values()) - { - Field f = m.field; - - if (!this.magic.containsKey(f)) - { - this.magic.put(f, m); - ++merged; - continue; - } - - System.err.println("field exists in both pass 1 and 2"); - } - System.out.println("Merged " + merged); - } - } - - private Field convertFieldFromPool(ClassGroup group, net.runelite.deob.pool.Field field) - { - ClassFile cf = group.findClass(field.getClassEntry().getName()); - if (cf == null) - return null; - return cf.findFieldDeep(field.getNameAndType()); - } - - private List checkDown(InstructionContext context) - { - List fields = new ArrayList<>(); - - if (context.getInstruction() instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) context.getInstruction(); - fields.add(fi.getField()); - } - - for (StackContext ctx : context.getPops()) - { - InstructionContext i = ctx.getPushed(); - - fields.addAll(checkDown(i)); - } - - return fields; - } - - private List checkUp(InstructionContext context) - { - List fields = new ArrayList<>(); - - if (context.getInstruction() instanceof InvokeInstruction) - { - // field = func(field * constant), the output of the function isn't directly related to the result of field * constant - return fields; - } - - if (context.getInstruction() instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) context.getInstruction(); - fields.add(fi.getField()); - } - - for (StackContext ctx : context.getPushes()) - { - InstructionContext i = ctx.getPopped(); - - if (i == null) - continue; - - fields.addAll(checkUp(i)); - } - - return fields; - } - - /* check there are no other fields */ - private boolean checkFields(Magics goodMagics, ClassGroup group, Set obFields, net.runelite.deob.pool.Field imulField, InstructionContext context) - { - List fields = new ArrayList<>(); - fields.addAll(checkUp(context)); - fields.addAll(checkDown(context)); - - assert !fields.isEmpty(); - - for (net.runelite.deob.pool.Field f : fields) - { - if (f.equals(imulField)) - continue; - - Field field = convertFieldFromPool(group, f); - assert field != null; - - if (!obFields.contains(field)) - continue; - - return false; - } - - return true; - } - - private List getDown(InstructionContext context) - { - List instructions = new ArrayList<>(); - - instructions.add(context); - - for (StackContext ctx : context.getPops()) - { - InstructionContext i = ctx.getPushed(); - - instructions.addAll(getDown(i)); - } - - return instructions; - } - - private List getInstructions(InstructionContext context) - { - List instructions = new ArrayList<>(); - - instructions.add(context); - - instructions.addAll(getDown(context)); - - return instructions; - } - - private Set getObfuscatedFields(Execution execution, ClassGroup group) - { - Set fields = new HashSet<>(); - - // XXX this detects field = field * constant as ob when field isn't - - for (Frame frame : execution.processedFrames) - { - for (InstructionContext ctx : frame.getInstructions()) - { - if (ctx.getInstruction() instanceof IMul) - { - Instruction one = ctx.getPops().get(0).getPushed().getInstruction(); - Instruction two = ctx.getPops().get(1).getPushed().getInstruction(); - - PushConstantInstruction pc = null; - GetFieldInstruction gf = null; - if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) one; - gf = (GetFieldInstruction) two; - } - else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) two; - gf = (GetFieldInstruction) one; - } - - if (pc == null) - continue; - - // get Field from pool Field - net.runelite.deob.pool.Field field = gf.getField(); - Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType()); - - assert f != null; - - fields.add(f); - } - else if (ctx.getInstruction() instanceof SetFieldInstruction) - { - SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction(); - - StackContext value = ctx.getPops().get(0); // what setfield pops as value - if (!(value.getPushed().getInstruction() instanceof IMul)) - continue; - - Instruction one = value.getPushed().getPops().get(0).getPushed().getInstruction(); - Instruction two = value.getPushed().getPops().get(1).getPushed().getInstruction(); - - PushConstantInstruction pc = null; - Instruction other = null; - if (one instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) one; - other = two; - } - else if (two instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) two; - other = one; - } - - if (pc == null) - continue; - - // get Field from pool Field - net.runelite.deob.pool.Field field = sf.getField(); - Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType()); - - assert f != null; - - fields.add(f); - } - } - } - - return fields; - } - - private void detectSetters(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx) - { - if (!(ctx.getInstruction() instanceof SetFieldInstruction)) - return; - - SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction(); - - StackContext value = ctx.getPops().get(0); // what setfield pops as value - if (!(value.getPushed().getInstruction() instanceof IMul)) - return; - - Instruction one = value.getPushed().getPops().get(0).getPushed().getInstruction(); - Instruction two = value.getPushed().getPops().get(1).getPushed().getInstruction(); - - PushConstantInstruction pc = null; - Instruction other = null; - if (one instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) one; - other = two; - } - else if (two instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) two; - other = one; - } - - if (pc == null) - return; - - if (!checkFields(goodMagics, group, obfuscatedFields, sf.getField(), value.getPushed())) - return; - - //System.out.println("Setter " + sf.getField().getClassEntry().getName() + "." + sf.getField().getNameAndType().getName() + " -> " + pc.getConstant().toString()); - - int constant = Integer.parseInt(pc.getConstant().toString()); - try - { - modInverse(constant); - } - catch (ArithmeticException ex) - { - //System.err.println("Constant " + constant + " passed setter logic tests but is not inversable"); - //printWhatCalls(execution, frame.getMethod(), 0); - return; // if the constant isn't inversable then it can't be the right one - } - - Field field = convertFieldFromPool(group, sf.getField()); - Magic magic = workMagics.getMagic(field); - - if (!magic.unknownSetter) - { - if (magic.setter == 0) - magic.setter = constant; - else if (magic.setter != constant) - { - magic.setter = 0; - magic.unknownSetter = true; - } - } - } - - private void detectGetters(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx) - { - if (!(ctx.getInstruction() instanceof IMul)) - return; - - // check for push constant and for get field instruction - Instruction one = ctx.getPops().get(0).getPushed().getInstruction(); - Instruction two = ctx.getPops().get(1).getPushed().getInstruction(); - - PushConstantInstruction pc = null; - GetFieldInstruction gf = null; - if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) one; - gf = (GetFieldInstruction) two; - } - else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) two; - gf = (GetFieldInstruction) one; - } - - if (pc == null) - return; - - int constant = Integer.parseInt(pc.getConstant().toString()); - - StackContext push = ctx.getPushes().get(0); // result of imul operation - InstructionContext popCtx = push.getPopped(); // instruction which popped the result of mul - - if (popCtx == null) - { - return; - //System.err.println("Stack ctx never popped! Pushed by " + push.getPushed().getInstruction()); - //int i = frame.getInstructions().indexOf(push.getPushed().getInstruction()); - //System.err.println("next ins is " + frame.getInstructions().get(i + 1).getInstruction()); - } - - if (!checkFields(goodMagics, group, obfuscatedFields, gf.getField(), ctx)) - return; - - try - { - modInverse(constant); - } - catch (ArithmeticException ex) - { - //System.err.println("Constant " + constant + " passed getter logic tests but is not inversable"); - //printWhatCalls(execution, frame.getMethod(), 0); - return; // if the constant isn't inversable then it can't be the right one - } - - // get Field from pool Field - net.runelite.deob.pool.Field field = gf.getField(); - Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType()); - - Magic magic = workMagics.getMagic(f); - - if (!magic.unknownGetter) - { - if (magic.getter == 0) - magic.getter = constant; - else if (magic.getter != constant) - { - magic.getter = 0; - magic.unknownGetter = true; - } - } - } - - private void detectCombined(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx) - { - // look for put involving one other field, assume constant is combined field getter/setter - - if (!(ctx.getInstruction() instanceof SetFieldInstruction)) - return; - - SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction(); - Field thisField = convertFieldFromPool(group, sf.getField()); - - List ins = getInstructions(ctx); - - Field other = null; - int constant = 0; - for (InstructionContext i : ins) - if (i.getInstruction() instanceof FieldInstruction) - { - FieldInstruction fin = (FieldInstruction) i.getInstruction(); - if (fin.getField().equals(sf.getField())) - continue; - - if (other != null) - return; - - other = convertFieldFromPool(group, fin.getField()); - } - else if (i.getInstruction() instanceof PushConstantInstruction) - { - PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction(); - try - { - constant = Integer.parseInt(pci.getConstant().toString()); - } - catch (NumberFormatException ex) - { - return; - } - } - - if (other == null || constant == 0) - return; - - if (goodMagics.magic.containsKey(thisField) && goodMagics.magic.containsKey(other)) - return; - - if (!thisField.getType().toString().equals("I") || !other.getType().toString().equals("I")) - return; - - // thisField = operations with field/constant - - //if (obfuscatedFields.contains(thisField) && obfuscatedFields.contains(other)) - { - // constant is thisField setter * otherField getter - - Magic thisMagic = goodMagics.magic.get(thisField); - Magic otherMagic = goodMagics.magic.get(other); - - if (thisMagic == null && otherMagic == null) - { - System.err.println("Combined fields with no known good magic"); - return; - } - - //if (thisMagic != null && otherMagic != null) - //{ - // return; // check? - //} - - if (thisMagic == null) - { - //System.out.println("Combined 1"); - - // this = other * constant - // constant = other getter * this setter - // solve for this setter - // this setter = constant * modInverse(other.getter) - - int thisSetter = constant * modInverse(otherMagic.getter); - - if (thisSetter == 1) - { - System.out.println(thisField.getFields().getClassFile().getName() + "." + thisField.getName() + " is not obd"); - // this means that this field isn't obbed - obfuscatedFields.remove(thisField); - otherMagic.setter = constant; - return; - } - - System.out.println("Calculated setter for " + thisField.getFields().getClassFile().getName() + "." + thisField.getName() + " to be " + thisSetter); - - Magic m = workMagics.getMagic(thisField); - - if (!m.unknownSetter) - if (m.setter != 0 && m.setter != thisSetter) - { - System.err.println("Calculated setter mismatch"); - m.unknownSetter = true; - m.setter = 0; - } - - m.setter = thisSetter; - } - else if (otherMagic == null) - { - //System.out.println("Combined 2"); - - // this = other * constant - // constant = other getter * this setter - // solve for other getter - // other getter = constant * modInverse(this setter) - - int otherGetter = constant * modInverse(thisMagic.setter); - - if (otherGetter == 1) - { - System.out.println(other.getFields().getClassFile().getName() + "." + other.getName() + " is not obd"); - obfuscatedFields.remove(other); - thisMagic.getter = constant; - return; - } - - System.out.println("Calculated getter for " + other.getFields().getClassFile().getName() + "." + other.getName() + " to be " + otherGetter); - - Magic m = workMagics.getMagic(other); - - if (!m.unknownGetter) - if (m.getter != 0 && m.getter != otherGetter) - { - System.err.println("Calculated getter mismatch"); - m.unknownGetter = true; - m.getter = 0; - } - - m.getter = otherGetter; - } - } - /* - else if (obfuscatedFields.contains(thisField)) - { - // constant is this fields setter - System.out.println("Only one field is obd 1 " + thisField.getFields().getClassFile().getName() + "." + thisField.getName() - + ", " + other.getFields().getClassFile().getName() + "." + other.getName()); - } - else if (obfuscatedFields.contains(other)) - { - // constant is other fields getter - System.out.println("Only one field is obd 2"); - } - else - { - System.err.println("detected combined field with both fields non obfuscated. " + thisField.getFields().getClassFile().getName() + "." + thisField.getName() - + ", " + other.getFields().getClassFile().getName() + "." + other.getName()); - //return; - }*/ - } - - private void check(Magics magics) - { - int missing = 0, mismatch = 0, good = 0, half = 0; - for (Field f : obfuscatedFields) - { - Magic magic = magics.magic.get(f); - - if (magic == null) - { - System.err.println(f.getFields().getClassFile().getName() + "." + f.getName() + " is obfuscated, but no magic found"); - ++missing; - continue; - } - - if (magic.getter != 0 && magic.setter != 0) - { - if (magic.getter != modInverse(magic.setter) || magic.setter != modInverse(magic.getter)) - { - ++mismatch; - System.err.println(f.getFields().getClassFile().getName() + "." + f.getName() + " has mismatch, get " + magic.getter + ", set " + magic.setter + ", modInverse(get) " + modInverse(magic.getter) + ", modInverse(set) " + modInverse(magic.setter)); - } - else - { - ++good; - //System.out.println(f.getFields().getClassFile().getName() + "." + f.getName() + " has get " + magic.getter + ", set " + magic.setter); - } - } - else - { - ++half; - System.out.println(f.getFields().getClassFile().getName() + "." + f.getName() + " 2 has get " + magic.getter + ", set " + magic.setter); - } - } - System.out.println("Check done missing: "+ missing + ", mismatch: " + mismatch + ", good: " + good + ", half: " + half); - } - - private void run(Magics magics /* known good */, Magics work, Execution execution, ClassGroup group) - { - obfuscatedFields = getObfuscatedFields(execution, group); - - for (Frame frame : execution.processedFrames) - { - for (InstructionContext ctx : frame.getInstructions()) - { - if (magics == null) - { - detectGetters(magics, work, execution, group, ctx); - detectSetters(magics, work, execution, group, ctx); - } - else - if (magics != null) - detectCombined(magics, work, execution, group, ctx); - } - } - - //if (magics == null) - //check(work); - } - - private static BigInteger modInverse(BigInteger val, int bits) - { - BigInteger shift = BigInteger.ONE.shiftLeft(bits); - return val.modInverse(shift); - } - - private static int modInverse(int val) - { - return modInverse(BigInteger.valueOf(val), 32).intValue(); - } - - private static long modInverse(long val) - { - return modInverse(BigInteger.valueOf(val), 64).longValue(); - } - - @Override - public void run(ClassGroup group) - { - group.buildClassGraph(); - - Execution execution = new Execution(group); - execution.populateInitialMethods(); - execution.run(); - - Magics work = new Magics(); - run(null, work, execution, group); - work.pass1(); -// check(work); - System.out.println("END OF PASS 1"); - - Magics magics = work; - work = new Magics(); - run(magics, work, execution, group); - work.pass2(); - - magics.merge(work); - - check(magics); - - replace(execution, group, magics); - } - - private void replace(Execution execution, ClassGroup group, Magics magics) - { - Set done = new HashSet<>(); - int replaced = 0; - for (Frame frame : execution.processedFrames) - { - for (InstructionContext ctx : frame.getInstructions()) - { - if (ctx.getInstruction() instanceof IMul) - { - Instruction one = ctx.getPops().get(0).getPushed().getInstruction(); - Instruction two = ctx.getPops().get(1).getPushed().getInstruction(); - - PushConstantInstruction pc = null; - GetFieldInstruction gf = null; - if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) one; - gf = (GetFieldInstruction) two; - } - else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) - { - pc = (PushConstantInstruction) two; - gf = (GetFieldInstruction) one; - } - - if (pc == null) - continue; - - Magic m = magics.magic.get(this.convertFieldFromPool(group, gf.getField())); - if (m == null) - { - System.out.println("No magc for field " + gf.getField()); - continue; - } - - if (done.contains(ctx.getInstruction())) - continue; - done.add(ctx.getInstruction()); - - int constant = Integer.parseInt(pc.getConstant().toString()); - - // we have field * constant - - // eg constant is 42 * getter do * modInverse(getter) to get result - - //assert m.setter == modInverse(m.getter); - int newConstant = constant * m.setter; - - pc.setConstant(new net.runelite.deob.pool.Integer(newConstant)); - if (newConstant != 1) - System.out.println("new constant: " + newConstant); - else - ++replaced; - } - else if (ctx.getInstruction() instanceof SetFieldInstruction) - { - SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction(); - StackContext value = ctx.getPops().get(0); // what setfield pops as value - - if (value.getPushed().getInstruction() instanceof PushConstantInstruction) - { - // field = constant - PushConstantInstruction pi = (PushConstantInstruction) value.getPushed().getInstruction(); - - Magic m = magics.magic.get(this.convertFieldFromPool(group, sf.getField())); - if (m == null) - continue; - - int constant = Integer.parseInt(pi.getConstant().toString()); - - if (done.contains(ctx.getInstruction())) - continue; - done.add(ctx.getInstruction()); - - // field = setter * value, solve for value by * modInverse(setter) - int newConstant = constant * m.getter; - pi.setConstant(new net.runelite.deob.pool.Integer(newConstant)); - ++replaced; - } - else if (value.getPushed().getInstruction() instanceof IMul) - { - InstructionContext imul = value.getPushed(); - - StackContext one = imul.getPops().get(0), two = imul.getPops().get(1); - - PushConstantInstruction pc; - if (one.getPushed().getInstruction() instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) one.getPushed().getInstruction(); - } - else if (two.getPushed().getInstruction() instanceof PushConstantInstruction) - { - pc = (PushConstantInstruction) two.getPushed().getInstruction(); - } - else - { - continue; - } - - int constant = Integer.parseInt(pc.getConstant().toString()); - - Magic m = magics.magic.get(this.convertFieldFromPool(group, sf.getField())); - if (m == null) - continue; - - if (done.contains(ctx.getInstruction())) - continue; - done.add(ctx.getInstruction()); - - // field = expression * constant - int newConstant = constant * m.getter; - pc.setConstant(new net.runelite.deob.pool.Integer(newConstant)); - ++replaced; - } - } - } - } - System.out.println("Replaced " + replaced + " constants"); - } -} diff --git a/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java b/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java index 7a603a2653..e7eb79b840 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java +++ b/src/main/java/net/runelite/deob/deobfuscators/UnreachedCode.java @@ -22,7 +22,6 @@ public class UnreachedCode implements Deobfuscator List insCopy = new ArrayList<>(ins.getInstructions()); for (int j = 0; j < insCopy.size(); ++j) - //for (Instruction i : new ArrayList<>(ins.getInstructions())) { Instruction i = insCopy.get(j); diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/DMath.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/DMath.java new file mode 100644 index 0000000000..3fe017b9c2 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/DMath.java @@ -0,0 +1,43 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.math.BigInteger; + +public class DMath +{ + public static BigInteger modInverse(BigInteger val, int bits) + { + BigInteger shift = BigInteger.ONE.shiftLeft(bits); + return val.modInverse(shift); + } + + public static int modInverse(int val) + { + return modInverse(BigInteger.valueOf(val), 32).intValue(); + } + + public static long modInverse(long val) + { + return modInverse(BigInteger.valueOf(val), 64).longValue(); + } + + public static boolean isInversable(int val) + { + try + { + modInverse(val); + return true; + } + catch (ArithmeticException ex) + { + return false; + } + } + + public static boolean isBig(int val) + { + if ((val & 0x80000000) != 0) + val = ~val + 1; + + return (val & 0x7FF00000) != 0; + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Encryption.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Encryption.java new file mode 100644 index 0000000000..e626e94835 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Encryption.java @@ -0,0 +1,20 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.HashMap; +import java.util.Map; +import net.runelite.deob.Field; + +public class Encryption +{ + private final Map fields = new HashMap<>(); + + public void addPair(Pair pair) + { + fields.put(pair.field, pair); + } + + public Pair getField(Field field) + { + return fields.get(field); + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java new file mode 100644 index 0000000000..7be0b2f06a --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java @@ -0,0 +1,542 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.runelite.deob.ClassFile; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.Deobfuscator; +import net.runelite.deob.Field; +import net.runelite.deob.Method; +import net.runelite.deob.attributes.Code; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.FieldInstruction; +import net.runelite.deob.attributes.code.instruction.types.GetFieldInstruction; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.attributes.code.instruction.types.SetFieldInstruction; +import net.runelite.deob.attributes.code.instructions.IMul; +import net.runelite.deob.attributes.code.instructions.LDC_W; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.execution.StackContext; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.map.MultiValueMap; + +public class ModArith implements Deobfuscator +{ + private ClassGroup group; + private Execution execution; + private MultiValueMap constantGetters = new MultiValueMap<>(), + constantSetters = new MultiValueMap<>(); + private List pairs = new ArrayList<>(); + private Set deobfuscatedFields = new HashSet<>(); + + private List getInsInExpr(InstructionContext ctx, Set set) + { + List l = new ArrayList<>(); + + if (ctx == null || set.contains(ctx.getInstruction())) + return l; + + set.add(ctx.getInstruction()); + + l.add(ctx); + + for (StackContext s : ctx.getPops()) + l.addAll(getInsInExpr(s.getPushed(), set)); + for (StackContext s : ctx.getPushes()) + for (InstructionContext i : s.getPopped()) + l.addAll(getInsInExpr(i, set)); + + return l; + } + + private boolean isFieldObfuscated(Execution e, Field field) + { + // field isn't obfuscated if there are no usages with big constants and no other fields + + for (Frame f : execution.processedFrames) + outer: + for (InstructionContext ctx : f.getInstructions()) + { + if (!(ctx.getInstruction() instanceof FieldInstruction)) + continue; + + FieldInstruction fi = (FieldInstruction) ctx.getInstruction(); + + if (fi.getMyField() != field) + continue; + + List ins = getInsInExpr(ctx, new HashSet()); + + // continue if expr contains another ins + for (InstructionContext i : ins) + { + if (i.getInstruction() instanceof FieldInstruction) + { + FieldInstruction ifi = (FieldInstruction) i.getInstruction(); + + if (ifi.getMyField() != field) + continue outer; + } + } + + // find big constant + for (InstructionContext i : ins) + { + if (i.getInstruction() instanceof LDC_W) + { + LDC_W ldc = (LDC_W) i.getInstruction(); + if (ldc.getConstant().getObject() instanceof Integer) + { + int value = ldc.getConstantAsInt(); + + if (DMath.isBig(value)) + return true; + } + } + } + } + + return false; + } + + private List findAssocConstants(Field field, InstructionContext ctx) throws OtherFieldException + { + // starts with ctx = setfield + + List list = new ArrayList<>(); + + if (ctx.getInstruction() instanceof LDC_W) + { + LDC_W pci = (LDC_W) ctx.getInstruction(); + if (pci.getConstant().getObject() instanceof Integer) + list.add((int) pci.getConstant().getObject()); + } + + if (ctx.getInstruction() instanceof FieldInstruction) + { + FieldInstruction fi = (FieldInstruction) ctx.getInstruction(); + + // if the field is already deobbed, constants here don't include it + if (fi.getMyField() != field && !deobfuscatedFields.contains(fi.getMyField())) + throw new OtherFieldException(); + } + + for (StackContext sctx : ctx.getPops()) + { + list.addAll(findAssocConstants(field, sctx.getPushed())); + } + + return list; + } + + private void findUses() + { + for (Frame f : execution.processedFrames) + for (InstructionContext ctx : f.getInstructions()) + { + if (ctx.getInstruction() instanceof IMul) + { + Instruction one = ctx.getPops().get(0).getPushed().getInstruction(); + Instruction two = ctx.getPops().get(1).getPushed().getInstruction(); + + PushConstantInstruction pc = null; + GetFieldInstruction gf = null; + if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) + { + pc = (PushConstantInstruction) one; + gf = (GetFieldInstruction) two; + } + else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) + { + pc = (PushConstantInstruction) two; + gf = (GetFieldInstruction) one; + } + + if (pc == null) + continue; + + Field field = gf.getMyField(); + if (field == null) + continue; + + int value = (int) pc.getConstant().getObject(); + + if (value == 1 || value == 0) + continue; + + constantGetters.put(field, value); + } + else if (ctx.getInstruction() instanceof SetFieldInstruction) + { + SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction(); + + Field field = sf.getMyField(); + if (field == null) + continue; + +// List constants = null; +// try +// { +// constants = findAssocConstants(field, ctx); +// for (int i : constants) +// if (i != 1 && i != 0) +// constantSetters.put(field, i); +// } +// catch (OtherFieldException ex) { } + + StackContext value = ctx.getPops().get(0); // the first thing popped from both putfield and putstatic is the value + if (!(value.getPushed().getInstruction() instanceof IMul)) + continue; + + Instruction one = value.getPushed().getPops().get(0).getPushed().getInstruction(); + Instruction two = value.getPushed().getPops().get(1).getPushed().getInstruction(); + + PushConstantInstruction pc = null; + Instruction other = null; + if (one instanceof PushConstantInstruction) + { + pc = (PushConstantInstruction) one; + other = two; + } + else if (two instanceof PushConstantInstruction) + { + pc = (PushConstantInstruction) two; + other = one; + } + + if (pc == null) + continue; + + int value2 = (int) pc.getConstant().getObject(); + + if (value2 == 1 || value2 == 0) + continue; + + if (field.getName().equals("field2201")) + { + int k=7; + } + + constantSetters.put(field, value2); + } + } + } + + private Pair reduce(Collection getters, Collection setters) + { + Pair p = null; + + for (Integer i : getters) + { + Integer inverse; + try + { + inverse = DMath.modInverse(i); + } + catch (ArithmeticException ex) + { + continue; + } + + if (setters.contains(inverse)) + { + if (p != null && p.getter != i) + return null; + + if (p == null) + { + p = new Pair(); + p.getter = i; + p.setter = inverse; + } + } + } + + for (Integer i : setters) + { + Integer inverse; + try + { + inverse = DMath.modInverse(i); + } + catch (ArithmeticException ex) + { + continue; + } + + if (getters.contains(inverse)) + { + if (p != null && p.setter != i) + return null; + + if (p == null) + { + p = new Pair(); + p.setter = i; + p.getter = inverse; + } + } + } + + return p; + } + + private Pair guess(Field field, Collection values, boolean getter) + { + Map map = CollectionUtils.getCardinalityMap(values); // value -> how many times it occurs + int max = Collections.max(map.values()); // largest occurance # + int size = values.size(); + + try + { + if (max == size) + { + // all getters are the same value + int constant = values.iterator().next(); + if (DMath.isBig(constant)) + { + Pair pair = new Pair(); + if (getter) + { + pair.getter = constant; + //System.out.println("Guessing " + field.getName() + " getter " + constant + " setter "); + pair.setter = DMath.modInverse(constant); + } + else + { + pair.setter = constant; + pair.getter = DMath.modInverse(constant); + } + return pair; + } + } + } + catch (ArithmeticException ex) { } + +// if (size < 50) +// return null; + + if (((float) max / (float) size) < 0.9) + return null; + + for (final Map.Entry entry : map.entrySet()) { + if (max == entry.getValue()) { + int constant = entry.getKey(); + int inverse; + try + { + inverse = DMath.modInverse(constant); + } + catch (ArithmeticException ex) + { + break; + } + + Pair pair = new Pair(); + if (getter) + { + pair.getter = constant; + pair.setter = inverse; + } + else + { + pair.getter = inverse; + pair.setter = constant; + } + + return pair; + } + } + + return null; + } + + private void reduce() + { + for (ClassFile cf : group.getClasses()) + for (Field f : cf.getFields().getFields()) + { + Collection getters = constantGetters.getCollection(f), + setters = constantSetters.getCollection(f); + + if (f.getName().equals("field2976")) + { + int k=5; + } + + + Pair answer = null; + + if (getters != null && setters != null) + answer = reduce(getters, setters); + + if (answer == null && getters != null) + answer = guess(f, getters, true); + + if (answer == null && setters != null) + answer = guess(f, setters, false); + + if (answer == null) + continue; + + if (!this.isFieldObfuscated(execution, f)) + { + System.out.println("Skipping field " + f.getName() + " which isnt obfuscated"); + continue; + } + + answer.field = f; + pairs.add(answer); + } + } + + @Override + public void run(ClassGroup group) + { + this.group = group; + //return runOnce(); +// if (true) return; +// +// int passes = 0, total = 0, i; +// while ((i = runOnce()) > 0) +// { +// ++passes; +// total += i; +// } +// System.out.println("Finished arith deob on " + total + " fields in " + passes + " passes"); + } +// +// private void translateSetFields(Execution e) +// { +// //Set visited = new HashSet<>(); +// for (Frame f : e.processedFrames) +// for (InstructionContext ins : f.getInstructions()) +// if (ins.getInstruction() instanceof SetFieldInstruction) +// { +// SetFieldInstruction sfi = (SetFieldInstruction) ins.getInstruction(); +// Pair pair = e.getEncryption().getField(sfi.getMyField()); +// +// if (pair != null) +// PutStatic.translate(e.getEncryption(), pair, ins, new HashSet()); +// // +// } +// } + + private void insertGetterSetterMuls(Encryption encr) + { + // after getfield insert imul * setter + // before setfield insert inul * getter + for (ClassFile cf : group.getClasses()) + for (Method m : cf.getMethods().getMethods()) + { + Code code = m.getCode(); + if (code == null) + continue; + + Instructions ins = code.getInstructions(); + List ilist = ins.getInstructions(); + + for (int i = 0; i < ilist.size(); ++i) + { + Instruction in = ilist.get(i); + + if (in instanceof SetFieldInstruction) + { + SetFieldInstruction sfi = (SetFieldInstruction) in; + Field f = sfi.getMyField(); + + if (f == null) + continue; + + Pair p = encr.getField(f); + if (p == null) + continue; + + // insert push getter + // insert imul + + ilist.add(i++, new LDC_W(ins, new net.runelite.deob.pool.Integer(p.getter))); + ilist.add(i++, new IMul(ins)); + } + else if (in instanceof GetFieldInstruction) + { + GetFieldInstruction sfi = (GetFieldInstruction) in; + Field f = sfi.getMyField(); + + if (f == null) + continue; + + Pair p = encr.getField(f); + if (p == null) + continue; + + // add after: push setter + // imul + ilist.add(++i, new LDC_W(ins, new net.runelite.deob.pool.Integer(p.setter))); + ilist.add(++i, new IMul(ins)); + } + } + } + } + + public int runOnce() + { + group.buildClassGraph(); + + pairs.clear(); + constantGetters.clear();; + constantSetters.clear(); + + execution = new Execution(group); + execution.populateInitialMethods(); + execution.run(); + + findUses(); + reduce(); + +// Encryption encr = new Encryption(); +// for (Pair pair : pairs) +// encr.addPair(pair); +// +// insertGetterSetterMuls(encr); + + int i = 0; + for (Pair pair : pairs) + { + Field field = pair.field; + + //field933 = -193434591 * field743; + // var143.field3014 = (var143.field2960 = 1 * var92.field2960) * 1496783801; + //if (!field.getName().equals("field3014") && !field.getName().equals("field2960")) + if (!field.getName().equals("field2201")) + { + int j =5; + // continue; + } + + System.out.println("Processing " + field.getName() + " getter " + pair.getter + " setter " + pair.setter); + + Encryption encr = new Encryption(); + encr.addPair(pair); + + insertGetterSetterMuls(encr); + + System.out.println("Changed " + ++i); + //assert !deobfuscatedFields.contains(field); + deobfuscatedFields.add(field); + } + + System.out.println(pairs); + + return i; + } + +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java new file mode 100644 index 0000000000..b162082d7b --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java @@ -0,0 +1,416 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.Deobfuscator; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.DupInstruction; +import net.runelite.deob.attributes.code.instruction.types.GetFieldInstruction; +import net.runelite.deob.attributes.code.instruction.types.LVTInstruction; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.attributes.code.instructions.BiPush; +import net.runelite.deob.attributes.code.instructions.IAdd; +import net.runelite.deob.attributes.code.instructions.IConst_M1; +import net.runelite.deob.attributes.code.instructions.IMul; +import net.runelite.deob.attributes.code.instructions.ISub; +import net.runelite.deob.attributes.code.instructions.LDC_W; +import net.runelite.deob.attributes.code.instructions.SiPush; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.execution.StackContext; +import net.runelite.deob.execution.VariableContext; +import net.runelite.deob.execution.Variables; + +public class MultiplicationDeobfuscator implements Deobfuscator +{ + private ClassGroup group; + + @Override + public void run(ClassGroup group) + { + this.group = group; + + int i; + int count = 0; + while ((i = runOnce()) > 0) + { + System.out.println("Replaced " + i + " constants"); + count += i; + } + System.out.println("Total changed " + count); + } + + private MultiplicationExpression parseExpression(Execution e, InstructionContext ctx) + { + MultiplicationExpression me = new MultiplicationExpression(); + + assert !(ctx.getInstruction() instanceof DupInstruction); + + if (ctx.getInstruction() instanceof LVTInstruction) + { + LVTInstruction lvt = (LVTInstruction) ctx.getInstruction(); + + // loading a variable + if (!lvt.store()) + { + int idx = lvt.getVariableIndex(); // var index + Variables vars = ctx.getVariables(); // variables at time of execution + + VariableContext vctx = vars.get(idx); // get the variable + + if (vctx.getRead().size() == 1) // ? + { + InstructionContext storeCtx = vctx.getInstructionWhichStored(); // this is an istore + if (storeCtx.getInstruction() instanceof LVTInstruction) + { + // invoking funcs can put stuff in lvt + + LVTInstruction storelvt = (LVTInstruction) storeCtx.getInstruction(); + + assert storelvt.store(); + + InstructionContext pushed = storeCtx.getPops().get(0).getPushed(); + return parseExpression(e, pushed); + } + } + } + } + + if (ctx.getInstruction() instanceof PushConstantInstruction) + { + if (ctx.getInstruction() instanceof BiPush || ctx.getInstruction() instanceof SiPush + || ctx.getInstruction() instanceof IConst_M1) + { + throw new IllegalStateException(); + } + + me.instructions.add(ctx); + return me; + } + + for (StackContext sctx : ctx.getPops()) + { + if (ctx.getInstruction() instanceof IMul) + { + if (!isOnlyPath(e, ctx, sctx)) + continue; + } + + InstructionContext i = sctx.getPushed(); + + // if this instruction is imul, look at pops + if (ctx.getInstruction() instanceof IMul) + { + if (i.getInstruction() instanceof PushConstantInstruction) + { + if (i.getInstruction() instanceof BiPush || i.getInstruction() instanceof SiPush) + throw new IllegalStateException(); + + // a constant of imul + me.instructions.add(i); + } + else if (i.getInstruction() instanceof IMul) + { + // chained imul, append to me + try + { + MultiplicationExpression other = parseExpression(e, i); + + me.instructions.addAll(other.instructions); + me.subexpressions.addAll(other.subexpressions); + } + catch (IllegalStateException ex) + { + // this is ok? just don't include it? + } + } + else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub) + { + // imul using result of iadd or isub. evaluate expression + try + { + MultiplicationExpression other = parseExpression(e, i); + + // subexpr + //if (other != null) + me.subexpressions.add(other); + } + catch (IllegalStateException ex) + { + assert me.subexpressions.isEmpty(); + // subexpression is too complex. we can still simplify the top level though + } + } + else if (i.getInstruction() instanceof DupInstruction) + { + //if(true) throw new IllegalStateException(); + DupInstruction dup = (DupInstruction) i.getInstruction(); + + //if (dup instanceof Dup || dup instanceof Dup_X1) + { + + // find other branch of the dup instruction + // sctx = what dup pushed, find other + StackContext otherCtx = dup.getOtherBranch(sctx); // other side of dup + //InstructionContext otherCtxI = otherCtx.getPopped(); // would insert imul here? + InstructionContext otherCtxI = otherCtx.getPopped().get(0); // is this irght? + + if (otherCtxI.getInstruction() instanceof IMul) + { + //assert otherCtxI.getInstruction() instanceof IMul; + + InstructionContext pushConstant = otherCtxI.getPops().get(0).getPushed(); + assert pushConstant.getInstruction() instanceof LDC_W; + + me.dupmagic = pushConstant; + + StackContext orig = dup.getOriginal(sctx); // original + try + { + MultiplicationExpression other = parseExpression(e, orig.getPushed()); + // this expression is used elsewhere like 'pushConstant' so any changes + // done to it affect that, too. so multiply it by existing values? + if (orig.getPushed().getInstruction() instanceof IAdd || orig.getPushed().getInstruction() instanceof ISub) + { + me.subexpressions.add(other); + } + else + { + me.instructions.addAll(other.instructions); + me.dupedInstructions.addAll(other.instructions); + me.subexpressions.addAll(other.subexpressions); + } + } + catch (IllegalStateException ex) + { + assert me.subexpressions.isEmpty(); + } + } + else + { + System.out.println("dup ins " + otherCtxI.getInstruction()); + //throw new IllegalStateException(); + } + } + } + else if (i.getInstruction() instanceof GetFieldInstruction) + { + // non constant, ignore + } + else + { + //throw new IllegalStateException(); + //System.out.println("imul pops something I don't know " + i.getInstruction()); + } + } + // this is an iadd/sub + else if (ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub) + { + MultiplicationExpression other = parseExpression(e, i); // parse this side of the add/sub + + //if (other != null) + me.subexpressions.add(other); + } + else + { + //throw new IllegalStateException(); + //System.out.println(ctx.getInstruction() + " pops something I dont know " + i.getInstruction()); + } +// else if (i.getInstruction() instanceof PushConstantInstruction) +// { +// me.instructions.add(i); +// //PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction(); +// //int value = (int) pci.getConstant().getObject(); +// //if (value != 1) // already been touched, otherwise we keep multiplying the same ins over and over +// // l.add(i); +// } +// else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub) +// { +// MultiplicationExpression other = parseExpression(i); +// +// me.subexpressions.add(other); +// } + } + + if (me.instructions.isEmpty() && me.subexpressions.isEmpty()) + throw new IllegalStateException(); + //return null; + + return me; + } + + // for each instruction ctx in ths expression, see if it !equals any other for each ins? +// +// private List getInsInExpr(InstructionContext ctx, Set set) +// { +// List l = new ArrayList<>(); +// +// if (ctx == null || set.contains(ctx.getInstruction())) +// return l; +// +// set.add(ctx.getInstruction()); +// +// l.add(ctx); +// for (StackContext s : ctx.getPops()) +// l.addAll(getInsInExpr(s.getPushed(), set)); +// for (StackContext s : ctx.getPushes()) +// l.addAll(getInsInExpr(s.getPopped(), set)); +// +// return l; +// } + + public static boolean isOnlyPath(Execution execution, InstructionContext ctx) + { + assert ctx.getInstruction() instanceof IMul; + Collection ins = execution.getInstructonContexts(ctx.getInstruction()); + for (InstructionContext i : ins) + { + if (!i.equals(ctx)) + { + return false; + } + + for (StackContext sctx : i.getPushes()) + if (sctx.getPopped().size() > 1) + return false; + } + return true; + } + + private static boolean ictxEqualsDir(InstructionContext one, InstructionContext two, StackContext sctx) + { + if (one.getInstruction() != two.getInstruction()) + return false; + + assert one.getPops().contains(sctx); + int i = one.getPops().indexOf(sctx); + + StackContext theirsctx = two.getPops().get(i); +// // check if stack at time of execution is equal +// List ours = one.getStack().getStack(), theirs = two.getStack().getStack(); +// //Stack ours = new Stack(one.getStack()), // copy stacks since we destroy them +//// theirs = new Stack(two.getStack()); +// +// if (ours.size() != theirs.size()) // is this possible? +// return false; +// +// assert ours.contains(sctx); +// int i = ours.indexOf(sctx); +// +// StackContext theirsctx = theirs.get(i); +// + if (sctx.getPushed().getInstruction() != theirsctx.getPushed().getInstruction()) + return false; + + return true; + } + + public static boolean isOnlyPath(Execution execution, InstructionContext ctx, StackContext sctx) + { + // + assert ctx.getInstruction() instanceof IMul; + Collection ins = execution.getInstructonContexts(ctx.getInstruction()); + for (InstructionContext i : ins) + { + if (!ictxEqualsDir(ctx, i, sctx)) +/// if (!i.equals(ctx)) + { + return false; + } + + for (StackContext s : i.getPushes()) + if (s.getPopped().size() > 1) + return false; + } + return true; + } + + private Set done = new HashSet<>(); + + private int runOnce() + { + group.buildClassGraph(); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + + int count = 0; + int mcount = 0; + + for (Frame frame : e.processedFrames) + //outer: + for (InstructionContext ictx : frame.getInstructions()) + { + Instruction instruction = ictx.getInstruction(); + Instructions instructions = instruction.getInstructions(); + + String cname = frame.getMethod().getMethods().getClassFile().getName(); + + if (!(instruction instanceof IMul)) + continue; + +// if (cname.equals("client")) +// { +// // 7500 works ok +// // 8250 doesnt work +// //if (mcount++ > 8250) +// ++mcount; +// if (!(mcount >= 7500 && mcount <= 8250)) +// continue; +// } +// else +// { +// continue; +// } +//field721 = (-1 != var5 && 1 != var5 ? +// (class139.field2363 * 1381104939 + 981643079 * field721 * 1807370871) / 2 : +// 1381104939 * class139.field2363) +// * 1807370871 * 981643079; +// +//field721 = (-1 != var5 && 1 != var5 ? +// (class139.field2363 * 1381104939 + 981643079 * field721 * 1807370871) / 2 : +// 1 * class139.field2363) +// * 1 * 1381104939; + + + MultiplicationExpression expression; + try + { + expression = parseExpression(e, ictx); + } + catch (IllegalStateException ex) + { + continue; + } + + if (expression == null) + continue; + + //if (expression.subexpressions.isEmpty()) + // continue; + + // there can only be one path to here, or else combinging would change code logic +// List ilist = this.getInsInExpr(ictx, new HashSet()); +// for (InstructionContext i2 : ilist) +// if (i2.getInstruction() instanceof IMul) +// if (!isOnlyPath(e, i2)) +// continue outer; + + + if (done.contains(instruction)) + continue; + done.add(instruction); + + count += expression.simplify(1); + } + + return count; + } + +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationExpression.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationExpression.java new file mode 100644 index 0000000000..0cab866840 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationExpression.java @@ -0,0 +1,84 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.ArrayList; +import java.util.List; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.execution.InstructionContext; + +public class MultiplicationExpression +{ + List instructions = new ArrayList<>(), // push constant instructions that are being multiplied + dupedInstructions = new ArrayList<>(); + List subexpressions = new ArrayList<>(); // for distributing, each subexpr is * by this + InstructionContext dupmagic; // inverse of what is distributed to subexpressions gets set here + + int simplify(int start) + { + int count = 0; + int result = start; + + // calculate result + for (InstructionContext i : instructions) + { + PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction(); + int value = (int) pci.getConstant().getObject(); + + result *= value; + } + + // assert (dupmagic != null) == !dupedInstructions.isEmpty(); + if (dupmagic != null) + { + // mul dupmagic by result of dup ins? + + PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction(); + int value = (int) pci.getConstant().getObject(); + + for (InstructionContext ic : dupedInstructions) + { + PushConstantInstruction pci2 = (PushConstantInstruction) ic.getInstruction(); + int value2 = (int) pci2.getConstant().getObject(); + + value *= value2; + } + + Instruction newIns = pci.setConstant(new net.runelite.deob.pool.Integer(value)); + System.out.println("dupmagic"); + assert newIns == (Instruction) pci; + } + + // multiply subexpressions by result + if (!subexpressions.isEmpty()) + { + for (MultiplicationExpression me : subexpressions) + { + count += me.simplify(result); + } + + if (dupmagic != null) + { + PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction(); + int value = (int) pci.getConstant().getObject(); + + value *= DMath.modInverse(result); + + pci.setConstant(new net.runelite.deob.pool.Integer(value)); + } + + result = 1; // constant has been distributed, outer numbers all go to 1 + } + + // set result on ins + for (InstructionContext i : instructions) + { + PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction(); + Instruction newIns = pci.setConstant(new net.runelite.deob.pool.Integer(result)); + ++count; + assert newIns == pci; + result = 1; // rest of the results go to 1 + } + + return count; + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyOneDeobfuscator.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyOneDeobfuscator.java new file mode 100644 index 0000000000..f4bd559d39 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyOneDeobfuscator.java @@ -0,0 +1,71 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.List; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.Deobfuscator; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.attributes.code.instructions.IMul; +import net.runelite.deob.attributes.code.instructions.NOP; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.execution.StackContext; + +public class MultiplyOneDeobfuscator implements Deobfuscator +{ + @Override + public void run(ClassGroup group) + { + group.buildClassGraph(); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + int count = 0; + + for (Frame frame : e.processedFrames) + for (InstructionContext ictx : frame.getInstructions()) + { + Instruction instruction = ictx.getInstruction(); + + if (!(instruction instanceof IMul)) + continue; + + Instructions ins = ictx.getInstruction().getInstructions(); + List ilist = ins.getInstructions(); + + if (!ilist.contains(ictx.getInstruction())) + continue; // already done + + StackContext one = ictx.getPops().get(0); + StackContext two = ictx.getPops().get(1); + + int removeIdx = -1; + if (one.getPushed().getInstruction() instanceof PushConstantInstruction + && (int) ((PushConstantInstruction) one.getPushed().getInstruction()).getConstant().getObject() == 1) + { + removeIdx = 0; + } + else if (two.getPushed().getInstruction() instanceof PushConstantInstruction + && (int) ((PushConstantInstruction) two.getPushed().getInstruction()).getConstant().getObject() == 1) + { + removeIdx = 1; + } + + if (removeIdx == -1) + continue; + + ictx.removeStack(removeIdx); + ins.replace(ictx.getInstruction(), new NOP(ins)); + //ins.remove(ictx.getInstruction()); + + ++count; + } + + System.out.println("Removed " + count + " 1 multiplications"); + } + +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyZeroDeobfuscator.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyZeroDeobfuscator.java new file mode 100644 index 0000000000..916640c935 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplyZeroDeobfuscator.java @@ -0,0 +1,84 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.List; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.Deobfuscator; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.deob.attributes.code.instructions.IMul; +import net.runelite.deob.attributes.code.instructions.LDC_W; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.Frame; +import net.runelite.deob.execution.InstructionContext; +import net.runelite.deob.execution.StackContext; + +public class MultiplyZeroDeobfuscator implements Deobfuscator +{ + @Override + public void run(ClassGroup group) + { + group.buildClassGraph(); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + int count = 0; + + for (Frame frame : e.processedFrames) + for (InstructionContext ictx : frame.getInstructions()) + { + Instruction instruction = ictx.getInstruction(); + Instructions ins = instruction.getInstructions(); + + if (!(instruction instanceof IMul)) + continue; + + List ilist = ins.getInstructions(); + + StackContext one = ictx.getPops().get(0); + StackContext two = ictx.getPops().get(1); + + Instruction ione = one.getPushed().getInstruction(), + itwo = two.getPushed().getInstruction(); + + boolean remove = false; + if (ione instanceof PushConstantInstruction) + { + PushConstantInstruction pci = (PushConstantInstruction) ione; + int value = (int) pci.getConstant().getObject(); + + if (value == 0) + remove = true; + } + if (itwo instanceof PushConstantInstruction) + { + PushConstantInstruction pci = (PushConstantInstruction) itwo; + int value = (int) pci.getConstant().getObject(); + + if (value == 0) + remove = true; + } + + if (remove == false) + { + continue; + } + + if (!ilist.contains(instruction)) + continue; // already done + + // remove both, remove imul, push 0 + + ictx.removeStack(1); + ictx.removeStack(0); + + ins.replace(instruction, new LDC_W(ins, new net.runelite.deob.pool.Integer(0))); + + ++count; + } + + System.out.println("Removed " + count + " 0 multiplications"); + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/OtherFieldException.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/OtherFieldException.java new file mode 100644 index 0000000000..5591eb3d8c --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/OtherFieldException.java @@ -0,0 +1,6 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +class OtherFieldException extends Exception +{ + +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Pair.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Pair.java new file mode 100644 index 0000000000..f68d9eea8d --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/Pair.java @@ -0,0 +1,9 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import net.runelite.deob.Field; + +public class Pair +{ + public Field field; + public int getter, setter; +} diff --git a/src/main/java/net/runelite/deob/execution/Execution.java b/src/main/java/net/runelite/deob/execution/Execution.java index d216e6c9f6..c920535e83 100644 --- a/src/main/java/net/runelite/deob/execution/Execution.java +++ b/src/main/java/net/runelite/deob/execution/Execution.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import net.runelite.deob.deobfuscators.arithmetic.Encryption; import org.apache.commons.collections4.map.MultiValueMap; public class Execution @@ -21,11 +22,23 @@ public class Execution public Set methods = new HashSet<>(); // all methods public Set executed = new HashSet<>(); // executed instructions private MultiValueMap invokes = new MultiValueMap<>(); + private Encryption encryption; + public MultiValueMap contexts = new MultiValueMap<>(); public Execution(ClassGroup group) { this.group = group; } + + public Encryption getEncryption() + { + return encryption; + } + + public void setEncryption(Encryption encryption) + { + this.encryption = encryption; + } public void populateInitialMethods() { @@ -90,4 +103,9 @@ public class Execution System.out.println("Processed " + fcount + " frames"); } + + public Collection getInstructonContexts(Instruction i) + { + return contexts.getCollection(i); + } } diff --git a/src/main/java/net/runelite/deob/execution/Frame.java b/src/main/java/net/runelite/deob/execution/Frame.java index 9761555f08..5fa1af7cfc 100644 --- a/src/main/java/net/runelite/deob/execution/Frame.java +++ b/src/main/java/net/runelite/deob/execution/Frame.java @@ -30,6 +30,8 @@ public class Frame private Variables variables; private List instructions = new ArrayList<>(); // instructions executed in this frame private MultiValueMap visited = new MultiValueMap<>(); // shared + + public static long num; public Frame(Execution execution, Method method) { @@ -174,6 +176,10 @@ public class Frame throw ex; } + InstructionContext ictx = this.instructions.get(this.instructions.size() - 1); + assert ictx.getInstruction() == oldCur; + execution.contexts.put(oldCur, ictx); + execution.executed.add(oldCur); processExceptions(oldCur); diff --git a/src/main/java/net/runelite/deob/execution/InstructionContext.java b/src/main/java/net/runelite/deob/execution/InstructionContext.java index 903cdbd837..10c62f6c9d 100644 --- a/src/main/java/net/runelite/deob/execution/InstructionContext.java +++ b/src/main/java/net/runelite/deob/execution/InstructionContext.java @@ -12,6 +12,7 @@ public class InstructionContext private Instruction ins; private Frame frame; private Stack stack; // stack at time ins was executed + private Variables variables; // variables at time ins was executed private List pops = new ArrayList<>(); // stack contexts popped by instruction execution private List pushes = new ArrayList<>(); // stack contexts pushed by instruction execution private List reads = new ArrayList<>(); // lvt reads @@ -22,13 +23,14 @@ public class InstructionContext ins = i; frame = f; stack = new Stack(frame.getStack()); + variables = new Variables(frame.getVariables()); } public void pop(StackContext... ctx) { for (StackContext c : ctx) { - c.setPopped(this); // now we know which instruction popped this, record it + c.addPopped(this); // now we know which instruction popped this, record it pops.add(c); } } @@ -42,7 +44,10 @@ public class InstructionContext public void read(VariableContext... ctx) { for (VariableContext c : ctx) + { + c.addRead(this); reads.add(c); + } } public void invoke(Method method) @@ -60,6 +65,11 @@ public class InstructionContext return stack; } + public Variables getVariables() + { + return variables; + } + public List getPops() { return pops; diff --git a/src/main/java/net/runelite/deob/execution/Stack.java b/src/main/java/net/runelite/deob/execution/Stack.java index 0cde672b51..7db393816e 100644 --- a/src/main/java/net/runelite/deob/execution/Stack.java +++ b/src/main/java/net/runelite/deob/execution/Stack.java @@ -1,6 +1,7 @@ package net.runelite.deob.execution; import java.util.Arrays; +import java.util.List; public class Stack { @@ -9,10 +10,10 @@ public class Stack public Stack(int sz) { - stack = new StackContext[sz]; + stack = new StackContext[sz*2]; // XXX FIXME } - protected Stack(Stack other) + public Stack(Stack other) { this.size = other.size; this.stack = Arrays.copyOf(other.stack, other.stack.length); @@ -56,4 +57,9 @@ public class Stack { return size; } + + public List getStack() + { + return Arrays.asList(stack); + } } diff --git a/src/main/java/net/runelite/deob/execution/StackContext.java b/src/main/java/net/runelite/deob/execution/StackContext.java index 92fc0f3f93..27cd190364 100644 --- a/src/main/java/net/runelite/deob/execution/StackContext.java +++ b/src/main/java/net/runelite/deob/execution/StackContext.java @@ -6,7 +6,7 @@ import java.util.List; public class StackContext { public InstructionContext pushed; // instruction which pushed this - public InstructionContext popped; // instruction which popped this + public List poppeds = new ArrayList<>(); // instructions which popped this public Type type; // type of this public boolean removed; @@ -33,14 +33,15 @@ public class StackContext return pushed; } - public InstructionContext getPopped() + public List getPopped() { - return popped; + return poppeds; } - public void setPopped(InstructionContext popped) + public void addPopped(InstructionContext popped) { - this.popped = popped; + if (!this.poppeds.contains(popped)) + this.poppeds.add(popped); } public Type getType() diff --git a/src/main/java/net/runelite/deob/execution/VariableContext.java b/src/main/java/net/runelite/deob/execution/VariableContext.java index 3e6a0f9fd6..9b4560e4c5 100644 --- a/src/main/java/net/runelite/deob/execution/VariableContext.java +++ b/src/main/java/net/runelite/deob/execution/VariableContext.java @@ -1,10 +1,14 @@ package net.runelite.deob.execution; +import java.util.ArrayList; +import java.util.List; + public class VariableContext { private StackContext ctx; // the value stored private InstructionContext ic; // the instruction which stored it. also ctx.popped? private Type type; + private List read = new ArrayList<>(); // instructions which reads this public VariableContext(InstructionContext i, StackContext ctx) { @@ -23,8 +27,24 @@ public class VariableContext return ctx; } + public InstructionContext getInstructionWhichStored() + { + return ic; + } + public Type getType() { return type; } + + public void addRead(InstructionContext ctx) + { + if (!read.contains(ctx)) + read.add(ctx); + } + + public List getRead() + { + return read; + } } diff --git a/src/main/java/net/runelite/deob/pool/Class.java b/src/main/java/net/runelite/deob/pool/Class.java index b10b3b3f11..12c405fed4 100644 --- a/src/main/java/net/runelite/deob/pool/Class.java +++ b/src/main/java/net/runelite/deob/pool/Class.java @@ -12,11 +12,10 @@ public class Class extends PoolEntry private int index; private java.lang.String name; - public Class(ConstantPool pool) throws IOException + public Class(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.CLASS); - DataInputStream is = pool.getClassFile().getStream(); index = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/Double.java b/src/main/java/net/runelite/deob/pool/Double.java index 79a5915d90..7ed74a9ade 100644 --- a/src/main/java/net/runelite/deob/pool/Double.java +++ b/src/main/java/net/runelite/deob/pool/Double.java @@ -11,12 +11,10 @@ public class Double extends PoolEntry { private double value; - public Double(ConstantPool pool) throws IOException + public Double(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.DOUBLE); - DataInputStream is = pool.getClassFile().getStream(); - value = is.readDouble(); } diff --git a/src/main/java/net/runelite/deob/pool/Field.java b/src/main/java/net/runelite/deob/pool/Field.java index ee8adbd168..87b569e7f3 100644 --- a/src/main/java/net/runelite/deob/pool/Field.java +++ b/src/main/java/net/runelite/deob/pool/Field.java @@ -12,12 +12,10 @@ public class Field extends PoolEntry private Class clazz; private NameAndType nat; - public Field(ConstantPool pool) throws IOException + public Field(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.FIELDREF); - DataInputStream is = pool.getClassFile().getStream(); - classIndex = is.readUnsignedShort(); natIndex = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/Float.java b/src/main/java/net/runelite/deob/pool/Float.java index 293db1a282..33fa6f297d 100644 --- a/src/main/java/net/runelite/deob/pool/Float.java +++ b/src/main/java/net/runelite/deob/pool/Float.java @@ -11,12 +11,10 @@ public class Float extends PoolEntry { private float value; - public Float(ConstantPool pool) throws IOException + public Float(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.FLOAT); - DataInputStream is = pool.getClassFile().getStream(); - value = is.readFloat(); } diff --git a/src/main/java/net/runelite/deob/pool/Integer.java b/src/main/java/net/runelite/deob/pool/Integer.java index dd53b013f4..b0746dba10 100644 --- a/src/main/java/net/runelite/deob/pool/Integer.java +++ b/src/main/java/net/runelite/deob/pool/Integer.java @@ -11,12 +11,10 @@ public class Integer extends PoolEntry { private int value; - public Integer(ConstantPool pool) throws IOException + public Integer(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.INTEGER); - DataInputStream is = pool.getClassFile().getStream(); - value = is.readInt(); } diff --git a/src/main/java/net/runelite/deob/pool/InterfaceMethod.java b/src/main/java/net/runelite/deob/pool/InterfaceMethod.java index 836e62b148..0da3118783 100644 --- a/src/main/java/net/runelite/deob/pool/InterfaceMethod.java +++ b/src/main/java/net/runelite/deob/pool/InterfaceMethod.java @@ -20,12 +20,10 @@ public class InterfaceMethod extends PoolEntry this.nat = nat; } - public InterfaceMethod(ConstantPool pool) throws IOException + public InterfaceMethod(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.INTERFACE_METHOD_REF); - DataInputStream is = pool.getClassFile().getStream(); - classIndex = is.readUnsignedShort(); natIndex = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/Long.java b/src/main/java/net/runelite/deob/pool/Long.java index 532dd049f2..c372c31a74 100644 --- a/src/main/java/net/runelite/deob/pool/Long.java +++ b/src/main/java/net/runelite/deob/pool/Long.java @@ -11,12 +11,10 @@ public class Long extends PoolEntry { private long value; - public Long(ConstantPool pool) throws IOException + public Long(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.LONG); - DataInputStream is = pool.getClassFile().getStream(); - value = is.readLong(); } diff --git a/src/main/java/net/runelite/deob/pool/Method.java b/src/main/java/net/runelite/deob/pool/Method.java index d7fa9d3c1b..91d2e34d44 100644 --- a/src/main/java/net/runelite/deob/pool/Method.java +++ b/src/main/java/net/runelite/deob/pool/Method.java @@ -20,12 +20,10 @@ public class Method extends PoolEntry this.nat = nat; } - public Method(ConstantPool pool) throws IOException + public Method(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.METHODREF); - DataInputStream is = pool.getClassFile().getStream(); - classIndex = is.readUnsignedShort(); natIndex = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/NameAndType.java b/src/main/java/net/runelite/deob/pool/NameAndType.java index 85e6e2cede..58a7b12d3f 100644 --- a/src/main/java/net/runelite/deob/pool/NameAndType.java +++ b/src/main/java/net/runelite/deob/pool/NameAndType.java @@ -18,12 +18,10 @@ public class NameAndType extends PoolEntry /* type */ private Type type; - public NameAndType(ConstantPool pool) throws IOException + public NameAndType(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.NAME_AND_TYPE); - DataInputStream is = pool.getClassFile().getStream(); - nameIndex = is.readUnsignedShort(); descriptorIndex = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/String.java b/src/main/java/net/runelite/deob/pool/String.java index 5bab46875c..b135e3f4a5 100644 --- a/src/main/java/net/runelite/deob/pool/String.java +++ b/src/main/java/net/runelite/deob/pool/String.java @@ -12,12 +12,10 @@ public class String extends PoolEntry private int stringIndex; private java.lang.String string; - public String(ConstantPool pool) throws IOException + public String(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.STRING); - DataInputStream is = pool.getClassFile().getStream(); - stringIndex = is.readUnsignedShort(); } diff --git a/src/main/java/net/runelite/deob/pool/UTF8.java b/src/main/java/net/runelite/deob/pool/UTF8.java index 95f3ca8cf7..e431e93837 100644 --- a/src/main/java/net/runelite/deob/pool/UTF8.java +++ b/src/main/java/net/runelite/deob/pool/UTF8.java @@ -10,12 +10,11 @@ public class UTF8 extends PoolEntry { private java.lang.String string; - public UTF8(ConstantPool pool) throws IOException + public UTF8(ConstantPool pool, DataInputStream is) throws IOException { super(ConstantType.UTF8); - DataInputStream ios = pool.getClassFile().getStream(); - string = ios.readUTF(); + string = is.readUTF(); } public UTF8(java.lang.String value) diff --git a/src/test/java/net/runelite/deob/ClassGroupFactory.java b/src/test/java/net/runelite/deob/ClassGroupFactory.java new file mode 100644 index 0000000000..f9553259e6 --- /dev/null +++ b/src/test/java/net/runelite/deob/ClassGroupFactory.java @@ -0,0 +1,50 @@ +package net.runelite.deob; + +import net.runelite.deob.attributes.Attributes; +import net.runelite.deob.attributes.Code; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instructions.VReturn; +import net.runelite.deob.signature.Signature; +import net.runelite.deob.signature.Type; + +public class ClassGroupFactory +{ + public static ClassGroup generateGroup() + { + ClassGroup group = new ClassGroup(); + + ClassFile cf = new ClassFile(group); + cf.setName("test"); + cf.setSuperName("java/lang/Object"); + group.addClass(cf); + + Fields fields = cf.getFields(); + Field field = new Field(fields, "field", new Type("I")); + field.setStatic(); + fields.addField(field); + + Methods methods = cf.getMethods(); + Method method = new Method(methods, "func", new Signature("()V")); + method.setStatic(); + methods.addMethod(method); + + Attributes methodAttributes = method.getAttributes(); + + Code code = new Code(methodAttributes); + methodAttributes.addAttribute(code); + + method = new Method(methods, "func2", new Signature("(III)V")); + method.setStatic(); + methods.addMethod(method); + + methodAttributes = method.getAttributes(); + + code = new Code(methodAttributes); + methodAttributes.addAttribute(code); + + Instructions ins = code.getInstructions(); + ins.addInstruction(new VReturn(ins)); + + return group; + } +} diff --git a/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java b/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java new file mode 100644 index 0000000000..d1fc2b2952 --- /dev/null +++ b/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java @@ -0,0 +1,537 @@ +package net.runelite.deob.deobfuscators.arithmetic; + +import java.util.Collection; +import net.runelite.deob.ClassGroup; +import net.runelite.deob.ClassGroupFactory; +import net.runelite.deob.Deobfuscator; +import net.runelite.deob.Field; +import net.runelite.deob.attributes.Code; +import net.runelite.deob.attributes.code.Instruction; +import net.runelite.deob.attributes.code.Instructions; +import net.runelite.deob.attributes.code.instructions.Dup_X1; +import net.runelite.deob.attributes.code.instructions.GetStatic; +import net.runelite.deob.attributes.code.instructions.Goto; +import net.runelite.deob.attributes.code.instructions.IAdd; +import net.runelite.deob.attributes.code.instructions.IConst_0; +import net.runelite.deob.attributes.code.instructions.IConst_1; +import net.runelite.deob.attributes.code.instructions.IConst_2; +import net.runelite.deob.attributes.code.instructions.IConst_3; +import net.runelite.deob.attributes.code.instructions.IConst_M1; +import net.runelite.deob.attributes.code.instructions.IDiv; +import net.runelite.deob.attributes.code.instructions.ILoad; +import net.runelite.deob.attributes.code.instructions.IMul; +import net.runelite.deob.attributes.code.instructions.IStore; +import net.runelite.deob.attributes.code.instructions.IStore_0; +import net.runelite.deob.attributes.code.instructions.If0; +import net.runelite.deob.attributes.code.instructions.InvokeStatic; +import net.runelite.deob.attributes.code.instructions.LDC_W; +import net.runelite.deob.attributes.code.instructions.NOP; +import net.runelite.deob.attributes.code.instructions.Pop; +import net.runelite.deob.attributes.code.instructions.VReturn; +import net.runelite.deob.execution.Execution; +import net.runelite.deob.execution.InstructionContext; +import org.junit.Assert; +import org.junit.Test; + +public class MultiplicationDeobfuscatorTest +{ + // aload 2 + // ldc_w 1587543155 + // iload 4 + // imul + // dup_x1 + // ldc_w -2130376517 + // imul + // putfield class2/field279 I + // ldc_w -67313687 + // imul + // putstatic class29/field949 I + @Test + public void test1() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(5); + + // vars[0] = 3 + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, 1587543155), + constant2 = new LDC_W(ins, -2130376517), + constant3 = new LDC_W(ins, -67313687); + + Instruction body[] = { + new IConst_0(ins), // for dup_x1 to place before this + constant1, + new ILoad(ins, 0), + new IMul(ins), + new Dup_X1(ins), + constant2, + new IMul(ins), + new Pop(ins), + new Pop(ins), + constant3, + new IMul(ins), + new Pop(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + // check execution runs ok + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1; + assert constant1.getConstantAsInt() * constant3.getConstantAsInt() == -1_095_175_765; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + Assert.assertEquals(-1_095_175_765, constant3.getConstantAsInt()); + } + + // aload_0 + // dup + // getfield class118/field2201 I + // ldc_w -2079217519 + // imul + // ldc -2079217519 + // iadd + // dup_x1 + // ldc_w 561453169 + // imul + // putfield class118/field2201 I + // ldc 561453169 + // imul + @Test + public void test2() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(4); + + // vars[0] = 3 + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, -2079217519), + constant2 = new LDC_W(ins, -2079217519), + constant3 = new LDC_W(ins, 561453169), + constant4 = new LDC_W(ins, 561453169); + + Instruction body[] = { + new IConst_0(ins), // for dup_x1 to place before this + new ILoad(ins, 0), + constant1, + new IMul(ins), + constant2, + new IAdd(ins), + new Dup_X1(ins), // result, 0, result + constant3, + new IMul(ins), + new Pop(ins), + new Pop(ins), + constant4, + new IMul(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant3.getConstantAsInt() == 1; + assert constant2.getConstantAsInt() * constant4.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + Assert.assertEquals(1, constant3.getConstantAsInt()); + Assert.assertEquals(1, constant4.getConstantAsInt()); + } + + @Test + public void test3() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins), + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, 1381104939), + constant2 = new LDC_W(ins, 1381104939), + constant3 = new LDC_W(ins, 981643079), + constant4 = new LDC_W(ins, 1807370871), + constant5 = new LDC_W(ins, 981643079); + + NOP label1 = new NOP(ins); + + Instruction body[] = { + constant4, + constant1, + new ILoad(ins, 0), + new IMul(ins), + new IConst_0(ins), + new If0(ins, label1), + constant2, + new IMul(ins), + label1, + constant3, + new IMul(ins), + new IMul(ins), // constant4 + constant5, + new IMul(ins), + new Pop(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant4.getConstantAsInt() * constant5.getConstantAsInt() == 1; + + { + Collection ctxs = e.getInstructonContexts(body[3]); + assert ctxs.size() == 1; + + InstructionContext ictx = ctxs.iterator().next(); + boolean onlyPath = MultiplicationDeobfuscator.isOnlyPath(e, ictx); + Assert.assertFalse(onlyPath); + } + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1381104939, constant1.getConstantAsInt()); + Assert.assertEquals(1381104939, constant2.getConstantAsInt()); + Assert.assertEquals(1, constant3.getConstantAsInt()); + Assert.assertEquals(1, constant4.getConstantAsInt()); + Assert.assertEquals(981643079, constant5.getConstantAsInt()); // assumes result is moved to the end here. + } + + @Test + public void test4() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins), + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, 1807370871), + constant2 = new LDC_W(ins, 981643079); + + NOP label1 = new NOP(ins); + + Instruction body[] = { + new ILoad(ins, 0), + new LDC_W(ins, 2), + new IMul(ins), + + new IConst_0(ins), + new If0(ins, label1), + + new Pop(ins), + new LDC_W(ins, 3), + + label1, + constant1, + new IMul(ins), + constant2, + new IMul(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + } + + @Test + public void test5() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins), + new IConst_2(ins), + new IStore(ins, 1) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, -2079217519), + constant2 = new LDC_W(ins, -2079217519), + constant3 = new LDC_W(ins, 561453169); + + Instruction body[] = { + new ILoad(ins, 0), + constant1, + new IMul(ins), + new IStore(ins, 2), + + new ILoad(ins, 2), + + new ILoad(ins, 1), + constant2, + new IMul(ins), + + new IAdd(ins), + + constant3, + new IMul(ins), + + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant3.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + Assert.assertEquals(1, constant3.getConstantAsInt()); + } + + @Test + public void test6() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins), + new IConst_2(ins), + new IStore(ins, 1) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, 575391417), + constant2 = new LDC_W(ins, -497786999); + + Instruction body[] = { + new ILoad(ins, 0), + new ILoad(ins, 1), + new Dup_X1(ins), + new Pop(ins), + new Pop(ins), + constant1, + new IMul(ins), + constant2, + new IMul(ins), + new Pop(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + } + + @Test + public void test7() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins), + new IConst_2(ins), + new IStore(ins, 1) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, 2131037801), + constant2 = new LDC_W(ins, -1306959399), + constant3 = new LDC_W(ins, -1); + + Instruction body[] = { + constant3, + constant1, + new IMul(ins), + constant2, + new IMul(ins), + new Pop(ins), + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(-1, constant2.getConstantAsInt()); + Assert.assertEquals(1, constant3.getConstantAsInt()); + } + + @Test + public void test8() + { + ClassGroup group = ClassGroupFactory.generateGroup(); + Code code = group.findClass("test").findMethod("func").getCode(); + Code code2 = group.findClass("test").findMethod("func2").getCode(); + Field field = group.findClass("test").findField("field"); + Instructions ins = code.getInstructions(); + + code.setMaxStack(2); + + Instruction[] prepareVariables = { + new IConst_3(ins), + new IStore_0(ins) + }; + + for (Instruction i : prepareVariables) + ins.addInstruction(i); + + LDC_W constant1 = new LDC_W(ins, -1616202347), + constant2 = new LDC_W(ins, 2747837); + + NOP label1 = new NOP(ins), + label2 = new NOP(ins), + label3 = new NOP(ins); + + Instruction body[] = { + new GetStatic(ins, field.getPoolField()), + constant1, + new IMul(ins), + constant2, + new IMul(ins), + + new ILoad(ins, 0), + + new LDC_W(ins, 42), + new If0(ins, label1), + new Goto(ins, label2), + + label1, + new IConst_M1(ins), + new Goto(ins, label3), + + label2, + new IConst_0(ins), + new Goto(ins, label3), + + label3, + new InvokeStatic(ins, group.findClass("test").findMethod("func2").getPoolMethod()), + + new VReturn(ins) + }; + + for (Instruction i : body) + ins.addInstruction(i); + + Execution e = new Execution(group); + e.populateInitialMethods(); + e.run(); + + assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1; + + Deobfuscator d = new MultiplicationDeobfuscator(); + d.run(group); + + Assert.assertEquals(1, constant1.getConstantAsInt()); + Assert.assertEquals(1, constant2.getConstantAsInt()); + } +}