[core] native api (#108)
* [core] Propose the LSPosed native API * update native api specification * add symbol cache * [core] Native API implementation * Fix typo * Allow modules to load their own so * bug fixes * Fix crash in InstallRiruHooks * Ignore failed dlopen
This commit is contained in:
parent
a4e69792d5
commit
c9b73630ae
|
|
@ -22,7 +22,7 @@ namespace art {
|
|||
return PrettyMethod(thiz, true);
|
||||
}
|
||||
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
LOGD("art_method hook setup, handle=%p", handle);
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ namespace art {
|
|||
}
|
||||
|
||||
// @ApiSensitive(Level.MIDDLE)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
LOGD("Classlinker hook setup, handle=%p", handle);
|
||||
int api_level = lspd::GetAndroidApiLevel();
|
||||
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
|
||||
|
|
@ -128,7 +128,7 @@ namespace art {
|
|||
RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter,
|
||||
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE");
|
||||
|
||||
lspd::HookSyms(handle, hook_func, ShouldUseInterpreterEntrypoint);
|
||||
lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint);
|
||||
|
||||
if (api_level >= __ANDROID_API_R__) {
|
||||
// In android R, FixupStaticTrampolines won't be called unless it's marking it as
|
||||
|
|
@ -136,9 +136,9 @@ namespace art {
|
|||
// So we miss some calls between initialized and visiblyInitialized.
|
||||
// Therefore we hook the new introduced MarkClassInitialized instead
|
||||
// This only happens on non-x86 devices
|
||||
lspd::HookSyms(handle, hook_func, MarkClassInitialized);
|
||||
lspd::HookSyms(handle, MarkClassInitialized);
|
||||
} else {
|
||||
lspd::HookSyms(handle, hook_func, FixupStaticTrampolines);
|
||||
lspd::HookSyms(handle, FixupStaticTrampolines);
|
||||
}
|
||||
|
||||
// MakeInitializedClassesVisiblyInitialized will cause deadlock
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace art {
|
|||
}
|
||||
|
||||
// @ApiSensitive(Level.MIDDLE)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
int api_level = lspd::GetAndroidApiLevel();
|
||||
size_t OFFSET_heap; // Get offset from art::Runtime::RunRootClinits() call in IDA
|
||||
switch (api_level) {
|
||||
|
|
|
|||
|
|
@ -39,17 +39,17 @@ namespace art {
|
|||
});
|
||||
|
||||
// @ApiSensitive(Level.HIGH)
|
||||
static void DisableHiddenApi(void *handle, HookFunType hook_func) {
|
||||
static void DisableHiddenApi(void *handle) {
|
||||
const int api_level = lspd::GetAndroidApiLevel();
|
||||
if (api_level < __ANDROID_API_P__) {
|
||||
return;
|
||||
}
|
||||
if (api_level == __ANDROID_API_P__) {
|
||||
lspd::HookSyms(handle, hook_func, GetMethodActionImpl);
|
||||
lspd::HookSyms(handle, hook_func, GetFieldActionImpl);
|
||||
lspd::HookSyms(handle, GetMethodActionImpl);
|
||||
lspd::HookSyms(handle, GetFieldActionImpl);
|
||||
} else {
|
||||
lspd::HookSyms(handle, hook_func, ShouldDenyAccessToMethodImpl);
|
||||
lspd::HookSyms(handle, hook_func, ShouldDenyAccessToFieldImpl);
|
||||
lspd::HookSyms(handle, ShouldDenyAccessToMethodImpl);
|
||||
lspd::HookSyms(handle, ShouldDenyAccessToFieldImpl);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ namespace art {
|
|||
}
|
||||
});
|
||||
|
||||
static void DisableUpdateHookedMethodsCode(void *handle, HookFunType hook_func) {
|
||||
lspd::HookSym(handle, hook_func, UpdateMethodsCode);
|
||||
static void DisableUpdateHookedMethodsCode(void *handle) {
|
||||
lspd::HookSym(handle, UpdateMethodsCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace art {
|
|||
JNIEnvExt(void *thiz) : HookedObject(thiz) {}
|
||||
|
||||
// @ApiSensitive(Level.MIDDLE)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(NewLocalRef, "_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE");
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(DeleteLocalRef, "_ZN3art9JNIEnvExt14DeleteLocalRefEP8_jobject");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,13 +55,13 @@ namespace art {
|
|||
Class(void *thiz) : HookedObject(thiz) {}
|
||||
|
||||
// @ApiSensitive(Level.MIDDLE)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor, "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112"
|
||||
"basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE");
|
||||
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv");
|
||||
|
||||
lspd::HookSyms(handle, hook_func, IsInSamePackage);
|
||||
lspd::HookSyms(handle, IsInSamePackage);
|
||||
}
|
||||
|
||||
const char *GetDescriptor(std::string *storage) {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ namespace art {
|
|||
return backup(obj, declaring_class, access_flags, calling_class);
|
||||
});
|
||||
|
||||
static void PermissiveAccessByReflection(void *handle, HookFunType hook_func) {
|
||||
lspd::HookSym(handle, hook_func, VerifyAccess);
|
||||
static void PermissiveAccessByReflection(void *handle) {
|
||||
lspd::HookSym(handle, VerifyAccess);
|
||||
}
|
||||
}
|
||||
#endif //LSPOSED_REFLECTION_H
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace art {
|
|||
}
|
||||
|
||||
// @ApiSensitive(Level.LOW)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E");
|
||||
void * thiz = *reinterpret_cast<void**>(instance);
|
||||
LOGD("_ZN3art7Runtime9instance_E = %p", thiz);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace art {
|
|||
return Thread(CurrentFromGdb());
|
||||
}
|
||||
|
||||
static void Setup(void *handle, [[maybe_unused]] HookFunType hook_func) {
|
||||
static void Setup(void *handle) {
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(DecodeJObject,
|
||||
"_ZNK3art6Thread13DecodeJObjectEP8_jobject");
|
||||
RETRIEVE_FUNC_SYMBOL(CurrentFromGdb,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <dlfcn.h>
|
||||
#include <sys/mman.h>
|
||||
#include "config.h"
|
||||
#include "native_hook.h"
|
||||
|
||||
#define _uintval(p) reinterpret_cast<uintptr_t>(p)
|
||||
#define _ptr(p) reinterpret_cast<void *>(p)
|
||||
|
|
@ -19,8 +20,6 @@
|
|||
_page_align(_uintval(p) + n) != _page_align(_uintval(p)) ? _page_align(n) + _page_size : _page_align(n), \
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
|
||||
typedef void (*HookFunType)(void *, void *, void **);
|
||||
|
||||
#define CONCATENATE(a, b) a##b
|
||||
|
||||
#define CREATE_HOOK_STUB_ENTRIES(SYM, RET, FUNC, PARAMS, DEF) \
|
||||
|
|
@ -110,10 +109,9 @@ namespace lspd {
|
|||
return Dlsym(handle, last...);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline static void HookFunction(HookFunType hook_fun, void *original,
|
||||
void *replace, void **backup) {
|
||||
ALWAYS_INLINE inline static void HookFunction(void *original, void *replace, void **backup) {
|
||||
_make_rwx(original, _page_size);
|
||||
hook_fun(original, replace, backup);
|
||||
hook_func(original, replace, backup);
|
||||
}
|
||||
|
||||
template<class, template<class, class...> class>
|
||||
|
|
@ -207,15 +205,14 @@ namespace lspd {
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
inline static bool HookSym(void *handle, HookFunType hook_fun, T &arg) {
|
||||
auto original = Dlsym(handle, arg.sym);
|
||||
inline static bool HookSymNoHandle(void *original, T &arg) {
|
||||
if (original) {
|
||||
if constexpr(is_instance<decltype(arg.backup), MemberFunction>::value) {
|
||||
void *backup;
|
||||
HookFunction(hook_fun, original, reinterpret_cast<void *>(arg.replace), &backup);
|
||||
HookFunction(original, reinterpret_cast<void *>(arg.replace), &backup);
|
||||
arg.backup = reinterpret_cast<typename decltype(arg.backup)::FunType>(backup);
|
||||
} else {
|
||||
HookFunction(hook_fun, original, reinterpret_cast<void *>(arg.replace),
|
||||
HookFunction(original, reinterpret_cast<void *>(arg.replace),
|
||||
reinterpret_cast<void **>(&arg.backup));
|
||||
}
|
||||
return true;
|
||||
|
|
@ -224,9 +221,15 @@ namespace lspd {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static bool HookSym(void *handle, T &arg) {
|
||||
auto original = Dlsym(handle, arg.sym);
|
||||
return HookSymNoHandle(original, arg);
|
||||
}
|
||||
|
||||
template<typename T, typename...Args>
|
||||
inline static bool HookSyms(void *handle, HookFunType hook_fun, T &first, Args &...rest) {
|
||||
if (!(HookSym(handle, hook_fun, first) || ... || HookSym(handle, hook_fun, rest))) {
|
||||
inline static bool HookSyms(void *handle, T &first, Args &...rest) {
|
||||
if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) {
|
||||
LOGW("Hook Fails: %s", first.sym);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <jni.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <JNIHelper.h>
|
||||
#include <android-base/logging.h>
|
||||
#include "jni/config_manager.h"
|
||||
#include "jni/art_class_linker.h"
|
||||
#include "jni/art_heap.h"
|
||||
|
|
@ -9,19 +8,16 @@
|
|||
#include "jni/resources_hook.h"
|
||||
#include <dl_util.h>
|
||||
#include <art/runtime/jni_env_ext.h>
|
||||
#include <art/runtime/mirror/class.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <nativehelper/scoped_local_ref.h>
|
||||
#include "jni/pending_hooks.h"
|
||||
#include <sandhook.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "context.h"
|
||||
#include "config_manager.h"
|
||||
#include "art/runtime/runtime.h"
|
||||
#include "art/runtime/gc/heap.h"
|
||||
#include "native_hook.h"
|
||||
#include "jni/logger.h"
|
||||
#include "jni/native_api.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-value"
|
||||
|
|
@ -121,6 +117,7 @@ namespace lspd {
|
|||
RegisterArtHeap(env);
|
||||
RegisterEdxpYahfa(env);
|
||||
RegisterPendingHooks(env);
|
||||
RegisterNativeAPI(env);
|
||||
|
||||
variant_ = Variant(ConfigManager::GetInstance()->GetVariant());
|
||||
LOGI("LSP Variant: %d", variant_);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by 双草酸酯 on 2/7/21.
|
||||
//
|
||||
#include "native_api.h"
|
||||
#include "nativehelper/jni_macros.h"
|
||||
#include "native_util.h"
|
||||
#include "JNIHelper.h"
|
||||
#include "../native_api.h"
|
||||
|
||||
namespace lspd {
|
||||
LSP_DEF_NATIVE_METHOD(void, NativeAPI, recordNativeEntrypoint, jstring jstr) {
|
||||
JUTFString str(env, jstr);
|
||||
RegisterNativeLib(str);
|
||||
}
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
LSP_NATIVE_METHOD(NativeAPI, recordNativeEntrypoint, "(Ljava/lang/String;)V")
|
||||
};
|
||||
|
||||
void RegisterNativeAPI(JNIEnv *env) {
|
||||
REGISTER_LSP_NATIVE_METHODS(NativeAPI);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// Created by 双草酸酯 on 2/7/21.
|
||||
//
|
||||
|
||||
#ifndef LSPOSED_JNI_NATIVE_API_H
|
||||
#define LSPOSED_JNI_NATIVE_API_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace lspd {
|
||||
void RegisterNativeAPI(JNIEnv*);
|
||||
}
|
||||
|
||||
|
||||
#endif //LSPOSED_JNI_NATIVE_API_H
|
||||
|
|
@ -1,22 +1,13 @@
|
|||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sys/mman.h>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <android-base/logging.h>
|
||||
#include "logging.h"
|
||||
#include "config.h"
|
||||
#include "context.h"
|
||||
#include <riru.h>
|
||||
#include "config_manager.h"
|
||||
#include "native_hook.h"
|
||||
#include "symbol_cache.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-value"
|
||||
|
|
@ -25,6 +16,7 @@ namespace lspd {
|
|||
static void onModuleLoaded() {
|
||||
LOGI("onModuleLoaded: welcome to LSPosed!");
|
||||
// rirud must be used in onModuleLoaded
|
||||
InitSymbolCache();
|
||||
ConfigManager::Init();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// Created by kotori on 2/4/21.
|
||||
//
|
||||
|
||||
#include "native_api.h"
|
||||
#include "symbol_cache.h"
|
||||
#include <dobby.h>
|
||||
#include <vector>
|
||||
#include <base/object.h>
|
||||
|
||||
/*
|
||||
* Module: define xposed_native file in /assets, each line is a .so file name
|
||||
* LSP: Hook do_dlopen, if any .so file matches the name above, try to call
|
||||
* "native_init(void*)" function in target so with function pointer of "init" below.
|
||||
* Module: Call init function with the pointer of callback function.
|
||||
* LSP: Store the callback function pointer (multiple callback allowed) and return
|
||||
* LsposedNativeAPIEntries struct.
|
||||
* Module: Since JNI is not yet available at that time, module can store the struct to somewhere else,
|
||||
* and handle them in JNI_Onload or later.
|
||||
* Module: Do some MAGIC provided by LSPosed framework.
|
||||
* LSP: If any so loaded by target app, we will send a callback to the specific module callback function.
|
||||
* But an exception is, if the target skipped dlopen and handle linker stuffs on their own, the
|
||||
* callback will not work.
|
||||
*/
|
||||
|
||||
namespace lspd {
|
||||
std::vector<LsposedNativeOnModuleLoaded> moduleLoadedCallbacks;
|
||||
std::vector<std::string> moduleNativeLibs;
|
||||
|
||||
LsposedNativeAPIEntriesV1 init(LsposedNativeOnModuleLoaded onModuleLoaded) {
|
||||
if (onModuleLoaded != nullptr) moduleLoadedCallbacks.push_back(onModuleLoaded);
|
||||
|
||||
LsposedNativeAPIEntriesV1 ret{
|
||||
.version = 1,
|
||||
.inlineHookFunc = HookFunction
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RegisterNativeLib(const std::string& library_name) {
|
||||
LOGD("native_api: Registered %s", library_name.c_str());
|
||||
moduleNativeLibs.push_back(library_name);
|
||||
}
|
||||
|
||||
bool hasEnding(std::string_view fullString, std::string_view ending) {
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CREATE_HOOK_STUB_ENTRIES(
|
||||
"__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv",
|
||||
void*, do_dlopen, (const char* name, int flags, const void* extinfo,
|
||||
const void* caller_addr), {
|
||||
auto *handle = backup(name, flags, extinfo, caller_addr);
|
||||
std::string ns(name);
|
||||
LOGD("native_api: do_dlopen(%s)", name);
|
||||
if (handle == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (std::string_view module_lib: moduleNativeLibs) {
|
||||
// the so is a module so
|
||||
if (UNLIKELY(hasEnding(ns, module_lib))) {
|
||||
LOGI("Loading module native library %s", module_lib.data());
|
||||
void* native_init_sym = dlsym(handle, "native_init");
|
||||
if (UNLIKELY(native_init_sym == nullptr)) {
|
||||
LOGE("Failed to get symbol \"native_init\" from library %s", module_lib.data());
|
||||
break;
|
||||
}
|
||||
auto native_init = reinterpret_cast<NativeInit>(native_init_sym);
|
||||
native_init(reinterpret_cast<void*>(init));
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
for (LsposedNativeOnModuleLoaded callback: moduleLoadedCallbacks) {
|
||||
callback(name, handle);
|
||||
}
|
||||
return handle;
|
||||
});
|
||||
|
||||
void InstallNativeAPI() {
|
||||
LOGD("InstallNativeAPI: %p", symbol_do_dlopen);
|
||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
||||
HookSymNoHandle(symbol_do_dlopen, do_dlopen);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by kotori on 2/4/21.
|
||||
//
|
||||
|
||||
#ifndef LSPOSED_NATIVE_API_H
|
||||
#define LSPOSED_NATIVE_API_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <base/object.h>
|
||||
|
||||
// typedef int (*HookFunType)(void *, void *, void **); // For portability
|
||||
typedef void (*LsposedNativeOnModuleLoaded) (const char* name, void* handle);
|
||||
typedef void (*NativeInit)(void * init_func);
|
||||
struct LsposedNativeAPIEntriesV1 {
|
||||
uint32_t version;
|
||||
lspd::HookFunType inlineHookFunc;
|
||||
};
|
||||
|
||||
namespace lspd {
|
||||
void InstallNativeAPI();
|
||||
void RegisterNativeLib(const std::string& library_name);
|
||||
}
|
||||
|
||||
#endif //LSPOSED_NATIVE_API_H
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include "bionic_linker_restriction.h"
|
||||
#include "utils.h"
|
||||
#include "logging.h"
|
||||
#include "native_api.h"
|
||||
#include "native_hook.h"
|
||||
#include "riru_hook.h"
|
||||
#include "art/runtime/mirror/class.h"
|
||||
|
|
@ -17,7 +18,6 @@
|
|||
#include "art/runtime/class_linker.h"
|
||||
#include "art/runtime/gc/heap.h"
|
||||
#include "art/runtime/hidden_api.h"
|
||||
#include "art/runtime/art_method.h"
|
||||
#include "art/runtime/instrumentation.h"
|
||||
#include "art/runtime/reflection.h"
|
||||
|
||||
|
|
@ -27,7 +27,6 @@ namespace lspd {
|
|||
|
||||
static volatile bool installed = false;
|
||||
static volatile bool art_hooks_installed = false;
|
||||
static HookFunType hook_func = reinterpret_cast<HookFunType>(DobbyHook);
|
||||
|
||||
void InstallArtHooks(void *art_handle);
|
||||
|
||||
|
|
@ -44,7 +43,7 @@ namespace lspd {
|
|||
return;
|
||||
}
|
||||
LOGI("Using api level %d", api_level);
|
||||
InstallRiruHooks(hook_func);
|
||||
InstallRiruHooks();
|
||||
// install ART hooks
|
||||
if (api_level >= __ANDROID_API_Q__) {
|
||||
// From Riru v22 we can't get ART handle by hooking dlopen, so we get libart.so from soinfo.
|
||||
|
|
@ -68,22 +67,24 @@ namespace lspd {
|
|||
ScopedDlHandle art_handle(kLibArtLegacyPath.c_str());
|
||||
InstallArtHooks(art_handle.Get());
|
||||
}
|
||||
|
||||
InstallNativeAPI();
|
||||
}
|
||||
|
||||
void InstallArtHooks(void *art_handle) {
|
||||
if (art_hooks_installed) {
|
||||
return;
|
||||
}
|
||||
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
|
||||
art::Runtime::Setup(art_handle, hook_func);
|
||||
art::gc::Heap::Setup(art_handle, hook_func);
|
||||
art::art_method::Setup(art_handle, hook_func);
|
||||
art::Thread::Setup(art_handle, hook_func);
|
||||
art::ClassLinker::Setup(art_handle, hook_func);
|
||||
art::mirror::Class::Setup(art_handle, hook_func);
|
||||
art::JNIEnvExt::Setup(art_handle, hook_func);
|
||||
art::instrumentation::DisableUpdateHookedMethodsCode(art_handle, hook_func);
|
||||
art::PermissiveAccessByReflection(art_handle, hook_func);
|
||||
art::hidden_api::DisableHiddenApi(art_handle);
|
||||
art::Runtime::Setup(art_handle);
|
||||
art::gc::Heap::Setup(art_handle);
|
||||
art::art_method::Setup(art_handle);
|
||||
art::Thread::Setup(art_handle);
|
||||
art::ClassLinker::Setup(art_handle);
|
||||
art::mirror::Class::Setup(art_handle);
|
||||
art::JNIEnvExt::Setup(art_handle);
|
||||
art::instrumentation::DisableUpdateHookedMethodsCode(art_handle);
|
||||
art::PermissiveAccessByReflection(art_handle);
|
||||
|
||||
art_hooks_installed = true;
|
||||
LOGI("ART hooks installed");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
|
||||
#pragma once
|
||||
#include <dobby.h>
|
||||
|
||||
namespace lspd {
|
||||
|
||||
typedef void (*HookFunType)(void *, void *, void **);
|
||||
static HookFunType hook_func = reinterpret_cast<HookFunType>(DobbyHook);
|
||||
void InstallInlineHooks();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ namespace lspd {
|
|||
return res;
|
||||
});
|
||||
|
||||
void InstallRiruHooks(HookFunType hook_func) {
|
||||
void InstallRiruHooks() {
|
||||
|
||||
LOGI("Start to install Riru hook");
|
||||
|
||||
|
|
@ -112,8 +112,7 @@ namespace lspd {
|
|||
LOGE("Failed to get symbol of __system_property_get");
|
||||
return;
|
||||
}
|
||||
HookFunction(hook_func, sym, reinterpret_cast<void *>(decltype(__system_property_get)::replace),
|
||||
reinterpret_cast<void **>(&decltype(__system_property_get)::backup));
|
||||
HookSymNoHandle(sym, __system_property_get);
|
||||
|
||||
if (GetAndroidApiLevel() >= __ANDROID_API_P__) {
|
||||
sym = DobbySymbolResolver(nullptr,
|
||||
|
|
@ -122,8 +121,7 @@ namespace lspd {
|
|||
LOGE("Failed to get symbol of _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
||||
return;
|
||||
}
|
||||
HookFunction(hook_func, sym, reinterpret_cast<void *>(decltype(GetProperty)::replace),
|
||||
reinterpret_cast<void **>(&decltype(GetProperty)::backup));
|
||||
HookSymNoHandle(sym, GetProperty);
|
||||
}
|
||||
|
||||
LOGI("Riru hooks installed");
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ namespace lspd {
|
|||
static constexpr const char *kPropValueCompilerFlagsWS = " --inline-max-code-units=0";
|
||||
|
||||
|
||||
void InstallRiruHooks(HookFunType hook_func);
|
||||
void InstallRiruHooks();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by kotori on 2/7/21.
|
||||
//
|
||||
|
||||
#include "symbol_cache.h"
|
||||
#include <dobby.h>
|
||||
#include <art/base/macros.h>
|
||||
#include <logging.h>
|
||||
|
||||
namespace lspd {
|
||||
void InitSymbolCache() {
|
||||
if (LIKELY(initialized)) return;
|
||||
LOGD("InitSymbolCache");
|
||||
// TODO: set image name
|
||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Created by kotori on 2/7/21.
|
||||
//
|
||||
|
||||
#ifndef LSPOSED_SYMBOL_CACHE_H
|
||||
#define LSPOSED_SYMBOL_CACHE_H
|
||||
#include <atomic>
|
||||
|
||||
namespace lspd {
|
||||
static std::atomic_bool initialized;
|
||||
static void* symbol_do_dlopen = nullptr;
|
||||
|
||||
void InitSymbolCache();
|
||||
}
|
||||
|
||||
#endif //LSPOSED_SYMBOL_CACHE_H
|
||||
|
|
@ -41,6 +41,7 @@ import de.robv.android.xposed.callbacks.XC_InitPackageResources;
|
|||
import de.robv.android.xposed.callbacks.XC_InitZygote;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
import de.robv.android.xposed.callbacks.XCallback;
|
||||
import io.github.lsposed.lspd.nativebridge.NativeAPI;
|
||||
|
||||
import static de.robv.android.xposed.XposedBridge.hookAllConstructors;
|
||||
import static de.robv.android.xposed.XposedBridge.hookAllMethods;
|
||||
|
|
@ -345,6 +346,7 @@ public final class XposedInit {
|
|||
newLoadedApk.add(apk);
|
||||
} else {
|
||||
loadedModules.add(apk); // temporarily add it for XSharedPreference
|
||||
loadNativeLibs(apk);
|
||||
boolean loadSuccess = loadModule(apk, topClassLoader, callInitZygote);
|
||||
if (loadSuccess) {
|
||||
newLoadedApk.add(apk);
|
||||
|
|
@ -391,6 +393,45 @@ public final class XposedInit {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all so from an APK by reading <code>assets/native_init</code>.
|
||||
* It will only store the so names but not doing anything.
|
||||
*/
|
||||
private static boolean loadNativeLibs(String apk) {
|
||||
ZipFile zipFile = null;
|
||||
InputStream is;
|
||||
try {
|
||||
zipFile = new ZipFile(apk);
|
||||
ZipEntry zipEntry = zipFile.getEntry("assets/native_init");
|
||||
if (zipEntry == null) {
|
||||
Log.e(TAG, " assets/native_init not found in the APK");
|
||||
closeSilently(zipFile);
|
||||
return false;
|
||||
}
|
||||
is = zipFile.getInputStream(zipEntry);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, " Cannot read assets/native_init in the APK. Maybe it doesn't support native API", e);
|
||||
closeSilently(zipFile);
|
||||
return false;
|
||||
}
|
||||
BufferedReader moduleLibraryReader = new BufferedReader(new InputStreamReader(is));
|
||||
String moduleLibraryName;
|
||||
try {
|
||||
while ((moduleLibraryName = moduleLibraryReader.readLine()) != null) {
|
||||
if (!moduleLibraryName.startsWith("#") && moduleLibraryName.endsWith(".so")) {
|
||||
NativeAPI.recordNativeEntrypoint(moduleLibraryName);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, " Failed to load native library list from " + apk, e);
|
||||
return false;
|
||||
} finally {
|
||||
closeSilently(is);
|
||||
closeSilently(zipFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a module from an APK by calling the init(String) method for all classes defined
|
||||
* in <code>assets/xposed_init</code>.
|
||||
|
|
@ -403,7 +444,14 @@ public final class XposedInit {
|
|||
return false;
|
||||
}
|
||||
|
||||
ClassLoader mcl = new PathClassLoader(apk, topClassLoader);
|
||||
// module can load it's own so
|
||||
StringBuilder nativePath = new StringBuilder();
|
||||
for (String i: Build.SUPPORTED_ABIS) {
|
||||
nativePath.append(apk).append("!/lib/").append(i).append(File.pathSeparator);
|
||||
}
|
||||
// Log.d(TAG, "Allowed native path" + nativePath.toString());
|
||||
ClassLoader mcl = new PathClassLoader(apk, nativePath.toString(), topClassLoader);
|
||||
|
||||
try {
|
||||
if (mcl.loadClass(INSTANT_RUN_CLASS) != null) {
|
||||
Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio.");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package io.github.lsposed.lspd.nativebridge;
|
||||
|
||||
public class NativeAPI {
|
||||
public static native void recordNativeEntrypoint(String library_name);
|
||||
}
|
||||
Loading…
Reference in New Issue