First modarith test
This commit is contained in:
@@ -68,7 +68,6 @@ public class ModArith implements Deobfuscator
|
|||||||
outer:
|
outer:
|
||||||
for (InstructionContext ctx : f.getInstructions())
|
for (InstructionContext ctx : f.getInstructions())
|
||||||
{
|
{
|
||||||
// detect field = constant
|
|
||||||
if (ctx.getInstruction() instanceof SetFieldInstruction)
|
if (ctx.getInstruction() instanceof SetFieldInstruction)
|
||||||
{
|
{
|
||||||
SetFieldInstruction sfi = (SetFieldInstruction) ctx.getInstruction();
|
SetFieldInstruction sfi = (SetFieldInstruction) ctx.getInstruction();
|
||||||
@@ -83,6 +82,7 @@ public class ModArith implements Deobfuscator
|
|||||||
{
|
{
|
||||||
int it = ldc.getConstantAsInt();
|
int it = ldc.getConstantAsInt();
|
||||||
if (DMath.isBig(it))
|
if (DMath.isBig(it))
|
||||||
|
// field = constant
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,12 +111,14 @@ public class ModArith implements Deobfuscator
|
|||||||
{
|
{
|
||||||
int i = pci.getConstantAsInt();
|
int i = pci.getConstantAsInt();
|
||||||
if (DMath.isBig(i))
|
if (DMath.isBig(i))
|
||||||
|
// field = constant * not other field
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// field * imul
|
// field * imul
|
||||||
if (!(ctx.getInstruction() instanceof IMul))
|
if (!(ctx.getInstruction() instanceof IMul))
|
||||||
continue;
|
continue;
|
||||||
@@ -179,11 +181,12 @@ public class ModArith implements Deobfuscator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class numgs {
|
static class AssociatedConstant
|
||||||
|
{
|
||||||
int value;
|
int value;
|
||||||
boolean other;
|
boolean other;
|
||||||
}
|
}
|
||||||
private MultiValueMap<Field, numgs> values2 = new MultiValueMap();
|
private MultiValueMap<Field, AssociatedConstant> constants = new MultiValueMap();
|
||||||
|
|
||||||
private void findUses2()
|
private void findUses2()
|
||||||
{
|
{
|
||||||
@@ -202,7 +205,7 @@ public class ModArith implements Deobfuscator
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
List<InstructionContext> l = this.getInsInExpr(ctx, new HashSet());
|
List<InstructionContext> l = this.getInsInExpr(ctx, new HashSet());
|
||||||
boolean other = false;
|
boolean other = false; // check if this contains another field
|
||||||
for (InstructionContext i : l)
|
for (InstructionContext i : l)
|
||||||
{
|
{
|
||||||
if (i.getInstruction() instanceof InvokeInstruction)
|
if (i.getInstruction() instanceof InvokeInstruction)
|
||||||
@@ -225,10 +228,10 @@ public class ModArith implements Deobfuscator
|
|||||||
LDC_W w = (LDC_W) i.getInstruction();
|
LDC_W w = (LDC_W) i.getInstruction();
|
||||||
if (w.getConstant().getObject() instanceof Integer)
|
if (w.getConstant().getObject() instanceof Integer)
|
||||||
{
|
{
|
||||||
numgs n = new numgs();
|
AssociatedConstant n = new AssociatedConstant();
|
||||||
n.value = w.getConstantAsInt();
|
n.value = w.getConstantAsInt();
|
||||||
n.other = other;
|
n.other = other;
|
||||||
values2.put(fi.getMyField(), n);
|
constants.put(fi.getMyField(), n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +241,6 @@ public class ModArith implements Deobfuscator
|
|||||||
|
|
||||||
private void findUses()
|
private void findUses()
|
||||||
{
|
{
|
||||||
// XXX Here needs to be able pick up setters like ield489 -= -2129182073, and also constant setters
|
|
||||||
for (Frame f : execution.processedFrames)
|
for (Frame f : execution.processedFrames)
|
||||||
for (InstructionContext ctx : f.getInstructions())
|
for (InstructionContext ctx : f.getInstructions())
|
||||||
{
|
{
|
||||||
@@ -272,6 +274,7 @@ public class ModArith implements Deobfuscator
|
|||||||
if (value == 1 || value == 0)
|
if (value == 1 || value == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// field * constant
|
||||||
constantGetters.put(field, value);
|
constantGetters.put(field, value);
|
||||||
}
|
}
|
||||||
else if (ctx.getInstruction() instanceof SetFieldInstruction)
|
else if (ctx.getInstruction() instanceof SetFieldInstruction)
|
||||||
@@ -294,6 +297,7 @@ public class ModArith implements Deobfuscator
|
|||||||
int i = ldc.getConstantAsInt();
|
int i = ldc.getConstantAsInt();
|
||||||
|
|
||||||
if (DMath.isBig(i))
|
if (DMath.isBig(i))
|
||||||
|
// field = constant
|
||||||
constantSetters.put(field, i);
|
constantSetters.put(field, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,12 +328,13 @@ public class ModArith implements Deobfuscator
|
|||||||
if (value2 == 1 || value2 == 0)
|
if (value2 == 1 || value2 == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// field = something * constant
|
||||||
constantSetters.put(field, value2);
|
constantSetters.put(field, value2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair guess2(Field field, Collection col, Collection<Integer> constants)
|
private Pair guess(Field field, Collection<Integer> constants)
|
||||||
{
|
{
|
||||||
// multiply each by each,
|
// multiply each by each,
|
||||||
// lowest number wins
|
// lowest number wins
|
||||||
@@ -411,16 +416,16 @@ public class ModArith implements Deobfuscator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean g = isGetterOrSetter(field, true, col, s1),
|
boolean g = isGetterOrSetter(field, true, s1),
|
||||||
g2 = isGetterOrSetter(field, true, col, s2);
|
g2 = isGetterOrSetter(field, true, s2);
|
||||||
|
|
||||||
if (g == null || g2 == null || g == g2)
|
if (g == g2)
|
||||||
{
|
{
|
||||||
g = isGetterOrSetter(field, false, col, s1);
|
g = isGetterOrSetter(field, false, s1);
|
||||||
g2 = isGetterOrSetter(field, false, col, s2);
|
g2 = isGetterOrSetter(field, false, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g == null || g2 == null || g == g2)
|
if (g == g2)
|
||||||
System.out.println("BAD " + field.getName() + " " + s1 + " * " + s2 + " = " + smallest + " " + g + " " + g2);
|
System.out.println("BAD " + field.getName() + " " + s1 + " * " + s2 + " = " + smallest + " " + g + " " + g2);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -442,7 +447,8 @@ public class ModArith implements Deobfuscator
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean isGetterOrSetter(Field field, boolean getter, Collection<numgs> col, int value)
|
// figure out if value is a getter or setter
|
||||||
|
private boolean isGetterOrSetter(Field field, boolean getter, int value)
|
||||||
{
|
{
|
||||||
Collection<Integer> c;
|
Collection<Integer> c;
|
||||||
if (getter)
|
if (getter)
|
||||||
@@ -469,6 +475,7 @@ public class ModArith implements Deobfuscator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove duplicates from a collection
|
||||||
private void removeDupes(Collection<Integer> in)
|
private void removeDupes(Collection<Integer> in)
|
||||||
{
|
{
|
||||||
Set set = new HashSet();
|
Set set = new HashSet();
|
||||||
@@ -491,31 +498,32 @@ public class ModArith implements Deobfuscator
|
|||||||
for (ClassFile cf : group.getClasses())
|
for (ClassFile cf : group.getClasses())
|
||||||
for (Field f : cf.getFields().getFields())
|
for (Field f : cf.getFields().getFields())
|
||||||
{
|
{
|
||||||
Collection<numgs> col = values2.getCollection(f);
|
Collection<AssociatedConstant> col = constants.getCollection(f); // all constants in instructions associated with the field
|
||||||
if (col == null)
|
if (col == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
{
|
// filter out non big ones
|
||||||
Collection<numgs> col2 = col.stream().filter(i -> DMath.isBig(i.value)).collect(Collectors.toList());
|
Collection<AssociatedConstant> col2 = col.stream().filter(i -> DMath.isBig(i.value)).collect(Collectors.toList());
|
||||||
|
|
||||||
Collection<Integer> noOther = col2.stream().filter(i -> !i.other).map(i -> i.value).collect(Collectors.toList());
|
|
||||||
Collection<Integer> other = col2.stream().filter(i -> i.other).map(i -> i.value).collect(Collectors.toList());
|
|
||||||
other.addAll(noOther);
|
|
||||||
|
|
||||||
removeDupes(noOther);
|
// filer out ones that have another field in the expression
|
||||||
removeDupes(other);
|
Collection<Integer> noOther = col2.stream().filter(i -> !i.other).map(i -> i.value).collect(Collectors.toList());
|
||||||
|
Collection<Integer> other = col2.stream().filter(i -> i.other).map(i -> i.value).collect(Collectors.toList());
|
||||||
if (!isFieldObfuscated(execution, f))
|
other.addAll(noOther);
|
||||||
continue;
|
|
||||||
|
removeDupes(noOther);
|
||||||
Pair p = this.guess2(f, null, noOther);
|
removeDupes(other);
|
||||||
if (p == null)
|
|
||||||
p = this.guess2(f, null, other);
|
if (!isFieldObfuscated(execution, f))
|
||||||
|
continue;
|
||||||
if (p != null)
|
|
||||||
{
|
// guess with constants not associated with other fields
|
||||||
pairs.add(p);
|
Pair p = this.guess(f, noOther);
|
||||||
}
|
if (p == null)
|
||||||
|
p = this.guess(f, other); // fall back to all constants
|
||||||
|
|
||||||
|
if (p != null)
|
||||||
|
{
|
||||||
|
pairs.add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,7 +598,7 @@ public class ModArith implements Deobfuscator
|
|||||||
pairs.clear();
|
pairs.clear();
|
||||||
constantGetters.clear();;
|
constantGetters.clear();;
|
||||||
constantSetters.clear();
|
constantSetters.clear();
|
||||||
values2.clear();
|
constants.clear();
|
||||||
|
|
||||||
execution = new Execution(group);
|
execution = new Execution(group);
|
||||||
execution.populateInitialMethods();
|
execution.populateInitialMethods();
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package net.runelite.deob.deobfuscators.arithmetic;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import net.runelite.deob.ClassFile;
|
||||||
|
import net.runelite.deob.ClassGroup;
|
||||||
|
import net.runelite.deob.Deobfuscator;
|
||||||
|
import net.runelite.deob.attributes.Code;
|
||||||
|
import net.runelite.deob.attributes.code.Instruction;
|
||||||
|
import net.runelite.deob.attributes.code.Instructions;
|
||||||
|
import net.runelite.deob.attributes.code.instructions.LDC_W;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
class TestClass
|
||||||
|
{
|
||||||
|
private static int dummy(Object... args) { return 0; }
|
||||||
|
|
||||||
|
public int field1051 = -1611704481;
|
||||||
|
|
||||||
|
public void test()
|
||||||
|
{
|
||||||
|
if(-1 != this.field1051 * 1928543073)
|
||||||
|
{
|
||||||
|
dummy(this.field1051 * 1928543073);
|
||||||
|
this.field1051 = dummy() * 1611704481;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModArithTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void test() throws IOException
|
||||||
|
{
|
||||||
|
InputStream in = this.getClass().getClassLoader().getResourceAsStream("net/runelite/deob/deobfuscators/arithmetic/TestClass.class");
|
||||||
|
Assert.assertNotNull(in);
|
||||||
|
|
||||||
|
ClassGroup group = new ClassGroup();
|
||||||
|
|
||||||
|
ClassFile cf = new ClassFile(group, new DataInputStream(in));
|
||||||
|
group.addClass(cf);
|
||||||
|
|
||||||
|
ModArith d1 = new ModArith();
|
||||||
|
d1.run(group);
|
||||||
|
d1.runOnce();
|
||||||
|
|
||||||
|
Deobfuscator d2 = new MultiplicationDeobfuscator();
|
||||||
|
d2.run(group);
|
||||||
|
|
||||||
|
Code code = cf.findMethod("test").getCode();
|
||||||
|
Instructions instructions = code.getInstructions();
|
||||||
|
for (Instruction i : instructions.getInstructions())
|
||||||
|
if (i instanceof LDC_W)
|
||||||
|
{
|
||||||
|
LDC_W ldc = (LDC_W) i;
|
||||||
|
Assert.assertFalse(DMath.isBig(ldc.getConstantAsInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user