diff --git a/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java b/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java deleted file mode 100644 index 927fb5c13f..0000000000 --- a/src/main/java/net/runelite/deob/deobfuscators/ModularArithmeticDeobfuscation.java +++ /dev/null @@ -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 obfuscatedFields; // reliability of these sucks - - static class Magic - { - Field field; - int getter, setter; - boolean unknownGetter, unknownSetter; - } - - static class Magics - { - Map 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 checkDown(InstructionContext context) - { - List 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 checkUp(InstructionContext context) - { - List 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 obFields, net.runelite.deob.pool.Field imulField, InstructionContext context) - { - List 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 getDown(InstructionContext context) - { - List instructions = new ArrayList<>(); - - instructions.add(context); - - for (StackContext ctx : context.getPops()) - { - InstructionContext i = ctx.getPushed(); - - instructions.addAll(getDown(i)); - } - - return instructions; - } - - private List getInstructions(InstructionContext context) - { - List instructions = new ArrayList<>(); - - instructions.add(context); - - instructions.addAll(getDown(context)); - - return instructions; - } - - private Set getObfuscatedFields(Execution execution, ClassGroup group) - { - Set 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 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 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"); - } -} diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java index c6749cdb1a..9ee09713dc 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscator.java @@ -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 getInsInExpr(InstructionContext ctx, Set set) +// { +// List 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 getInsInExpr(InstructionContext ctx, Set set) - { - List 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 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 ilist = this.getInsInExpr(ictx, new HashSet()); - for (InstructionContext i2 : ilist) - if (i2.getInstruction() instanceof IMul) - if (!isOnlyPath(e, i2)) - continue outer; +// List 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)) diff --git a/src/main/java/net/runelite/deob/execution/Frame.java b/src/main/java/net/runelite/deob/execution/Frame.java index ade776f508..5fa1af7cfc 100644 --- a/src/main/java/net/runelite/deob/execution/Frame.java +++ b/src/main/java/net/runelite/deob/execution/Frame.java @@ -30,6 +30,8 @@ public class Frame private Variables variables; private List instructions = new ArrayList<>(); // instructions executed in this frame private MultiValueMap visited = new MultiValueMap<>(); // shared + + public static long num; public Frame(Execution execution, Method method) { diff --git a/src/main/java/net/runelite/deob/execution/InstructionContext.java b/src/main/java/net/runelite/deob/execution/InstructionContext.java index 903cdbd837..fad054668b 100644 --- a/src/main/java/net/runelite/deob/execution/InstructionContext.java +++ b/src/main/java/net/runelite/deob/execution/InstructionContext.java @@ -16,6 +16,7 @@ public class InstructionContext private List pushes = new ArrayList<>(); // stack contexts pushed by instruction execution private List reads = new ArrayList<>(); // lvt reads private List 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); } } diff --git a/src/main/java/net/runelite/deob/execution/StackContext.java b/src/main/java/net/runelite/deob/execution/StackContext.java index 78d4a75f9d..ced878477c 100644 --- a/src/main/java/net/runelite/deob/execution/StackContext.java +++ b/src/main/java/net/runelite/deob/execution/StackContext.java @@ -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 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 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() diff --git a/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java b/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java index 006d5f1512..7d304f5280 100644 --- a/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java +++ b/src/test/java/net/runelite/deob/deobfuscators/arithmetic/MultiplicationDeobfuscatorTest.java @@ -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 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);