Lsposed Java HOOK原理及检测
当使用 XposedBridge.hookMethod 这个 api对java函数进行hook时:
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
if (!(hookMethod instanceof Executable)) {
throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod);
} else if (Modifier.isAbstract(hookMethod.getModifiers())) {
throw new IllegalArgumentException("Cannot hook abstract methods: " + hookMethod);
} else if (hookMethod.getDeclaringClass().getClassLoader() == XposedBridge.class.getClassLoader()) {
throw new IllegalArgumentException("Do not allow hooking inner methods");
} else if (hookMethod.getDeclaringClass() == Method.class && hookMethod.getName().equals("invoke")) {
throw new IllegalArgumentException("Cannot hook Method.invoke");
}
if (callback == null) {
throw new IllegalArgumentException("callback should not be null!");
}
if (!HookBridge.hookMethod(false, (Executable) hookMethod, LSPosedBridge.NativeHooker.class, callback.priority, callback)) {
log("Failed to hook " + hookMethod);
return null;
}
return callback.new Unhook(hookMethod);
}
会调用 HookBridge.hookMethod 这个内部api,实现在native层:
public class HookBridge {
public static native boolean hookMethod(boolean useModernApi, Executable hookMethod, Class<?> hooker, int priority, Object callback);
public static native boolean unhookMethod(boolean useModernApi, Executable hookMethod, Object callback);
public static native boolean deoptimizeMethod(Executable method);
public static native <T> T allocateObject(Class<T> clazz) throws InstantiationException;
public static native Object invokeOriginalMethod(Executable method, Object thisObject, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
public static native <T> Object invokeSpecialMethod(Executable method, char[] shorty, Class<T> clazz, Object thisObject, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
@FastNative
public static native boolean instanceOf(Object obj, Class<?> clazz);
@FastNative
public static native boolean setTrusted(Object cookie);
public static native Object[][] callbackSnapshot(Class<?> hooker_callback, Executable method);
}
native层方法定义如下:
LSP_DEF_NATIVE_METHOD(jboolean, HookBridge, hookMethod, jboolean useModernApi, jobject hookMethod,
jclass hooker, jint priority, jobject callback) {
bool newHook = false;
#ifndef NDEBUG
struct finally {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
bool &newHook;
~finally() {
auto finish = std::chrono::steady_clock::now();
if (newHook) {
LOGV("New hook took {}us",
std::chrono::duration_cast<std::chrono::microseconds>(finish - start).count());
}
}
} finally {
.newHook = newHook
};
#endif
auto target = env->FromReflectedMethod(hookMethod); //ArtMethod 结构体
HookItem * hook_item = nullptr;
hooked_methods.lazy_emplace_l(target, [&hook_item](auto &it) {
hook_item = it.second.get();
}, [&hook_item, &target, &newHook](const auto &ctor) {
auto ptr = std::make_unique<HookItem>();
hook_item = ptr.get();
ctor(target, std::move(ptr));
newHook = true;
});
if (newHook) {
auto init = env->GetMethodID(hooker, "<init>", "(Ljava/lang/reflect/Executable;)V");
auto callback_method = env->ToReflectedMethod(hooker, env->GetMethodID(hooker, "callback", //LSPosedBridge.NativeHooker
"([Ljava/lang/Object;)Ljava/lang/Object;"),
false);
auto hooker_object = env->NewObject(hooker, init, hookMethod); //新建 NativeHooker 对象,传入 目标hookMethod
hook_item->SetBackup(lsplant::Hook(env, hookMethod, hooker_object, callback_method)); //传入的目标method 和 NativeHooker对象
env->DeleteLocalRef(hooker_object);
}
jobject backup = hook_item->GetBackup();
if (!backup) return JNI_FALSE;
JNIMonitor monitor(env, backup);
if (useModernApi) {
if (before_method_field == nullptr) {
auto callback_class = JNI_GetObjectClass(env, callback);
callback_ctor = JNI_GetMethodID(env, callback_class, "<init>", "(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V");
before_method_field = JNI_GetFieldID(env, callback_class, &#