Riru和Lsp

参考 lsposed运行流程分析

riru

  1. 通过修改系统属性ro.dalvik.vm.native.bridge将libriruloader.so注入到zygote进程中

    zygote会执行LoadNativeBridge函数, LoadNativeBridge函数会根据属性ro.dalvik.vm.native.bridge的值进行dlopen,因此.init_array成为了Hook点

  2. libriru的init函数分别调用了PrepareMapsHideLibrary,InstallHooks和 Load

  • PrepareMapsHideLibrary // 隐藏maps

  • InstallHooks // 利用xHook框架hook函数jniRegisterNativeMethods,因此可以拿到nativeForkAndSpecialize, nativeSpecializeAppProcess, nativeForkSystemServer的函数地址

  • Load // 调用LoadModule函数,通过dlopen加载所有的riru模块so,隐藏maps, 加载的riru模块so的onModuleLoaded函数


riru主动调用Loadmodule

static void LoadModule(std::string_view id, std::string_view path, std::string_view magisk_module_path) {

    auto *handle = DlopenExt(path.data(), 0);
    if (!handle) {
        LOGE("dlopen %s failed: %s", path.data(), dlerror());
        return;
    }

    auto init = reinterpret_cast<RiruInit_t *>(dlsym(handle, "init"));
    if (!init) {
        LOGW("%s does not export init", path.data());
        Cleanup(handle);
        return;
    }

    auto allow_unload = std::make_unique<int>();
    auto riru = std::make_unique<Riru>(Riru{
            .riruApiVersion = riru::apiVersion,
            .unused = nullptr,
            .magiskModulePath = magisk_module_path.data(),
            .allowUnload = allow_unload.get()
    });

    auto *module_info = init(riru.get());    //主动调用riru模块中的init函数
    if (module_info == nullptr) {
        LOGE("%s requires higher Riru version (or its broken)", path.data());
        Cleanup(handle);
        return;
    }

    auto api_version = module_info->moduleApiVersion;
    if (api_version < riru::minApiVersion || api_version > riru::apiVersion) {//校验下版本
        LOGW("unsupported API %s: %d", id.data(), api_version);
        Cleanup(handle);
        return;
    }

    LOGI("module loaded: %s (api %d)", id.data(), api_version);

    modules::Get().emplace_back(id, path, magisk_module_path, api_version, module_info->moduleInfo,
                                handle,
                                std::move(allow_unload)); //全局保存
}

LSP中对应返回模块信息代码如下:

// LSPosed/magisk-loader/src/main/jni/api/riru_main.cpp

RIRU_EXPORT RiruVersionedModuleInfo *init(Riru *riru) {
    LOGD("using riru {}", riru->riruApiVersion);
    LOGD("module path: {}", riru->magiskModulePath);
    lspd::magiskPath = riru->magiskModulePath;
    if (!lspd::isDebug && lspd::magiskPath.find(lspd::moduleName) == std::string::npos) {
        LOGE("who am i");
        return nullptr;
    }
    lspd::allowUnload = riru->allowUnload;
    return &lspd::module; //返回lsp模块信息给riru
}

RiruVersionedModuleInfo module{
        .moduleApiVersion = apiVersion,
        .moduleInfo = RiruModuleInfo{
                .supportHide = !isDebug,
                .version = versionCode,
                .versionName = versionName,
                .onModuleLoaded = lspd::onModuleLoaded,
                .forkAndSpecializePre = lspd::nativeForkAndSpecializePre,
                .forkAndSpecializePost = lspd::nativeForkAndSpecializePost,
                .forkSystemServerPre = lspd::nativeForkSystemServerPre,
                .forkSystemServerPost = lspd::nativeForkSystemServerPost,
                .specializeAppProcessPre = lspd::specializeAppProcessPre,
                .specializeAppProcessPost = lspd::specializeAppProcessPost,
        }
};

再看OnLoad何时调用, 但Riru.so被加载时候, 调用其init函数,init函数中再调用modules::Load()中回调Riru模块的onModuleLoaded方法

