Try to fix #740
This commit is contained in:
parent
01143501c7
commit
c23e3ff33d
|
|
@ -20,7 +20,9 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass
|
||||||
void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz,
|
void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz,
|
||||||
jobject hook,
|
jobject hook,
|
||||||
jobject backup);
|
jobject backup);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void setNonCompilable(void *method);
|
void setNonCompilable(void *method);
|
||||||
|
|
||||||
void *getArtMethod(JNIEnv *env, jobject jmethod);
|
void *getArtMethod(JNIEnv *env, jobject jmethod);
|
||||||
|
|
@ -28,8 +30,7 @@ void *getArtMethod(JNIEnv *env, jobject jmethod);
|
||||||
// TODO: move to common utils instead of in YAHFA's code
|
// TODO: move to common utils instead of in YAHFA's code
|
||||||
void *getEntryPoint(void* method);
|
void *getEntryPoint(void* method);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void *getOriginalEntryPointFromHookedEntryPoint(void* method);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // HOOK_MAIN_H
|
#endif // HOOK_MAIN_H
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
extern int SDKVersion;
|
extern int SDKVersion;
|
||||||
|
|
||||||
extern unsigned char trampoline[];
|
extern unsigned char trampoline[];
|
||||||
|
extern unsigned char trampolineForBackup[];
|
||||||
|
|
||||||
void* doInitHookCap(size_t cap);
|
void* doInitHookCap(size_t cap);
|
||||||
void setupTrampoline(uint8_t offset);
|
void setupTrampoline(uint8_t offset);
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <stdbool.h>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "trampoline.h"
|
|
||||||
#include "HookMain.h"
|
#include "HookMain.h"
|
||||||
|
extern "C" {
|
||||||
|
#include "trampoline.h"
|
||||||
|
}
|
||||||
|
|
||||||
int SDKVersion;
|
int SDKVersion;
|
||||||
static uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
static uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
||||||
|
|
@ -14,7 +16,8 @@ static uint32_t OFFSET_ArtMehod_in_Object;
|
||||||
static uint32_t OFFSET_access_flags_in_ArtMethod;
|
static uint32_t OFFSET_access_flags_in_ArtMethod;
|
||||||
static uint32_t kAccCompileDontBother = 0x01000000;
|
static uint32_t kAccCompileDontBother = 0x01000000;
|
||||||
|
|
||||||
static jfieldID fieldArtMethod = NULL;
|
static jfieldID fieldArtMethod = nullptr;
|
||||||
|
static std::unordered_map<void*, void*> replaced_entrypoint;
|
||||||
|
|
||||||
static inline uint32_t read32(void *addr) {
|
static inline uint32_t read32(void *addr) {
|
||||||
return *((uint32_t *) addr);
|
return *((uint32_t *) addr);
|
||||||
|
|
@ -32,14 +35,14 @@ static inline void writeAddr(void *addr, void *value) {
|
||||||
*((void **)addr) = value;
|
*((void **)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) {
|
extern "C" void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) {
|
||||||
SDKVersion = sdkVersion;
|
SDKVersion = sdkVersion;
|
||||||
jclass classExecutable;
|
jclass classExecutable;
|
||||||
LOGI("init to SDK %d", sdkVersion);
|
LOGI("init to SDK %d", sdkVersion);
|
||||||
switch (sdkVersion) {
|
switch (sdkVersion) {
|
||||||
case __ANDROID_API_R__:
|
case __ANDROID_API_R__:
|
||||||
classExecutable = (*env)->FindClass(env, "java/lang/reflect/Executable");
|
classExecutable = env->FindClass("java/lang/reflect/Executable");
|
||||||
fieldArtMethod = (*env)->GetFieldID(env, classExecutable, "artMethod", "J");
|
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
|
||||||
case __ANDROID_API_Q__:
|
case __ANDROID_API_Q__:
|
||||||
case __ANDROID_API_P__:
|
case __ANDROID_API_P__:
|
||||||
kAccCompileDontBother = 0x02000000;
|
kAccCompileDontBother = 0x02000000;
|
||||||
|
|
@ -93,12 +96,14 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers
|
||||||
setupTrampoline(OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
setupTrampoline(OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t getFlags(char *method) {
|
static uint32_t getFlags(void *method_) {
|
||||||
|
char* method = (char*)method_;
|
||||||
uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod);
|
uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod);
|
||||||
return access_flags;
|
return access_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setFlags(char *method, uint32_t access_flags) {
|
static void setFlags(void *method_, uint32_t access_flags) {
|
||||||
|
char* method = (char*)method_;
|
||||||
write32(method + OFFSET_access_flags_in_ArtMethod, access_flags);
|
write32(method + OFFSET_access_flags_in_ArtMethod, access_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +124,7 @@ void *getEntryPoint(void* method) {
|
||||||
|
|
||||||
static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
||||||
// replace entry point
|
// replace entry point
|
||||||
void *newEntrypoint = NULL;
|
void *newEntrypoint = nullptr;
|
||||||
if(isBackup) {
|
if(isBackup) {
|
||||||
void *originEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
void *originEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
||||||
// entry point hardcoded
|
// entry point hardcoded
|
||||||
|
|
@ -127,24 +132,28 @@ static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// entry point from ArtMethod struct
|
// entry point from ArtMethod struct
|
||||||
newEntrypoint = genTrampoline(toMethod, NULL);
|
newEntrypoint = genTrampoline(toMethod, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* fromEntrypoint = (char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||||
|
replaced_entrypoint[fromEntrypoint] = newEntrypoint;
|
||||||
|
|
||||||
LOGI("replace entry point from %p to %p",
|
LOGI("replace entry point from %p to %p",
|
||||||
readAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod),
|
readAddr(fromEntrypoint),
|
||||||
newEntrypoint
|
newEntrypoint
|
||||||
);
|
);
|
||||||
if (newEntrypoint) {
|
if (newEntrypoint) {
|
||||||
writeAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod,
|
writeAddr(fromEntrypoint,
|
||||||
newEntrypoint);
|
newEntrypoint);
|
||||||
} else {
|
} else {
|
||||||
LOGE("failed to allocate space for trampoline of target method");
|
LOGE("failed to allocate space for trampoline of target method");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For pre Android M devices, should be not used by EdXposed.
|
||||||
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
|
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
|
||||||
void *interpEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod);
|
void *interpEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod);
|
||||||
writeAddr((char *) fromMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
|
writeAddr(fromEntrypoint,
|
||||||
interpEntrypoint);
|
interpEntrypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,16 +189,16 @@ static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMet
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getArtMethod(JNIEnv *env, jobject jmethod) {
|
void *getArtMethod(JNIEnv *env, jobject jmethod) {
|
||||||
void *artMethod = NULL;
|
void *artMethod = nullptr;
|
||||||
|
|
||||||
if (jmethod == NULL) {
|
if (jmethod == nullptr) {
|
||||||
return artMethod;
|
return artMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDKVersion == __ANDROID_API_R__) {
|
if (SDKVersion == __ANDROID_API_R__) {
|
||||||
artMethod = (void *) (*env)->GetLongField(env, jmethod, fieldArtMethod);
|
artMethod = (void *) env->GetLongField(jmethod, fieldArtMethod);
|
||||||
} else {
|
} else {
|
||||||
artMethod = (void *) (*env)->FromReflectedMethod(env, jmethod);
|
artMethod = (void *) env->FromReflectedMethod(jmethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("HookMain: getArtMethod: %p", artMethod);
|
LOGI("HookMain: getArtMethod: %p", artMethod);
|
||||||
|
|
@ -197,34 +206,34 @@ void *getArtMethod(JNIEnv *env, jobject jmethod) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz,
|
extern "C" jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz,
|
||||||
jclass targetClass, jstring methodName,
|
jclass targetClass, jstring methodName,
|
||||||
jstring methodSig) {
|
jstring methodSig) {
|
||||||
const char *c_methodName = (*env)->GetStringUTFChars(env, methodName, NULL);
|
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
|
||||||
const char *c_methodSig = (*env)->GetStringUTFChars(env, methodSig, NULL);
|
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
|
||||||
jobject ret = NULL;
|
jobject ret = nullptr;
|
||||||
|
|
||||||
|
|
||||||
//Try both GetMethodID and GetStaticMethodID -- Whatever works :)
|
//Try both GetMethodID and GetStaticMethodID -- Whatever works :)
|
||||||
jmethodID method = (*env)->GetMethodID(env, targetClass, c_methodName, c_methodSig);
|
jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig);
|
||||||
if (!(*env)->ExceptionCheck(env)) {
|
if (!env->ExceptionCheck()) {
|
||||||
ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_FALSE);
|
ret = env->ToReflectedMethod(targetClass, method, JNI_FALSE);
|
||||||
} else {
|
} else {
|
||||||
(*env)->ExceptionClear(env);
|
env->ExceptionClear();
|
||||||
method = (*env)->GetStaticMethodID(env, targetClass, c_methodName, c_methodSig);
|
method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig);
|
||||||
if (!(*env)->ExceptionCheck(env)) {
|
if (!env->ExceptionCheck()) {
|
||||||
ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_TRUE);
|
ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE);
|
||||||
} else {
|
} else {
|
||||||
(*env)->ExceptionClear(env);
|
env->ExceptionClear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, methodName, c_methodName);
|
env->ReleaseStringUTFChars(methodName, c_methodName);
|
||||||
(*env)->ReleaseStringUTFChars(env, methodSig, c_methodSig);
|
env->ReleaseStringUTFChars(methodSig, c_methodSig);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz,
|
extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz,
|
||||||
jobject target, jobject hook,
|
jobject target, jobject hook,
|
||||||
jobject backup) {
|
jobject backup) {
|
||||||
|
|
||||||
|
|
@ -232,10 +241,14 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass
|
||||||
getArtMethod(env, hook),
|
getArtMethod(env, hook),
|
||||||
getArtMethod(env, backup)
|
getArtMethod(env, backup)
|
||||||
)) {
|
)) {
|
||||||
(*env)->NewGlobalRef(env, hook); // keep a global ref so that the hook method would not be GCed
|
env->NewGlobalRef(hook); // keep a global ref so that the hook method would not be GCed
|
||||||
if (backup) (*env)->NewGlobalRef(env, backup);
|
if (backup) env->NewGlobalRef(backup);
|
||||||
return JNI_TRUE;
|
return JNI_TRUE;
|
||||||
} else {
|
} else {
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *getOriginalEntryPointFromHookedEntryPoint(void* method) {
|
||||||
|
return replaced_entrypoint[method];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Created by 双草酸酯 on 12/18/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EDXPOSED_OAT_QUICK_METHOD_HEADER_H
|
||||||
|
#define EDXPOSED_OAT_QUICK_METHOD_HEADER_H
|
||||||
|
|
||||||
|
#include <base/object.h>
|
||||||
|
#include <config_manager.h>
|
||||||
|
#include <HookMain.h>
|
||||||
|
namespace art {
|
||||||
|
// https://github.com/ElderDrivers/EdXposed/issues/740
|
||||||
|
class OatQuickMethodHeader : public edxp::HookedObject {
|
||||||
|
private:
|
||||||
|
CREATE_HOOK_STUB_ENTRIES(uint32_t, GetCodeSize, void *thiz) {
|
||||||
|
LOGD("OatQuickMethodHeader::GetCodeSize: %p", thiz);
|
||||||
|
void* oep = getOriginalEntryPointFromHookedEntryPoint(thiz);
|
||||||
|
if (oep) {
|
||||||
|
LOGD("OatQuickMethodHeader: Original entry point: %p", oep);
|
||||||
|
return GetCodeSizeBackup(oep);
|
||||||
|
} else {
|
||||||
|
LOGD("OatQuickMethodHeader: Original entry point not found");
|
||||||
|
return GetCodeSizeBackup(thiz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Setup(void *handle, HookFunType hook_func) {
|
||||||
|
if (edxp::GetAndroidApiLevel() >= __ANDROID_API_R__) {
|
||||||
|
HOOK_FUNC(GetCodeSize, "_ZNK3art20OatQuickMethodHeader11GetCodeSizeEv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EDXPOSED_OAT_QUICK_METHOD_HEADER_H
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include "art/runtime/gc/heap.h"
|
#include "art/runtime/gc/heap.h"
|
||||||
#include "art/runtime/hidden_api.h"
|
#include "art/runtime/hidden_api.h"
|
||||||
#include "art/runtime/oat_file_manager.h"
|
#include "art/runtime/oat_file_manager.h"
|
||||||
|
#include "art/runtime/oat_quick_method_header.h"
|
||||||
#include "art/runtime/jit/jit_code_cache.h"
|
#include "art/runtime/jit/jit_code_cache.h"
|
||||||
|
|
||||||
std::vector<soinfo_t> linker_get_solist(); // Dobby but not in .h
|
std::vector<soinfo_t> linker_get_solist(); // Dobby but not in .h
|
||||||
|
|
@ -79,6 +80,7 @@ namespace edxp {
|
||||||
art::mirror::Class::Setup(art_handle, hook_func);
|
art::mirror::Class::Setup(art_handle, hook_func);
|
||||||
art::JNIEnvExt::Setup(art_handle, hook_func);
|
art::JNIEnvExt::Setup(art_handle, hook_func);
|
||||||
art::oat_file_manager::DisableOnlyUseSystemOatFiles(art_handle, hook_func);
|
art::oat_file_manager::DisableOnlyUseSystemOatFiles(art_handle, hook_func);
|
||||||
|
art::OatQuickMethodHeader::Setup(art_handle, hook_func);
|
||||||
art::jit::HookJitCacheCode(art_handle, hook_func);
|
art::jit::HookJitCacheCode(art_handle, hook_func);
|
||||||
|
|
||||||
art_hooks_installed = true;
|
art_hooks_installed = true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue