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

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

View File

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

View File

@@ -50,4 +50,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

@@ -17,6 +17,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 GetField extends Instruction implements GetFieldInstruction
{
@@ -48,6 +50,18 @@ public class GetField extends Instruction implements GetFieldInstruction
ins.pop(object);
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);
ins.push(ctx);

View File

@@ -17,6 +17,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 GetStatic extends Instruction implements GetFieldInstruction
{
@@ -45,6 +47,18 @@ public class GetStatic extends Instruction implements GetFieldInstruction
Stack stack = frame.getStack();
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);
ins.push(ctx);
@@ -55,17 +69,9 @@ public class GetStatic extends Instruction implements GetFieldInstruction
@Override
public void buildInstructionGraph()
{
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 f = cf.findFieldDeep(nat);
assert f != null;
f.addReference(this);
net.runelite.deob.Field f = getMyField();
if (f != null)
f.addReference(this);
}
@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.List;
import java.util.Set;
import net.runelite.deob.deobfuscators.arithmetic.Encryption;
import org.apache.commons.collections4.map.MultiValueMap;
public class Execution
@@ -21,11 +22,17 @@ public class Execution
public Set<Method> methods = new HashSet<>(); // all methods
public Set<Instruction> executed = new HashSet<>(); // executed instructions
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
private Encryption encryption;
public Execution(ClassGroup group)
{
this.group = group;
}
public Encryption getEncryption()
{
return encryption;
}
public void populateInitialMethods()
{

View File

@@ -9,6 +9,7 @@ public class StackContext
public InstructionContext popped; // instruction which popped this
public Type type; // type of this
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)
{