This commit is contained in:
Adam
2015-08-23 12:40:12 -04:00
parent 4d4dd9715e
commit 0a8d233083
11 changed files with 314 additions and 12 deletions

View File

@@ -149,6 +149,11 @@ public class ClassFile
return children; return children;
} }
public Field findField(String name)
{
return fields.findField(name);
}
public Field findFieldDeep(NameAndType nat) public Field findFieldDeep(NameAndType nat)
{ {
Field f = fields.findField(nat); Field f = fields.findField(nat);

View File

@@ -25,6 +25,7 @@ import net.runelite.deob.deobfuscators.UnusedClass;
import net.runelite.deob.deobfuscators.UnusedFields; 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;
//move static methods //move static methods
//move static fields //move static fields
@@ -102,7 +103,7 @@ public class Deob
// System.out.println("unused methods took " + bdur/1000L + " seconds"); // System.out.println("unused methods took " + bdur/1000L + " seconds");
new MethodInliner().run(group); //new MethodInliner().run(group);
// //
// new MethodMover().run(group); // new MethodMover().run(group);
// //
@@ -116,6 +117,8 @@ public class Deob
// new ModularArithmeticDeobfuscation().run(group); // new ModularArithmeticDeobfuscation().run(group);
new ModArith().run(group);
saveJar(group, args[1]); saveJar(group, args[1]);
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();

View File

@@ -50,4 +50,12 @@ public class Fields
return f; return f;
return null; return null;
} }
public Field findField(String name)
{
for (Field f : fields)
if (f.getName().equals(name))
return f;
return null;
}
} }

View File

@@ -17,6 +17,8 @@ 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 net.runelite.deob.deobfuscators.arithmetic.Encryption;
import net.runelite.deob.deobfuscators.arithmetic.Pair;
public class GetField extends Instruction implements GetFieldInstruction public class GetField extends Instruction implements GetFieldInstruction
{ {
@@ -48,6 +50,18 @@ public class GetField extends Instruction implements GetFieldInstruction
ins.pop(object); ins.pop(object);
StackContext ctx = new StackContext(ins, new Type(field.getNameAndType().getDescriptorType()).toStackType()); StackContext ctx = new StackContext(ins, new Type(field.getNameAndType().getDescriptorType()).toStackType());
Encryption encryption = frame.getExecution().getEncryption();
net.runelite.deob.Field f = getMyField();
if (f != null)
{
Pair pair = encryption.getField(f);
if (pair != null)
{
ctx.encryption = pair.getter;
}
}
stack.push(ctx); stack.push(ctx);
ins.push(ctx); ins.push(ctx);

View File

@@ -17,6 +17,8 @@ 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 net.runelite.deob.deobfuscators.arithmetic.Encryption;
import net.runelite.deob.deobfuscators.arithmetic.Pair;
public class GetStatic extends Instruction implements GetFieldInstruction public class GetStatic extends Instruction implements GetFieldInstruction
{ {
@@ -45,6 +47,18 @@ public class GetStatic extends Instruction implements GetFieldInstruction
Stack stack = frame.getStack(); 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());
Encryption encryption = frame.getExecution().getEncryption();
net.runelite.deob.Field f = getMyField();
if (f != null)
{
Pair pair = encryption.getField(f);
if (pair != null)
{
ctx.encryption = pair.getter;
}
}
stack.push(ctx); stack.push(ctx);
ins.push(ctx); ins.push(ctx);
@@ -55,17 +69,9 @@ public class GetStatic extends Instruction implements GetFieldInstruction
@Override @Override
public void buildInstructionGraph() public void buildInstructionGraph()
{ {
Class clazz = field.getClassEntry(); net.runelite.deob.Field f = getMyField();
NameAndType nat = field.getNameAndType(); if (f != null)
f.addReference(this);
ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName());
if (cf == null)
return;
net.runelite.deob.Field f = cf.findFieldDeep(nat);
assert f != null;
f.addReference(this);
} }
@Override @Override

View File

@@ -0,0 +1,35 @@
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;
}
}
}

View File

@@ -0,0 +1,25 @@
package net.runelite.deob.deobfuscators.arithmetic;
import java.util.HashMap;
import java.util.Map;
import net.runelite.deob.Field;
public class Encryption
{
private Map<Field, Pair> fields = new HashMap<>();
public Pair getField(Field field)
{
if (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;
}
return null;
//return fields.get(field);
}
}

View File

