refactor: improve hook and dex loading logic
重構了 patch_loader.cpp 並修改了bypass_sig.cpp,優化了 openat hook 的實現方式,簡化了 HookOpenat 和 enableOpenatHook 的流程。PatchLoader 的 LoadDex、InitArtHooker、InitHooks、SetupEntryClass、Load 方法也進行了結構優化,提升了代碼可讀性和健壯性,減少了重複代碼,並加強了錯誤處理。
參考自 802d3fbe28 爲什麽這樣改我也有點忘了,commit用Copilot寫的
This commit is contained in:
parent
4e63d61cd3
commit
c2fdd4941d
|
|
@ -195,7 +195,7 @@ fun AppManageBody(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(text = it.first.label, color = MaterialTheme.colorScheme.primary) },
|
text = { Text(text = appInfo.label, color = MaterialTheme.colorScheme.primary) },
|
||||||
onClick = {}, enabled = false
|
onClick = {}, enabled = false
|
||||||
)
|
)
|
||||||
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
||||||
|
|
@ -205,18 +205,18 @@ fun AppManageBody(
|
||||||
onClick = {
|
onClick = {
|
||||||
expanded = false
|
expanded = false
|
||||||
scope.launch {
|
scope.launch {
|
||||||
viewModel.dispatch(AppManageViewModel.ViewAction.UpdateLoader(it.first, it.second))
|
viewModel.dispatch(AppManageViewModel.ViewAction.UpdateLoader(appInfo, patchConfig))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (it.second.useManager) {
|
if (patchConfig.useManager) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.manage_module_scope)) },
|
text = { Text(stringResource(R.string.manage_module_scope)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
expanded = false
|
expanded = false
|
||||||
scope.launch {
|
scope.launch {
|
||||||
scopeApp = it.first.app.packageName
|
scopeApp = appInfo.app.packageName
|
||||||
val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet()
|
val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet()
|
||||||
val initialSelected = LSPPackageManager.appList.mapNotNullTo(ArrayList()) {
|
val initialSelected = LSPPackageManager.appList.mapNotNullTo(ArrayList()) {
|
||||||
if (activated.contains(it.app.packageName)) it.app.packageName else null
|
if (activated.contains(it.app.packageName)) it.app.packageName else null
|
||||||
|
|
@ -234,7 +234,7 @@ fun AppManageBody(
|
||||||
if (!ShizukuApi.isPermissionGranted) {
|
if (!ShizukuApi.isPermissionGranted) {
|
||||||
snackbarHost.showSnackbar(shizukuUnavailable)
|
snackbarHost.showSnackbar(shizukuUnavailable)
|
||||||
} else {
|
} else {
|
||||||
viewModel.dispatch(AppManageViewModel.ViewAction.PerformOptimize(it.first))
|
viewModel.dispatch(AppManageViewModel.ViewAction.PerformOptimize(appInfo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +252,7 @@ fun AppManageBody(
|
||||||
onClick = {
|
onClick = {
|
||||||
expanded = false
|
expanded = false
|
||||||
val intent = Intent(Intent.ACTION_DELETE).apply {
|
val intent = Intent(Intent.ACTION_DELETE).apply {
|
||||||
data = Uri.parse("package:${it.first.app.packageName}")
|
data = Uri.parse("package:${appInfo.app.packageName}")
|
||||||
putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||||
}
|
}
|
||||||
launcher.launch(intent)
|
launcher.launch(intent)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//
|
//
|
||||||
// Created by VIP on 2021/4/25.
|
// Created by VIP on 2021/4/25.
|
||||||
|
// Update by HSSkyBoy on 2025/9/7
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "bypass_sig.h"
|
#include "bypass_sig.h"
|
||||||
|
|
@ -19,14 +20,14 @@ namespace lspd {
|
||||||
std::string apkPath;
|
std::string apkPath;
|
||||||
std::string redirectPath;
|
std::string redirectPath;
|
||||||
|
|
||||||
inline static constexpr auto kLibCName = "libc.so";
|
inline static constexpr const char* kLibCName = "libc.so";
|
||||||
|
|
||||||
std::unique_ptr<const SandHook::ElfImg> &GetC(bool release = false) {
|
// 修改回傳型別以匹配 kImg 的實際型別
|
||||||
static std::unique_ptr<const SandHook::ElfImg> kImg = nullptr;
|
std::unique_ptr<SandHook::ElfImg> &GetC(bool release = false) {
|
||||||
|
static auto kImg = std::make_unique<SandHook::ElfImg>(kLibCName);
|
||||||
if (release) {
|
if (release) {
|
||||||
kImg.reset();
|
kImg.reset();
|
||||||
} else if (!kImg) {
|
kImg = nullptr;
|
||||||
kImg = std::make_unique<SandHook::ElfImg>(kLibCName);
|
|
||||||
}
|
}
|
||||||
return kImg;
|
return kImg;
|
||||||
}
|
}
|
||||||
|
|
@ -34,17 +35,21 @@ std::unique_ptr<const SandHook::ElfImg> &GetC(bool release = false) {
|
||||||
inline static auto __openat_ =
|
inline static auto __openat_ =
|
||||||
"__openat"_sym.hook->*[]<lsplant::Backup auto backup>(int fd, const char *pathname, int flag,
|
"__openat"_sym.hook->*[]<lsplant::Backup auto backup>(int fd, const char *pathname, int flag,
|
||||||
int mode) static -> int {
|
int mode) static -> int {
|
||||||
if (pathname == apkPath) {
|
if (pathname && strcmp(pathname, apkPath.c_str()) == 0) {
|
||||||
LOGD("Redirect openat from {} to {}", pathname, redirectPath);
|
|
||||||
return backup(fd, redirectPath.c_str(), flag, mode);
|
return backup(fd, redirectPath.c_str(), flag, mode);
|
||||||
}
|
}
|
||||||
return backup(fd, pathname, flag, mode);
|
return backup(fd, pathname, flag, mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HookOpenat(const lsplant::HookHandler &handler) { return handler(__openat_); }
|
static bool HookOpenat(const lsplant::HookHandler &handler) { return handler(__openat_); }
|
||||||
|
|
||||||
|
LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath,
|
||||||
|
jstring cacheApkPath) {
|
||||||
|
lsplant::JUTFString str1(env, origApkPath);
|
||||||
|
lsplant::JUTFString str2(env, cacheApkPath);
|
||||||
|
apkPath = str1.get();
|
||||||
|
redirectPath = str2.get();
|
||||||
|
|
||||||
LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath,
|
|
||||||
jstring cacheApkPath) {
|
|
||||||
auto r = HookOpenat(lsplant::InitInfo{
|
auto r = HookOpenat(lsplant::InitInfo{
|
||||||
.inline_hooker =
|
.inline_hooker =
|
||||||
[](auto t, auto r) {
|
[](auto t, auto r) {
|
||||||
|
|
@ -55,16 +60,10 @@ LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath,
|
||||||
});
|
});
|
||||||
if (!r) {
|
if (!r) {
|
||||||
LOGE("Hook __openat fail");
|
LOGE("Hook __openat fail");
|
||||||
return;
|
}
|
||||||
|
// 无论 Hook 成功与否,都确保清除 libc.so 的 ElfImg
|
||||||
|
GetC(true);
|
||||||
}
|
}
|
||||||
lsplant::JUTFString str1(env, origApkPath);
|
|
||||||
lsplant::JUTFString str2(env, cacheApkPath);
|
|
||||||
apkPath = str1.get();
|
|
||||||
redirectPath = str2.get();
|
|
||||||
LOGD("apkPath {}", apkPath.c_str());
|
|
||||||
LOGD("redirectPath {}", redirectPath.c_str());
|
|
||||||
GetC(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static JNINativeMethod gMethods[] = {
|
static JNINativeMethod gMethods[] = {
|
||||||
LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;)V")};
|
LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;)V")};
|
||||||
|
|
|
||||||
|
|
@ -35,95 +35,91 @@ using namespace lsplant;
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
|
|
||||||
void PatchLoader::LoadDex(JNIEnv* env, Context::PreloadedDex&& dex) {
|
void PatchLoader::LoadDex(JNIEnv* env, Context::PreloadedDex&& dex) {
|
||||||
auto class_activity_thread = JNI_FindClass(env, "android/app/ActivityThread");
|
auto class_activity_thread = JNI_FindClass(env, "android/app/ActivityThread");
|
||||||
auto class_activity_thread_app_bind_data =
|
auto class_activity_thread_app_bind_data = JNI_FindClass(env, "android/app/ActivityThread$AppBindData");
|
||||||
JNI_FindClass(env, "android/app/ActivityThread$AppBindData");
|
auto class_loaded_apk = JNI_FindClass(env, "android/app/LoadedApk");
|
||||||
auto class_loaded_apk = JNI_FindClass(env, "android/app/LoadedApk");
|
|
||||||
|
|
||||||
auto mid_current_activity_thread = JNI_GetStaticMethodID(
|
auto mid_current_activity_thread = JNI_GetStaticMethodID(env, class_activity_thread, "currentActivityThread", "()Landroid/app/ActivityThread;");
|
||||||
env, class_activity_thread, "currentActivityThread", "()Landroid/app/ActivityThread;");
|
auto mid_get_classloader = JNI_GetMethodID(env, class_loaded_apk, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
auto mid_get_classloader =
|
auto fid_m_bound_application = JNI_GetFieldID(env, class_activity_thread, "mBoundApplication", "Landroid/app/ActivityThread$AppBindData;");
|
||||||
JNI_GetMethodID(env, class_loaded_apk, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
auto fid_info = JNI_GetFieldID(env, class_activity_thread_app_bind_data, "info", "Landroid/app/LoadedApk;");
|
||||||
auto fid_m_bound_application = JNI_GetFieldID(env, class_activity_thread, "mBoundApplication",
|
|
||||||
"Landroid/app/ActivityThread$AppBindData;");
|
|
||||||
auto fid_info =
|
|
||||||
JNI_GetFieldID(env, class_activity_thread_app_bind_data, "info", "Landroid/app/LoadedApk;");
|
|
||||||
|
|
||||||
auto activity_thread =
|
auto activity_thread = JNI_CallStaticObjectMethod(env, class_activity_thread, mid_current_activity_thread);
|
||||||
JNI_CallStaticObjectMethod(env, class_activity_thread, mid_current_activity_thread);
|
auto m_bound_application = JNI_GetObjectField(env, activity_thread, fid_m_bound_application);
|
||||||
auto m_bound_application = JNI_GetObjectField(env, activity_thread, fid_m_bound_application);
|
auto info = JNI_GetObjectField(env, m_bound_application, fid_info);
|
||||||
auto info = JNI_GetObjectField(env, m_bound_application, fid_info);
|
auto stub_classloader = JNI_CallObjectMethod(env, info, mid_get_classloader);
|
||||||
auto stub_classloader = JNI_CallObjectMethod(env, info, mid_get_classloader);
|
|
||||||
|
|
||||||
if (!stub_classloader) [[unlikely]] {
|
if (!stub_classloader) {
|
||||||
LOGE("getStubClassLoader failed!!!");
|
LOGE("getStubClassLoader failed!!!");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
|
||||||
|
auto mid_init = JNI_GetMethodID(env, in_memory_classloader, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
|
auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
|
||||||
|
|
||||||
|
ScopedLocalRef<jobject> my_cl(JNI_NewObject(env, in_memory_classloader, mid_init, dex_buffer, stub_classloader));
|
||||||
|
if (!my_cl) {
|
||||||
|
LOGE("InMemoryDexClassLoader creation failed!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
|
void PatchLoader::InitArtHooker(JNIEnv* env, const InitInfo& initInfo) {
|
||||||
auto mid_init = JNI_GetMethodID(env, in_memory_classloader, "<init>",
|
Context::InitArtHooker(env, initInfo);
|
||||||
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
handler = initInfo;
|
||||||
auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
|
art::ProfileSaver::DisableInline(initInfo);
|
||||||
auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
|
art::FileManager::DisableBackgroundVerification(initInfo);
|
||||||
if (auto my_cl =
|
|
||||||
JNI_NewObject(env, in_memory_classloader, mid_init, dex_buffer, stub_classloader)) {
|
|
||||||
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
|
|
||||||
} else {
|
|
||||||
LOGE("InMemoryDexClassLoader creation failed!!!");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
env->DeleteLocalRef(dex_buffer);
|
void PatchLoader::InitHooks(JNIEnv* env) {
|
||||||
}
|
Context::InitHooks(env);
|
||||||
|
RegisterBypass(env);
|
||||||
void PatchLoader::InitArtHooker(JNIEnv* env, const InitInfo& initInfo) {
|
|
||||||
Context::InitArtHooker(env, initInfo);
|
|
||||||
handler = initInfo;
|
|
||||||
art::ProfileSaver::DisableInline(initInfo);
|
|
||||||
art::FileManager::DisableBackgroundVerification(initInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PatchLoader::InitHooks(JNIEnv* env) {
|
|
||||||
Context::InitHooks(env);
|
|
||||||
RegisterBypass(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PatchLoader::SetupEntryClass(JNIEnv* env) {
|
|
||||||
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
|
|
||||||
"org.lsposed.lspatch.loader.LSPApplication")) {
|
|
||||||
entry_class_ = JNI_NewGlobalRef(env, entry_class);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PatchLoader::Load(JNIEnv* env) {
|
void PatchLoader::SetupEntryClass(JNIEnv* env) {
|
||||||
/* InitSymbolCache(nullptr); */
|
ScopedLocalRef<jclass> entry_class(FindClassFromLoader(env, GetCurrentClassLoader(), "org.lsposed.lspatch.loader.LSPApplication"));
|
||||||
lsplant::InitInfo initInfo{
|
if (entry_class) {
|
||||||
.inline_hooker =
|
entry_class_ = JNI_NewGlobalRef(env, entry_class.get());
|
||||||
[](auto t, auto r) {
|
} else {
|
||||||
void* bk = nullptr;
|
LOGE("Failed to find entry class.");
|
||||||
return HookInline(t, r, &bk) == 0 ? bk : nullptr;
|
}
|
||||||
},
|
}
|
||||||
.inline_unhooker = [](auto t) { return UnhookInline(t) == 0; },
|
|
||||||
.art_symbol_resolver = [](auto symbol) { return GetArt()->getSymbAddress(symbol); },
|
|
||||||
.art_symbol_prefix_resolver =
|
|
||||||
[](auto symbol) { return GetArt()->getSymbPrefixFirstAddress(symbol); },
|
|
||||||
};
|
|
||||||
|
|
||||||
auto stub = JNI_FindClass(env, "org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub");
|
void PatchLoader::Load(JNIEnv* env) {
|
||||||
auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B");
|
lsplant::InitInfo initInfo{
|
||||||
|
.inline_hooker =
|
||||||
|
[](auto t, auto r) {
|
||||||
|
void* bk = nullptr;
|
||||||
|
return HookInline(t, r, &bk) == 0 ? bk : nullptr;
|
||||||
|
},
|
||||||
|
.inline_unhooker = [](auto t) { return UnhookInline(t) == 0; },
|
||||||
|
.art_symbol_resolver = [](auto symbol) { return GetArt()->getSymbAddress(symbol); },
|
||||||
|
.art_symbol_prefix_resolver =
|
||||||
|
[](auto symbol) { return GetArt()->getSymbPrefixFirstAddress(symbol); },
|
||||||
|
};
|
||||||
|
|
||||||
ScopedLocalRef<jbyteArray> array = JNI_GetStaticObjectField(env, stub, dex_field);
|
auto stub = JNI_FindClass(env, "org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub");
|
||||||
auto dex = PreloadedDex{env->GetByteArrayElements(array.get(), nullptr),
|
auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B");
|
||||||
static_cast<size_t>(JNI_GetArrayLength(env, array))};
|
ScopedLocalRef<jbyteArray> array = JNI_GetStaticObjectField(env, stub, dex_field);
|
||||||
|
|
||||||
InitArtHooker(env, initInfo);
|
if (!array) {
|
||||||
LoadDex(env, std::move(dex));
|
LOGE("Failed to get dex byte array from stub.");
|
||||||
InitHooks(env);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GetArt(true);
|
auto dex = PreloadedDex{env->GetByteArrayElements(array.get(), nullptr), static_cast<size_t>(JNI_GetArrayLength(env, array.get()))};
|
||||||
|
|
||||||
SetupEntryClass(env);
|
InitArtHooker(env, initInfo);
|
||||||
FindAndCall(env, "onLoad", "()V");
|
LoadDex(env, std::move(dex));
|
||||||
}
|
InitHooks(env);
|
||||||
|
|
||||||
|
GetArt(true);
|
||||||
|
|
||||||
|
SetupEntryClass(env);
|
||||||
|
FindAndCall(env, "onLoad", "()V");
|
||||||
|
}
|
||||||
} // namespace lspd
|
} // namespace lspd
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue