Search in sources :

Example 1 with PushConstantInstruction

use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.

the class MenuActionDeobfuscator method run.

private void run(Method method) {
    if (method.getCode() == null) {
        return;
    }
    Execution execution = new Execution(method.getClassFile().getGroup());
    execution.addMethod(method);
    execution.noInvoke = true;
    Multimap<Integer, Comparison> comps = HashMultimap.create();
    execution.addExecutionVisitor((InstructionContext ictx) -> {
        Instruction i = ictx.getInstruction();
        Frame frame = ictx.getFrame();
        if (i instanceof If) {
            // constant
            InstructionContext ctx1 = ictx.getPops().get(0).getPushed();
            // lvt
            InstructionContext ctx2 = ictx.getPops().get(1).getPushed();
            if (ctx1.getInstruction() instanceof PushConstantInstruction && ctx2.getInstruction() instanceof LVTInstruction) {
                Comparison comparison = new Comparison();
                comparison.cmp = i;
                comparison.ldc = ctx1.getInstruction();
                comparison.lvt = (LVTInstruction) ctx2.getInstruction();
                comps.put(comparison.lvt.getVariableIndex(), comparison);
            }
        }
    });
    execution.run();
    for (int i : comps.keySet()) {
        Collection<Comparison> get = comps.get(i);
        long l = get.stream().filter(c -> c.cmp.getType() == IF_ICMPGE || c.cmp.getType() == IF_ICMPGT || c.cmp.getType() == IF_ICMPLE || c.cmp.getType() == IF_ICMPLT).count();
        List<Comparison> eqcmp = get.stream().filter(c -> c.cmp.getType() == IF_ICMPEQ || c.cmp.getType() == IF_ICMPNE).collect(Collectors.toList());
        if (get.size() > THRESHOLD_EQ && l <= THRESHOLD_LT) {
            logger.info("Sorting {} comparisons in {}", eqcmp.size(), method);
            insert(method, eqcmp);
        }
    }
}
Also used : IfICmpEq(net.runelite.asm.attributes.code.instructions.IfICmpEq) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) LoggerFactory(org.slf4j.LoggerFactory) Multimap(com.google.common.collect.Multimap) IF_ICMPGE(net.runelite.asm.attributes.code.InstructionType.IF_ICMPGE) Goto(net.runelite.asm.attributes.code.instructions.Goto) ArrayList(java.util.ArrayList) ClassGroup(net.runelite.asm.ClassGroup) HashMultimap(com.google.common.collect.HashMultimap) Method(net.runelite.asm.Method) IF_ICMPNE(net.runelite.asm.attributes.code.InstructionType.IF_ICMPNE) If(net.runelite.asm.attributes.code.instructions.If) IF_ICMPEQ(net.runelite.asm.attributes.code.InstructionType.IF_ICMPEQ) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) IF_ICMPGT(net.runelite.asm.attributes.code.InstructionType.IF_ICMPGT) Frame(net.runelite.asm.execution.Frame) Logger(org.slf4j.Logger) InstructionType(net.runelite.asm.attributes.code.InstructionType) IF_ICMPLT(net.runelite.asm.attributes.code.InstructionType.IF_ICMPLT) Collection(java.util.Collection) IF_ICMPLE(net.runelite.asm.attributes.code.InstructionType.IF_ICMPLE) Deobfuscator(net.runelite.deob.Deobfuscator) Collectors(java.util.stream.Collectors) InstructionContext(net.runelite.asm.execution.InstructionContext) Execution(net.runelite.asm.execution.Execution) List(java.util.List) ClassFile(net.runelite.asm.ClassFile) Label(net.runelite.asm.attributes.code.Label) IfICmpNe(net.runelite.asm.attributes.code.instructions.IfICmpNe) Instructions(net.runelite.asm.attributes.code.Instructions) Instruction(net.runelite.asm.attributes.code.Instruction) Collections(java.util.Collections) InstructionContext(net.runelite.asm.execution.InstructionContext) Frame(net.runelite.asm.execution.Frame) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) Instruction(net.runelite.asm.attributes.code.Instruction) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) Execution(net.runelite.asm.execution.Execution) If(net.runelite.asm.attributes.code.instructions.If)

Example 2 with PushConstantInstruction

use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.

the class IfICmpEq method is.

