Search in sources :

Example 1 with IInc

use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.

the class CodeVisitor method visitIincInsn.

@Override
public void visitIincInsn(int var, int increment) {
    IInc iinc = new IInc(code.getInstructions(), InstructionType.IINC);
    iinc.setVariableIndex(var);
    iinc.setIncrement(increment);
    code.getInstructions().addInstruction(iinc);
}
Also used : IInc(net.runelite.asm.attributes.code.instructions.IInc)

Example 2 with IInc

use of net.runelite.asm.attributes.code.instructions.IInc 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 3 with IInc

use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.

the class ExprArgOrder method canRemove.

private boolean canRemove(MethodContext mctx, Instructions ins, Instruction i) {
    Set<InstructionContext> ctxs = new HashSet<>(mctx.getInstructonContexts(i));
    if (!alwaysPoppedBySameInstruction(ctxs, i) || !alwaysPopsFromSameInstructions(ctxs, i)) {
        return false;
    }
    if (i instanceof InvokeInstruction) {
        // func1() + func2() vs func2() + func1() is not the same thing
        return false;
    }
    int idx = ins.getInstructions().indexOf(i);
    if (idx == -1) {
        return false;
    }
    for (InstructionContext ictx : ctxs) {
        for (StackContext sctx : ictx.getPops()) {
            Instruction pushed = sctx.getPushed().getInstruction();
            int idx2 = ins.getInstructions().indexOf(pushed);
            if (idx2 == -1) {
                return false;
            }
            assert idx > idx2;
            // instructions, we can't move them
            for (int j = idx2; j <= idx; ++j) {
                Instruction i2 = ins.getInstructions().get(j);
                if (i2 instanceof LVTInstruction) {
                    if (((LVTInstruction) i2).store()) {
                        return false;
                    }
                }
                if (i2 instanceof IInc) {
                    return false;
                }
            }
            if (!canRemove(mctx, ins, pushed)) {
                return false;
            }
        }
    }
    return true;
}
Also used : InstructionContext(net.runelite.asm.execution.InstructionContext) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) StackContext(net.runelite.asm.execution.StackContext) IInc(net.runelite.asm.attributes.code.instructions.IInc) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) 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) HashSet(java.util.HashSet)

Example 4 with IInc

use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.

the class ScriptVM method injectScriptVMHooks.

