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.UnusedMethods;
import net.runelite.deob.deobfuscators.UnusedParameters; import net.runelite.deob.deobfuscators.UnusedParameters;
import net.runelite.deob.deobfuscators.arithmetic.ModArith; import net.runelite.deob.deobfuscators.arithmetic.ModArith;
import net.runelite.deob.execution.Execution;
//move static methods //move static methods
//move static fields //move static fields
@@ -41,7 +42,6 @@ public class Deob
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
ClassGroup group = loadJar(args[0]); ClassGroup group = loadJar(args[0]);
long bstart, bdur;
// bstart = System.currentTimeMillis(); // bstart = System.currentTimeMillis();
// new RenameUnique().run(group); // new RenameUnique().run(group);
@@ -49,71 +49,45 @@ public class Deob
// System.out.println("rename unique took " + bdur/1000L + " seconds"); // System.out.println("rename unique took " + bdur/1000L + " seconds");
// // remove except RuntimeException // // remove except RuntimeException
// bstart = System.currentTimeMillis(); // run(group, new RuntimeExceptions());
// new RuntimeExceptions().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("runtime exception took " + bdur/1000L + " seconds");
// //
// // remove unused methods // // remove unused methods
// bstart = System.currentTimeMillis(); // run(group, new UnusedMethods());
// new UnusedMethods().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused methods took " + bdur/1000L + " seconds");
// //
// new UnreachedCode().run(group); // run(group, new UnreachedCode());
// //
// // remove illegal state exceptions, frees up some parameters // // remove illegal state exceptions, frees up some parameters
// bstart = System.currentTimeMillis(); // run(group, new IllegalStateExceptions());
// new IllegalStateExceptions().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("illegal state exception took " + bdur/1000L + " seconds");
// //
// // remove constant logically dead parameters // // remove constant logically dead parameters
// bstart = System.currentTimeMillis(); // run(group, new ConstantParameter());
// new ConstantParameter().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("constant param took " + bdur/1000L + " seconds");
// //
// // remove unhit blocks // // remove unhit blocks
// bstart = System.currentTimeMillis(); // run(group, new UnreachedCode());
// new UnreachedCode().run(group);
// //new UnusedBlocks().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused blocks took " + bdur/1000L + " seconds");
// //
// // remove unused parameters // // remove unused parameters
// bstart = System.currentTimeMillis(); // run(group, new UnusedParameters());
// new UnusedParameters().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused params took " + bdur/1000L + " seconds");
// //
// // remove jump obfuscation // // remove jump obfuscation
// //new Jumps().run(group); // //new Jumps().run(group);
// //
// // remove unused fields // // remove unused fields
// bstart = System.currentTimeMillis(); // run(group, new UnusedFields());
// new UnusedFields().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused fields took " + bdur/1000L + " seconds");
// //
// // remove unused methods, again? // // remove unused methods, again?
// bstart = System.currentTimeMillis(); // run(group, new UnusedMethods());
// 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 MethodInliner());
// //
// new FieldInliner().run(group); // run(group, new MethodMover());
//
// XXX this is broken because when moving clinit around, some fields can depend on other fields // run(group, new FieldInliner());
// (like multianewarray) //
//new FieldMover().run(group); // // XXX this is broken because when moving clinit around, some fields can depend on other fields
// // (like multianewarray)
//new UnusedClass().run(group); // //new FieldMover().run(group);
//
// run(group, new UnusedClass());
// new ModularArithmeticDeobfuscation().run(group); // new ModularArithmeticDeobfuscation().run(group);
@@ -168,4 +142,20 @@ public class Deob
jout.close(); 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); int o = other * DMath.modInverse(one.encryption);
System.out.println(other + " -> " + o);
encryption.change(pci, o); encryption.change(pci, o);
} }
@@ -64,8 +62,6 @@ public class IMul extends Instruction
{ {
int o = other * DMath.modInverse(two.encryption); int o = other * DMath.modInverse(two.encryption);
System.out.println(other + " -> " + o);
encryption.change(pci, o); encryption.change(pci, o);
} }
} }

View File

@@ -16,6 +16,10 @@ import net.runelite.deob.pool.NameAndType;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; 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 public class PutField extends Instruction implements SetFieldInstruction
{ {
@@ -43,10 +47,89 @@ public class PutField extends Instruction implements SetFieldInstruction
InstructionContext ins = new InstructionContext(this, frame); InstructionContext ins = new InstructionContext(this, frame);
Stack stack = frame.getStack(); Stack stack = frame.getStack();
StackContext object = stack.pop();
StackContext value = stack.pop(); StackContext value = stack.pop();
StackContext object = stack.pop();
ins.pop(object, value); 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); frame.addInstructionContext(ins);
} }

