This commit is contained in:
Adam
2015-09-05 23:19:38 -04:00
parent fae040a98f
commit 88bd6490de
6 changed files with 332 additions and 225 deletions

View File

@@ -26,6 +26,7 @@ import net.runelite.deob.deobfuscators.UnusedFields;
import net.runelite.deob.deobfuscators.UnusedMethods;
import net.runelite.deob.deobfuscators.UnusedParameters;
import net.runelite.deob.deobfuscators.arithmetic.ModArith;
import net.runelite.deob.execution.Execution;
//move static methods
//move static fields
@@ -41,7 +42,6 @@ public class Deob
long start = System.currentTimeMillis();
ClassGroup group = loadJar(args[0]);
long bstart, bdur;
// bstart = System.currentTimeMillis();
// new RenameUnique().run(group);
@@ -49,71 +49,45 @@ public class Deob
// System.out.println("rename unique took " + bdur/1000L + " seconds");
// // 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);
//
// new MethodMover().run(group);
// run(group, new UnusedMethods());
//
// new FieldInliner().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);
// run(group, new MethodInliner());
//
// run(group, new MethodMover());
//
// 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());
// new ModularArithmeticDeobfuscation().run(group);
@@ -168,4 +142,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

@@ -45,8 +45,6 @@ public class IMul extends Instruction
{
int o = other * DMath.modInverse(one.encryption);
System.out.println(other + " -> " + o);
encryption.change(pci, o);
}
@@ -64,8 +62,6 @@ public class IMul extends Instruction
{
int o = other * DMath.modInverse(two.encryption);
System.out.println(other + " -> " + o);
encryption.change(pci, o);
}
}

View File

@@ -16,6 +16,10 @@ import net.runelite.deob.pool.NameAndType;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
import net.runelite.deob.deobfuscators.arithmetic.Encryption;
import net.runelite.deob.deobfuscators.arithmetic.Pair;
public class PutField extends Instruction implements SetFieldInstruction
{
@@ -43,10 +47,89 @@ public class PutField extends Instruction implements SetFieldInstruction
InstructionContext ins = new InstructionContext(this, frame);
Stack stack = frame.getStack();
StackContext object = stack.pop();
StackContext value = stack.pop();
StackContext object = stack.pop();
ins.pop(object, value);
Encryption encryption = frame.getExecution().getEncryption();
net.runelite.deob.Field myField = getMyField();
if (encryption != null && myField != null)
{
Pair pair = encryption.getField(myField);
InstructionContext ctx = value.getPushed();
if (ctx.getInstruction() instanceof IAdd && pair != null)
{
// field += constant * crap;
// in bytecode is really
// field = field + constant * crap
List<StackContext> pops = ctx.getPops();
if (pops.get(0).getPushed().getInstruction() instanceof IMul)
{
ctx = pops.get(0).getPushed();
}
else if (pops.get(1).getPushed().getInstruction() instanceof IMul)
{
ctx = pops.get(1).getPushed();
}
}
if (ctx.getInstruction() instanceof PushConstantInstruction && pair != null)
{
// field = encryptedvalue
// decrypt value by * getter
PushConstantInstruction pci = (PushConstantInstruction) ctx.getInstruction();
int v = (int) pci.getConstant().getObject();
if (v != 0 && v != 1)
{
v = v * pair.getter;
encryption.change(pci, v);
}
}
if (ctx.getInstruction() instanceof ISub)
{
List<StackContext> stackCtx = ctx.getPops();
StackContext one = stackCtx.get(0), two = stackCtx.get(1);
if (one.getPushed().getInstruction() instanceof IMul)
{
ctx = one.getPushed();
}
else if (two.getPushed().getInstruction() instanceof IMul)
{
ctx = two.getPushed();
}
}
if (ctx.getInstruction() instanceof IMul && pair != null)
{
List<StackContext> stackCtx = ctx.getPops();
StackContext one = stackCtx.get(0), two = stackCtx.get(1);
StackContext magicStack = PutStatic.findMagic(one, two);
if (magicStack != null)
{
PushConstantInstruction pci = (PushConstantInstruction) magicStack.getPushed().getInstruction();
int v = (int) pci.getConstant().getObject();
// field is encrypted with pair
// divide value by setter
if (v != 0 && v != 1)
{
v = v * pair.getter;
encryption.change(pci, v);
}
}
}
}
frame.addInstructionContext(ins);
}

View File

@@ -42,7 +42,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction
out.writeShort(this.getPool().make(field));
}
private static StackContext findMagic(StackContext one, StackContext two)
protected static StackContext findMagic(StackContext one, StackContext two)
{
if (one.getPushed().getInstruction() instanceof PushConstantInstruction)
{
@@ -68,6 +68,44 @@ public class PutStatic extends Instruction implements SetFieldInstruction
return null;
}
private static boolean translate(Encryption encryption, Pair pair, InstructionContext ctx)
{
if (ctx.getInstruction() instanceof LDC_W)
{
LDC_W pci = (LDC_W) ctx.getInstruction();
int value = (int) pci.getConstant().getObject();
if (encryption.hasChange(pci))
return true;
if (value != 0 && value != 1)
{
value = value * pair.getter;
encryption.change(pci, value);
}
return true;
}
boolean multipleBranches = ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub;
boolean retVal = false;
for (StackContext sctx : ctx.getPops())
{
InstructionContext i = sctx.getPushed();
if (translate(encryption, pair, i))
{
retVal = true;
if (!multipleBranches)
break;
}
}
return retVal;
}
@Override
public void execute(Frame frame)
@@ -83,80 +121,67 @@ public class PutStatic extends Instruction implements SetFieldInstruction
if (encryption != null && myField != null)
{
Pair pair = encryption.getField(myField);
InstructionContext ctx = object.getPushed();
if (ctx.getInstruction() instanceof PushConstantInstruction && pair != null)
{
// field = encryptedvalue
// decrypt value by * getter
PushConstantInstruction pci = (PushConstantInstruction) ctx.getInstruction();
int value = (int) pci.getConstant().getObject();
if (value != 0 && value != 1)
{
value = value * pair.getter;
encryption.change(pci, value);
}
}
if (ctx.getInstruction() instanceof ISub)
{
List<StackContext> stackCtx = ctx.getPops();
StackContext one = stackCtx.get(0), two = stackCtx.get(1);
if (one.getPushed().getInstruction() instanceof IMul)
{
ctx = one.getPushed();
}
else if (two.getPushed().getInstruction() instanceof IMul)
{
ctx = two.getPushed();
}
}
if (ctx.getInstruction() instanceof IMul && pair != null)
{
List<StackContext> stackCtx = ctx.getPops();
StackContext one = stackCtx.get(0), two = stackCtx.get(1);
StackContext magicStack = findMagic(one, two);
if (magicStack != null)
{
PushConstantInstruction pci = (PushConstantInstruction) magicStack.getPushed().getInstruction();
int value = (int) pci.getConstant().getObject();
// field is encrypted with pair
// divide value by setter
if (value != 0 && value != 1)
{
value = value * pair.getter;
encryption.change(pci, value);
}
}
// if (one.getPushed().getInstruction() instanceof PushConstantInstruction)
if (pair != null)
translate(encryption, pair, ins);
// InstructionContext ctx = object.getPushed();
// if (ctx.getInstruction() instanceof IAdd && pair != null)
// {
// // field += constant * crap;
// // in bytecode is really
// // field = field + constant * crap
//
// List<StackContext> pops = ctx.getPops();
//
// if (pops.get(0).getPushed().getInstruction() instanceof IMul)
// {
// PushConstantInstruction pci = (PushConstantInstruction) one.getPushed().getInstruction();
// int value = (int) pci.getConstant().getObject();
//
// // field is encrypted with pair
// // divide value by setter
//
// if (value != 0 && value != 1)
// {
// value = value * pair.getter;
//
// encryption.change(pci, value);
// }
//
// ctx = pops.get(0).getPushed();
// }
// else if (two.getPushed().getInstruction() instanceof PushConstantInstruction)
// else if (pops.get(1).getPushed().getInstruction() instanceof IMul)
// {
// PushConstantInstruction pci = (PushConstantInstruction) two.getPushed().getInstruction();
// ctx = pops.get(1).getPushed();
// }
// }
// if (ctx.getInstruction() instanceof PushConstantInstruction && pair != null)
// {
// // field = encryptedvalue
// // decrypt value by * getter
//
// PushConstantInstruction pci = (PushConstantInstruction) ctx.getInstruction();
// int value = (int) pci.getConstant().getObject();
//
// if (value != 0 && value != 1)
// {
// value = value * pair.getter;
//
// encryption.change(pci, value);
// }
// }
// if (ctx.getInstruction() instanceof ISub)
// {
// List<StackContext> stackCtx = ctx.getPops();
//
// StackContext one = stackCtx.get(0), two = stackCtx.get(1);
//
// if (one.getPushed().getInstruction() instanceof IMul)
// {
// ctx = one.getPushed();
// }
// else if (two.getPushed().getInstruction() instanceof IMul)
// {
// ctx = two.getPushed();
// }
// }
// if (ctx.getInstruction() instanceof IMul && pair != null)
// {
// List<StackContext> stackCtx = ctx.getPops();
//
// StackContext one = stackCtx.get(0), two = stackCtx.get(1);
//
// StackContext magicStack = findMagic(one, two);
//
// if (magicStack != null)
// {
// PushConstantInstruction pci = (PushConstantInstruction) magicStack.getPushed().getInstruction();
// int value = (int) pci.getConstant().getObject();
//
// // field is encrypted with pair
@@ -169,9 +194,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction
// encryption.change(pci, value);
// }
// }
// else
// assert false;
}
// }
}
frame.addInstructionContext(ins);

View File

@@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Map.Entry;
import net.runelite.deob.Field;
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
import net.runelite.deob.attributes.code.instructions.SiPush;
public class Encryption
{
@@ -19,34 +18,16 @@ public class Encryption
public Pair getField(Field field)
{
// if (i == 0 && field.getName().equals("field1170"))
// {
// Pair p = new Pair();
// p.field = field;
// p.getter = -1570098313;
// p.setter = DMath.modInverse(p.getter);
// assert p.setter == 1237096007;
// return p;
// }
// if (i == 1 && field.getName().equals("field700"))
// {
// Pair p = new Pair();
// p.field = field;
// p.getter = -478315765;
// p.setter = DMath.modInverse(p.getter);
// //assert p.setter ==
// return p;
// }
// return null;
return fields.get(field);
}
public boolean hasChange(PushConstantInstruction pci)
{
return changes.containsKey(pci);
}
public void change(PushConstantInstruction pci, int value)
{
if (pci instanceof SiPush)
{
int i =5;
}
assert !changes.containsKey(pci) || changes.get(pci) == value;
changes.put(pci, value);
}

View File

@@ -2,11 +2,10 @@ 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;
@@ -21,7 +20,6 @@ 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;
/*
@@ -32,20 +30,12 @@ public class ModArith implements Deobfuscator
{
private ClassGroup group;
private Execution execution;
private MultiValueMap<Field, Integer> constants = new MultiValueMap<>();
//private MultiValueMap<Field, InstructionContext> fieldIns = new MultiValueMap<>();
private MultiValueMap<Field, Integer> constantGetters = new MultiValueMap<>(),
constantSetters = new MultiValueMap<>();
private List<Pair> pairs = new ArrayList<>();
// private void findGetField(InstructionContext ctx)
// {
//
// }
private void findUses()
{
//List<InstructionContext> list = new ArrayList<>();
{
for (Frame f : execution.processedFrames)
for (InstructionContext ctx : f.getInstructions())
{
@@ -71,9 +61,12 @@ public class ModArith implements Deobfuscator
continue;
Field field = gf.getMyField();
if (field == null)
continue;
int value = (int) pc.getConstant().getObject();
constants.put(field, value);
constantGetters.put(field, value);
}
else if (ctx.getInstruction() instanceof SetFieldInstruction)
{
@@ -103,67 +96,113 @@ public class ModArith implements Deobfuscator
continue;
Field field = sf.getMyField();
if (field == null)
continue;
int value2 = (int) pc.getConstant().getObject();
constants.put(field, value2);
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 void reduce()
{
MultiValueMap<Field, Integer> values = constants;
constants = new MultiValueMap<>();
for (Field field : values.keySet())
{
Collection<Integer> col = values.getCollection(field);
Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(col);
int max = Collections.max(map.values());
for (final Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (max == entry.getValue()) {
int constant = entry.getKey();
constants.put(field, constant);
break;
}
for (ClassFile cf : group.getClasses())
for (Field f : cf.getFields().getFields())
{
Collection<Integer> getters = constantGetters.getCollection(f),
setters = constantSetters.getCollection(f);
if (getters == null || setters == null)
continue;
Pair answer = reduce(getters, setters);
if (answer == null)
continue;
answer.field = f;
pairs.add(answer);
}
}
}
// public void calculate(Field field)
// {
// Collection<InstructionContext> c = fieldIns.getCollection(field);
// if (c == null)
// return;
// MultiValueMap<Field, Integer> values = constants;
// constants = new MultiValueMap<>();
//
// List<Integer> constants = new ArrayList<>();
// for (InstructionContext ctx : c)
// for (Field field : values.keySet())
// {
// if (ctx.getInstruction() instanceof GetFieldInstruction)
// {
// List<Field> fields = getFieldsInExpression(ctx, constants);
// if (fields.size() == 1)
// {
// Collection<Integer> col = values.getCollection(field);
//
// Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(col);
// int max = Collections.max(map.values());
//
// for (final Map.Entry<Integer, Integer> entry : map.entrySet()) {
// if (max == entry.getValue()) {
// int constant = entry.getKey();
//
// constants.put(field, constant);
// break;
// }
// }
// }
//
// Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(constants);
// int max = Collections.max(map.values());
//
// for (final Map.Entry<Integer, Integer> entry : map.entrySet()) {
// if (max == entry.getValue()) {
// int constant = entry.getKey();
//
// System.out.println(constant);
// assert DMath.isInversable(constant);
// break;
// }
// }
// }
}
private List<Field> getFieldsInExpression(InstructionContext ctx, List<Integer> constants)
{
@@ -234,19 +273,14 @@ public class ModArith implements Deobfuscator
reduce();
int i = 0;
for (Field field : constants.keySet())
for (Pair pair : pairs)
{
System.out.println("Processing " + field.getName());
int getter = constants.getCollection(field).iterator().next();
Field field = pair.field;
System.out.println("Processing " + field.getName() + " getter " + pair.getter + " setter " + pair.setter);
if (i > 50)
if (i > 10) // 25
break;
Pair pair = new Pair();
pair.field = field;
pair.getter = getter;
pair.setter = DMath.modInverse(getter);
Encryption encr = new Encryption();
encr.addPair(pair);
@@ -256,11 +290,11 @@ public class ModArith implements Deobfuscator
execution.run();
encr.doChange();
System.out.println("Changed" + ++i);
System.out.println("Changed " + ++i);
}
Encryption encr = new Encryption();
System.out.println(constants);
System.out.println(pairs);
// execution = new Execution(group);
// execution.populateInitialMethods();