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,
jobject hook,
jobject backup);
#ifdef __cplusplus
}
#endif
void setNonCompilable(void *method);
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
void *getEntryPoint(void* method);
#ifdef __cplusplus
}
#endif
void *getOriginalEntryPointFromHookedEntryPoint(void* method);
#endif // HOOK_MAIN_H

View File

@ -8,6 +8,7 @@
extern int SDKVersion;
extern unsigned char trampoline[];
extern unsigned char trampolineForBackup[];
void* doInitHookCap(size_t cap);
void setupTrampoline(uint8_t offset);

View File

@ -1,11 +1,13 @@
#include "jni.h"
#include <sys/mman.h>
#include <stdlib.h>
#include <stdbool.h>
#include <cstdlib>
#include <unordered_map>
#include "common.h"
#include "trampoline.h"
#include "HookMain.h"
extern "C" {
#include "trampoline.h"
}
int SDKVersion;
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 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) {
return *((uint32_t *) addr);
@ -32,14 +35,14 @@ static inline void writeAddr(void *addr, void *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;
jclass classExecutable;
LOGI("init to SDK %d", sdkVersion);
switch (sdkVersion) {
case __ANDROID_API_R__:
classExecutable = (*env)->FindClass(env, "java/lang/reflect/Executable");
fieldArtMethod = (*env)->GetFieldID(env, classExecutable, "artMethod", "J");
classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
case __ANDROID_API_Q__:
case __ANDROID_API_P__:
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);
}
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);
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);
}
@ -119,7 +124,7 @@ void *getEntryPoint(void* method) {
static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
// replace entry point
void *newEntrypoint = NULL;
void *newEntrypoint = nullptr;
if(isBackup) {
void *originEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
// entry point hardcoded
@ -127,24 +132,28 @@ static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
}
else {
// 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",
readAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod),
readAddr(fromEntrypoint),
newEntrypoint
);
if (newEntrypoint) {
writeAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod,
writeAddr(fromEntrypoint,
newEntrypoint);
} else {
LOGE("failed to allocate space for trampoline of target method");
return 1;
}
// For pre Android M devices, should be not used by EdXposed.
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
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);
}
@ -180,16 +189,16 @@ static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMet
}
void *getArtMethod(JNIEnv *env, jobject jmethod) {
void *artMethod = NULL;
void *artMethod = nullptr;
if (jmethod == NULL) {
if (jmethod == nullptr) {
return artMethod;
}
if (SDKVersion == __ANDROID_API_R__) {
artMethod = (void *) (*env)->GetLongField(env, jmethod, fieldArtMethod);
artMethod = (void *) env->GetLongField(jmethod, fieldArtMethod);
} else {
artMethod = (void *) (*env)->FromReflectedMethod(env, jmethod);
artMethod = (void *) env->FromReflectedMethod(jmethod);
}
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,
jstring methodSig) {
const char *c_methodName = (*env)->GetStringUTFChars(env, methodName, NULL);
const char *c_methodSig = (*env)->GetStringUTFChars(env, methodSig, NULL);
jobject ret = NULL;
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
jobject ret = nullptr;
//Try both GetMethodID and GetStaticMethodID -- Whatever works :)
jmethodID method = (*env)->GetMethodID(env, targetClass, c_methodName, c_methodSig);
if (!(*env)->ExceptionCheck(env)) {
ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_FALSE);
jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig);
if (!env->ExceptionCheck()) {
ret = env->ToReflectedMethod(targetClass, method, JNI_FALSE);
} else {
(*env)->ExceptionClear(env);
method = (*env)->GetStaticMethodID(env, targetClass, c_methodName, c_methodSig);
if (!(*env)->ExceptionCheck(env)) {
ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_TRUE);
env->ExceptionClear();
method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig);
if (!env->ExceptionCheck()) {
ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE);
} else {
(*env)->ExceptionClear(env);
env->ExceptionClear();
}
}
(*env)->ReleaseStringUTFChars(env, methodName, c_methodName);
(*env)->ReleaseStringUTFChars(env, methodSig, c_methodSig);
env->ReleaseStringUTFChars(methodName, c_methodName);
env->ReleaseStringUTFChars(methodSig, c_methodSig);
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 backup) {
@ -232,10 +241,14 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass
getArtMethod(env, hook),
getArtMethod(env, backup)
)) {
(*env)->NewGlobalRef(env, hook); // keep a global ref so that the hook method would not be GCed
if (backup) (*env)->NewGlobalRef(env, backup);
env->NewGlobalRef(hook); // keep a global ref so that the hook method would not be GCed
if (backup) env->NewGlobalRef(backup);
return JNI_TRUE;
} else {
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/hidden_api.h"
#include "art/runtime/oat_file_manager.h"
#include "art/runtime/oat_quick_method_header.h"
#include "art/runtime/jit/jit_code_cache.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::JNIEnvExt::Setup(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_hooks_installed = true;