Search in sources :

Example 21 with Method

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

the class HookImporter method importHooks.

@Test
@Ignore
public void importHooks() {
    int classes = 0, fields = 0, methods = 0, callbacks = 0;
    for (String deobfuscatedClassName : hooks.keySet()) {
        ClassHook ch = hooks.get(deobfuscatedClassName);
        ClassFile cf = this.findClassWithObfuscatedName(ch.getClazz());
        assert cf != null;
        String implementsName = getAnnotation(cf.getAnnotations(), IMPLEMENTS);
        if (implementsName.isEmpty()) {
            cf.getAnnotations().addAnnotation(IMPLEMENTS, "value", deobfuscatedClassName);
            ++classes;
        }
        for (String deobfuscatedFieldName : ch.getFields().keySet()) {
            FieldHook fh = ch.getFields().get(deobfuscatedFieldName);
            String[] s = fh.getField().split("\\.");
            Field f;
            if (s.length == 2) {
                ClassFile cf2 = this.findClassWithObfuscatedName(s[0]);
                assert cf2 != null;
                f = this.findFieldWithObfuscatedName(cf2, s[1]);
            } else if (s.length == 1) {
                f = this.findFieldWithObfuscatedName(cf, fh.getField());
            } else {
                throw new RuntimeException();
            }
            assert f != null;
            String exportedName = getAnnotation(f.getAnnotations(), EXPORT);
            if (exportedName.isEmpty()) {
                f.getAnnotations().addAnnotation(EXPORT, "value", deobfuscatedFieldName);
                ++fields;
            }
        }
        for (String deobfuscatedMethodName : ch.getMethods().keySet()) {
            MethodHook mh = ch.getMethods().get(deobfuscatedMethodName);
            String[] s = mh.getMethod().split("\\.");
            Method m;
            if (s.length == 2) {
                ClassFile cf2 = this.findClassWithObfuscatedName(s[0]);
                assert cf2 != null;
                m = this.findMethodWithObfuscatedName(cf2, s[1], mh.getClientDesc());
            } else if (s.length == 1) {
                m = this.findMethodWithObfuscatedName(cf, mh.getMethod(), mh.getClientDesc());
            } else {
                throw new RuntimeException();
            }
            assert m != null;
            String exportedName = getAnnotation(m.getAnnotations(), EXPORT);
            if (exportedName.isEmpty()) {
                m.getAnnotations().addAnnotation(EXPORT, "value", deobfuscatedMethodName);
                ++methods;
            }
        }
        for (String deobfuscatedMethodName : ch.getCallbacks().keySet()) {
            MethodHook mh = ch.getCallbacks().get(deobfuscatedMethodName);
            String[] s = mh.getMethod().split("\\.");
            Method m;
            if (s.length == 2) {
                ClassFile cf2 = this.findClassWithObfuscatedName(s[0]);
                assert cf2 != null;
                m = this.findMethodWithObfuscatedName(cf2, s[1], mh.getClientDesc());
            } else if (s.length == 1) {
                m = this.findMethodWithObfuscatedName(cf, mh.getMethod(), mh.getClientDesc());
            } else {
                throw new RuntimeException();
            }
            assert m != null;
            String exportedName = getAnnotation(m.getAnnotations(), EXPORT);
            if (exportedName.isEmpty()) {
                m.getAnnotations().addAnnotation(EXPORT, "value", deobfuscatedMethodName);
                ++callbacks;
            }
        }
    }
    System.out.println("Imported " + classes + " classes, " + fields + " fields, " + methods + " methods, " + callbacks + " callbacks");
}
Also used : MethodHook(net.runelite.osb.inject.MethodHook) Field(net.runelite.asm.Field) ClassHook(net.runelite.osb.inject.ClassHook) ClassFile(net.runelite.asm.ClassFile) FieldHook(net.runelite.osb.inject.FieldHook) Method(net.runelite.asm.Method) Ignore(org.junit.Ignore) Test(org.junit.Test)

Example 22 with Method

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

the class HookImporter method findMethodWithObfuscatedName.

private Method findMethodWithObfuscatedName(ClassFile c, String name, String signature) {
    Signature sig = new Signature(signature);
    for (Method m : c.getMethods()) {
        Annotations an = m.getAnnotations();
        if (getAnnotation(an, OBFUSCATED_NAME).equals(name)) {
            Signature methodSig = getObfuscatedMethodSignature(m);
            if (methodSig.equals(sig)) {
                return m;
            } else {
                methodSig.equals(sig);
                getObfuscatedMethodSignature(m);
            }
        }
    }
    return null;
}
Also used : Annotations(net.runelite.asm.attributes.Annotations) Signature(net.runelite.asm.signature.Signature) Method(net.runelite.asm.Method)

Example 23 with Method

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

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

the class InjectConstructTest method testInjectConstruct.

@Test
public void testInjectConstruct() throws Exception {
    ClassFile targetClass = new ClassFile();
    targetClass.setName("test");
    ClassFile vanillaClass = new ClassFile();
    vanillaClass.setName("ab");
    Method constructor = new Method(vanillaClass, "<init>", new Signature("()V"));
    vanillaClass.addMethod(constructor);
    Inject inject = mock(Inject.class);
    when(inject.findVanillaForInterface(Matchers.any(Class.class))).thenReturn(vanillaClass);
    InjectConstruct injectConstruct = new InjectConstruct(inject);
    injectConstruct.injectConstruct(targetClass, APIClass.class.getDeclaredMethod("create"));
    assertNotNull(targetClass.findMethod("create"));
}
Also used : ClassFile(net.runelite.asm.ClassFile) Signature(net.runelite.asm.signature.Signature) Method(net.runelite.asm.Method) Test(org.junit.Test)

Example 25 with Method

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

the class InjectHookMethod method process.

public void process(Method method) throws InjectionException {
    Annotations an = method.getAnnotations();
    if (an == null) {
        return;
    }
    Annotation a = an.find(DeobAnnotations.HOOK);
    if (a == null) {
        return;
    }
    // Method is hooked
    // String hookName = DeobAnnotations.getHookName(an); // hook name
    // Find equivalent method in vanilla, and insert callback at the beginning
    ClassFile cf = method.getClassFile();
    String obfuscatedMethodName = DeobAnnotations.getObfuscatedName(an), obfuscatedClassName = DeobAnnotations.getObfuscatedName(cf.getAnnotations());
    // might be a constructor
    if (obfuscatedMethodName == null && method.getName().equals("<init>")) {
        obfuscatedMethodName = "<init>";
    }
    assert obfuscatedClassName != null : "hook on method in class with no obfuscated name";
    assert obfuscatedMethodName != null : "hook on method with no obfuscated name";
    Signature obfuscatedSignature = inject.getMethodSignature(method);
    ClassGroup vanilla = inject.getVanilla();
    ClassFile vanillaClass = vanilla.findClass(obfuscatedClassName);
    Method vanillaMethod = vanillaClass.findMethod(obfuscatedMethodName, obfuscatedSignature);
    // Insert instructions at beginning of method
    injectHookMethod(a, method, vanillaMethod);
}
Also used : Annotations(net.runelite.asm.attributes.Annotations) DeobAnnotations(net.runelite.deob.DeobAnnotations) ClassFile(net.runelite.asm.ClassFile) ClassGroup(net.runelite.asm.ClassGroup) Signature(net.runelite.asm.signature.Signature) Method(net.runelite.asm.Method) Annotation(net.runelite.asm.attributes.annotation.Annotation)

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