View File

@@ -42,7 +42,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction
out.writeShort(this.getPool().make(field)); 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) if (one.getPushed().getInstruction() instanceof PushConstantInstruction)
{ {
@@ -69,6 +69,44 @@ public class PutStatic extends Instruction implements SetFieldInstruction
return null; 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 @Override
public void execute(Frame frame) public void execute(Frame frame)
{ {
@@ -83,68 +121,33 @@ public class PutStatic extends Instruction implements SetFieldInstruction
if (encryption != null && myField != null) if (encryption != null && myField != null)
{ {
Pair pair = encryption.getField(myField); Pair pair = encryption.getField(myField);
InstructionContext ctx = object.getPushed(); if (pair != null)
if (ctx.getInstruction() instanceof PushConstantInstruction && pair != null) translate(encryption, pair, ins);
{ // InstructionContext ctx = object.getPushed();
// field = encryptedvalue // if (ctx.getInstruction() instanceof IAdd && pair != null)
// 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)
// { // {
// PushConstantInstruction pci = (PushConstantInstruction) one.getPushed().getInstruction(); // // field += constant * crap;
// int value = (int) pci.getConstant().getObject(); // // in bytecode is really
// // field = field + constant * crap
// //
// // field is encrypted with pair // List<StackContext> pops = ctx.getPops();
// // divide value by setter //
// 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 value = (int) pci.getConstant().getObject();
// //
// if (value != 0 && value != 1) // if (value != 0 && value != 1)
// { // {
@@ -152,11 +155,33 @@ public class PutStatic extends Instruction implements SetFieldInstruction
// //
// encryption.change(pci, value); // encryption.change(pci, value);
// } // }
//
// } // }
// else if (two.getPushed().getInstruction() instanceof PushConstantInstruction) // if (ctx.getInstruction() instanceof ISub)
// { // {
// PushConstantInstruction pci = (PushConstantInstruction) two.getPushed().getInstruction(); // 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(); // int value = (int) pci.getConstant().getObject();
// //
// // field is encrypted with pair // // field is encrypted with pair
@@ -169,9 +194,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction
// encryption.change(pci, value); // encryption.change(pci, value);
// } // }
// } // }
// else // }
// assert false;
}
} }
frame.addInstructionContext(ins); frame.addInstructionContext(ins);

View File

@@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import net.runelite.deob.Field; import net.runelite.deob.Field;
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction; import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
import net.runelite.deob.attributes.code.instructions.SiPush;
public class Encryption public class Encryption
{ {
@@ -19,34 +18,16 @@ public class Encryption
public Pair getField(Field field) 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); return fields.get(field);
} }
public boolean hasChange(PushConstantInstruction pci)
{
return changes.containsKey(pci);
}
public void change(PushConstantInstruction pci, int value) public void change(PushConstantInstruction pci, int value)
{ {
if (pci instanceof SiPush)
{
int i =5;
}
assert !changes.containsKey(pci) || changes.get(pci) == value; assert !changes.containsKey(pci) || changes.get(pci) == value;
changes.put(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.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import net.runelite.deob.ClassFile;
import net.runelite.deob.ClassGroup; import net.runelite.deob.ClassGroup;
import net.runelite.deob.Deobfuscator; import net.runelite.deob.Deobfuscator;
import net.runelite.deob.Field; 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.Frame;
import net.runelite.deob.execution.InstructionContext; import net.runelite.deob.execution.InstructionContext;
import net.runelite.deob.execution.StackContext; import net.runelite.deob.execution.StackContext;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.map.MultiValueMap; import org.apache.commons.collections4.map.MultiValueMap;
/* /*
@@ -32,20 +30,12 @@ public class ModArith implements Deobfuscator
{ {
private ClassGroup group; private ClassGroup group;
private Execution execution; private Execution execution;
private MultiValueMap<Field, Integer> constants = new MultiValueMap<>(); private MultiValueMap<Field, Integer> constantGetters = new MultiValueMap<>(),
//private MultiValueMap<Field, InstructionContext> fieldIns = new MultiValueMap<>(); constantSetters = new MultiValueMap<>();
private List<Pair> pairs = new ArrayList<>();
// private void findGetField(InstructionContext ctx)
// {
//
// }
private void findUses() private void findUses()
{ {
//List<InstructionContext> list = new ArrayList<>();
for (Frame f : execution.processedFrames) for (Frame f : execution.processedFrames)
for (InstructionContext ctx : f.getInstructions()) for (InstructionContext ctx : f.getInstructions())
{ {
@@ -71,9 +61,12 @@ public class ModArith implements Deobfuscator
continue; continue;
Field field = gf.getMyField(); Field field = gf.getMyField();
if (field == null)
continue;
int value = (int) pc.getConstant().getObject(); int value = (int) pc.getConstant().getObject();
constants.put(field, value); constantGetters.put(field, value);
} }
else if (ctx.getInstruction() instanceof SetFieldInstruction) else if (ctx.getInstruction() instanceof SetFieldInstruction)
{ {
@@ -103,67 +96,113 @@ public class ModArith implements Deobfuscator
continue; continue;
Field field = sf.getMyField(); Field field = sf.getMyField();
if (field == null)
continue;
int value2 = (int) pc.getConstant().getObject(); 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() private void reduce()
{ {
MultiValueMap<Field, Integer> values = constants; for (ClassFile cf : group.getClasses())
constants = new MultiValueMap<>(); for (Field f : cf.getFields().getFields())
for (Field field : values.keySet())
{ {
Collection<Integer> col = values.getCollection(field); Collection<Integer> getters = constantGetters.getCollection(f),
setters = constantSetters.getCollection(f);
Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(col); if (getters == null || setters == null)
int max = Collections.max(map.values()); continue;
for (final Map.Entry<Integer, Integer> entry : map.entrySet()) { Pair answer = reduce(getters, setters);
if (max == entry.getValue()) { if (answer == null)
int constant = entry.getKey(); continue;
constants.put(field, constant); answer.field = f;
break; pairs.add(answer);
} }
} // MultiValueMap<Field, Integer> values = constants;
} // constants = new MultiValueMap<>();
}
// public void calculate(Field field)
// {
// Collection<InstructionContext> c = fieldIns.getCollection(field);
// if (c == null)
// return;
// //
// List<Integer> constants = new ArrayList<>(); // for (Field field : values.keySet())
// for (InstructionContext ctx : c)
// { // {
// if (ctx.getInstruction() instanceof GetFieldInstruction) // Collection<Integer> col = values.getCollection(field);
// {
// List<Field> fields = getFieldsInExpression(ctx, constants);
// if (fields.size() == 1)
// {
// }
// }
// }
// //
// Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(constants); // Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(col);
// int max = Collections.max(map.values()); // int max = Collections.max(map.values());
// //
// for (final Map.Entry<Integer, Integer> entry : map.entrySet()) { // for (final Map.Entry<Integer, Integer> entry : map.entrySet()) {
// if (max == entry.getValue()) { // if (max == entry.getValue()) {
// int constant = entry.getKey(); // int constant = entry.getKey();
// //
// System.out.println(constant); // constants.put(field, constant);
// assert DMath.isInversable(constant);
// break; // break;
// } // }
// } // }
// } // }
}
private List<Field> getFieldsInExpression(InstructionContext ctx, List<Integer> constants) private List<Field> getFieldsInExpression(InstructionContext ctx, List<Integer> constants)
{ {
@@ -234,19 +273,14 @@ public class ModArith implements Deobfuscator
reduce(); reduce();
int i = 0; int i = 0;
for (Field field : constants.keySet()) for (Pair pair : pairs)
{ {
System.out.println("Processing " + field.getName()); Field field = pair.field;
int getter = constants.getCollection(field).iterator().next(); System.out.println("Processing " + field.getName() + " getter " + pair.getter + " setter " + pair.setter);
if (i > 50) if (i > 10) // 25
break; break;
Pair pair = new Pair();
pair.field = field;
pair.getter = getter;
pair.setter = DMath.modInverse(getter);
Encryption encr = new Encryption(); Encryption encr = new Encryption();
encr.addPair(pair); encr.addPair(pair);
@@ -260,7 +294,7 @@ public class ModArith implements Deobfuscator
} }
Encryption encr = new Encryption(); Encryption encr = new Encryption();
System.out.println(constants); System.out.println(pairs);
// execution = new Execution(group); // execution = new Execution(group);
// execution.populateInitialMethods(); // execution.populateInitialMethods();