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 extends PoolEntry> con = type.getPoolClass().getConstructor(new Class[] { ConstantPool.class });
- PoolEntry entry = con.newInstance(this);
+ Constructor extends PoolEntry> 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 extends Attribute> 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 extends Instruction> 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 extends Instruction> 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());
+ }
+}