This commit is contained in:
kotori0 2020-12-18 17:40:02 +08:00
parent 01143501c7
commit c23e3ff33d
5 changed files with 94 additions and 39 deletions

View File

@ -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

View File

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

View File

@ -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];
}

View File

@ -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

View File

@ -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;