hey this passes the test but doesnt compile. allow tracking more than one pops for stackctx.

This commit is contained in:
Adam
2015-10-08 17:29:31 -04:00
parent f4c004b7ad
commit 9b4f4242eb
6 changed files with 81 additions and 880 deletions

View File

@@ -1,824 +0,0 @@
package net.runelite.deob.deobfuscators;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.runelite.deob.ClassFile;
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.attributes.code.instruction.types.SetFieldInstruction;
import net.runelite.deob.attributes.code.instructions.IMul;
import net.runelite.deob.execution.Execution;
import net.runelite.deob.execution.Frame;
import net.runelite.deob.execution.InstructionContext;
import net.runelite.deob.execution.StackContext;
public class ModularArithmeticDeobfuscation implements Deobfuscator
{
private Set<Field> obfuscatedFields; // reliability of these sucks
static class Magic
{
Field field;
int getter, setter;
boolean unknownGetter, unknownSetter;
}
static class Magics
{
Map<Field, Magic> magic = new HashMap<>();
Magic getMagic(Field field)
{
Magic m = magic.get(field);
if (m != null)
return m;
m = new Magic();
m.field = field;
magic.put(field, m);
return m;
}
void pass1()
{
int good = 0, bad = 0, calculated = 0, mismatch = 0;
for (Magic m : new ArrayList<>(magic.values()))
if (m.getter == 0 && m.setter == 0)
{
magic.remove(m.field);
++bad;
}
else if (m.getter == 0)
{
m.unknownGetter = false;
m.getter = modInverse(m.setter);
++calculated;
}
else if (m.setter == 0)
{
m.unknownSetter = false;
m.setter = modInverse(m.getter);
++calculated;
}
else if (m.getter != modInverse(m.setter) || m.setter != modInverse(m.getter))
{
magic.remove(m.field);
++mismatch;
}
else
{
++good;
}
System.out.println("Pass 1: Bad: " + bad + ", good: " + good + ", calculated " + calculated + ", mismatch: " + mismatch);
}
void pass2()
{
int found = 0;
for (Magic m : new ArrayList<>(magic.values()))
{
if (!m.unknownGetter && !m.unknownSetter && (m.setter != 0 || m.getter != 0))
{
++found;
}
}
System.out.println("Pass 2: Calculated " + found);
}
void merge(Magics other)
{
int merged = 0;
for (Magic m : other.magic.values())
{
Field f = m.field;
if (!this.magic.containsKey(f))
{
this.magic.put(f, m);
++merged;
continue;
}
System.err.println("field exists in both pass 1 and 2");
}
System.out.println("Merged " + merged);
}
}
private Field convertFieldFromPool(ClassGroup group, net.runelite.deob.pool.Field field)
{
ClassFile cf = group.findClass(field.getClassEntry().getName());
if (cf == null)
return null;
return cf.findFieldDeep(field.getNameAndType());
}
private List<net.runelite.deob.pool.Field> checkDown(InstructionContext context)
{
List<net.runelite.deob.pool.Field> fields = new ArrayList<>();
if (context.getInstruction() instanceof FieldInstruction)
{
FieldInstruction fi = (FieldInstruction) context.getInstruction();
fields.add(fi.getField());
}
for (StackContext ctx : context.getPops())
{
InstructionContext i = ctx.getPushed();
fields.addAll(checkDown(i));
}
return fields;
}
private List<net.runelite.deob.pool.Field> checkUp(InstructionContext context)
{
List<net.runelite.deob.pool.Field> fields = new ArrayList<>();
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();
fields.add(fi.getField());
}
for (StackContext ctx : context.getPushes())
{
InstructionContext i = ctx.getPopped();
if (i == null)
continue;
fields.addAll(checkUp(i));
}
return fields;
}
/* check there are no other fields */
private boolean checkFields(Magics goodMagics, ClassGroup group, Set<Field> obFields, net.runelite.deob.pool.Field imulField, InstructionContext context)
{
List<net.runelite.deob.pool.Field> fields = new ArrayList<>();
fields.addAll(checkUp(context));
fields.addAll(checkDown(context));
assert !fields.isEmpty();
for (net.runelite.deob.pool.Field f : fields)
{
if (f.equals(imulField))
continue;
Field field = convertFieldFromPool(group, f);
assert field != null;
if (!obFields.contains(field))
continue;
return false;
}
return true;
}
private List<InstructionContext> getDown(InstructionContext context)
{
List<InstructionContext> instructions = new ArrayList<>();
instructions.add(context);
for (StackContext ctx : context.getPops())
{
InstructionContext i = ctx.getPushed();
instructions.addAll(getDown(i));
}
return instructions;
}
private List<InstructionContext> getInstructions(InstructionContext context)
{
List<InstructionContext> instructions = new ArrayList<>();
instructions.add(context);
instructions.addAll(getDown(context));
return instructions;
}
private Set<Field> getObfuscatedFields(Execution execution, ClassGroup group)
{
Set<Field> fields = new HashSet<>();
// XXX this detects field = field * constant as ob when field isn't
for (Frame frame : execution.processedFrames)
{
for (InstructionContext ctx : frame.getInstructions())
{
if (ctx.getInstruction() instanceof IMul)
{
Instruction one = ctx.getPops().get(0).getPushed().getInstruction();
Instruction two = ctx.getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
GetFieldInstruction gf = null;
if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) one;
gf = (GetFieldInstruction) two;
}
else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) two;
gf = (GetFieldInstruction) one;
}
if (pc == null)
continue;
// get Field from pool Field
net.runelite.deob.pool.Field field = gf.getField();
Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType());
assert f != null;
fields.add(f);
}
else if (ctx.getInstruction() instanceof SetFieldInstruction)
{
SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction();
StackContext value = ctx.getPops().get(0); // what setfield pops as value
if (!(value.getPushed().getInstruction() instanceof IMul))
continue;
Instruction one = value.getPushed().getPops().get(0).getPushed().getInstruction();
Instruction two = value.getPushed().getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
Instruction other = null;
if (one instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) one;
other = two;
}
else if (two instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) two;
other = one;
}
if (pc == null)
continue;
// get Field from pool Field
net.runelite.deob.pool.Field field = sf.getField();
Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType());
assert f != null;
fields.add(f);
}
}
}
return fields;
}
private void detectSetters(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx)
{
if (!(ctx.getInstruction() instanceof SetFieldInstruction))
return;
SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction();
StackContext value = ctx.getPops().get(0); // what setfield pops as value
if (!(value.getPushed().getInstruction() instanceof IMul))
return;
Instruction one = value.getPushed().getPops().get(0).getPushed().getInstruction();
Instruction two = value.getPushed().getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
Instruction other = null;
if (one instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) one;
other = two;
}
else if (two instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) two;
other = one;
}
if (pc == null)
return;
if (!checkFields(goodMagics, group, obfuscatedFields, sf.getField(), value.getPushed()))
return;
//System.out.println("Setter " + sf.getField().getClassEntry().getName() + "." + sf.getField().getNameAndType().getName() + " -> " + pc.getConstant().toString());
int constant = Integer.parseInt(pc.getConstant().toString());
try
{
modInverse(constant);
}
catch (ArithmeticException ex)
{
//System.err.println("Constant " + constant + " passed setter logic tests but is not inversable");
//printWhatCalls(execution, frame.getMethod(), 0);
return; // if the constant isn't inversable then it can't be the right one
}
Field field = convertFieldFromPool(group, sf.getField());
Magic magic = workMagics.getMagic(field);
if (!magic.unknownSetter)
{
if (magic.setter == 0)
magic.setter = constant;
else if (magic.setter != constant)
{
magic.setter = 0;
magic.unknownSetter = true;
}
}
}
private void detectGetters(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx)
{
if (!(ctx.getInstruction() instanceof IMul))
return;
// check for push constant and for get field instruction
Instruction one = ctx.getPops().get(0).getPushed().getInstruction();
Instruction two = ctx.getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
GetFieldInstruction gf = null;
if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) one;
gf = (GetFieldInstruction) two;
}
else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) two;
gf = (GetFieldInstruction) one;
}
if (pc == null)
return;
int constant = Integer.parseInt(pc.getConstant().toString());
StackContext push = ctx.getPushes().get(0); // result of imul operation
InstructionContext popCtx = push.getPopped(); // instruction which popped the result of mul
if (popCtx == null)
{
return;
//System.err.println("Stack ctx never popped! Pushed by " + push.getPushed().getInstruction());
//int i = frame.getInstructions().indexOf(push.getPushed().getInstruction());
//System.err.println("next ins is " + frame.getInstructions().get(i + 1).getInstruction());
}
if (!checkFields(goodMagics, group, obfuscatedFields, gf.getField(), ctx))
return;
try
{
modInverse(constant);
}
catch (ArithmeticException ex)
{
//System.err.println("Constant " + constant + " passed getter logic tests but is not inversable");
//printWhatCalls(execution, frame.getMethod(), 0);
return; // if the constant isn't inversable then it can't be the right one
}
// get Field from pool Field
net.runelite.deob.pool.Field field = gf.getField();
Field f = group.findClass(field.getClassEntry().getName()).findFieldDeep(field.getNameAndType());
Magic magic = workMagics.getMagic(f);
if (!magic.unknownGetter)
{
if (magic.getter == 0)
magic.getter = constant;
else if (magic.getter != constant)
{
magic.getter = 0;
magic.unknownGetter = true;
}
}
}
private void detectCombined(Magics goodMagics, Magics workMagics, Execution execution, ClassGroup group, InstructionContext ctx)
{
// look for put involving one other field, assume constant is combined field getter/setter
if (!(ctx.getInstruction() instanceof SetFieldInstruction))
return;
SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction();
Field thisField = convertFieldFromPool(group, sf.getField());
List<InstructionContext> ins = getInstructions(ctx);
Field other = null;
int constant = 0;
for (InstructionContext i : ins)
if (i.getInstruction() instanceof FieldInstruction)
{
FieldInstruction fin = (FieldInstruction) i.getInstruction();
if (fin.getField().equals(sf.getField()))
continue;
if (other != null)
return;
other = convertFieldFromPool(group, fin.getField());
}
else if (i.getInstruction() instanceof PushConstantInstruction)
{
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
try
{
constant = Integer.parseInt(pci.getConstant().toString());
}
catch (NumberFormatException ex)
{
return;
}
}
if (other == null || constant == 0)
return;
if (goodMagics.magic.containsKey(thisField) && goodMagics.magic.containsKey(other))
return;
if (!thisField.getType().toString().equals("I") || !other.getType().toString().equals("I"))
return;
// thisField = operations with field/constant
//if (obfuscatedFields.contains(thisField) && obfuscatedFields.contains(other))
{
// constant is thisField setter * otherField getter
Magic thisMagic = goodMagics.magic.get(thisField);
Magic otherMagic = goodMagics.magic.get(other);
if (thisMagic == null && otherMagic == null)
{
System.err.println("Combined fields with no known good magic");
return;
}
//if (thisMagic != null && otherMagic != null)
//{
// return; // check?
//}
if (thisMagic == null)
{
//System.out.println("Combined 1");
// this = other * constant
// constant = other getter * this setter
// solve for this setter
// this setter = constant * modInverse(other.getter)
int thisSetter = constant * modInverse(otherMagic.getter);
if (thisSetter == 1)
{
System.out.println(thisField.getFields().getClassFile().getName() + "." + thisField.getName() + " is not obd");
// this means that this field isn't obbed
obfuscatedFields.remove(thisField);
otherMagic.setter = constant;
return;
}
System.out.println("Calculated setter for " + thisField.getFields().getClassFile().getName() + "." + thisField.getName() + " to be " + thisSetter);
Magic m = workMagics.getMagic(thisField);
if (!m.unknownSetter)
if (m.setter != 0 && m.setter != thisSetter)
{
System.err.println("Calculated setter mismatch");
m.unknownSetter = true;
m.setter = 0;
}
m.setter = thisSetter;
}
else if (otherMagic == null)
{
//System.out.println("Combined 2");
// this = other * constant
// constant = other getter * this setter
// solve for other getter
// other getter = constant * modInverse(this setter)
int otherGetter = constant * modInverse(thisMagic.setter);
if (otherGetter == 1)
{
System.out.println(other.getFields().getClassFile().getName() + "." + other.getName() + " is not obd");
obfuscatedFields.remove(other);
thisMagic.getter = constant;
return;
}
System.out.println("Calculated getter for " + other.getFields().getClassFile().getName() + "." + other.getName() + " to be " + otherGetter);
Magic m = workMagics.getMagic(other);
if (!m.unknownGetter)
if (m.getter != 0 && m.getter != otherGetter)
{
System.err.println("Calculated getter mismatch");
m.unknownGetter = true;
m.getter = 0;
}
m.getter = otherGetter;
}
}
/*
else if (obfuscatedFields.contains(thisField))
{
// constant is this fields setter
System.out.println("Only one field is obd 1 " + thisField.getFields().getClassFile().getName() + "." + thisField.getName()
+ ", " + other.getFields().getClassFile().getName() + "." + other.getName());
}
else if (obfuscatedFields.contains(other))
{
// constant is other fields getter
System.out.println("Only one field is obd 2");
}
else
{
System.err.println("detected combined field with both fields non obfuscated. " + thisField.getFields().getClassFile().getName() + "." + thisField.getName()
+ ", " + other.getFields().getClassFile().getName() + "." + other.getName());
//return;
}*/
}
private void check(Magics magics)
{
int missing = 0, mismatch = 0, good = 0, half = 0;
for (Field f : obfuscatedFields)
{
Magic magic = magics.magic.get(f);
if (magic == null)
{
System.err.println(f.getFields().getClassFile().getName() + "." + f.getName() + " is obfuscated, but no magic found");
++missing;
continue;
}
if (magic.getter != 0 && magic.setter != 0)
{
if (magic.getter != modInverse(magic.setter) || magic.setter != modInverse(magic.getter))
{
++mismatch;
System.err.println(f.getFields().getClassFile().getName() + "." + f.getName() + " has mismatch, get " + magic.getter + ", set " + magic.setter + ", modInverse(get) " + modInverse(magic.getter) + ", modInverse(set) " + modInverse(magic.setter));
}
else
{
++good;
//System.out.println(f.getFields().getClassFile().getName() + "." + f.getName() + " has get " + magic.getter + ", set " + magic.setter);
}
}
else
{
++half;
System.out.println(f.getFields().getClassFile().getName() + "." + f.getName() + " 2 has get " + magic.getter + ", set " + magic.setter);
}
}
System.out.println("Check done missing: "+ missing + ", mismatch: " + mismatch + ", good: " + good + ", half: " + half);
}
private void run(Magics magics /* known good */, Magics work, Execution execution, ClassGroup group)
{
obfuscatedFields = getObfuscatedFields(execution, group);
for (Frame frame : execution.processedFrames)
{
for (InstructionContext ctx : frame.getInstructions())
{
if (magics == null)
{
detectGetters(magics, work, execution, group, ctx);
detectSetters(magics, work, execution, group, ctx);
}
else
if (magics != null)
detectCombined(magics, work, execution, group, ctx);
}
}
//if (magics == null)
//check(work);
}
private static BigInteger modInverse(BigInteger val, int bits)
{
BigInteger shift = BigInteger.ONE.shiftLeft(bits);
return val.modInverse(shift);
}
private static int modInverse(int val)
{
return modInverse(BigInteger.valueOf(val), 32).intValue();
}
private static long modInverse(long val)
{
return modInverse(BigInteger.valueOf(val), 64).longValue();
}
@Override
public void run(ClassGroup group)
{
group.buildClassGraph();
Execution execution = new Execution(group);
execution.populateInitialMethods();
execution.run();
Magics work = new Magics();
run(null, work, execution, group);
work.pass1();
// check(work);
System.out.println("END OF PASS 1");
Magics magics = work;
work = new Magics();
run(magics, work, execution, group);
work.pass2();
magics.merge(work);
check(magics);
replace(execution, group, magics);
}
private void replace(Execution execution, ClassGroup group, Magics magics)
{
Set<Instruction> done = new HashSet<>();
int replaced = 0;
for (Frame frame : execution.processedFrames)
{
for (InstructionContext ctx : frame.getInstructions())
{
if (ctx.getInstruction() instanceof IMul)
{
Instruction one = ctx.getPops().get(0).getPushed().getInstruction();
Instruction two = ctx.getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
GetFieldInstruction gf = null;
if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) one;
gf = (GetFieldInstruction) two;
}
else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction)
{
pc = (PushConstantInstruction) two;
gf = (GetFieldInstruction) one;
}
if (pc == null)
continue;
Magic m = magics.magic.get(this.convertFieldFromPool(group, gf.getField()));
if (m == null)
{
System.out.println("No magc for field " + gf.getField());
continue;
}
if (done.contains(ctx.getInstruction()))
continue;
done.add(ctx.getInstruction());
int constant = Integer.parseInt(pc.getConstant().toString());
// we have field * constant
// eg constant is 42 * getter do * modInverse(getter) to get result
//assert m.setter == modInverse(m.getter);
int newConstant = constant * m.setter;
Instruction i2 = pc.setConstant(new net.runelite.deob.pool.Integer(newConstant));
assert i2 == (Instruction) pc;
if (newConstant != 1)
System.out.println("new constant: " + newConstant);
else
++replaced;
}
else if (ctx.getInstruction() instanceof SetFieldInstruction)
{
SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction();
StackContext value = ctx.getPops().get(0); // what setfield pops as value
if (value.getPushed().getInstruction() instanceof PushConstantInstruction)
{
// field = constant
PushConstantInstruction pi = (PushConstantInstruction) value.getPushed().getInstruction();
Magic m = magics.magic.get(this.convertFieldFromPool(group, sf.getField()));
if (m == null)
continue;
int constant = Integer.parseInt(pi.getConstant().toString());
if (done.contains(ctx.getInstruction()))
continue;
done.add(ctx.getInstruction());
// field = setter * value, solve for value by * modInverse(setter)
int newConstant = constant * m.getter;
Instruction i2 = pi.setConstant(new net.runelite.deob.pool.Integer(newConstant));
assert i2 == (Instruction) pi;
++replaced;
}
else if (value.getPushed().getInstruction() instanceof IMul)
{
InstructionContext imul = value.getPushed();
StackContext one = imul.getPops().get(0), two = imul.getPops().get(1);
PushConstantInstruction pc;
if (one.getPushed().getInstruction() instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) one.getPushed().getInstruction();
}
else if (two.getPushed().getInstruction() instanceof PushConstantInstruction)
{
pc = (PushConstantInstruction) two.getPushed().getInstruction();
}
else
{
continue;
}
int constant = Integer.parseInt(pc.getConstant().toString());
Magic m = magics.magic.get(this.convertFieldFromPool(group, sf.getField()));
if (m == null)
continue;
if (done.contains(ctx.getInstruction()))
continue;
done.add(ctx.getInstruction());
// field = expression * constant
int newConstant = constant * m.getter;
Instruction i2 = pc.setConstant(new net.runelite.deob.pool.Integer(newConstant));
assert i2 == (Instruction) pc;
++replaced;
}
}
}
}
System.out.println("Replaced " + replaced + " constants");
}
}

