Skip to content

Commit

Permalink
Avoid resolving libart symbols twice
Browse files Browse the repository at this point in the history
LSPlt is only used to hook libart symbols.
The file `native_util.h` is reformatted by clangd.
Fallback to Dobby if LSPlt fails.
  • Loading branch information
JingMatrix committed Aug 31, 2024
1 parent 1730700 commit 30043e2
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 81 deletions.
128 changes: 59 additions & 69 deletions core/src/main/jni/include/native_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -49,83 +52,70 @@ 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) \
}
#define LSP_NATIVE_METHOD(className, functionName, signature) \
{#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__)
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
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))

static std::vector<std::tuple<dev_t, ino_t, const char *, void **>> plt_hook_list = {};
static auto scan_maps = lsplt::MapInfo::Scan();

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) {
inode = map.inode;
dev = map.dev;
break;
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, \
arraysize(gMethods))

static dev_t dev = 0;
static ino_t inode = 0;
static std::vector<std::pair<std::string_view, void **>> plt_hook_saved = {};

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);
return 0;
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 1;
return *backup == nullptr;
}

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);
}
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; });

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;
}
}
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;
}
Expand All @@ -136,6 +126,6 @@ inline std::string GetNativeBridgeSignature() {
return signature;
}

} // namespace lspd
} // namespace lspd

#pragma clang diagnostic pop
6 changes: 3 additions & 3 deletions core/src/main/jni/src/native_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,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);
Expand All @@ -71,7 +71,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;
},
});
}();
Expand Down
10 changes: 6 additions & 4 deletions core/src/main/jni/src/native_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion external/lsplant
8 changes: 4 additions & 4 deletions magisk-loader/src/main/jni/src/magisk_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 30043e2

Please sign in to comment.