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:
parent
75e300532e
commit
1d7de6c78e
|
|
@ -31,7 +31,6 @@ namespace lspd {
|
||||||
|
|
||||||
//#define LOG_DISABLED
|
//#define LOG_DISABLED
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
using lsplant::operator""_tstr;
|
|
||||||
|
|
||||||
inline bool constexpr Is64() {
|
inline bool constexpr Is64() {
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
|
|
|
||||||
|
|
@ -19,27 +19,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include "lsplt.hpp"
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "elf_util.h"
|
||||||
|
#include "lsplt.hpp"
|
||||||
|
#include "symbol_cache.h"
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wunused-value"
|
#pragma clang diagnostic ignored "-Wunused-value"
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <context.h>
|
#include <context.h>
|
||||||
#include "utils/jni_helper.hpp"
|
|
||||||
#include "logging.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../src/native_api.h"
|
||||||
|
#include "config.h"
|
||||||
#include "config_bridge.h"
|
#include "config_bridge.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "utils/jni_helper.hpp"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
|
|
||||||
[[gnu::always_inline]]
|
[[gnu::always_inline]]
|
||||||
inline bool RegisterNativeMethodsInternal(JNIEnv *env,
|
inline bool RegisterNativeMethodsInternal(JNIEnv *env, std::string_view class_name,
|
||||||
std::string_view class_name,
|
const JNINativeMethod *methods, jint method_count) {
|
||||||
const JNINativeMethod *methods,
|
|
||||||
jint method_count) {
|
|
||||||
|
|
||||||
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data());
|
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data());
|
||||||
if (clazz.get() == nullptr) {
|
if (clazz.get() == nullptr) {
|
||||||
LOGF("Couldn't find class: {}", class_name.data());
|
LOGF("Couldn't find class: {}", class_name.data());
|
||||||
|
|
@ -49,87 +52,74 @@ inline bool RegisterNativeMethodsInternal(JNIEnv *env,
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
|
#define _NATIVEHELPER_JNI_MACRO_CAST(to) reinterpret_cast<to>
|
||||||
reinterpret_cast<to>
|
|
||||||
#else
|
#else
|
||||||
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
|
#define _NATIVEHELPER_JNI_MACRO_CAST(to) (to)
|
||||||
(to)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LSP_NATIVE_METHOD
|
#ifndef LSP_NATIVE_METHOD
|
||||||
#define LSP_NATIVE_METHOD(className, functionName, signature) \
|
#define LSP_NATIVE_METHOD(className, functionName, signature) \
|
||||||
{ #functionName, \
|
{#functionName, signature, \
|
||||||
signature, \
|
_NATIVEHELPER_JNI_MACRO_CAST(void *)( \
|
||||||
_NATIVEHELPER_JNI_MACRO_CAST(void*) (Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName) \
|
Java_org_lsposed_lspd_nativebridge_##className##_##functionName)}
|
||||||
}
|
|
||||||
#endif
|
#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
|
#ifndef LSP_DEF_NATIVE_METHOD
|
||||||
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
|
#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
|
#endif
|
||||||
|
|
||||||
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
|
#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 dev_t dev = 0;
|
||||||
static auto scan_maps = lsplt::MapInfo::Scan();
|
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) {
|
inline int HookArtFunction(void *original, void *callback, void **backup, bool save = true) {
|
||||||
dev_t dev = 0;
|
auto symbol = *reinterpret_cast<std::string_view *>(original);
|
||||||
ino_t inode = 0;
|
if (dev == 0 || inode == 0) {
|
||||||
for (auto map : scan_maps) {
|
auto libart_path = GetArt()->name();
|
||||||
if (map.path == lib) {
|
for (auto map : lsplt::MapInfo::Scan()) {
|
||||||
|
if (map.path == libart_path) {
|
||||||
inode = map.inode;
|
inode = map.inode;
|
||||||
dev = map.dev;
|
dev = map.dev;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto result = lsplt::RegisterHook(dev, inode, symbol, callback, backup) && lsplt::CommitHook();
|
auto result = lsplt::RegisterHook(dev, inode, symbol, callback, backup) && lsplt::CommitHook();
|
||||||
if (result) {
|
if (result && *backup != nullptr) {
|
||||||
plt_hook_list.emplace_back(dev, inode, symbol, backup);
|
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 0;
|
||||||
}
|
}
|
||||||
return 1;
|
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() {
|
inline std::string GetNativeBridgeSignature() {
|
||||||
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
||||||
static auto signature = obfs_map.at("org.lsposed.lspd.nativebridge.");
|
static auto signature = obfs_map.at("org.lsposed.lspd.nativebridge.");
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
|
|
||||||
using lsplant::operator""_tstr;
|
|
||||||
std::list<NativeOnModuleLoaded> moduleLoadedCallbacks;
|
std::list<NativeOnModuleLoaded> moduleLoadedCallbacks;
|
||||||
std::list<std::string> moduleNativeLibs;
|
std::list<std::string> moduleNativeLibs;
|
||||||
std::unique_ptr<void, std::function<void(void *)>> protected_page(
|
std::unique_ptr<void, std::function<void(void *)>> protected_page(
|
||||||
|
|
@ -58,8 +57,8 @@ namespace lspd {
|
||||||
const auto[entries] = []() {
|
const auto[entries] = []() {
|
||||||
auto *entries = new(protected_page.get()) NativeAPIEntries{
|
auto *entries = new(protected_page.get()) NativeAPIEntries{
|
||||||
.version = 2,
|
.version = 2,
|
||||||
.hookFunc = &DobbyHookFunction,
|
.hookFunc = &HookFunction,
|
||||||
.unhookFunc = &DobbyUnhookFunction,
|
.unhookFunc = &UnhookFunction,
|
||||||
};
|
};
|
||||||
|
|
||||||
mprotect(protected_page.get(), 4096, PROT_READ);
|
mprotect(protected_page.get(), 4096, PROT_READ);
|
||||||
|
|
@ -71,7 +70,7 @@ namespace lspd {
|
||||||
return InstallNativeAPI({
|
return InstallNativeAPI({
|
||||||
.inline_hooker = [](auto t, auto r) {
|
.inline_hooker = [](auto t, auto r) {
|
||||||
void* bk = nullptr;
|
void* bk = nullptr;
|
||||||
return DobbyHookFunction(t, r, &bk) == 0 ? bk : nullptr;
|
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}();
|
}();
|
||||||
|
|
|
||||||
|
|
@ -52,23 +52,25 @@ namespace lspd {
|
||||||
|
|
||||||
void RegisterNativeLib(const std::string &library_name);
|
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) {
|
if constexpr (isDebug) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
if (dladdr(original, &info))
|
if (dladdr(original, &info))
|
||||||
LOGD("Dobby hooking {} ({}) from {} ({})",
|
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);
|
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));
|
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) {
|
if constexpr (isDebug) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
if (dladdr(original, &info))
|
if (dladdr(original, &info))
|
||||||
LOGD("Dobby unhooking {} ({}) from {} ({})",
|
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);
|
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
|
||||||
}
|
}
|
||||||
return DobbyDestroy(original);
|
return DobbyDestroy(original);
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9ce26897d3fc9a07ded56b3da612d154c1031a62
|
Subproject commit 2009a1922c63e5838eaeff79eacf821d4f6b536f
|
||||||
|
|
@ -119,10 +119,10 @@ namespace lspd {
|
||||||
lsplant::InitInfo initInfo{
|
lsplant::InitInfo initInfo{
|
||||||
.inline_hooker = [](auto t, auto r) {
|
.inline_hooker = [](auto t, auto r) {
|
||||||
void* bk = nullptr;
|
void* bk = nullptr;
|
||||||
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
|
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
|
||||||
},
|
},
|
||||||
.inline_unhooker = [](auto t) {
|
.inline_unhooker = [](auto t) {
|
||||||
return UnhookFunction(t) == 0 ;
|
return UnhookArtFunction(t) == 0 ;
|
||||||
},
|
},
|
||||||
.art_symbol_resolver = [](auto symbol) {
|
.art_symbol_resolver = [](auto symbol) {
|
||||||
return GetArt()->getSymbAddress(symbol);
|
return GetArt()->getSymbAddress(symbol);
|
||||||
|
|
@ -198,10 +198,10 @@ namespace lspd {
|
||||||
lsplant::InitInfo initInfo{
|
lsplant::InitInfo initInfo{
|
||||||
.inline_hooker = [](auto t, auto r) {
|
.inline_hooker = [](auto t, auto r) {
|
||||||
void* bk = nullptr;
|
void* bk = nullptr;
|
||||||
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
|
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
|
||||||
},
|
},
|
||||||
.inline_unhooker = [](auto t) {
|
.inline_unhooker = [](auto t) {
|
||||||
return UnhookFunction(t) == 0;
|
return UnhookArtFunction(t) == 0;
|
||||||
},
|
},
|
||||||
.art_symbol_resolver = [](auto symbol){
|
.art_symbol_resolver = [](auto symbol){
|
||||||
return GetArt()->getSymbAddress(symbol);
|
return GetArt()->getSymbAddress(symbol);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue