Merge branch 'master+arith'

Conflicts:
	src/main/java/net/runelite/deob/deobfuscators/MethodInliner.java
This commit is contained in:
Adam
2015-10-12 17:41:06 -04:00
121 changed files with 3023 additions and 1239 deletions

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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())
);
}
}

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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();

View File

@@ -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());
}

View File

@@ -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)
{

View File

@@ -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];

View File

@@ -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();

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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.
}

View File

@@ -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;
}

View File

@@ -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.
}

View File

@@ -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.
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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.
}
}

View File

@@ -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.
}
}

View File

@@ -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.
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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.
}

View File

@@ -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.
}

View File

@@ -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.
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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()
{

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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
{

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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.
}

View File

@@ -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.
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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.
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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)

View File

@@ -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");
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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