__used __attribute__((constructor)) void Constructor() {
  ...
    auto *handle = DlopenExt(riru_path, 0);
    if (handle) {
        auto init = reinterpret_cast<void (*)(void *, const char *, const RirudSocket &)>(dlsym(
                handle, "init"));
        if (init) {
            init(handle, magisk_path.data(), rirud);
        } else {
            LOGE("dlsym init %s", dlerror());
        }
    } else {
        LOGE("dlopen riru.so %s", dlerror());
    }
  ...
}

//  Riru/riru/src/main/cpp/entry.cpp"

init(void *handle, const char* magisk_path, const RirudSocket& rirud) {
    self_handle = handle;

    magisk::SetPath(magisk_path);
    hide::PrepareMapsHideLibrary();
    jni::InstallHooks();
    modules::Load(rirud);    // 主动调用模块onLoad方法
}

void modules::Load(const RirudSocket &rirud) {
    ...
    for (const auto &module : modules::Get()) {
        if (module.hasOnModuleLoaded()) {
            LOGV("%s: onModuleLoaded", module.id.data());
            module.onModuleLoaded(); // 主动调用模块onModuleLoaded方法
        }
    }
    ...
}

LSP

LSP就是一个Riru模块

	void onModuleLoaded() {
		LOGI("onModuleLoaded: welcome to LSPosed!");
		LOGI("onModuleLoaded: version v{} ({})", versionName, versionCode);
		MagiskLoader::Init();
		ConfigImpl::Init();
	}

zygote上的钩子

./LSPosed/magisk-loader/src/main/jni/api/riru_main.cpp
./LSPosed/external/lsplant/lsplant/src/main/jni/art/runtime/art_method.hpp
./LSPosed/external/lsplant/lsplant/src/main/jni/lsplant.cc
./LSPosed/external/lsplant/lsplant/src/main/jni/art/runtime/class_linker.hpp
../LSPosed/core/src/main/jni/src/context.cpp    // Context::InitHooks
    RiruVersionedModuleInfo module{
            .moduleApiVersion = apiVersion,
            .moduleInfo = RiruModuleInfo{
                    .supportHide = !isDebug,
                    .version = versionCode,
                    .versionName = versionName,
                    .onModuleLoaded = lspd::onModuleLoaded,
                    .forkAndSpecializePre = lspd::nativeForkAndSpecializePre,
                    .forkAndSpecializePost = lspd::nativeForkAndSpecializePost,
                    .forkSystemServerPre = lspd::nativeForkSystemServerPre,
                    .forkSystemServerPost = lspd::nativeForkSystemServerPost,
                    .specializeAppProcessPre = lspd::specializeAppProcessPre,
                    .specializeAppProcessPost = lspd::specializeAppProcessPost,
            }
    };

OnNativeForkAndSpecializePre

这里forkAndSpecializePrespecializeAppProcessPre 都是调用OnNativeForkAndSpecializePre,只有forkSystemServerPre OnNativeForkSystemServerPre

void MagiskLoader::OnNativeForkAndSpecializePre(JNIEnv *env,
                                           jint uid,
                                           jintArray &gids,
                                           jstring nice_name,
                                           jboolean is_child_zygote,
                                           jstring app_data_dir) {
    Service::instance()->InitService(env);
    ...
}

//  ../LSPosed/magisk-loader/src/main/jni/src/service.cpp
void Service::InitService(JNIEnv *env) {
    if (initialized_) [[unlikely]] return;

    // ServiceManager
    if (auto service_manager_class = JNI_FindClass(env, "android/os/ServiceManager")) {
        service_manager_class_ = JNI_NewGlobalRef(env, service_manager_class);
    } else return;
    get_service_method_ = JNI_GetStaticMethodID(env, service_manager_class_, "getService",
                                                "(Ljava/lang/String;)Landroid/os/IBinder;");
    if (!get_service_method_) return;

		...
}

