Search in sources :

Example 86 with Method

use of net.runelite.asm.Method in project runelite by runelite.

the class DrawAfterWidgets method findStaticMethod.

private Method findStaticMethod(String name) {
    for (ClassFile c : inject.getDeobfuscated().getClasses()) {
        for (Method m : c.getMethods()) {
            if (!m.getName().equals(name)) {
                continue;
            }
            String obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations());
            Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(m);
            ClassFile c2 = inject.toObClass(c);
            return c2.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : m.getDescriptor());
        }
    }
    return null;
}
Also used : ClassFile(net.runelite.asm.ClassFile) Signature(net.runelite.asm.signature.Signature) Method(net.runelite.asm.Method)

Example 87 with Method

use of net.runelite.asm.Method in project runelite by runelite.

the class InjectInvoker method process.

/**
 * Inject an invoker for a method
 *
 * @param m Method in the deobfuscated client to inject an invoker for
 * @param other Class in the vanilla client of the same class m is a
 * member of
 * @param implementingClass Java class for the API interface the class
 * will implement
 */
public void process(Method m, ClassFile other, java.lang.Class<?> implementingClass) {
    Annotations an = m.getAnnotations();
    if (an == null || an.find(EXPORT) == null) {
        // not an exported method
        return;
    }
    String exportedName = DeobAnnotations.getExportedName(an);
    String obfuscatedName = DeobAnnotations.getObfuscatedName(an);
    if (obfuscatedName == null) {
        obfuscatedName = m.getName();
    }
    String garbage = DeobAnnotations.getObfuscatedValue(m);
    Method otherm = other.findMethod(obfuscatedName, inject.getMethodSignature(m));
    assert otherm != null;
    assert m.isStatic() == otherm.isStatic();
    ClassGroup vanilla = inject.getVanilla();
    ClassFile targetClass = m.isStatic() ? vanilla.findClass("client") : other;
    // Place into implementing class, unless the method is static
    java.lang.Class<?> targetClassJava = m.isStatic() ? Inject.CLIENT_CLASS : implementingClass;
    if (targetClassJava == null) {
        assert !m.isStatic();
        // non static exported method on non exported interface, weird.
        logger.debug("Non static exported method {} on non exported interface", exportedName);
        return;
    }
    // api method to invoke 'otherm'
    java.lang.reflect.Method apiMethod = inject.findImportMethodOnApi(targetClassJava, exportedName, null);
    if (apiMethod == null) {
        logger.debug("Unable to find api method on {} with imported name {}, not injecting invoker", targetClassJava, exportedName);
        return;
    }
    injectInvoker(targetClass, apiMethod, m, otherm, garbage);
    ++injectedInvokers;
}
Also used : Annotations(net.runelite.asm.attributes.Annotations) DeobAnnotations(net.runelite.deob.DeobAnnotations) ClassFile(net.runelite.asm.ClassFile) ClassGroup(net.runelite.asm.ClassGroup) Method(net.runelite.asm.Method)

Example 88 with Method

use of net.runelite.asm.Method in project runelite by runelite.

the class InjectSetter method injectSetter.

/**
 * inject a setter into the vanilla classgroup
 *
 * @param targetClass Class where to inject the setter (field's class,
 * or client)
 * @param targetApiClass API targetClass implements, which may have the
 * setter declared
 * @param field Field of vanilla that will be set
 * @param exportedName exported name of field
 * @param setter
 */
public void injectSetter(ClassFile targetClass, Class<?> targetApiClass, Field field, String exportedName, Number setter) {
    java.lang.reflect.Method method = inject.findImportMethodOnApi(targetApiClass, exportedName, true);
    if (method == null) {
        logger.warn("Setter injection for field {} but an API method was not found on {}", exportedName, targetApiClass);
        return;
    }
    if (method.getParameterCount() != 1) {
        logger.warn("Setter {} with not parameter count != 1?", exportedName);
        return;
    }
    logger.info("Injecting setter for {} on {}", exportedName, targetApiClass);
    assert targetClass.findMethod(method.getName()) == null;
    assert field.isStatic() || field.getClassFile() == targetClass;
    Signature sig = new Signature.Builder().setReturnType(Type.VOID).addArgument(Inject.classToType(method.getParameterTypes()[0])).build();
    Method setterMethod = new Method(targetClass, method.getName(), sig);
    setterMethod.setAccessFlags(ACC_PUBLIC);
    targetClass.addMethod(setterMethod);
    ++injectedSetters;
    Code code = new Code(setterMethod);
    setterMethod.setCode(code);
    Instructions instructions = code.getInstructions();
    List<Instruction> ins = instructions.getInstructions();
    // load this
    if (!field.isStatic()) {
        ins.add(new ALoad(instructions, 0));
    }
    // load argument
    Type argumentType = sig.getTypeOfArg(0);
    ins.add(inject.createLoadForTypeIndex(instructions, argumentType, 1));
    // cast argument to field type
    Type fieldType = field.getType();
    if (!argumentType.equals(fieldType)) {
        CheckCast checkCast = new CheckCast(instructions);
        checkCast.setType(fieldType);
        ins.add(checkCast);
    }
    if (setter != null) {
        assert setter instanceof Integer || setter instanceof Long;
        if (setter instanceof Integer) {
            ins.add(new LDC(instructions, (int) setter));
            ins.add(new IMul(instructions));
        } else {
            ins.add(new LDC(instructions, (long) setter));
            ins.add(new LMul(instructions));
        }
    }
    if (field.isStatic()) {
        ins.add(new PutStatic(instructions, field));
    } else {
        ins.add(new PutField(instructions, field));
    }
    ins.add(new VReturn(instructions));
}
Also used : Instructions(net.runelite.asm.attributes.code.Instructions) LDC(net.runelite.asm.attributes.code.instructions.LDC) Method(net.runelite.asm.Method) CheckCast(net.runelite.asm.attributes.code.instructions.CheckCast) Instruction(net.runelite.asm.attributes.code.Instruction) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) Code(net.runelite.asm.attributes.Code) VReturn(net.runelite.asm.attributes.code.instructions.VReturn) Type(net.runelite.asm.Type) Signature(net.runelite.asm.signature.Signature) IMul(net.runelite.asm.attributes.code.instructions.IMul) LMul(net.runelite.asm.attributes.code.instructions.LMul) ALoad(net.runelite.asm.attributes.code.instructions.ALoad) PutField(net.runelite.asm.attributes.code.instructions.PutField)