static boolean is(StackContext s, int val) {
    if (s.getPushed().getInstruction() instanceof PushConstantInstruction) {
        PushConstantInstruction pc = (PushConstantInstruction) s.getPushed().getInstruction();
        Object o = pc.getConstant();
        if (o instanceof Integer && (int) o == val) {
            return true;
        }
    }
    return false;
}
Also used : PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction)

Example 3 with PushConstantInstruction

use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.

the class DrawAfterWidgets method injectDrawAfterWidgets.

private void injectDrawAfterWidgets() throws InjectionException {
    /*
			This call has to be injected using raw injection because the
			drawWidgets method gets inlined in some revisions. If it wouldn't be,
			mixins would be used to add the call to the end of drawWidgets.

			--> This hook depends on the positions of "if (535573958 * kl != -1)" and "jz.db();".


			Revision 153 - client.ll():
			______________________________________________________

			if (535573958 * kl != -1) {
				me = 0;
				var1 = kl * 1593233303;
				var2 = 523525871 * q;
				var3 = -1668171507 * h.n;
				if (!bo.p(var1, (byte)111)) {
					for(var4 = 0; var4 < 100; ++var4) {
						mb[var4] = true;
					}
				} else {
					z.lj = null;
					bl.hz(fa.g[var1], -1, 0, 0, var2, var3, 0, 0, -1, 1505114436);
					if (z.lj != null) {
						bl.hz(z.lj, -1412584499, 0, 0, var2, var3, 1475313862 * bq.la, aq.lc * 1205565233, -1, 2123188146);
						z.lj = null;
					}
				}
			}

			// <-- INJECT CALL HERE

			jz.db(); <-- noClip method
			______________________________________________________
		 */
    boolean injected = false;
    Method noClip = findStaticMethod("noClip");
    if (noClip == null) {
        throw new InjectionException("Mapped method \"noClip\" could not be found.");
    }
    net.runelite.asm.pool.Method poolNoClip = noClip.getPoolMethod();
    for (ClassFile c : inject.getVanilla().getClasses()) {
        for (Method m : c.getMethods()) {
            if (m.getCode() == null) {
                continue;
            }
            Instructions instructions = m.getCode().getInstructions();
            Set<Label> labels = new HashSet<>();
            // Let's find "invokestatic <some class>.noClip()" and its label
            ListIterator<Instruction> labelIterator = instructions.getInstructions().listIterator();
            while (labelIterator.hasNext()) {
                Instruction i = labelIterator.next();
                if (!(i instanceof InvokeStatic)) {
                    continue;
                }
                InvokeStatic is = (InvokeStatic) i;
                if (!is.getMethod().equals(poolNoClip)) {
                    continue;
                }
                labelIterator.previous();
                Instruction i2 = labelIterator.previous();
                labelIterator.next();
                labelIterator.next();
                // Find the label that marks the code path for the instruction
                if (!(i2 instanceof Label)) {
                    continue;
                }
                // There can be several noClip invocations in a method, so let's catch them all
                labels.add((Label) i2);
            }
            if (labels.isEmpty()) {
                // If we get here, we're either in the wrong method
                // or Jagex has removed the "if (535573958 * kl != -1)"
                logger.debug("Could not find the label for jumping to the " + noClip + " call in " + m);
                continue;
            }
            Set<Label> labelsToInjectAfter = new HashSet<>();
            ListIterator<Instruction> jumpIterator = instructions.getInstructions().listIterator();
            while (jumpIterator.hasNext()) {
                Instruction i = jumpIterator.next();
                if (!(i instanceof JumpingInstruction)) {
                    continue;
                }
                JumpingInstruction ji = (JumpingInstruction) i;
                Label label = null;
                for (Label l : labels) {
                    if (ji.getJumps().contains(l)) {
                        label = l;
                        break;
                    }
                }
                if (label == null) {
                    continue;
                }
                jumpIterator.previous();
                Set<Instruction> insns = new HashSet<>();
                insns.add(jumpIterator.previous());
                insns.add(jumpIterator.previous());
                insns.add(jumpIterator.previous());
                insns.add(jumpIterator.previous());
                // Get the iterator back to i's position
                jumpIterator.next();
                jumpIterator.next();
                jumpIterator.next();
                jumpIterator.next();
                jumpIterator.next();
                /*
						Check that these instruction types are passed into the if-statement:

						ICONST_M1
						GETSTATIC client.kr : I
						LDC 634425425
						IMUL

						We cannot depend on the order of these because of the obfuscation,
						so let's make it easier by just checking that they are there.
					 */
                if (insns.stream().filter(i2 -> i2 instanceof PushConstantInstruction).count() != 2 || insns.stream().filter(i2 -> i2 instanceof IMul).count() != 1 || insns.stream().filter(i2 -> i2 instanceof GetStatic).count() != 1) {
                    continue;
                }
                // At this point, we have found the real injection point
                labelsToInjectAfter.add(label);
            }
            for (Label l : labelsToInjectAfter) {
                InvokeStatic invoke = new InvokeStatic(instructions, new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(HOOKS), "drawAfterWidgets", new Signature("()V")));
                instructions.addInstruction(instructions.getInstructions().indexOf(l) + 1, invoke);
                logger.info("injectDrawAfterWidgets injected a call after " + l);
                injected = true;
            }
        }
    }
    if (!injected) {
        throw new InjectionException("injectDrawAfterWidgets failed to inject!");
    }
}
Also used : DeobAnnotations(net.runelite.deob.DeobAnnotations) Logger(org.slf4j.Logger) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) ListIterator(java.util.ListIterator) HOOKS(net.runelite.injector.InjectHookMethod.HOOKS) IMul(net.runelite.asm.attributes.code.instructions.IMul) LoggerFactory(org.slf4j.LoggerFactory) Set(java.util.Set) Inject(net.runelite.injector.Inject) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic) HashSet(java.util.HashSet) ClassFile(net.runelite.asm.ClassFile) Label(net.runelite.asm.attributes.code.Label) Method(net.runelite.asm.Method) Instructions(net.runelite.asm.attributes.code.Instructions) JumpingInstruction(net.runelite.asm.attributes.code.instruction.types.JumpingInstruction) InjectionException(net.runelite.injector.InjectionException) Signature(net.runelite.asm.signature.Signature) Instruction(net.runelite.asm.attributes.code.Instruction) GetStatic(net.runelite.asm.attributes.code.instructions.GetStatic) ClassFile(net.runelite.asm.ClassFile) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) Label(net.runelite.asm.attributes.code.Label) Instructions(net.runelite.asm.attributes.code.Instructions) Method(net.runelite.asm.Method) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) JumpingInstruction(net.runelite.asm.attributes.code.instruction.types.JumpingInstruction) Instruction(net.runelite.asm.attributes.code.Instruction) InjectionException(net.runelite.injector.InjectionException) JumpingInstruction(net.runelite.asm.attributes.code.instruction.types.JumpingInstruction) GetStatic(net.runelite.asm.attributes.code.instructions.GetStatic) Signature(net.runelite.asm.signature.Signature) IMul(net.runelite.asm.attributes.code.instructions.IMul) HashSet(java.util.HashSet) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic)

