Move inline hooks to post fork

This commit is contained in:
LoveSy 2020-12-04 00:20:08 +08:00
parent 51dfa6b19f
commit d6c7570588
9 changed files with 125 additions and 86 deletions

View File

@ -41,67 +41,67 @@ ALWAYS_INLINE static int ClearException(JNIEnv *env) {
#define JNI_FindClass(env, name) \
env->FindClass(name); \
if (ClearException(env)) LOGE("FindClass " #name);
if (ClearException(env)) LOGE("FindClass " #name)
#define JNI_GetObjectClass(env, obj) \
env->GetObjectClass(obj); \
if (ClearException(env)) LOGE("GetObjectClass " #obj);
if (ClearException(env)) LOGE("GetObjectClass " #obj)
#define JNI_GetFieldID(env, class, name, sig) \
env->GetFieldID(class, name, sig); \
if (ClearException(env)) LOGE("GetFieldID " #name);
if (ClearException(env)) LOGE("GetFieldID " #name)
#define JNI_GetObjectField(env, class, fieldId) \
env->GetObjectField(class, fieldId); \
if (ClearException(env)) LOGE("GetObjectField " #fieldId);
if (ClearException(env)) LOGE("GetObjectField " #fieldId)
#define JNI_GetMethodID(env, class, name, sig) \
env->GetMethodID(class, name, sig); \
if (ClearException(env)) LOGE("GetMethodID " #name);
if (ClearException(env)) LOGE("GetMethodID " #name)
#define JNI_CallObjectMethod(env, obj, ...) \
env->CallObjectMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallObjectMethod " #obj " " #__VA_ARGS__);
if (ClearException(env)) LOGE("CallObjectMethod " #obj " " #__VA_ARGS__)
#define JNI_CallVoidMethod(env, obj, ...) \
env->CallVoidMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__);
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_GetStaticFieldID(env, class, name, sig) \
env->GetStaticFieldID(class, name, sig); \
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig);
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig)
#define JNI_GetStaticObjectField(env, class, fieldId) \
env->GetStaticObjectField(class, fieldId); \
if (ClearException(env)) LOGE("GetStaticObjectField " #fieldId);
if (ClearException(env)) LOGE("GetStaticObjectField " #fieldId)
#define JNI_GetStaticMethodID(env, class, name, sig) \
env->GetStaticMethodID(class, name, sig); \
if (ClearException(env)) LOGE("GetStaticMethodID " #name);
if (ClearException(env)) LOGE("GetStaticMethodID " #name)
#define JNI_CallStaticVoidMethod(env, obj, ...) \
env->CallStaticVoidMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__);
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__)
#define JNI_CallStaticObjectMethod(env, obj, ...) \
env->CallStaticObjectMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallStaticObjectMethod " #obj " " #__VA_ARGS__);
if (ClearException(env)) LOGE("CallStaticObjectMethod " #obj " " #__VA_ARGS__)
#define JNI_CallStaticIntMethod(env, obj, ...) \
env->CallStaticIntMethod(obj, __VA_ARGS__); \
if (ClearException(env)) LOGE("CallStaticIntMethod " #obj " " #__VA_ARGS__);
if (ClearException(env)) LOGE("CallStaticIntMethod " #obj " " #__VA_ARGS__)
#define JNI_GetArrayLength(env, array) \
env->GetArrayLength(array); \
if (ClearException(env)) LOGE("GetArrayLength " #array);
if (ClearException(env)) LOGE("GetArrayLength " #array)
#define JNI_NewObject(env, class, ...) \
env->NewObject(class, __VA_ARGS__); \
if (ClearException(env)) LOGE("NewObject " #class " " #__VA_ARGS__);
if (ClearException(env)) LOGE("NewObject " #class " " #__VA_ARGS__)
#define JNI_RegisterNatives(env, class, methods, size) \
env->RegisterNatives(class, methods, size); \
if (ClearException(env)) LOGE("RegisterNatives " #class);
if (ClearException(env)) LOGE("RegisterNatives " #class)
class JUTFString {
public:

View File

@ -46,7 +46,8 @@ namespace art {
}
}
CREATE_HOOK_STUB_ENTRIES(bool, ShouldUseInterpreterEntrypoint, void *art_method, const void* quick_code) {
CREATE_HOOK_STUB_ENTRIES(bool, ShouldUseInterpreterEntrypoint, void *art_method,
const void *quick_code) {
// TODO check hooked
bool hooked = false;
if (hooked && quick_code != nullptr) {
@ -68,46 +69,47 @@ namespace art {
// TODO: Maybe not compatible with Android 10-
int api_level = edxp::GetAndroidApiLevel();
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
switch(api_level) {
switch (api_level) {
case __ANDROID_API_O__:
[[fallthrough]];
case __ANDROID_API_O_MR1__:
#ifdef __LP64__
OFFSET_classlinker = 464 / 8;
#else
OFFSET_classlinker = 284 / 4;
#endif
if constexpr(edxp::is64) {
OFFSET_classlinker = 464;
} else {
OFFSET_classlinker = 284;
}
break;
case __ANDROID_API_P__:
#ifdef __LP64__
OFFSET_classlinker = 528 / 8;
#else
OFFSET_classlinker = 336 / 4;
#endif
if constexpr(edxp::is64) {
OFFSET_classlinker = 528;
} else {
OFFSET_classlinker = 336;
}
break;
case __ANDROID_API_Q__:
#ifdef __LP64__
OFFSET_classlinker = 480 / 8;
#else
OFFSET_classlinker = 280 / 4;
#endif
if constexpr(edxp::is64) {
OFFSET_classlinker = 480;
} else {
OFFSET_classlinker = 280;
}
break;
default:
LOGE("No valid offset for art::Runtime::class_linker_ found. Using Android R.");
[[fallthrough]];
case __ANDROID_API_R__:
#ifdef __LP64__
OFFSET_classlinker = 472 / 8;
#else
OFFSET_classlinker = 276 / 4;
#endif
if constexpr(edxp::is64) {
OFFSET_classlinker = 472;
} else {
OFFSET_classlinker = 276;
}
break;
}
void *thiz = *reinterpret_cast<void **>(
reinterpret_cast<size_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
// ClassLinker* GetClassLinker() but inlined
void* cl = reinterpret_cast<void*>(
reinterpret_cast<size_t*>(Runtime::Current()->Get()) + OFFSET_classlinker
);
LOGD("Classlinker object: %p", cl);
instance_ = new ClassLinker(cl);
LOGD("Classlinker object: %p", thiz);
instance_ = new ClassLinker(thiz);
HOOK_FUNC(Constructor, "_ZN3art11ClassLinkerC2EPNS_11InternTableE",
"_ZN3art11ClassLinkerC2EPNS_11InternTableEb"); // 10.0
@ -119,7 +121,8 @@ namespace art {
// Sandhook will hook ShouldUseInterpreterEntrypoint, so we just skip
// edxp::Context::GetInstance()->GetVariant() will not work here, so we use smh dirty hack
if (api_level >= __ANDROID_API_R__ && access(edxp::kLibSandHookNativePath.c_str(), F_OK) == -1) {
if (api_level >= __ANDROID_API_R__ &&
access(edxp::kLibSandHookNativePath.c_str(), F_OK) == -1) {
LOGD("Not sandhook, installing _ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");
HOOK_FUNC(ShouldUseInterpreterEntrypoint,
"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");

View File

@ -5,6 +5,7 @@
#include "collector/gc_type.h"
#include "gc_cause.h"
#include "../thread.h"
#include "../runtime.h"
namespace art {
@ -22,14 +23,6 @@ namespace art {
return art::gc::collector::GcType::kGcTypeNone;
}
CREATE_HOOK_STUB_ENTRIES(void, PreZygoteFork, void *thiz) {
if (instance_)
instance_->Reset(thiz);
else
instance_ = new Heap(thiz);
PreZygoteForkBackup(thiz);
}
public:
Heap(void *thiz) : HookedObject(thiz) {}
@ -39,7 +32,47 @@ namespace art {
// @ApiSensitive(Level.MIDDLE)
static void Setup(void *handle, HookFunType hook_func) {
HOOK_FUNC(PreZygoteFork, "_ZN3art2gc4Heap13PreZygoteForkEv");
int api_level = edxp::GetAndroidApiLevel();
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
switch (api_level) {
case __ANDROID_API_O__:
[[fallthrough]];
case __ANDROID_API_O_MR1__:
if constexpr(edxp::is64) {
OFFSET_classlinker = 464;
} else {
OFFSET_classlinker = 284;
}
break;
case __ANDROID_API_P__:
if constexpr(edxp::is64) {
OFFSET_classlinker = 528;
} else {
OFFSET_classlinker = 336;
}
break;
case __ANDROID_API_Q__:
if constexpr(edxp::is64) {
OFFSET_classlinker = 480;
} else {
OFFSET_classlinker = 280;
}
break;
default:
LOGE("No valid offset for art::Runtime::class_linker_ found. Using Android R.");
[[fallthrough]];
case __ANDROID_API_R__:
if constexpr(edxp::is64) {
OFFSET_classlinker = 392;
} else {
OFFSET_classlinker = 236;
}
break;
}
void *thiz = *reinterpret_cast<void **>(
reinterpret_cast<size_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
LOGD("HEAP object: %p", thiz);
instance_ = new Heap(thiz);
RETRIEVE_FUNC_SYMBOL(WaitForGcToComplete,
"_ZN3art2gc4Heap19WaitForGcToCompleteENS0_7GcCauseEPNS_6ThreadE");
}

View File

@ -16,19 +16,6 @@ namespace art {
DeoptimizeBootImageSym(thiz);
}
CREATE_HOOK_STUB_ENTRIES(bool, Init, void *thiz, void *runtime_options) {
if (LIKELY(instance_))
instance_->Reset(thiz);
else
instance_ = new Runtime(thiz);
bool success = InitBackup(thiz, runtime_options);
if (edxp::ConfigManager::GetInstance()->IsDeoptBootImageEnabled()) {
DeoptimizeBootImage(thiz);
LOGI("DeoptimizeBootImage done");
}
return success;
}
public:
Runtime(void *thiz) : HookedObject(thiz) {}
@ -38,19 +25,13 @@ namespace art {
// @ApiSensitive(Level.LOW)
static void Setup(void *handle, HookFunType hook_func) {
HOOK_FUNC(Init, "_ZN3art7Runtime4InitEONS_18RuntimeArgumentMapE");
RETRIEVE_FUNC_SYMBOL(DeoptimizeBootImage,
"_ZN3art7Runtime19DeoptimizeBootImageEv");
RETRIEVE_FIELD_SYMBOL(thiz, "_ZN3art7Runtime9instance_E");
RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E");
void * thiz = *reinterpret_cast<void**>(instance);
LOGD("_ZN3art7Runtime9instance_E = %p", thiz);
instance_ = new Runtime(thiz);
}
ALWAYS_INLINE void DeoptimizeBootImage() const {
if (LIKELY(thiz_))
DeoptimizeBootImage(thiz_);
}
};
}

View File

@ -12,6 +12,17 @@ namespace edxp {
//#define LOG_DISABLED
//#define DEBUG
inline bool constexpr Is64() {
#if defined(__LP64__)
return true;
#else
return false;
#endif
}
inline constexpr bool is64 = Is64();
#if defined(__LP64__)
# define LP_SELECT(lp32, lp64) (lp64)
#else

View File

@ -18,6 +18,9 @@
#include <sstream>
#include "edxp_context.h"
#include "config_manager.h"
#include "art/runtime/runtime.h"
#include "art/runtime/gc/heap.h"
#include "native_hook.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
@ -242,9 +245,22 @@ namespace edxp {
}
int Context::OnNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
int
Context::OnNativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) {
if (res == 0) {
if (!skip_) {
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE, -1,
0);
buf == MAP_FAILED) {
skip_ = true;
LOGE("skip injecting into android because sepolicy was not loaded properly");
} else {
munmap(buf, 1);
}
}
if (!skip_) {
InstallInlineHooks();
PrepareJavaEnv(env);
// only do work in child since FindAndCall would print log
FindAndCall(env, "forkSystemServerPost", "(I)V", res);
@ -345,6 +361,7 @@ namespace edxp {
if (res == 0) {
const JUTFString process_name(env, nice_name_);
if (!skip_) {
InstallInlineHooks();
PrepareJavaEnv(env);
LOGD("Done prepare");
FindAndCall(env, "forkAndSpecializePost",

View File

@ -9,18 +9,17 @@
namespace edxp {
static std::vector<void *> deopted_methods;
static std::unordered_set<void *> deopted_methods;
static void ClassLinker_setEntryPointsToInterpreter(JNI_START, jobject method) {
void *reflected_method = getArtMethod(env, method);
if (std::find(deopted_methods.begin(), deopted_methods.end(), reflected_method) !=
deopted_methods.end()) {
if (deopted_methods.count(reflected_method)) {
LOGD("method %p has been deopted before, skip...", reflected_method);
return;
}
LOGD("deoptimizing method: %p", reflected_method);
art::ClassLinker::Current()->SetEntryPointsToInterpreter(reflected_method);
deopted_methods.push_back(reflected_method);
deopted_methods.insert(reflected_method);
LOGD("method deoptimized: %p", reflected_method);
}

View File

@ -24,7 +24,6 @@ namespace edxp {
// TODO exclude unrelated processes
static void onModuleLoaded() {
LOG(INFO) << "onModuleLoaded: welcome to EdXposed!";
InstallInlineHooks();
}
static int shouldSkipUid(int uid) {

View File

@ -24,7 +24,7 @@ namespace edxp {
static volatile bool installed = false;
static volatile bool art_hooks_installed = false;
static HookFunType hook_func = nullptr;
static HookFunType hook_func = reinterpret_cast<HookFunType>(DobbyHook);
void InstallArtHooks(void *art_handle);
@ -42,8 +42,6 @@ namespace edxp {
}
LOGI("Using api level %d", api_level);
InstallRiruHooks();
hook_func = reinterpret_cast<HookFunType>(DobbyHook);
// 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.
@ -73,9 +71,7 @@ namespace edxp {
if (art_hooks_installed) {
return;
}
if (ConfigManager::GetInstance()->IsHiddenAPIBypassEnabled()) {
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
}
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
art::Runtime::Setup(art_handle, hook_func);
art::gc::Heap::Setup(art_handle, hook_func);
art::ClassLinker::Setup(art_handle, hook_func);