OnNativeForkAndSpecializePost

    void
    MagiskLoader::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, jstring app_dir) {
        const JUTFString process_name(env, nice_name);
        auto *instance = Service::instance();
        auto binder = skip_ ? ScopedLocalRef<jobject>{env, nullptr}
                            : instance->RequestBinder(env, nice_name);
        if (binder) {
            lsplant::InitInfo initInfo{
                    .inline_hooker = [](auto t, auto r) {
                        void* bk = nullptr;
                        return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr;
                    },
                    .inline_unhooker = [](auto t) {
                        return UnhookFunction(t) == RT_SUCCESS;
                    },
                    .art_symbol_resolver = [](auto symbol){
                        return GetArt()->getSymbAddress(symbol);
                    },
                    .art_symbol_prefix_resolver = [](auto symbol) {
                        return GetArt()->getSymbPrefixFirstAddress(symbol);
                    },
            };
            auto [dex_fd, size] = instance->RequestLSPDex(env, binder);
            auto obfs_map = instance->RequestObfuscationMap(env, binder);
            ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map));
            LoadDex(env, PreloadedDex(dex_fd, size));    //加载lspd.dex
            close(dex_fd);
            InitArtHooker(env, initInfo);
            InitHooks(env);
            SetupEntryClass(env);      //lspd.dex的入口类org.lsposed.lspd.core.Main
            LOGD("Done prepare");
            FindAndCall(env, "forkCommon",
                        "(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V",
                        JNI_FALSE, nice_name, app_dir, binder);   // 启动 xposed Startup.bootstrapXposed
            LOGD("injected xposed into {}", process_name.get());
            setAllowUnload(false);
            GetArt(true);
        } else {
            auto context = Context::ReleaseInstance();
            auto service = Service::ReleaseInstance();
            GetArt(true);
            LOGD("skipped {}", process_name.get());
            setAllowUnload(true);
        }
    }

  • LoadDex // 将lspd.dex文件从磁盘map到内存中, InMemoryClassLoader加载,而不是pathclassload可能还是怕被风控

  • InitArtHooker

    1. InitJNI(env) //通过jni env 获取java 比如 dalvik/system/PathClassLoader

    2. InitNative(env, info) //libart 符号hook一些函数, SetEntryPointsToInterpreter等等

  • InitHooks

InitNative 基本是一顿Hook,hook了非常多的函数,比如setTrusted允许访问系统级API

    CREATE_FUNC_SYMBOL_ENTRY(void, DexFile_setTrusted, JNIEnv* env, jclass clazz,
                             jobject j_cookie) {
        if (DexFile_setTrustedSym != nullptr) [[likely]] {
            DexFile_setTrustedSym(env, clazz, j_cookie);
        }
    }

ClassLinker::Init(const HookHandler &handler) --> SetEntryPointsToInterpreter

// LSPosed/external/lsplant/lsplant/src/main/jni/art/runtime/class_linker.hpp
    [[gnu::always_inline]] static bool SetEntryPointsToInterpreter(ArtMethod *art_method) {
        if (SetEntryPointsToInterpreterSym) [[likely]] {
            SetEntryPointsToInterpreter(nullptr, art_method);
            return true;
        }
        // Android 13
        if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] {
            if (art_method->GetAccessFlags() & ArtMethod::kAccNative) [[unlikely]] {
                LOGV("deoptimize native method %s from %p to %p",
                     art_method->PrettyMethod(true).data(), art_method->GetEntryPoint(),
                     art_quick_generic_jni_trampolineSym);
                art_method->SetEntryPoint(
                    reinterpret_cast<void *>(art_quick_generic_jni_trampolineSym));
            } else {
                LOGV("deoptimize method %s from %p to %p", art_method->PrettyMethod(true).data(),
                     art_method->GetEntryPoint(), art_quick_to_interpreter_bridgeSym);
                art_method->SetEntryPoint(
                    reinterpret_cast<void *>(art_quick_to_interpreter_bridgeSym));
            }
            return true;
        }
        return false;
    }

posted @ 2024-06-21 18:52  梦过无声  阅读(108)  评论(0编辑  收藏  举报