@@ -0,0 +1,189 @@
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.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.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;
/*
store an encryption context on stack context that shows the value the ctx is encrypted with
*/
public class ModArith implements Deobfuscator
{
private ClassGroup group;
private Execution execution;
private MultiValueMap<Field, InstructionContext> fieldIns = new MultiValueMap<>();
private void findGetField(InstructionContext ctx)
{
}
private void findUses()
{
//List<InstructionContext> list = new ArrayList<>();
for (Frame f : execution.processedFrames)
for (InstructionContext ctx : f.getInstructions())
{
Instruction i = ctx.getInstruction();
if (!(i instanceof FieldInstruction))
continue;
FieldInstruction fi = (FieldInstruction) i;
Field fifield = fi.getMyField();
if (fifield == null)
continue;
fieldIns.put(fifield, ctx);
// if (i instanceof GetFieldInstruction)
// {
// findGetField(ctx);
// }
}
//return list;
// for (ClassFile cf : group.getClasses())
// for (Field f : cf.getFields().getFields())
// {
//
// }
}
public void calculate(Field field)
{
Collection<InstructionContext> c = fieldIns.getCollection(field);
if (c == null)
return;
List<Integer> constants = new ArrayList<>();
for (InstructionContext ctx : c)
{
if (ctx.getInstruction() instanceof GetFieldInstruction)
{
List<Field> fields = getFieldsInExpression(ctx, constants);
if (fields.size() == 1)
{
}
}
}
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)
{
return check(ctx, new HashSet<InstructionContext>(), constants);
}
private List<Field> check(InstructionContext context, Set<InstructionContext> visited, List<Integer> constants)
{
List<Field> fields = new ArrayList<>();
if (visited.contains(context))
return fields;
visited.add(context);
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();
Field myf = fi.getMyField();
if (myf != null)
fields.add(myf);
}
if (context.getInstruction() instanceof PushConstantInstruction)
{
PushConstantInstruction pci = (PushConstantInstruction) context.getInstruction();
int i = (int) pci.getConstant().getObject();
constants.add(i);
}
for (StackContext ctx : context.getPops())
{
InstructionContext i = ctx.getPushed();
fields.addAll(check(i, visited, constants));
}
for (StackContext ctx : context.getPushes())
{
InstructionContext i = ctx.getPopped();
if (i == null)
continue;
fields.addAll(check(i, visited, constants));
}
return fields;
}
// private void replace(Pair pair)
// {
// // do replacements with pair
//
// for (Frame frame : execution.processedFrames)
// {
// for (InstructionContext ctx : frame.getInstructions())
// {
// }
// }
// }
@Override
public void run(ClassGroup group)
{
this.group = group;
group.buildClassGraph();
execution = new Execution(group);
execution.populateInitialMethods();
execution.run();
findUses();
Field f = group.findClass("class41").findField("field1170");
calculate(f);
}
}

View File

@@ -0,0 +1,9 @@
package net.runelite.deob.deobfuscators.arithmetic;
import net.runelite.deob.Field;
public class Pair
{
public Field field;
public int getter, setter;
}

View File

@@ -11,6 +11,7 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import net.runelite.deob.deobfuscators.arithmetic.Encryption;
import org.apache.commons.collections4.map.MultiValueMap; import org.apache.commons.collections4.map.MultiValueMap;
public class Execution public class Execution
@@ -21,12 +22,18 @@ public class Execution
public Set<Method> methods = new HashSet<>(); // all methods public Set<Method> methods = new HashSet<>(); // all methods
public Set<Instruction> executed = new HashSet<>(); // executed instructions public Set<Instruction> executed = new HashSet<>(); // executed instructions
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>(); private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
private Encryption encryption;
public Execution(ClassGroup group) public Execution(ClassGroup group)
{ {
this.group = group; this.group = group;
} }
public Encryption getEncryption()
{
return encryption;
}
public void populateInitialMethods() public void populateInitialMethods()
{ {
for (ClassFile cf : group.getClasses()) for (ClassFile cf : group.getClasses())

View File

@@ -9,6 +9,7 @@ public class StackContext
public InstructionContext popped; // instruction which popped this public InstructionContext popped; // instruction which popped this
public Type type; // type of this public Type type; // type of this
public boolean removed; public boolean removed;
public int encryption; // if this value is encrypted, this is the key to get the real value
public StackContext(InstructionContext pushed, Type type) public StackContext(InstructionContext pushed, Type type)
{ {