Merge branch 'master+arith'
Conflicts: src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java
This commit is contained in:
@@ -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<ClassFile> 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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,19 @@ public class Fields
|
||||
|
||||
private List<Field> 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<Field> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,18 +14,21 @@ public class Interfaces
|
||||
|
||||
private List<Class> interfaces = new ArrayList<Class>();
|
||||
|
||||
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<Class> getInterfaces()
|
||||
{
|
||||
return interfaces;
|
||||
|
||||
@@ -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())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,19 @@ public class Methods
|
||||
|
||||
private List<Method> 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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -19,18 +19,28 @@ public class Attributes
|
||||
|
||||
private List<Attribute> 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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Block> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<StackContext> pushes = ctx.getPushes();
|
||||
assert pushes.contains(sctx);
|
||||
|
||||
int idx = pushes.indexOf(sctx);
|
||||
assert idx == 0 || idx == 1;
|
||||
|
||||
return pushes.get(~idx & 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class IllegalStateExceptions implements Deobfuscator
|
||||
|
||||
Instructions instructions = c.getInstructions();
|
||||
instructions.clearBlockGraph();
|
||||
instructions.buildJumpGraph();
|
||||
|
||||
List<Instruction> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Field> obfuscatedFields; // reliability of these sucks
|
||||
|
||||
static class Magic
|
||||
{
|
||||
Field field;
|
||||
int getter, setter;
|
||||
boolean unknownGetter, unknownSetter;
|
||||
}
|
||||
|
||||
static class Magics
|
||||
{
|
||||
Map<Field, Magic> 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<net.runelite.deob.pool.Field> checkDown(InstructionContext context)
|
||||
{
|
||||
List<net.runelite.deob.pool.Field> 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<net.runelite.deob.pool.Field> checkUp(InstructionContext context)
|
||||
{
|
||||
List<net.runelite.deob.pool.Field> 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<Field> obFields, net.runelite.deob.pool.Field imulField, InstructionContext context)
|
||||
{
|
||||
List<net.runelite.deob.pool.Field> 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<InstructionContext> getDown(InstructionContext context)
|
||||
{
|
||||
List<InstructionContext> instructions = new ArrayList<>();
|
||||
|
||||
instructions.add(context);
|
||||
|
||||
for (StackContext ctx : context.getPops())
|
||||
{
|
||||
InstructionContext i = ctx.getPushed();
|
||||
|
||||
instructions.addAll(getDown(i));
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private List<InstructionContext> getInstructions(InstructionContext context)
|
||||
{
|
||||
List<InstructionContext> instructions = new ArrayList<>();
|
||||
|
||||
instructions.add(context);
|
||||
|
||||
instructions.addAll(getDown(context));
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private Set<Field> getObfuscatedFields(Execution execution, ClassGroup group)
|
||||
{
|
||||
Set<Field> 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<InstructionContext> 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<Instruction> 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");
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ public class UnreachedCode implements Deobfuscator
|
||||
List<Instruction> 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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Field, Pair> fields = new HashMap<>();
|
||||
|
||||
public void addPair(Pair pair)
|
||||
{
|
||||
fields.put(pair.field, pair);
|
||||
}
|
||||
|
||||
public Pair getField(Field field)
|
||||
{
|
||||
return fields.get(field);
|
||||
}
|
||||
}
|
||||
@@ -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<Field, Integer> constantGetters = new MultiValueMap<>(),
|
||||
constantSetters = new MultiValueMap<>();
|
||||
private List<Pair> pairs = new ArrayList<>();
|
||||
private Set<Field> deobfuscatedFields = new HashSet<>();
|
||||
|
||||
private List<InstructionContext> getInsInExpr(InstructionContext ctx, Set<Instruction> set)
|
||||
{
|
||||
List<InstructionContext> 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<InstructionContext> 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<Integer> findAssocConstants(Field field, InstructionContext ctx) throws OtherFieldException
|
||||
{
|
||||
// starts with ctx = setfield
|
||||
|
||||
List<Integer> 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<Integer> 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<Integer> getters, Collection<Integer> 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<Integer> values, boolean getter)
|
||||
{
|
||||
Map<Integer, Integer> 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<Integer, Integer> 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<Integer> 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<Instruction> 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<Instruction> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<InstructionContext> getInsInExpr(InstructionContext ctx, Set<Instruction> set)
|
||||
// {
|
||||
// List<InstructionContext> 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<InstructionContext> 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<StackContext> 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<InstructionContext> 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<Instruction> 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<InstructionContext> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<InstructionContext> instructions = new ArrayList<>(), // push constant instructions that are being multiplied
|
||||
dupedInstructions = new ArrayList<>();
|
||||
List<MultiplicationExpression> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<Instruction> 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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Instruction> 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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.runelite.deob.deobfuscators.arithmetic;
|
||||
|
||||
class OtherFieldException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user