Example 4 with PushConstantInstruction

use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.

the class MultiplicationDeobfuscator method parseExpression.

public static MultiplicationExpression parseExpression(InstructionContext ctx, Class want) {
    MultiplicationExpression me = new MultiplicationExpression();
    if (ctx.getInstruction() instanceof LVTInstruction) {
        LVTInstruction lvt = (LVTInstruction) ctx.getInstruction();
        // loading a variable
        if (!lvt.store()) {
            // var index
            int idx = lvt.getVariableIndex();
            // variables at time of execution
            Variables vars = ctx.getVariables();
            // get the variable
            VariableContext vctx = vars.get(idx);
            if (// ?
            vctx.getRead().size() == 1) {
                // this is an istore
                InstructionContext storeCtx = vctx.getInstructionWhichStored();
                if (storeCtx.getInstruction() instanceof LVTInstruction) {
                    // invoking funcs can put stuff in lvt
                    LVTInstruction storelvt = (LVTInstruction) storeCtx.getInstruction();
                    if (storelvt instanceof IInc)
                        throw new IllegalStateException();
                    assert storelvt.store();
                    InstructionContext pushed = storeCtx.getPops().get(0).getPushed();
                    return parseExpression(pushed, want);
                }
            }
        }
    }
    if (ctx.getInstruction() instanceof PushConstantInstruction) {
        if (ctx.getInstruction() instanceof BiPush || ctx.getInstruction() instanceof SiPush) {
            throw new IllegalStateException();
        }
        me.instructions.add(ctx);
        return me;
    }
    for (StackContext sctx : ctx.getPops()) {
        if (ctx.getInstruction().getClass() == want) {
            if (!isOnlyPath(ctx, sctx))
                continue;
        }
        InstructionContext i = sctx.getPushed();
        // if this instruction is imul, look at pops
        if (ctx.getInstruction().getClass() == want) {
            if (i.getInstruction() instanceof Swap) {
                logger.debug("Resolving swap");
                Swap swap = (Swap) i.getInstruction();
                sctx = swap.getOriginal(sctx);
                i = sctx.getPushed();
            }
            if (i.getInstruction() instanceof PushConstantInstruction) {
                // bipush/sipush are always not obfuscated
                if (i.getInstruction() instanceof BiPush || i.getInstruction() instanceof SiPush)
                    continue;
                // a constant of imul
                me.instructions.add(i);
            } else if (i.getInstruction().getClass() == want) {
                // chained imul, append to me
                try {
                    MultiplicationExpression other = parseExpression(i, want);
                    if (other.dupmagic != null) {
                        assert me.dupmagic == null;
                        me.dupmagic = other.dupmagic;
                    }
                    me.instructions.addAll(other.instructions);
                    me.dupedInstructions.addAll(other.dupedInstructions);
                    me.subexpressions.addAll(other.subexpressions);
                } catch (IllegalStateException ex) {
                // this is ok? just don't include it?
                }
            } else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub || i.getInstruction() instanceof LAdd || i.getInstruction() instanceof LSub) {
                // imul using result of iadd or isub. evaluate expression
                try {
                    MultiplicationExpression other = parseExpression(i, want);
                    assert other.dupmagic == null;
                    // subexpr
                    me.subexpressions.add(other);
                } catch (IllegalStateException ex) {
                    assert me.subexpressions.isEmpty();
                // subexpression is too complex. we can still simplify the top level though
                }
            } else if (i.getInstruction() instanceof DupInstruction) {
                DupInstruction dup = (DupInstruction) i.getInstruction();
                // find other branch of the dup instruction
                // sctx = what dup pushed, find other
                // other side of dup
                StackContext otherCtx = dup.getOtherBranch(sctx);
                // what popped other side of dup. is this right?
                InstructionContext otherCtxI = otherCtx.getPopped().get(0);
                if (otherCtxI.getInstruction().getClass() == want) {
                    // assert otherCtxI.getInstruction() instanceof IMul;
                    // other side of that imul
                    InstructionContext pushConstant = otherCtxI.getPops().get(0).getPushed();
                    assert pushConstant.getInstruction() instanceof LDC;
                    me.dupmagic = pushConstant;
                    // original
                    StackContext orig = dup.getOriginal(sctx);
                    try {
                        MultiplicationExpression other = parseExpression(orig.getPushed(), want);
                        // done to it affect that, too. so multiply it by existing values?
                        if (orig.getPushed().getInstruction() instanceof IAdd || orig.getPushed().getInstruction() instanceof ISub || orig.getPushed().getInstruction() instanceof LAdd || orig.getPushed().getInstruction() instanceof LSub) {
                            me.subexpressions.add(other);
                        } else {
                            assert other.dupmagic == null;
                            me.instructions.addAll(other.instructions);
                            me.dupedInstructions.addAll(other.instructions);
                            me.subexpressions.addAll(other.subexpressions);
                        }
                    } catch (IllegalStateException ex) {
                        assert me.subexpressions.isEmpty();
                    }
                }
            } else if (i.getInstruction() instanceof GetFieldInstruction) {
                me.fieldInstructions.add(i);
            // non constant, ignore
            } else {
            // System.out.println("imul pops something I don't know " + i.getInstruction());
            }
        } else // this is an iadd/sub
        if (ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub || ctx.getInstruction() instanceof LAdd || ctx.getInstruction() instanceof LSub) {
            // parse this side of the add/sub
            MultiplicationExpression other = parseExpression(i, want);
            me.subexpressions.add(other);
        } else {
        // System.out.println(ctx.getInstruction() + " pops something I dont know " + i.getInstruction());
        }
    }
    if (me.instructions.isEmpty() && me.subexpressions.isEmpty())
        throw new IllegalStateException();
    return me;
}
Also used : SiPush(net.runelite.asm.attributes.code.instructions.SiPush) InstructionContext(net.runelite.asm.execution.InstructionContext) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) DupInstruction(net.runelite.asm.attributes.code.instruction.types.DupInstruction) LDC(net.runelite.asm.attributes.code.instructions.LDC) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) VariableContext(net.runelite.asm.execution.VariableContext) BiPush(net.runelite.asm.attributes.code.instructions.BiPush) Variables(net.runelite.asm.execution.Variables) Swap(net.runelite.asm.attributes.code.instructions.Swap) ISub(net.runelite.asm.attributes.code.instructions.ISub) StackContext(net.runelite.asm.execution.StackContext) LAdd(net.runelite.asm.attributes.code.instructions.LAdd) IInc(net.runelite.asm.attributes.code.instructions.IInc) LSub(net.runelite.asm.attributes.code.instructions.LSub) IAdd(net.runelite.asm.attributes.code.instructions.IAdd) GetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction)

