arith v2
This commit is contained in:
@@ -148,6 +148,11 @@ public class ClassFile
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
public Field findField(String name)
|
||||
{
|
||||
return fields.findField(name);
|
||||
}
|
||||
|
||||
public Field findFieldDeep(NameAndType nat)
|
||||
{
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user