View File

@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import net.runelite.deob.ClassGroup;
import net.runelite.deob.Deobfuscator;
@@ -42,7 +43,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
System.out.println("Total changed " + count);
}
private MultiplicationExpression parseExpression(InstructionContext ctx)
private MultiplicationExpression parseExpression(Execution e, InstructionContext ctx)
{
MultiplicationExpression me = new MultiplicationExpression();
@@ -59,6 +60,12 @@ public class MultiplicationDeobfuscator implements Deobfuscator
return me;
}
if (ctx.getInstruction() instanceof IMul)
{
if (!this.isOnlyPath(e, ctx))
throw new IllegalStateException();
}
for (StackContext sctx : ctx.getPops())
{
InstructionContext i = sctx.getPushed();
@@ -91,7 +98,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
// chained imul, append to me
try
{
MultiplicationExpression other = parseExpression(i);
MultiplicationExpression other = parseExpression(e, i);
me.instructions.addAll(other.instructions);
me.subexpressions.addAll(other.subexpressions);
@@ -106,7 +113,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
// imul using result of iadd or isub. evaluate expression
try
{
MultiplicationExpression other = parseExpression(i);
MultiplicationExpression other = parseExpression(e, i);
// subexpr
//if (other != null)
@@ -129,7 +136,8 @@ public class MultiplicationDeobfuscator implements Deobfuscator
// find other branch of the dup instruction
// sctx = what dup pushed, find other
StackContext otherCtx = dup.getOtherBranch(sctx); // other side of dup
InstructionContext otherCtxI = otherCtx.getPopped(); // would insert imul here?
//InstructionContext otherCtxI = otherCtx.getPopped(); // would insert imul here?
InstructionContext otherCtxI = otherCtx.getPopped().get(0); // is this irght?
if (otherCtxI.getInstruction() instanceof IMul)
{
@@ -143,7 +151,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
StackContext orig = dup.getOriginal(sctx); // original
try
{
MultiplicationExpression other = parseExpression(orig.getPushed());
MultiplicationExpression other = parseExpression(e, orig.getPushed());
// this expression is used elsewhere like 'pushConstant' so any changes
// done to it affect that, too. so multiply it by existing values?
if (orig.getPushed().getInstruction() instanceof IAdd || orig.getPushed().getInstruction() instanceof ISub)
@@ -182,7 +190,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
// this is an iadd/sub
else if (ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub)
{
MultiplicationExpression other = parseExpression(i); // parse this side of the add/sub
MultiplicationExpression other = parseExpression(e, i); // parse this side of the add/sub
//if (other != null)
me.subexpressions.add(other);
@@ -216,39 +224,46 @@ public class MultiplicationDeobfuscator implements Deobfuscator
}
// for each instruction ctx in ths expression, see if it !equals any other for each ins?
//
// private List<InstructionContext> getInsInExpr(InstructionContext ctx, Set<Instruction> set)
// {
// List<InstructionContext> l = new ArrayList<>();
//
// if (ctx == null || set.contains(ctx.getInstruction()))
// return l;
//
// set.add(ctx.getInstruction());
//
// l.add(ctx);
// for (StackContext s : ctx.getPops())
// l.addAll(getInsInExpr(s.getPushed(), set));
// for (StackContext s : ctx.getPushes())
// l.addAll(getInsInExpr(s.getPopped(), set));
//
// return l;
// }
private List<InstructionContext> getInsInExpr(InstructionContext ctx, Set<Instruction> set)
{
List<InstructionContext> l = new ArrayList<>();
if (ctx == null || set.contains(ctx.getInstruction()))
return l;
set.add(ctx.getInstruction());
l.add(ctx);
for (StackContext s : ctx.getPops())
l.addAll(getInsInExpr(s.getPushed(), set));
for (StackContext s : ctx.getPushes())
l.addAll(getInsInExpr(s.getPopped(), set));
return l;
}
private boolean isOnlyPath(Execution execution, InstructionContext ctx)
public static boolean isOnlyPath(Execution execution, InstructionContext ctx)
{
assert ctx.getInstruction() instanceof IMul;
Collection<InstructionContext> ins = execution.getInstructonContexts(ctx.getInstruction());
for (InstructionContext i : ins)
//for (Frame f : execution.processedFrames)
// if (f.getMethod() == frame.getMethod())
// for (InstructionContext i : f.getInstructions())
//if (i.getInstruction() == ctx.getInstruction())
{
if (!i.equals(ctx))
{
return false;
}
}
{
if (!i.equals(ctx))
{
return false;
}
for (StackContext sctx : i.getPushes())
if (sctx.getPopped().size() > 1)
return false;
///if (i.getPushes().size() > 1)
// return false;
// if (!Objects.equals(i.getPushes().get(0).getPopped(), ctx.getPushes().get(0).getPopped()))
// {
// return false;
// }
}
return true;
}
@@ -267,7 +282,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
int mcount = 0;
for (Frame frame : e.processedFrames)
outer:
//outer:
for (InstructionContext ictx : frame.getInstructions())
{
Instruction instruction = ictx.getInstruction();
@@ -305,7 +320,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
MultiplicationExpression expression;
try
{
expression = parseExpression(ictx);
expression = parseExpression(e, ictx);
}
catch (IllegalStateException ex)
{
@@ -319,11 +334,11 @@ public class MultiplicationDeobfuscator implements Deobfuscator
// continue;
// there can only be one path to here, or else combinging would change code logic
List<InstructionContext> ilist = this.getInsInExpr(ictx, new HashSet());
for (InstructionContext i2 : ilist)
if (i2.getInstruction() instanceof IMul)
if (!isOnlyPath(e, i2))
continue outer;
// List<InstructionContext> ilist = this.getInsInExpr(ictx, new HashSet());
// for (InstructionContext i2 : ilist)
// if (i2.getInstruction() instanceof IMul)
// if (!isOnlyPath(e, i2))
// continue outer;
if (done.contains(instruction))

View File

@@ -30,6 +30,8 @@ public class Frame
private Variables variables;
private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame
private MultiValueMap<InstructionContext, Instruction> visited = new MultiValueMap<>(); // shared
public static long num;
public Frame(Execution execution, Method method)
{

View File

@@ -16,6 +16,7 @@ public class InstructionContext
private List<StackContext> pushes = new ArrayList<>(); // stack contexts pushed by instruction execution
private List<VariableContext> reads = new ArrayList<>(); // lvt reads
private List<Method> invokes = new ArrayList<>(); // invokes
public long frameNum;
public InstructionContext(Instruction i, Frame f)
{
@@ -28,7 +29,7 @@ public class InstructionContext
{
for (StackContext c : ctx)
{
c.setPopped(this); // now we know which instruction popped this, record it
c.addPopped(this); // now we know which instruction popped this, record it
pops.add(c);
}
}

View File

@@ -6,7 +6,7 @@ import java.util.List;
public class StackContext
{
public InstructionContext pushed; // instruction which pushed this
public InstructionContext popped; // instruction which popped this
public List<InstructionContext> poppeds = new ArrayList<>(); // instructions 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
@@ -34,14 +34,18 @@ public class StackContext
return pushed;
}
public InstructionContext getPopped()
public List<InstructionContext> getPopped()
{
return popped;
return poppeds;
}
public void setPopped(InstructionContext popped)
public void addPopped(InstructionContext popped)
{
this.popped = popped;
//assert !this.poppeds.contains(popped);
if (!this.poppeds.contains(popped))
this.poppeds.add(popped);
//assert this.popped == null;
//this.popped = popped;
}
public Type getType()

View File

@@ -1,5 +1,6 @@
package net.runelite.deob.deobfuscators.arithmetic;
import java.util.Collection;
import net.runelite.deob.ClassGroup;
import net.runelite.deob.ClassGroupFactory;
import net.runelite.deob.Deobfuscator;
@@ -7,26 +8,19 @@ 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.Dup_X1;
import net.runelite.deob.attributes.code.instructions.Goto;
import net.runelite.deob.attributes.code.instructions.IAdd;
import net.runelite.deob.attributes.code.instructions.IConst_0;
import net.runelite.deob.attributes.code.instructions.IConst_1;
import net.runelite.deob.attributes.code.instructions.IConst_2;
import net.runelite.deob.attributes.code.instructions.IConst_3;
import net.runelite.deob.attributes.code.instructions.IDiv;
import net.runelite.deob.attributes.code.instructions.ILoad;
import net.runelite.deob.attributes.code.instructions.IMul;
import net.runelite.deob.attributes.code.instructions.IStore;
import net.runelite.deob.attributes.code.instructions.IStore_0;
import net.runelite.deob.attributes.code.instructions.IStore_1;
import net.runelite.deob.attributes.code.instructions.IStore_2;
import net.runelite.deob.attributes.code.instructions.If;
import net.runelite.deob.attributes.code.instructions.If0;
import net.runelite.deob.attributes.code.instructions.LDC_W;
import net.runelite.deob.attributes.code.instructions.NOP;
import net.runelite.deob.attributes.code.instructions.Pop;
import net.runelite.deob.attributes.code.instructions.VReturn;
import net.runelite.deob.execution.Execution;
import net.runelite.deob.execution.InstructionContext;
import org.junit.Assert;
import org.junit.Test;
@@ -303,6 +297,15 @@ public class MultiplicationDeobfuscatorTest
assert constant4.getConstantAsInt() * constant5.getConstantAsInt() == 1;
{
Collection<InstructionContext> ctxs = e.getInstructonContexts(body[3]);
assert ctxs.size() == 1;
InstructionContext ictx = ctxs.iterator().next();
boolean onlyPath = MultiplicationDeobfuscator.isOnlyPath(e, ictx);
Assert.assertFalse(onlyPath);
}
Deobfuscator d = new MultiplicationDeobfuscator();
d.run(group);