jOOQ / jOOR

jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK's reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better.
http://www.jooq.org/products
Apache License 2.0
2.8k stars 377 forks source link

Working with Obfuscation - Duplicate Names #113

Open MizzMaster opened 3 years ago

MizzMaster commented 3 years ago

Versions:

Reflection is actually helpful most of the time, even with obfuscation, but there is a problem while working against obfuscation. Some obfuscators make member names duplicate so we can't directly access it just by giving the name and maybe arguments. As an example, this is allowed at both compile time and runtime:

public void foo(String str) {
    System.out.println(str);
}

public void foo() {
    System.out.println("Legit");
}

public void random() {
    this.foo();
    this.foo("Legit");
}

This example is not allowed at compile time but allowed at runtime:

public int duplicate() {
    return 0;
}

public String duplicate() {
    return "Duplicate";
}

public void random() {
    int i = this.duplicate();         //INVOKEVIRTUAL randomPackage/randomClass.duplicate()I
    String str = this.duplicate();    //INVOKEVIRTUAL randomPackage/randomClass.duplicate()Ljava/lang/String;
}

There should be some additional methods that considers return types to fully recognize method signatures (name and description) to solve this problem.

By the way I am not talking about runtime compilation, this issue is about calling duplicate methods

lukaseder commented 3 years ago

Yes, we could do that at some point, also to call bridge methods explicitly for whatever reason. In the meantime, you can try to look up the Method by iterating Class.getMethods()

MizzMaster commented 3 years ago

I didn't tested this code yet but this would do the job

    public Reflect callDuplicate(Class<?> returnType, String name, Object... args) throws ReflectException {
        Class<?>[] types = types(args);

        try {
            Method method = duplicateMethod(returnType, name, types);
            return on(method, object, args);
        } catch (NoSuchMethodException e) {
            throw new ReflectException(e);
        }
    }

    private Method duplicateMethod(Class<?> returnType, String name, Class<?>[] types) throws NoSuchMethodException {
        Class<?> t = type();

        for(Method method : t.getMethods()) {
            if (method.getName().equals(name) &&
                method.getReturnType().equals(returnType) &&
                Arrays.equals(method.getParameterTypes(), types))
            {
                return method;
            }
        }

        do {
            for(Method method : t.getDeclaredMethods()) {
                if (method.getName().equals(name) &&
                    method.getReturnType().equals(returnType) &&
                    Arrays.equals(method.getParameterTypes(), types))
                {
                    return method;
                }
            }

            t = t.getSuperclass();
        }
        while (t != null);

        throw new NoSuchMethodException();
    }
onClass("randomPackage.randomClass")
    .create()
    .callDuplicate(int.class, "duplicate")
    .get();

onClass("randomPackage.randomClass")
    .create()
    .callDuplicate(String.class, "duplicate")
    .get();

Please double check the code if you want to commit, i am kinda sleepy and not sure about this code

lukaseder commented 3 years ago

Sure, but then again "at some point" means that I really wouldn't want to rush adding API for such a rare edge case. It is extremely rare having to call an overload-by-return-type on the JVM, let alone having to call it via reflection.

I don't think such a feature will make it into this library very soon.