First modarith test

This commit is contained in:
Adam
2015-10-25 19:11:25 -04:00
parent 8e39328eca
commit e81e46c68c
2 changed files with 106 additions and 37 deletions

View File

@@ -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();

View File

@@ -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()));
}
}
}