Example 89 with Method

use of net.runelite.asm.Method in project runelite by runelite.

the class MixinInjector method setOwnersToTargetClass.

private void setOwnersToTargetClass(ClassFile mixinCf, ClassFile cf, Method method, Map<net.runelite.asm.pool.Field, Field> shadowFields, Map<net.runelite.asm.pool.Method, CopiedMethod> copiedMethods) throws InjectionException {
    ListIterator<Instruction> iterator = method.getCode().getInstructions().getInstructions().listIterator();
    while (iterator.hasNext()) {
        Instruction i = iterator.next();
        if (i instanceof InvokeInstruction) {
            InvokeInstruction ii = (InvokeInstruction) i;
            CopiedMethod copiedMethod = copiedMethods.get(ii.getMethod());
            if (copiedMethod != null) {
                ii.setMethod(copiedMethod.obMethod.getPoolMethod());
                // Pass through garbage value if the method has one
                if (copiedMethod.hasGarbageValue) {
                    int garbageIndex = copiedMethod.obMethod.isStatic() ? copiedMethod.obMethod.getDescriptor().size() - 1 : copiedMethod.obMethod.getDescriptor().size();
                    iterator.previous();
                    iterator.add(new ILoad(method.getCode().getInstructions(), garbageIndex));
                    iterator.next();
                }
            } else if (ii.getMethod().getClazz().getName().equals(mixinCf.getName())) {
                ii.setMethod(new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(cf.getName()), ii.getMethod().getName(), ii.getMethod().getType()));
            }
        } else if (i instanceof FieldInstruction) {
            FieldInstruction fi = (FieldInstruction) i;
            Field shadowed = shadowFields.get(fi.getField());
            if (shadowed != null) {
                fi.setField(shadowed.getPoolField());
            } else if (fi.getField().getClazz().getName().equals(mixinCf.getName())) {
                fi.setField(new net.runelite.asm.pool.Field(new net.runelite.asm.pool.Class(cf.getName()), fi.getField().getName(), fi.getField().getType()));
            }
        } else if (i instanceof PushConstantInstruction) {
            PushConstantInstruction pi = (PushConstantInstruction) i;
            if (mixinCf.getPoolClass().equals(pi.getConstant())) {
                pi.setConstant(cf.getPoolClass());
            }
        }
        verify(mixinCf, i);
    }
}
Also used : PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) ILoad(net.runelite.asm.attributes.code.instructions.ILoad) Method(net.runelite.asm.Method) FieldInstruction(net.runelite.asm.attributes.code.instruction.types.FieldInstruction) 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) ReturnInstruction(net.runelite.asm.attributes.code.instruction.types.ReturnInstruction) Instruction(net.runelite.asm.attributes.code.Instruction) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) GetField(net.runelite.asm.attributes.code.instructions.GetField) Field(net.runelite.asm.Field) PutField(net.runelite.asm.attributes.code.instructions.PutField) FieldInstruction(net.runelite.asm.attributes.code.instruction.types.FieldInstruction)

Example 90 with Method

use of net.runelite.asm.Method 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

Method (net.runelite.asm.Method)90 ClassFile (net.runelite.asm.ClassFile)64 Field (net.runelite.asm.Field)34 Instruction (net.runelite.asm.attributes.code.Instruction)29 Code (net.runelite.asm.attributes.Code)28 Instructions (net.runelite.asm.attributes.code.Instructions)28 Signature (net.runelite.asm.signature.Signature)28 ClassGroup (net.runelite.asm.ClassGroup)20 ArrayList (java.util.ArrayList)18 Type (net.runelite.asm.Type)18 List (java.util.List)13 Test (org.junit.Test)13 PushConstantInstruction (net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction)12 Logger (org.slf4j.Logger)12 LoggerFactory (org.slf4j.LoggerFactory)12 LDC (net.runelite.asm.attributes.code.instructions.LDC)10 DeobAnnotations (net.runelite.deob.DeobAnnotations)9 Annotation (net.runelite.asm.attributes.annotation.Annotation)8 InstructionType (net.runelite.asm.attributes.code.InstructionType)8 Label (net.runelite.asm.attributes.code.Label)8