mirror of
https://github.com/QM4RS/FridaBox.git
synced 2026-10-09 01:12:18 +02:00
feat: Introduce black-reflection and compiler modules, integrate reflection utilities, and update core components.
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
package top.niunaijun.blackreflection;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import top.niunaijun.blackreflection.annotation.BClass;
|
||||
import top.niunaijun.blackreflection.annotation.BClassName;
|
||||
import top.niunaijun.blackreflection.annotation.BClassNameNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BConstructor;
|
||||
import top.niunaijun.blackreflection.annotation.BConstructorNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BField;
|
||||
import top.niunaijun.blackreflection.annotation.BFieldCheckNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BFieldNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BFieldSetNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BMethodCheckNotProcess;
|
||||
import top.niunaijun.blackreflection.annotation.BParamClass;
|
||||
import top.niunaijun.blackreflection.annotation.BParamClassName;
|
||||
import top.niunaijun.blackreflection.utils.Reflector;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BlackReflection {
|
||||
public static boolean DEBUG = false;
|
||||
public static boolean CACHE = false;
|
||||
private static final Map<Class<?>, Object> sProxyCache = new HashMap<>();
|
||||
private static final Map<Class<?>, Object> sProxyWithExceptionCache = new HashMap<>();
|
||||
|
||||
// key caller
|
||||
private static final WeakHashMap<Object, Map<Class<?>, Object>> sCallerProxyCache = new WeakHashMap<>();
|
||||
|
||||
// public static <T> T create(Class<T> clazz, final Object caller) {
|
||||
// return create(clazz, caller, false);
|
||||
// }
|
||||
|
||||
public static <T> T create(Class<T> clazz, final Object caller, boolean withException) {
|
||||
try {
|
||||
T proxy = getProxy(clazz, caller, withException);
|
||||
if (proxy != null)
|
||||
return proxy;
|
||||
final WeakReference<Object> weakCaller = caller == null ? null : new WeakReference<>(caller);
|
||||
|
||||
final Class<?> aClass = getClassNameByBlackClass(clazz);
|
||||
Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
Class<?> returnType = method.getReturnType();
|
||||
|
||||
try {
|
||||
boolean isStatic = weakCaller == null;
|
||||
|
||||
Object callerByWeak = isStatic ? null : weakCaller.get();
|
||||
|
||||
// fidel
|
||||
BField bField = method.getAnnotation(BField.class);
|
||||
BFieldNotProcess bFieldNotProcess = method.getAnnotation(BFieldNotProcess.class);
|
||||
if (bField != null || bFieldNotProcess != null) {
|
||||
Object call;
|
||||
Reflector on = Reflector.on(aClass).field(name);
|
||||
if (isStatic) {
|
||||
call = on.get();
|
||||
} else {
|
||||
if (callerByWeak == null) {
|
||||
return generateNullValue(returnType);
|
||||
}
|
||||
call = on.get(callerByWeak);
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
// void
|
||||
BFieldSetNotProcess bFieldSetNotProcess = method.getAnnotation(BFieldSetNotProcess.class);
|
||||
if (bFieldSetNotProcess != null) {
|
||||
// startsWith "_set_"
|
||||
name = name.substring("_set_".length());
|
||||
Reflector on = Reflector.on(aClass).field(name);
|
||||
if (isStatic) {
|
||||
on.set(args[0]);
|
||||
} else {
|
||||
if (callerByWeak == null) {
|
||||
return 0;
|
||||
}
|
||||
on.set(callerByWeak, args[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check field
|
||||
BFieldCheckNotProcess bFieldCheckNotProcess = method.getAnnotation(BFieldCheckNotProcess.class);
|
||||
if (bFieldCheckNotProcess != null) {
|
||||
// startsWith "_check_"
|
||||
name = name.substring("_check_".length());
|
||||
try {
|
||||
Reflector on = Reflector.on(aClass).field(name);
|
||||
return on.getField();
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?>[] paramClass = getParamClass(method);
|
||||
|
||||
// check method
|
||||
BMethodCheckNotProcess bMethodCheckNotProcess = method.getAnnotation(BMethodCheckNotProcess.class);
|
||||
if (bMethodCheckNotProcess != null) {
|
||||
// startsWith "_check_"
|
||||
name = name.substring("_check_".length());
|
||||
try {
|
||||
return Reflector.on(aClass).method(name, paramClass).getMethod();
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// method
|
||||
BConstructor bConstructor = method.getAnnotation(BConstructor.class);
|
||||
BConstructorNotProcess bConstructorNotProcess = method.getAnnotation(BConstructorNotProcess.class);
|
||||
if (bConstructor != null || bConstructorNotProcess != null) {
|
||||
Reflector on = Reflector.on(aClass).constructor(paramClass);
|
||||
return on.newInstance(args);
|
||||
}
|
||||
|
||||
Object call;
|
||||
Reflector on = Reflector.on(aClass).method(name, paramClass);
|
||||
if (isStatic) {
|
||||
call = on.call(args);
|
||||
} else {
|
||||
if (callerByWeak == null) {
|
||||
return generateNullValue(returnType);
|
||||
}
|
||||
call = on.callByCaller(callerByWeak, args);
|
||||
}
|
||||
return call;
|
||||
} catch (Throwable throwable) {
|
||||
if (DEBUG) {
|
||||
if (throwable.getCause() != null) {
|
||||
throwable.getCause().printStackTrace();
|
||||
} else {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (throwable instanceof BlackNullPointerException) {
|
||||
throw new NullPointerException(throwable.getMessage());
|
||||
}
|
||||
if (withException) {
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
return generateNullValue(returnType);
|
||||
}
|
||||
});
|
||||
|
||||
if (caller == null) {
|
||||
if (withException) {
|
||||
sProxyWithExceptionCache.put(clazz, o);
|
||||
} else {
|
||||
sProxyCache.put(clazz, o);
|
||||
}
|
||||
}
|
||||
return (T) o;
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <T> T getProxy(Class<T> clazz, final Object caller, boolean withException) {
|
||||
try {
|
||||
if (caller == null) {
|
||||
Object o;
|
||||
if (withException) {
|
||||
o = sProxyWithExceptionCache.get(clazz);
|
||||
} else {
|
||||
o = sProxyCache.get(clazz);
|
||||
}
|
||||
if (o != null) {
|
||||
return (T) o;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Class<?>[] getParamClass(Method method) throws Throwable {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Class<?>[] param = new Class[parameterTypes.length];
|
||||
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Annotation[] parameterAnnotation = parameterAnnotations[i];
|
||||
boolean found = false;
|
||||
for (Annotation annotation : parameterAnnotation) {
|
||||
if (annotation instanceof BParamClassName) {
|
||||
found = true;
|
||||
param[i] = Class.forName(((BParamClassName) annotation).value());
|
||||
break;
|
||||
} else if (annotation instanceof BParamClass) {
|
||||
found = true;
|
||||
param[i] = ((BParamClass) annotation).value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
param[i] = parameterTypes[i];
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
private static Class<?> getClassNameByBlackClass(Class<?> clazz) throws ClassNotFoundException {
|
||||
BClass bClass = clazz.getAnnotation(BClass.class);
|
||||
BClassName bClassName = clazz.getAnnotation(BClassName.class);
|
||||
BClassNameNotProcess bClassNameNotProcess = clazz.getAnnotation(BClassNameNotProcess.class);
|
||||
if (bClass == null && bClassName == null && bClassNameNotProcess == null) {
|
||||
throw new RuntimeException("Not found @BlackClass or @BlackStrClass");
|
||||
}
|
||||
|
||||
if (bClass != null) {
|
||||
return bClass.value();
|
||||
} else if (bClassName != null) {
|
||||
return Class.forName(bClassName.value());
|
||||
} else {
|
||||
return Class.forName(bClassNameNotProcess.value());
|
||||
}
|
||||
}
|
||||
|
||||
private static Object generateNullValue(Class<?> returnType) {
|
||||
if (returnType == void.class) {
|
||||
return 0;
|
||||
}
|
||||
if (returnType.isPrimitive()) {
|
||||
throw new BlackNullPointerException("value is null!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user