Indicate plt hook explicitly

The file magisk_loader.cpp is reformatted using clangd
This commit is contained in:
JingMatrix 2024-09-12 14:07:16 +02:00
parent c2c4e5207f
commit e28e194682
5 changed files with 190 additions and 202 deletions

View File

@ -80,7 +80,7 @@ static dev_t dev = 0;
static ino_t inode = 0;
static std::vector<std::pair<const char *, void **>> plt_hook_saved = {};
inline int HookArtFunction(void *art_symbol, void *callback, void **backup, bool save = true) {
inline int HookPLT(void *art_symbol, void *callback, void **backup, bool save = true) {
auto symbol = reinterpret_cast<const char *>(art_symbol);
if (GetArt()->isStripped()) {
@ -106,25 +106,25 @@ inline int HookArtFunction(void *art_symbol, void *callback, void **backup, bool
if (auto addr = GetArt()->getSymbAddress(symbol); addr) {
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname != nullptr && strcmp(info.dli_sname, symbol) == 0)
HookFunction(addr, callback, backup);
HookInline(addr, callback, backup);
} else if (*backup == nullptr && isDebug) {
LOGW("Failed to {} Art symbol {}", save ? "hook" : "unhook", symbol);
}
return *backup == nullptr;
}
inline int UnhookArtFunction(void *original) {
inline int UnhookPLT(void *original) {
Dl_info info;
if (!dladdr(original, &info) || info.dli_sname != nullptr) return 1;
if (!GetArt()->isStripped()) return UnhookFunction(original);
if (!GetArt()->isStripped()) return UnhookInline(original);
auto hook_iter =
std::find_if(plt_hook_saved.begin(), plt_hook_saved.end(),
[info](auto record) { return strcmp(record.first, info.dli_sname) == 0; });
void *stub = nullptr;
if (hook_iter != plt_hook_saved.end() &&
HookArtFunction(original, *(hook_iter->second), &stub, false)) {
HookPLT(original, *(hook_iter->second), &stub, false)) {
plt_hook_saved.erase(hook_iter);
return 0;
}

View File

@ -58,8 +58,8 @@ namespace lspd {
const auto[entries] = []() {
auto *entries = new(protected_page.get()) NativeAPIEntries{
.version = 2,
.hookFunc = &HookFunction,
.unhookFunc = &UnhookFunction,
.hookFunc = &HookInline,
.unhookFunc = &UnhookInline,
};
mprotect(protected_page.get(), 4096, PROT_READ);
@ -71,7 +71,7 @@ namespace lspd {
return InstallNativeAPI(lsplant::InitInfo {
.inline_hooker = [](auto t, auto r) {
void* bk = nullptr;
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
return HookInline(t, r, &bk) == 0 ? bk : nullptr;
},
.art_symbol_resolver = [](auto symbol){
return GetLinker()->getSymbAddress(symbol);

View File

@ -52,7 +52,7 @@ namespace lspd {
void RegisterNativeLib(const std::string &library_name);
inline int HookFunction(void *original, void *replace, void **backup) {
inline int HookInline(void *original, void *replace, void **backup) {
if constexpr (isDebug) {
Dl_info info;
if (dladdr(original, &info))
@ -64,7 +64,7 @@ namespace lspd {
return DobbyHook(original, reinterpret_cast<dobby_dummy_func_t>(replace), reinterpret_cast<dobby_dummy_func_t *>(backup));
}
inline int UnhookFunction(void *original) {
inline int UnhookInline(void *original) {
if constexpr (isDebug) {
Dl_info info;
if (dladdr(original, &info))

2
external/lsplant vendored

@ -1 +1 @@
Subproject commit 2a18d73b4d2150ca02b30938c0e82eb9aab1619e
Subproject commit d73aa7f9742b3c13084bb719962cfcd9358dd0f3

View File

@ -18,6 +18,8 @@
* Copyright (C) 2021 - 2022 LSPosed Contributors
*/
#include "magisk_loader.h"
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/mman.h>
@ -25,7 +27,6 @@
#include "config_impl.h"
#include "elf_util.h"
#include "loader.h"
#include "magisk_loader.h"
#include "native_util.h"
#include "service.h"
#include "symbol_cache.h"
@ -36,207 +37,194 @@ using namespace lsplant;
static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602));
namespace lspd {
extern int *allowUnload;
jboolean is_parasitic_manager = JNI_FALSE;
extern int *allowUnload;
jboolean is_parasitic_manager = JNI_FALSE;
constexpr int FIRST_ISOLATED_UID = 99000;
constexpr int LAST_ISOLATED_UID = 99999;
constexpr int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
constexpr int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
constexpr int SHARED_RELRO_UID = 1037;
constexpr int PER_USER_RANGE = 100000;
constexpr int FIRST_ISOLATED_UID = 99000;
constexpr int LAST_ISOLATED_UID = 99999;
constexpr int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
constexpr int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
constexpr int SHARED_RELRO_UID = 1037;
constexpr int PER_USER_RANGE = 100000;
static constexpr uid_t kAidInjected = INJECTED_AID;
static constexpr uid_t kAidInet = 3003;
static constexpr uid_t kAidInjected = INJECTED_AID;
static constexpr uid_t kAidInet = 3003;
void MagiskLoader::LoadDex(JNIEnv *env, PreloadedDex &&dex) {
auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
auto getsyscl_mid = JNI_GetStaticMethodID(
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (!sys_classloader) [[unlikely]] {
LOGE("getSystemClassLoader failed!!!");
return;
}
auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, sys_classloader)) {
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
} else {
LOGE("InMemoryDexClassLoader creation failed!!!");
return;
}
env->DeleteLocalRef(dex_buffer);
void MagiskLoader::LoadDex(JNIEnv *env, PreloadedDex &&dex) {
auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
auto getsyscl_mid = JNI_GetStaticMethodID(env, classloader, "getSystemClassLoader",
"()Ljava/lang/ClassLoader;");
auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (!sys_classloader) [[unlikely]] {
LOGE("getSystemClassLoader failed!!!");
return;
}
auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
if (auto my_cl =
JNI_NewObject(env, in_memory_classloader, initMid, dex_buffer, sys_classloader)) {
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
} else {
LOGE("InMemoryDexClassLoader creation failed!!!");
return;
}
std::string GetEntryClassName() {
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
static auto signature = obfs_map.at("org.lsposed.lspd.core.") + "Main";
return signature;
env->DeleteLocalRef(dex_buffer);
}
std::string GetEntryClassName() {
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
static auto signature = obfs_map.at("org.lsposed.lspd.core.") + "Main";
return signature;
}
void MagiskLoader::SetupEntryClass(JNIEnv *env) {
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), GetEntryClassName())) {
entry_class_ = JNI_NewGlobalRef(env, entry_class);
}
}
void MagiskLoader::SetupEntryClass(JNIEnv *env) {
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
GetEntryClassName())) {
entry_class_ = JNI_NewGlobalRef(env, entry_class);
}
}
void MagiskLoader::OnNativeForkSystemServerPre(JNIEnv *env) {
Service::instance()->InitService(env);
setAllowUnload(skip_);
}
void
MagiskLoader::OnNativeForkSystemServerPre(JNIEnv *env) {
Service::instance()->InitService(env);
setAllowUnload(skip_);
}
void
MagiskLoader::OnNativeForkSystemServerPost(JNIEnv *env) {
if (!skip_) {
auto *instance = Service::instance();
auto system_server_binder = instance->RequestSystemServerBinder(env);
if (!system_server_binder) {
LOGF("Failed to get system server binder, system server initialization failed.");
return;
}
auto application_binder = instance->RequestApplicationBinderFromSystemServer(env, system_server_binder);
// Call application_binder directly if application binder is available,
// or we proxy the request from system server binder
auto &&next_binder = application_binder ? application_binder : system_server_binder;
const auto [dex_fd, size] = instance->RequestLSPDex(env, next_binder);
auto obfs_map = instance->RequestObfuscationMap(env, next_binder);
ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map));
LoadDex(env, PreloadedDex(dex_fd, size));
close(dex_fd);
instance->HookBridge(*this, env);
// always inject into system server
lsplant::InitInfo initInfo{
.inline_hooker = [](auto t, auto r) {
void* bk = nullptr;
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) {
return UnhookArtFunction(t) == 0 ;
},
.art_symbol_resolver = [](auto symbol) {
return GetArt()->getSymbAddress(symbol);
},
.art_symbol_prefix_resolver = [](auto symbol) {
return GetArt()->getSymbPrefixFirstAddress(symbol);
},
};
InitArtHooker(env, initInfo);
InitHooks(env);
SetupEntryClass(env);
FindAndCall(env, "forkCommon",
"(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V",
JNI_TRUE, JNI_NewStringUTF(env, "system"), nullptr, application_binder, is_parasitic_manager);
GetArt(true);
}
}
void MagiskLoader::OnNativeForkAndSpecializePre(JNIEnv *env,
jint uid,
jintArray &gids,
jstring &nice_name,
jboolean is_child_zygote,
jstring app_data_dir) {
jboolean is_manager = JNI_FALSE;
if (uid == kAidInjected) {
const JUTFString name(env, nice_name);
if (name.get() == "org.lsposed.manager"sv) {
int array_size = gids ? env->GetArrayLength(gids) : 0;
auto region = std::make_unique<jint[]>(array_size + 1);
auto *new_gids = env->NewIntArray(array_size + 1);
if (gids) env->GetIntArrayRegion(gids, 0, array_size, region.get());
region.get()[array_size] = kAidInet;
env->SetIntArrayRegion(new_gids, 0, array_size + 1, region.get());
if (gids) env->SetIntArrayRegion(gids, 0, 1, region.get() + array_size);
gids = new_gids;
nice_name = JNI_NewStringUTF(env, "com.android.shell").release();
is_manager = JNI_TRUE;
}
}
is_parasitic_manager = is_manager;
Service::instance()->InitService(env);
const auto app_id = uid % PER_USER_RANGE;
JUTFString process_name(env, nice_name);
skip_ = false;
if (!skip_ && !app_data_dir) {
LOGD("skip injecting into {} because it has no data dir", process_name.get());
skip_ = true;
}
if (!skip_ && is_child_zygote) {
skip_ = true;
LOGD("skip injecting into {} because it's a child zygote", process_name.get());
}
if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID)) {
skip_ = true;
LOGI("skip injecting into {} because it's isolated", process_name.get());
}
setAllowUnload(skip_);
}
void
MagiskLoader::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, jstring app_dir) {
const JUTFString process_name(env, nice_name);
void MagiskLoader::OnNativeForkSystemServerPost(JNIEnv *env) {
if (!skip_) {
auto *instance = Service::instance();
if (is_parasitic_manager) nice_name = JNI_NewStringUTF(env, "org.lsposed.manager").release();
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 HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) {
return UnhookArtFunction(t) == 0;
},
.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));
close(dex_fd);
InitArtHooker(env, initInfo);
InitHooks(env);
SetupEntryClass(env);
LOGD("Done prepare");
FindAndCall(env, "forkCommon",
"(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V",
JNI_FALSE, nice_name, app_dir, binder);
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);
auto system_server_binder = instance->RequestSystemServerBinder(env);
if (!system_server_binder) {
LOGF("Failed to get system server binder, system server initialization failed.");
return;
}
auto application_binder =
instance->RequestApplicationBinderFromSystemServer(env, system_server_binder);
// Call application_binder directly if application binder is available,
// or we proxy the request from system server binder
auto &&next_binder = application_binder ? application_binder : system_server_binder;
const auto [dex_fd, size] = instance->RequestLSPDex(env, next_binder);
auto obfs_map = instance->RequestObfuscationMap(env, next_binder);
ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map));
LoadDex(env, PreloadedDex(dex_fd, size));
close(dex_fd);
instance->HookBridge(*this, env);
// always inject into system server
lsplant::InitInfo initInfo{
.inline_hooker =
[](auto t, auto r) {
void *bk = nullptr;
return HookPLT(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) { return UnhookPLT(t) == 0; },
.art_symbol_resolver = [](auto symbol) { return GetArt()->getSymbAddress(symbol); },
.art_symbol_prefix_resolver =
[](auto symbol) { return GetArt()->getSymbPrefixFirstAddress(symbol); },
.is_plt_hook = true};
InitArtHooker(env, initInfo);
InitHooks(env);
SetupEntryClass(env);
FindAndCall(env, "forkCommon",
"(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V", JNI_TRUE,
JNI_NewStringUTF(env, "system"), nullptr, application_binder,
is_parasitic_manager);
GetArt(true);
}
}
void MagiskLoader::OnNativeForkAndSpecializePre(JNIEnv *env, jint uid, jintArray &gids,
jstring &nice_name, jboolean is_child_zygote,
jstring app_data_dir) {
jboolean is_manager = JNI_FALSE;
if (uid == kAidInjected) {
const JUTFString name(env, nice_name);
if (name.get() == "org.lsposed.manager"sv) {
int array_size = gids ? env->GetArrayLength(gids) : 0;
auto region = std::make_unique<jint[]>(array_size + 1);
auto *new_gids = env->NewIntArray(array_size + 1);
if (gids) env->GetIntArrayRegion(gids, 0, array_size, region.get());
region.get()[array_size] = kAidInet;
env->SetIntArrayRegion(new_gids, 0, array_size + 1, region.get());
if (gids) env->SetIntArrayRegion(gids, 0, 1, region.get() + array_size);
gids = new_gids;
nice_name = JNI_NewStringUTF(env, "com.android.shell").release();
is_manager = JNI_TRUE;
}
}
is_parasitic_manager = is_manager;
Service::instance()->InitService(env);
const auto app_id = uid % PER_USER_RANGE;
JUTFString process_name(env, nice_name);
skip_ = false;
if (!skip_ && !app_data_dir) {
LOGD("skip injecting into {} because it has no data dir", process_name.get());
skip_ = true;
}
if (!skip_ && is_child_zygote) {
skip_ = true;
LOGD("skip injecting into {} because it's a child zygote", process_name.get());
}
void MagiskLoader::setAllowUnload(bool unload) {
if (allowUnload) {
*allowUnload = unload ? 1 : 0;
}
if (!skip_ &&
((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID && app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID)) {
skip_ = true;
LOGI("skip injecting into {} because it's isolated", process_name.get());
}
setAllowUnload(skip_);
}
void MagiskLoader::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, jstring app_dir) {
const JUTFString process_name(env, nice_name);
auto *instance = Service::instance();
if (is_parasitic_manager) nice_name = JNI_NewStringUTF(env, "org.lsposed.manager").release();
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 HookPLT(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) { return UnhookPLT(t) == 0; },
.art_symbol_resolver = [](auto symbol) { return GetArt()->getSymbAddress(symbol); },
.art_symbol_prefix_resolver =
[](auto symbol) { return GetArt()->getSymbPrefixFirstAddress(symbol); },
.is_plt_hook = true};
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));
close(dex_fd);
InitArtHooker(env, initInfo);
InitHooks(env);
SetupEntryClass(env);
LOGD("Done prepare");
FindAndCall(env, "forkCommon",
"(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V", JNI_FALSE,
nice_name, app_dir, binder);
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);
}
}
void MagiskLoader::setAllowUnload(bool unload) {
if (allowUnload) {
*allowUnload = unload ? 1 : 0;
}
}
} // namespace lspd