Avoid resolving `libart` symbols twice

LSPlt is only used to hook libart symbols.
The file `native_util.h` is reformatted by clangd.
Fallback to Dobby if LSPlt fails.
This commit is contained in:
JingMatrix 2024-08-30 16:50:30 +02:00
parent 75e300532e
commit 1d7de6c78e
6 changed files with 74 additions and 84 deletions

View File

@ -31,7 +31,6 @@ namespace lspd {
//#define LOG_DISABLED
//#define DEBUG
using lsplant::operator""_tstr;
inline bool constexpr Is64() {
#if defined(__LP64__)

View File

@ -19,27 +19,30 @@
*/
#include <dlfcn.h>
#include "lsplt.hpp"
#include <sys/mman.h>
#include "elf_util.h"
#include "lsplt.hpp"
#include "symbol_cache.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
#pragma once
#include <context.h>
#include "utils/jni_helper.hpp"
#include "logging.h"
#include "config.h"
#include <cassert>
#include "../src/native_api.h"
#include "config.h"
#include "config_bridge.h"
#include "logging.h"
#include "utils/jni_helper.hpp"
namespace lspd {
[[gnu::always_inline]]
inline bool RegisterNativeMethodsInternal(JNIEnv *env,
std::string_view class_name,
const JNINativeMethod *methods,
jint method_count) {
inline bool RegisterNativeMethodsInternal(JNIEnv *env, std::string_view class_name,
const JNINativeMethod *methods, jint method_count) {
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data());
if (clazz.get() == nullptr) {
LOGF("Couldn't find class: {}", class_name.data());
@ -49,87 +52,74 @@ inline bool RegisterNativeMethodsInternal(JNIEnv *env,
}
#if defined(__cplusplus)
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
reinterpret_cast<to>
#define _NATIVEHELPER_JNI_MACRO_CAST(to) reinterpret_cast<to>
#else
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
(to)
#define _NATIVEHELPER_JNI_MACRO_CAST(to) (to)
#endif
#ifndef LSP_NATIVE_METHOD
#define LSP_NATIVE_METHOD(className, functionName, signature) \
{ #functionName, \
signature, \
_NATIVEHELPER_JNI_MACRO_CAST(void*) (Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName) \
}
{#functionName, signature, \
_NATIVEHELPER_JNI_MACRO_CAST(void *)( \
Java_org_lsposed_lspd_nativebridge_##className##_##functionName)}
#endif
#define JNI_START [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz
#define JNI_START [[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass clazz
#ifndef LSP_DEF_NATIVE_METHOD
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
extern "C" ret Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName (JNI_START, ## __VA_ARGS__)
extern "C" ret Java_org_lsposed_lspd_nativebridge_##className##_##functionName(JNI_START, \
##__VA_ARGS__)
#endif
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, arraysize(gMethods))
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, \
arraysize(gMethods))
static std::vector<std::tuple<dev_t, ino_t, const char *, void **>> plt_hook_list = {};
static auto scan_maps = lsplt::MapInfo::Scan();
static dev_t dev = 0;
static ino_t inode = 0;
static std::vector<std::pair<std::string_view, void **>> plt_hook_saved = {};
inline int plt_hook(const char *lib, const char *symbol, void *callback, void **backup) {
dev_t dev = 0;
ino_t inode = 0;
for (auto map : scan_maps) {
if (map.path == lib) {
inline int HookArtFunction(void *original, void *callback, void **backup, bool save = true) {
auto symbol = *reinterpret_cast<std::string_view *>(original);
if (dev == 0 || inode == 0) {
auto libart_path = GetArt()->name();
for (auto map : lsplt::MapInfo::Scan()) {
if (map.path == libart_path) {
inode = map.inode;
dev = map.dev;
break;
}
}
}
auto result = lsplt::RegisterHook(dev, inode, symbol, callback, backup) && lsplt::CommitHook();
if (result) {
plt_hook_list.emplace_back(dev, inode, symbol, backup);
if (result && *backup != nullptr) {
if (save) plt_hook_saved.emplace_back(symbol, backup);
} else if (auto addr = GetArt()->getSymbAddress(symbol); addr) {
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname != nullptr && info.dli_sname == symbol)
HookFunction(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) {
std::string_view func_name = *reinterpret_cast<std::string_view *>(original);
auto hook_iter = std::find_if(plt_hook_saved.begin(), plt_hook_saved.end(),
[func_name](auto record) { return record.first == func_name; });
void *stub = nullptr;
if (hook_iter != plt_hook_saved.end() &&
HookArtFunction(original, *(hook_iter->second), &stub, false)) {
plt_hook_saved.erase(hook_iter);
return 0;
}
return 1;
}
inline int HookFunction(void *original, void *replace, void **backup) {
Dl_info info;
if (dladdr(original, &info)) {
if constexpr (isDebug) {
LOGD("Hooking {} ({}) from {} ({})",
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
}
if (info.dli_sname != NULL && info.dli_fname != NULL)
return plt_hook(info.dli_fname, info.dli_sname, replace, backup);
}
return 1;
}
inline int UnhookFunction(void *original) {
Dl_info info;
if (dladdr(original, &info)) {
if constexpr (isDebug) {
LOGD("Unhooking {} ({}) from {} ({})",
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
}
for (const auto [dev, inode, symbol, backup] : plt_hook_list) {
if (info.dli_sname == symbol) {
auto result = lsplt::RegisterHook(dev, inode, symbol, backup, nullptr)
&& lsplt::CommitHook();
return 1 - result;
}
}
}
return 1;
}
inline std::string GetNativeBridgeSignature() {
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
static auto signature = obfs_map.at("org.lsposed.lspd.nativebridge.");

View File

@ -48,7 +48,6 @@
namespace lspd {
using lsplant::operator""_tstr;
std::list<NativeOnModuleLoaded> moduleLoadedCallbacks;
std::list<std::string> moduleNativeLibs;
std::unique_ptr<void, std::function<void(void *)>> protected_page(
@ -58,8 +57,8 @@ namespace lspd {
const auto[entries] = []() {
auto *entries = new(protected_page.get()) NativeAPIEntries{
.version = 2,
.hookFunc = &DobbyHookFunction,
.unhookFunc = &DobbyUnhookFunction,
.hookFunc = &HookFunction,
.unhookFunc = &UnhookFunction,
};
mprotect(protected_page.get(), 4096, PROT_READ);
@ -71,7 +70,7 @@ namespace lspd {
return InstallNativeAPI({
.inline_hooker = [](auto t, auto r) {
void* bk = nullptr;
return DobbyHookFunction(t, r, &bk) == 0 ? bk : nullptr;
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
},
});
}();

View File

@ -52,23 +52,25 @@ namespace lspd {
void RegisterNativeLib(const std::string &library_name);
inline int DobbyHookFunction(void *original, void *replace, void **backup) {
inline int HookFunction(void *original, void *replace, void **backup) {
if constexpr (isDebug) {
Dl_info info;
if (dladdr(original, &info))
LOGD("Dobby hooking {} ({}) from {} ({})",
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
info.dli_sname ? info.dli_sname : "(unknown symbol)",
info.dli_saddr ? info.dli_saddr : original,
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
}
return DobbyHook(original, reinterpret_cast<dobby_dummy_func_t>(replace), reinterpret_cast<dobby_dummy_func_t *>(backup));
}
inline int DobbyUnhookFunction(void *original) {
inline int UnhookFunction(void *original) {
if constexpr (isDebug) {
Dl_info info;
if (dladdr(original, &info))
LOGD("Dobby unhooking {} ({}) from {} ({})",
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
info.dli_sname ? info.dli_sname : "(unknown symbol)",
info.dli_saddr ? info.dli_saddr : original,
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
}
return DobbyDestroy(original);

2
external/lsplant vendored

@ -1 +1 @@
Subproject commit 9ce26897d3fc9a07ded56b3da612d154c1031a62
Subproject commit 2009a1922c63e5838eaeff79eacf821d4f6b536f

View File

@ -119,10 +119,10 @@ namespace lspd {
lsplant::InitInfo initInfo{
.inline_hooker = [](auto t, auto r) {
void* bk = nullptr;
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) {
return UnhookFunction(t) == 0 ;
return UnhookArtFunction(t) == 0 ;
},
.art_symbol_resolver = [](auto symbol) {
return GetArt()->getSymbAddress(symbol);
@ -198,10 +198,10 @@ namespace lspd {
lsplant::InitInfo initInfo{
.inline_hooker = [](auto t, auto r) {
void* bk = nullptr;
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
},
.inline_unhooker = [](auto t) {
return UnhookFunction(t) == 0;
return UnhookArtFunction(t) == 0;
},
.art_symbol_resolver = [](auto symbol){
return GetArt()->getSymbAddress(symbol);