arith v2
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.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())
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user