isBig isnta lways right
This commit is contained in:
@@ -46,6 +46,9 @@ public class ModArith implements Deobfuscator
|
|||||||
if (ctx == null || set.contains(ctx.getInstruction()))
|
if (ctx == null || set.contains(ctx.getInstruction()))
|
||||||
return l;
|
return l;
|
||||||
|
|
||||||
|
// if (ctx.getInstruction() instanceof FieldInstruction)
|
||||||
|
// return l; // well do this one later?
|
||||||
|
|
||||||
set.add(ctx.getInstruction());
|
set.add(ctx.getInstruction());
|
||||||
|
|
||||||
l.add(ctx);
|
l.add(ctx);
|
||||||
@@ -59,103 +62,77 @@ public class ModArith implements Deobfuscator
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFieldObfuscated(Execution e, Field field)
|
// private boolean isFieldObfuscated(Execution e, Field field)
|
||||||
{
|
// {
|
||||||
// field isn't obfuscated if there are no usages with big constants and no other fields
|
// // field isn't obfuscated if there are no usages with big constants and no other fields
|
||||||
|
//
|
||||||
for (Frame f : execution.processedFrames)
|
// for (Frame f : execution.processedFrames)
|
||||||
outer:
|
// outer:
|
||||||
for (InstructionContext ctx : f.getInstructions())
|
// for (InstructionContext ctx : f.getInstructions())
|
||||||
{
|
// {
|
||||||
if (!(ctx.getInstruction() instanceof FieldInstruction))
|
// if (!(ctx.getInstruction() instanceof FieldInstruction))
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
FieldInstruction fi = (FieldInstruction) ctx.getInstruction();
|
// FieldInstruction fi = (FieldInstruction) ctx.getInstruction();
|
||||||
|
//
|
||||||
//if (fi.getMyField() != field)
|
// //if (fi.getMyField() != field)
|
||||||
// continue;
|
// // continue;
|
||||||
|
//
|
||||||
List<InstructionContext> ins = getInsInExpr(ctx, new HashSet());
|
// List<InstructionContext> ins = getInsInExpr(ctx, new HashSet());
|
||||||
|
//
|
||||||
// continue if expr contains another ins
|
// // continue if expr contains another ins
|
||||||
for (InstructionContext i : ins)
|
|
||||||
{
|
|
||||||
if (i.getInstruction() instanceof FieldInstruction)
|
|
||||||
{
|
|
||||||
FieldInstruction ifi = (FieldInstruction) i.getInstruction();
|
|
||||||
|
|
||||||
//if (ifi.getMyField() != field)
|
|
||||||
// continue outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find big constant
|
|
||||||
boolean big = false;
|
|
||||||
for (InstructionContext i : ins)
|
|
||||||
{
|
|
||||||
if (i.getInstruction() instanceof LDC_W)
|
|
||||||
{
|
|
||||||
LDC_W ldc = (LDC_W) i.getInstruction();
|
|
||||||
if (ldc.getConstant().getObject() instanceof Integer)
|
|
||||||
{
|
|
||||||
int value = ldc.getConstantAsInt();
|
|
||||||
|
|
||||||
if (DMath.isBig(value))
|
|
||||||
big = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for (InstructionContext i : ins)
|
// for (InstructionContext i : ins)
|
||||||
// {
|
// {
|
||||||
// if (i.getInstruction() instanceof InvokeInstruction)
|
// if (i.getInstruction() instanceof FieldInstruction)
|
||||||
// {
|
// {
|
||||||
// if (!big)
|
// FieldInstruction ifi = (FieldInstruction) i.getInstruction();
|
||||||
|
//
|
||||||
|
// //if (ifi.getMyField() != field)
|
||||||
|
// // continue outer;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // find big constant
|
||||||
|
// boolean big = false;
|
||||||
|
// for (InstructionContext i : ins)
|
||||||
|
// {
|
||||||
|
// if (i.getInstruction() instanceof LDC_W)
|
||||||
|
// {
|
||||||
|
// LDC_W ldc = (LDC_W) i.getInstruction();
|
||||||
|
// if (ldc.getConstant().getObject() instanceof Integer)
|
||||||
// {
|
// {
|
||||||
// // if no ob is detected and its passed to an invoke, it must be deobbed
|
// int value = ldc.getConstantAsInt();
|
||||||
// return false;
|
//
|
||||||
|
// if (DMath.isBig(value))
|
||||||
|
// big = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
//// for (InstructionContext i : ins)
|
||||||
|
//// {
|
||||||
|
//// if (i.getInstruction() instanceof InvokeInstruction)
|
||||||
|
//// {
|
||||||
|
//// if (!big)
|
||||||
|
//// {
|
||||||
|
//// // if no ob is detected and its passed to an invoke, it must be deobbed
|
||||||
|
//// return false;
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
// if (big)
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
if (big)
|
static class numgs {
|
||||||
return true;
|
int value;
|
||||||
}
|
boolean getter;
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
private MultiValueMap<Field, numgs> values2 = new MultiValueMap();
|
||||||
private List<Integer> findAssocConstants(Field field, InstructionContext ctx) throws OtherFieldException
|
|
||||||
{
|
|
||||||
// starts with ctx = setfield
|
|
||||||
|
|
||||||
List<Integer> list = new ArrayList<>();
|
|
||||||
|
|
||||||
if (ctx.getInstruction() instanceof LDC_W)
|
|
||||||
{
|
|
||||||
LDC_W pci = (LDC_W) ctx.getInstruction();
|
|
||||||
if (pci.getConstant().getObject() instanceof Integer)
|
|
||||||
list.add((int) pci.getConstant().getObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.getInstruction() instanceof FieldInstruction)
|
|
||||||
{
|
|
||||||
FieldInstruction fi = (FieldInstruction) ctx.getInstruction();
|
|
||||||
|
|
||||||
// if the field is already deobbed, constants here don't include it
|
|
||||||
if (fi.getMyField() != field && !deobfuscatedFields.contains(fi.getMyField()))
|
|
||||||
throw new OtherFieldException();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (StackContext sctx : ctx.getPops())
|
|
||||||
{
|
|
||||||
list.addAll(findAssocConstants(field, sctx.getPushed()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MultiValueMap<Field, Integer> values2 = new MultiValueMap();
|
|
||||||
|
|
||||||
private void findUses2()
|
private void findUses2()
|
||||||
{
|
{
|
||||||
@@ -181,7 +158,11 @@ 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)
|
||||||
{
|
{
|
||||||
values2.put(fi.getMyField(), (int) w.getConstant().getObject());
|
//boolean getter = fi instanceof GetFieldInstruction;
|
||||||
|
numgs n = new numgs();
|
||||||
|
n.value = w.getConstantAsInt();
|
||||||
|
//n.getter = getter;
|
||||||
|
values2.put(fi.getMyField(), n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,66 +263,66 @@ public class ModArith implements Deobfuscator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair reduce(Collection<Integer> getters, Collection<Integer> setters)
|
// private Pair reduce(Collection<Integer> getters, Collection<Integer> setters)
|
||||||
{
|
// {
|
||||||
Pair p = null;
|
// Pair p = null;
|
||||||
|
//
|
||||||
|
// for (Integer i : getters)
|
||||||
|
// {
|
||||||
|
// Integer inverse;
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// inverse = DMath.modInverse(i);
|
||||||
|
// }
|
||||||
|
// catch (ArithmeticException ex)
|
||||||
|
// {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (setters.contains(inverse))
|
||||||
|
// {
|
||||||
|
// if (p != null && p.getter != i)
|
||||||
|
// return null;
|
||||||
|
//
|
||||||
|
// if (p == null)
|
||||||
|
// {
|
||||||
|
// p = new Pair();
|
||||||
|
// p.getter = i;
|
||||||
|
// p.setter = inverse;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (Integer i : setters)
|
||||||
|
// {
|
||||||
|
// Integer inverse;
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// inverse = DMath.modInverse(i);
|
||||||
|
// }
|
||||||
|
// catch (ArithmeticException ex)
|
||||||
|
// {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (getters.contains(inverse))
|
||||||
|
// {
|
||||||
|
// if (p != null && p.setter != i)
|
||||||
|
// return null;
|
||||||
|
//
|
||||||
|
// if (p == null)
|
||||||
|
// {
|
||||||
|
// p = new Pair();
|
||||||
|
// p.setter = i;
|
||||||
|
// p.getter = inverse;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return p;
|
||||||
|
// }
|
||||||
|
|
||||||
for (Integer i : getters)
|
private Pair guess2(Field field, Collection col, Collection<Integer> constants)
|
||||||
{
|
|
||||||
Integer inverse;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inverse = DMath.modInverse(i);
|
|
||||||
}
|
|
||||||
catch (ArithmeticException ex)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setters.contains(inverse))
|
|
||||||
{
|
|
||||||
if (p != null && p.getter != i)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (p == null)
|
|
||||||
{
|
|
||||||
p = new Pair();
|
|
||||||
p.getter = i;
|
|
||||||
p.setter = inverse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Integer i : setters)
|
|
||||||
{
|
|
||||||
Integer inverse;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inverse = DMath.modInverse(i);
|
|
||||||
}
|
|
||||||
catch (ArithmeticException ex)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getters.contains(inverse))
|
|
||||||
{
|
|
||||||
if (p != null && p.setter != i)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (p == null)
|
|
||||||
{
|
|
||||||
p = new Pair();
|
|
||||||
p.setter = i;
|
|
||||||
p.getter = inverse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pair guess2(Field field, Collection<Integer> constants)
|
|
||||||
{
|
{
|
||||||
// multiply each by each,
|
// multiply each by each,
|
||||||
// lowest number wins
|
// lowest number wins
|
||||||
@@ -424,86 +405,32 @@ public class ModArith implements Deobfuscator
|
|||||||
//assert false;
|
//assert false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // pick the one that isn't inversible
|
|
||||||
//
|
|
||||||
// // set it to inverse(other)
|
|
||||||
//
|
|
||||||
// // check that inverse(other) * result == s2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println(field.getName() + " " + s1 + " * " + s2 + " = " + smallest);
|
Boolean g = isGetter(field, col, s1),
|
||||||
|
g2 = isGetter(field, col, s2);
|
||||||
|
|
||||||
|
if (g == null || g2 == null || g == g2)
|
||||||
|
System.out.println(field.getName() + " " + s1 + " * " + s2 + " = " + smallest + " " + g + " " + g2);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair guess(Field field, Collection<Integer> values, boolean getter)
|
private Boolean isGetter(Field field, Collection<numgs> col, int value)
|
||||||
{
|
{
|
||||||
Map<Integer, Integer> map = CollectionUtils.getCardinalityMap(values); // value -> how many times it occurs
|
Collection<Integer> c = this.constantGetters.getCollection(field);
|
||||||
int max = Collections.max(map.values()); // largest occurance #
|
return c != null && c.contains(value);
|
||||||
int size = values.size();
|
// Boolean b = null;
|
||||||
|
// for (numgs n : col)
|
||||||
try
|
// {
|
||||||
{
|
// if (n.value == value)
|
||||||
if (max == size)
|
// {
|
||||||
{
|
// if (b == null)
|
||||||
// all getters are the same value
|
// b = n.getter;
|
||||||
int constant = values.iterator().next();
|
// else if (b != n.getter)
|
||||||
if (DMath.isBig(constant))
|
// return null;
|
||||||
{
|
// }
|
||||||
Pair pair = new Pair();
|
// }
|
||||||
if (getter)
|
// return b;
|
||||||
{
|
|
||||||
pair.getter = constant;
|
|
||||||
//System.out.println("Guessing " + field.getName() + " getter " + constant + " setter ");
|
|
||||||
pair.setter = DMath.modInverse(constant);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pair.setter = constant;
|
|
||||||
pair.getter = DMath.modInverse(constant);
|
|
||||||
}
|
|
||||||
return pair;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ArithmeticException ex) { }
|
|
||||||
|
|
||||||
// if (size < 50)
|
|
||||||
// return null;
|
|
||||||
|
|
||||||
if (((float) max / (float) size) < 0.9)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
for (final Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
|
||||||
if (max == entry.getValue()) {
|
|
||||||
int constant = entry.getKey();
|
|
||||||
int inverse;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inverse = DMath.modInverse(constant);
|
|
||||||
}
|
|
||||||
catch (ArithmeticException ex)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair pair = new Pair();
|
|
||||||
if (getter)
|
|
||||||
{
|
|
||||||
pair.getter = constant;
|
|
||||||
pair.setter = inverse;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pair.getter = inverse;
|
|
||||||
pair.setter = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pair;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reduce2()
|
private void reduce2()
|
||||||
@@ -511,110 +438,27 @@ 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<Integer> col = values2.getCollection(f);
|
Collection<numgs> col = values2.getCollection(f);
|
||||||
if (col == null)
|
if (col == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
col = col.stream().filter(i -> DMath.isBig(i)).collect(Collectors.toList());
|
if (f.getName().equals("field3045"))
|
||||||
|
|
||||||
Set<Integer> set = new HashSet<>();
|
|
||||||
set.addAll(col);
|
|
||||||
|
|
||||||
//if (f.getName().equals("field297"))
|
|
||||||
{
|
{
|
||||||
this.guess2(f, set);
|
col = col.stream().filter(i -> DMath.isBig(i.value)).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Set set = col.stream().map(i -> i.value).collect(Collectors.toSet());
|
||||||
|
//
|
||||||
|
|
||||||
|
this.guess2(f, col, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reduce()
|
|
||||||
{
|
|
||||||
for (ClassFile cf : group.getClasses())
|
|
||||||
for (Field f : cf.getFields().getFields())
|
|
||||||
{
|
|
||||||
Collection<Integer> getters = constantGetters.getCollection(f),
|
|
||||||
setters = constantSetters.getCollection(f);
|
|
||||||
|
|
||||||
List<Integer> all = new LinkedList();
|
|
||||||
|
|
||||||
if (getters != null)
|
|
||||||
{
|
|
||||||
all.addAll(getters);
|
|
||||||
getters = getters.stream().filter(c -> DMath.isBig(c)).collect(Collectors.toList());
|
|
||||||
if (getters.isEmpty())
|
|
||||||
getters = null;
|
|
||||||
}
|
|
||||||
if (setters != null)
|
|
||||||
{
|
|
||||||
all.addAll(setters);
|
|
||||||
setters = setters.stream().filter(c -> DMath.isBig(c)).collect(Collectors.toList());
|
|
||||||
if (setters.isEmpty())
|
|
||||||
setters = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.guess2(f, all);
|
|
||||||
if (f.getName().equals("field33"))
|
|
||||||
{
|
|
||||||
this.guess2(f, all);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Pair answer = null;
|
|
||||||
//
|
|
||||||
// if (getters != null && setters != null)
|
|
||||||
// answer = reduce(getters, setters);
|
|
||||||
//
|
|
||||||
// if (answer == null && getters != null)
|
|
||||||
// answer = guess(f, getters, true);
|
|
||||||
//
|
|
||||||
// if (answer == null && setters != null)
|
|
||||||
// answer = guess(f, setters, false);
|
|
||||||
//
|
|
||||||
// if (answer == null)
|
|
||||||
// continue;
|
|
||||||
//
|
|
||||||
// if (!this.isFieldObfuscated(execution, f))
|
|
||||||
// {
|
|
||||||
// System.out.println("Skipping field " + f.getName() + " which isnt obfuscated");
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// answer.field = f;
|
|
||||||
// pairs.add(answer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ClassGroup group)
|
public void run(ClassGroup group)
|
||||||
{
|
{
|
||||||
this.group = group;
|
this.group = group;
|
||||||
//return runOnce();
|
|
||||||
// if (true) return;
|
|
||||||
//
|
|
||||||
// int passes = 0, total = 0, i;
|
|
||||||
// while ((i = runOnce()) > 0)
|
|
||||||
// {
|
|
||||||
// ++passes;
|
|
||||||
// total += i;
|
|
||||||
// }
|
|
||||||
// System.out.println("Finished arith deob on " + total + " fields in " + passes + " passes");
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// private void translateSetFields(Execution e)
|
|
||||||
// {
|
|
||||||
// //Set<Instruction> visited = new HashSet<>();
|
|
||||||
// for (Frame f : e.processedFrames)
|
|
||||||
// for (InstructionContext ins : f.getInstructions())
|
|
||||||
// if (ins.getInstruction() instanceof SetFieldInstruction)
|
|
||||||
// {
|
|
||||||
// SetFieldInstruction sfi = (SetFieldInstruction) ins.getInstruction();
|
|
||||||
// Pair pair = e.getEncryption().getField(sfi.getMyField());
|
|
||||||
//
|
|
||||||
// if (pair != null)
|
|
||||||
// PutStatic.translate(e.getEncryption(), pair, ins, new HashSet());
|
|
||||||
// //
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void insertGetterSetterMuls(Encryption encr)
|
private void insertGetterSetterMuls(Encryption encr)
|
||||||
{
|
{
|
||||||
@@ -686,6 +530,7 @@ public class ModArith implements Deobfuscator
|
|||||||
execution.populateInitialMethods();
|
execution.populateInitialMethods();
|
||||||
execution.run();
|
execution.run();
|
||||||
|
|
||||||
|
findUses();
|
||||||
findUses2();
|
findUses2();
|
||||||
reduce2();
|
reduce2();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user