private void injectScriptVMHooks() throws InjectionException {
    /*
			This hooks local variable assignments in the copied version of runScript:
			 - The currently executing script > client.currentScript
			 - The currently executing script's program counter > client.currentScriptPC
			 - The currently executing opcode > client.vmExecuteOpcode(I)Z

			The currently executing script variable is located as the outermost Script local

			The PC is located by its use in PutField ScriptState::invokedFromPC

			The currently executing opcode is found by searching for iaload with the script's instruction array

			The script's instruction array is identified by looking for the getfield from script.instructions

			bn.g @ rev 163 :
			// Jump back to here if vmExecuteOpcode returns true
			aload6 // Script.instructions
			iinc 5 1 // ++PC
			iload5 // PC
			iaload
			istore8
			// <- Inject here
			iload8
			bipush 100
			if_icmpge L52

		 */
    String scriptObName = DeobAnnotations.getObfuscatedName(inject.getDeobfuscated().findClass("Script").getAnnotations());
    Method runScript = findObMethod("copy$runScript");
    Method vmExecuteOpcode = findObMethod("vmExecuteOpcode");
    Field scriptInstructions = findDeobField("instructions");
    Field scriptStatePC = findDeobField("invokedFromPc");
    Field currentScriptField = findObField("currentScript");
    Field currentScriptPCField = findObField("currentScriptPC");
    Execution e = new Execution(inject.getVanilla());
    e.addMethod(runScript);
    e.noInvoke = true;
    AtomicReference<MethodContext> pcontext = new AtomicReference<>(null);
    e.addMethodContextVisitor(pcontext::set);
    e.run();
    Instructions instrs = runScript.getCode().getInstructions();
    Set<AStore> scriptStores = new HashSet<>();
    Integer pcLocalVar = null;
    Integer instructionArrayLocalVar = null;
    IStore currentOpcodeStore = null;
    ALoad localInstructionLoad = null;
    MethodContext methodContext = pcontext.get();
    for (InstructionContext instrCtx : methodContext.getInstructionContexts()) {
        Instruction instr = instrCtx.getInstruction();
        if (instr instanceof AStore) {
            AStore store = (AStore) instr;
            StackContext storedVarCtx = instrCtx.getPops().get(0);
            // Find AStores that store a Script
            if (storedVarCtx.getType().getInternalName().equals(scriptObName)) {
                scriptStores.add(store);
            }
            // Find AStores that store the instructions
            InstructionContext pusherCtx = storedVarCtx.getPushed();
            if (pusherCtx.getInstruction() instanceof GetField) {
                GetField getField = (GetField) pusherCtx.getInstruction();
                if (getField.getMyField().equals(scriptInstructions)) {
                    instructionArrayLocalVar = store.getVariableIndex();
                }
            }
        }
        // Find the local that invokedFromPc is set from
        if (instr instanceof PutField) {
            PutField put = (PutField) instr;
            if (put.getMyField() == scriptStatePC) {
                StackContext pc = instrCtx.getPops().get(0);
                assert Type.INT.equals(pc.getType()) : pc.getType();
                InstructionContext mulctx = pc.pushed;
                assert mulctx.getInstruction() instanceof IMul;
                pcLocalVar = mulctx.getPops().stream().map(StackContext::getPushed).filter(i -> i.getInstruction() instanceof ILoad).map(i -> ((ILoad) i.getInstruction()).getVariableIndex()).findFirst().orElse(null);
            }
        }
    }
    // This has to run after the first loop because it relies on instructionArrayLocalVar being set
    if (instructionArrayLocalVar == null) {
        throw new InjectionException("Unable to find local instruction array");
    }
    for (InstructionContext instrCtx : methodContext.getInstructionContexts()) {
        Instruction instr = instrCtx.getInstruction();
        if (instr instanceof IALoad) {
            StackContext array = instrCtx.getPops().get(1);
            // Check where the array came from (looking for a getField scriptInstructions
            InstructionContext pushedCtx = array.getPushed();
            Instruction pushed = pushedCtx.getInstruction();
            if (pushed instanceof ALoad) {
                ALoad arrayLoad = (ALoad) pushed;
                if (arrayLoad.getVariableIndex() == instructionArrayLocalVar) {
                    // Find the istore
                    IStore istore = (IStore) instrCtx.getPushes().get(0).getPopped().stream().map(InstructionContext::getInstruction).filter(i -> i instanceof IStore).findFirst().orElse(null);
                    if (istore != null) {
                        currentOpcodeStore = istore;
                        localInstructionLoad = arrayLoad;
                    }
                }
            }
        }
    }
    // Add PutStatics to all Script AStores
    {
        int outerSciptIdx = scriptStores.stream().mapToInt(AStore::getVariableIndex).reduce(Math::min).orElseThrow(() -> new InjectionException("Unable to find any Script AStores in runScript"));
        log.debug("Found script index {}", outerSciptIdx);
        ListIterator<Instruction> instrIter = instrs.getInstructions().listIterator();
        while (instrIter.hasNext()) {
            Instruction instr = instrIter.next();
            if (instr instanceof AStore) {
                AStore il = (AStore) instr;
                if (il.getVariableIndex() == outerSciptIdx) {
                    instrIter.previous();
                    instrIter.add(new Dup(instrs));
                    instrIter.add(new PutStatic(instrs, currentScriptField));
                    instrIter.next();
                }
            }
        }
    }
    // Add PutStatics to all PC IStores and IIncs
    {
        if (pcLocalVar == null) {
            throw new InjectionException("Unable to find ILoad for invokedFromPc IStore");
        }
        log.debug("Found pc index {}", pcLocalVar);
        ListIterator<Instruction> instrIter = instrs.getInstructions().listIterator();
        while (instrIter.hasNext()) {
            Instruction instr = instrIter.next();
            if (instr instanceof IStore) {
                IStore il = (IStore) instr;
                if (il.getVariableIndex() == pcLocalVar) {
                    instrIter.previous();
                    instrIter.add(new Dup(instrs));
                    instrIter.add(new PutStatic(instrs, currentScriptPCField));
                    instrIter.next();
                }
            }
            if (instr instanceof IInc) {
                IInc iinc = (IInc) instr;
                if (iinc.getVariableIndex() == pcLocalVar) {
                    instrIter.add(new ILoad(instrs, pcLocalVar));
                    instrIter.add(new PutStatic(instrs, currentScriptPCField));
                }
            }
        }
    }
    // Inject call to vmExecuteOpcode
    log.debug("Found instruction array index {}", instructionArrayLocalVar);
    if (currentOpcodeStore == null) {
        throw new InjectionException("Unable to find IStore for current opcode");
    }
    int istorepc = instrs.getInstructions().indexOf(currentOpcodeStore);
    assert istorepc >= 0;
    Label nextIteration = instrs.createLabelFor(localInstructionLoad);
    instrs.addInstruction(istorepc + 1, new ILoad(instrs, currentOpcodeStore.getVariableIndex()));
    instrs.addInstruction(istorepc + 2, new InvokeStatic(instrs, vmExecuteOpcode.getPoolMethod()));
    instrs.addInstruction(istorepc + 3, new IfNe(instrs, nextIteration));
}
Also used : ListIterator(java.util.ListIterator) GetField(net.runelite.asm.attributes.code.instructions.GetField) IMul(net.runelite.asm.attributes.code.instructions.IMul) LoggerFactory(org.slf4j.LoggerFactory) Dup(net.runelite.asm.attributes.code.instructions.Dup) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) ALoad(net.runelite.asm.attributes.code.instructions.ALoad) Inject(net.runelite.injector.Inject) AtomicReference(java.util.concurrent.atomic.AtomicReference) StackContext(net.runelite.asm.execution.StackContext) HashSet(java.util.HashSet) Method(net.runelite.asm.Method) ILoad(net.runelite.asm.attributes.code.instructions.ILoad) IStore(net.runelite.asm.attributes.code.instructions.IStore) IALoad(net.runelite.asm.attributes.code.instructions.IALoad) DeobAnnotations(net.runelite.deob.DeobAnnotations) Logger(org.slf4j.Logger) AStore(net.runelite.asm.attributes.code.instructions.AStore) Field(net.runelite.asm.Field) Set(java.util.Set) Type(net.runelite.asm.Type) InstructionContext(net.runelite.asm.execution.InstructionContext) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic) PutField(net.runelite.asm.attributes.code.instructions.PutField) Execution(net.runelite.asm.execution.Execution) ClassFile(net.runelite.asm.ClassFile) Label(net.runelite.asm.attributes.code.Label) MethodContext(net.runelite.asm.execution.MethodContext) Instructions(net.runelite.asm.attributes.code.Instructions) IInc(net.runelite.asm.attributes.code.instructions.IInc) InjectionException(net.runelite.injector.InjectionException) Instruction(net.runelite.asm.attributes.code.Instruction) IfNe(net.runelite.asm.attributes.code.instructions.IfNe) IStore(net.runelite.asm.attributes.code.instructions.IStore) Label(net.runelite.asm.attributes.code.Label) Instruction(net.runelite.asm.attributes.code.Instruction) InjectionException(net.runelite.injector.InjectionException) GetField(net.runelite.asm.attributes.code.instructions.GetField) Field(net.runelite.asm.Field) PutField(net.runelite.asm.attributes.code.instructions.PutField) Execution(net.runelite.asm.execution.Execution) AStore(net.runelite.asm.attributes.code.instructions.AStore) IALoad(net.runelite.asm.attributes.code.instructions.IALoad) IMul(net.runelite.asm.attributes.code.instructions.IMul) Dup(net.runelite.asm.attributes.code.instructions.Dup) HashSet(java.util.HashSet) PutField(net.runelite.asm.attributes.code.instructions.PutField) InstructionContext(net.runelite.asm.execution.InstructionContext) GetField(net.runelite.asm.attributes.code.instructions.GetField) ILoad(net.runelite.asm.attributes.code.instructions.ILoad) MethodContext(net.runelite.asm.execution.MethodContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) Instructions(net.runelite.asm.attributes.code.Instructions) Method(net.runelite.asm.Method) ListIterator(java.util.ListIterator) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) StackContext(net.runelite.asm.execution.StackContext) IfNe(net.runelite.asm.attributes.code.instructions.IfNe) IInc(net.runelite.asm.attributes.code.instructions.IInc) ALoad(net.runelite.asm.attributes.code.instructions.ALoad) IALoad(net.runelite.asm.attributes.code.instructions.IALoad) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic)

Aggregations

IInc (net.runelite.asm.attributes.code.instructions.IInc)4 InstructionContext (net.runelite.asm.execution.InstructionContext)3 StackContext (net.runelite.asm.execution.StackContext)3 HashSet (java.util.HashSet)2 Instruction (net.runelite.asm.attributes.code.Instruction)2 LVTInstruction (net.runelite.asm.attributes.code.instruction.types.LVTInstruction)2 PushConstantInstruction (net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction)2 ListIterator (java.util.ListIterator)1 Set (java.util.Set)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 ClassFile (net.runelite.asm.ClassFile)1 Field (net.runelite.asm.Field)1 Method (net.runelite.asm.Method)1 Type (net.runelite.asm.Type)1 Instructions (net.runelite.asm.attributes.code.Instructions)1 Label (net.runelite.asm.attributes.code.Label)1 DupInstruction (net.runelite.asm.attributes.code.instruction.types.DupInstruction)1 GetFieldInstruction (net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction)1 InvokeInstruction (net.runelite.asm.attributes.code.instruction.types.InvokeInstruction)1 ALoad (net.runelite.asm.attributes.code.instructions.ALoad)1