Example 5 with PushConstantInstruction

use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.

the class MultiplicationExpression method simplify.

int simplify(Number start) {
    int count = 0;
    Number result = start;
    // calculate result
    for (InstructionContext i : instructions) {
        PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
        Number value = (Number) pci.getConstant();
        result = DMath.multiply(result, value);
    }
    if (dupmagic != null) {
        // mul dupmagic by result of dup ins?
        PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction();
        Number value = (Number) pci.getConstant();
        for (InstructionContext ic : dupedInstructions) {
            PushConstantInstruction pci2 = (PushConstantInstruction) ic.getInstruction();
            Number value2 = (Number) pci2.getConstant();
            value = DMath.multiply(value, value2);
        }
        Instruction newIns = pci.setConstant(value);
        assert newIns == (Instruction) pci;
    }
    // multiply subexpressions by result
    if (!subexpressions.isEmpty()) {
        for (MultiplicationExpression me : subexpressions) {
            count += me.simplify(result);
        }
        if (dupmagic != null) {
            PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction();
            Number value = (Number) pci.getConstant();
            value = DMath.multiply(value, DMath.modInverse(result));
            pci.setConstant(value);
        }
        // constant has been distributed, outer numbers all go to 1
        if (result instanceof Long)
            result = 1L;
        else
            result = 1;
    }
    // set result on ins
    for (InstructionContext i : instructions) {
        PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
        Instruction newIns = pci.setConstant(result);
        ++count;
        assert newIns == pci;
        // rest of the results go to 1
        if (result instanceof Long)
            result = 1L;
        else
            result = 1;
    }
    return count;
}
Also used : InstructionContext(net.runelite.asm.execution.InstructionContext) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) FieldInstruction(net.runelite.asm.attributes.code.instruction.types.FieldInstruction) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) Instruction(net.runelite.asm.attributes.code.Instruction)

Aggregations

PushConstantInstruction (net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction)21 Instruction (net.runelite.asm.attributes.code.Instruction)16 Instructions (net.runelite.asm.attributes.code.Instructions)9 LVTInstruction (net.runelite.asm.attributes.code.instruction.types.LVTInstruction)8 InstructionContext (net.runelite.asm.execution.InstructionContext)8 Field (net.runelite.asm.Field)7 Method (net.runelite.asm.Method)7 StackContext (net.runelite.asm.execution.StackContext)7 GetFieldInstruction (net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction)6 InvokeInstruction (net.runelite.asm.attributes.code.instruction.types.InvokeInstruction)6 SetFieldInstruction (net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction)6 LDC (net.runelite.asm.attributes.code.instructions.LDC)6 ClassFile (net.runelite.asm.ClassFile)5 FieldInstruction (net.runelite.asm.attributes.code.instruction.types.FieldInstruction)5 ArrayList (java.util.ArrayList)4 Type (net.runelite.asm.Type)4 GetStatic (net.runelite.asm.attributes.code.instructions.GetStatic)4 Logger (org.slf4j.Logger)4 LoggerFactory (org.slf4j.LoggerFactory)4 HashSet (java.util.HashSet)3