Hook UpdateMethodCode
This commit is contained in:
parent
f6da55411d
commit
0e2783f8e5
|
|
@ -5,34 +5,40 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "HookMain.h"
|
||||
|
||||
extern "C" {
|
||||
#include "trampoline.h"
|
||||
}
|
||||
|
||||
int SDKVersion;
|
||||
static uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
||||
static uint32_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||
static uint32_t OFFSET_ArtMehod_in_Object;
|
||||
static uint32_t OFFSET_access_flags_in_ArtMethod;
|
||||
static uint32_t kAccCompileDontBother = 0x01000000;
|
||||
namespace {
|
||||
uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
||||
uint32_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||
uint32_t OFFSET_ArtMehod_in_Object;
|
||||
uint32_t OFFSET_access_flags_in_ArtMethod;
|
||||
uint32_t kAccCompileDontBother = 0x01000000;
|
||||
uint32_t kAccNative = 0x0100;
|
||||
uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
||||
|
||||
static jfieldID fieldArtMethod = nullptr;
|
||||
static std::unordered_map<void*, void*> replaced_entrypoint;
|
||||
jfieldID fieldArtMethod = nullptr;
|
||||
|
||||
static inline uint32_t read32(void *addr) {
|
||||
return *((uint32_t *) addr);
|
||||
}
|
||||
std::unordered_map<void *, void *> replaced_entrypoint;
|
||||
|
||||
static inline void write32(void *addr, uint32_t value) {
|
||||
*((uint32_t *) addr) = value;
|
||||
}
|
||||
inline uint32_t read32(void *addr) {
|
||||
return *((uint32_t *) addr);
|
||||
}
|
||||
|
||||
static inline void *readAddr(void *addr) {
|
||||
return *((void **) addr);
|
||||
}
|
||||
inline void write32(void *addr, uint32_t value) {
|
||||
*((uint32_t *) addr) = value;
|
||||
}
|
||||
|
||||
static inline void writeAddr(void *addr, void *value) {
|
||||
*((void **)addr) = value;
|
||||
inline void *readAddr(void *addr) {
|
||||
return *((void **) addr);
|
||||
}
|
||||
|
||||
inline void writeAddr(void *addr, void *value) {
|
||||
*((void **) addr) = value;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) {
|
||||
|
|
@ -97,13 +103,13 @@ extern "C" void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, j
|
|||
}
|
||||
|
||||
static uint32_t getFlags(void *method_) {
|
||||
char* method = (char*)method_;
|
||||
char *method = (char *) method_;
|
||||
uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod);
|
||||
return access_flags;
|
||||
}
|
||||
|
||||
static void setFlags(void *method_, uint32_t access_flags) {
|
||||
char* method = (char*)method_;
|
||||
char *method = (char *) method_;
|
||||
write32(method + OFFSET_access_flags_in_ArtMethod, access_flags);
|
||||
}
|
||||
|
||||
|
|
@ -118,20 +124,21 @@ void setNonCompilable(void *method) {
|
|||
LOGI("setNonCompilable: change access flags from 0x%x to 0x%x", old_flags, access_flags);
|
||||
}
|
||||
|
||||
void *getEntryPoint(void* method) {
|
||||
void *getEntryPoint(void *method) {
|
||||
return readAddr((char *) method + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
||||
}
|
||||
|
||||
static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
||||
// replace entry point
|
||||
void *newEntrypoint = nullptr;
|
||||
void* fromEntrypoint = (char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||
void *fromEntrypoint =
|
||||
(char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||
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
|
||||
newEntrypoint = genTrampoline(toMethod, originEntrypoint);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// entry point from ArtMethod struct
|
||||
newEntrypoint = genTrampoline(toMethod, nullptr);
|
||||
}
|
||||
|
|
@ -147,7 +154,8 @@ static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
|||
|
||||
// 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);
|
||||
void *interpEntrypoint = readAddr(
|
||||
(char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod);
|
||||
writeAddr(fromEntrypoint, interpEntrypoint);
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +173,7 @@ static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMet
|
|||
if (SDKVersion >= __ANDROID_API_N__) {
|
||||
setNonCompilable(targetMethod);
|
||||
// setNonCompilable(hookMethod);
|
||||
if(backupMethod) setNonCompilable(backupMethod);
|
||||
if (backupMethod) setNonCompilable(backupMethod);
|
||||
}
|
||||
|
||||
if (backupMethod) {// do method backup
|
||||
|
|
@ -201,8 +209,9 @@ void *getArtMethod(JNIEnv *env, jobject jmethod) {
|
|||
}
|
||||
|
||||
extern "C" jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz,
|
||||
jclass targetClass, jstring methodName,
|
||||
jstring methodSig) {
|
||||
jclass targetClass,
|
||||
jstring methodName,
|
||||
jstring methodSig) {
|
||||
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
|
||||
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
|
||||
jobject ret = nullptr;
|
||||
|
|
@ -228,8 +237,8 @@ extern "C" jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env,
|
|||
}
|
||||
|
||||
extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz,
|
||||
jobject target, jobject hook,
|
||||
jobject backup) {
|
||||
jobject target, jobject hook,
|
||||
jobject backup) {
|
||||
|
||||
if (!doBackupAndHook(getArtMethod(env, target),
|
||||
getArtMethod(env, hook),
|
||||
|
|
@ -243,6 +252,6 @@ extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *e
|
|||
}
|
||||
}
|
||||
|
||||
void *getOriginalEntryPointFromTargetMethod(void* method) {
|
||||
void *getOriginalEntryPointFromTargetMethod(void *method) {
|
||||
return replaced_entrypoint[method];
|
||||
}
|
||||
|
|
@ -26,40 +26,40 @@ namespace art {
|
|||
return PrettyMethod(thiz, true);
|
||||
}
|
||||
|
||||
CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||
LP_SELECT("_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj", "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"),
|
||||
void *, GetOatQuickMethodHeader,
|
||||
(void * thiz, uintptr_t pc), {
|
||||
// This is a partial copy from AOSP. We only touch them if they are hooked.
|
||||
if (UNLIKELY(edxp::isHooked(thiz))) {
|
||||
uintptr_t original_ep =
|
||||
reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
|
||||
thiz)) & ~0x1;
|
||||
if (original_ep) {
|
||||
char *code_length_loc =
|
||||
reinterpret_cast<char *>(original_ep) +
|
||||
oat_header_code_length_offset;
|
||||
uint32_t code_length =
|
||||
*reinterpret_cast<uint32_t *>(code_length_loc) &
|
||||
~0x80000000u;
|
||||
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%zux, code_length=0x%x, pc=0x%zux",
|
||||
thiz, PrettyMethod(thiz).c_str(),
|
||||
original_ep, code_length, pc);
|
||||
if (original_ep <= pc &&
|
||||
pc <= original_ep + code_length)
|
||||
return reinterpret_cast<void *>(
|
||||
original_ep -
|
||||
oat_header_length);
|
||||
// If PC is not in range, we mark it as not found.
|
||||
LOGD("art_method::GetOatQuickMethodHeader: PC not found in current method.");
|
||||
return nullptr;
|
||||
} else {
|
||||
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s) isHooked but not backup, fallback to system",
|
||||
thiz, PrettyMethod(thiz).c_str());
|
||||
}
|
||||
}
|
||||
return backup(thiz, pc);
|
||||
});
|
||||
// CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||
// LP_SELECT("_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj", "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"),
|
||||
// void *, GetOatQuickMethodHeader,
|
||||
// (void * thiz, uintptr_t pc), {
|
||||
// // This is a partial copy from AOSP. We only touch them if they are hooked.
|
||||
// if (UNLIKELY(edxp::isHooked(thiz))) {
|
||||
// uintptr_t original_ep =
|
||||
// reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
|
||||
// thiz)) & ~0x1;
|
||||
// if (original_ep) {
|
||||
// char *code_length_loc =
|
||||
// reinterpret_cast<char *>(original_ep) +
|
||||
// oat_header_code_length_offset;
|
||||
// uint32_t code_length =
|
||||
// *reinterpret_cast<uint32_t *>(code_length_loc) &
|
||||
// ~0x80000000u;
|
||||
// LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%zux, code_length=0x%x, pc=0x%zux",
|
||||
// thiz, PrettyMethod(thiz).c_str(),
|
||||
// original_ep, code_length, pc);
|
||||
// if (original_ep <= pc &&
|
||||
// pc <= original_ep + code_length)
|
||||
// return reinterpret_cast<void *>(
|
||||
// original_ep -
|
||||
// oat_header_length);
|
||||
// // If PC is not in range, we mark it as not found.
|
||||
// LOGD("art_method::GetOatQuickMethodHeader: PC not found in current method.");
|
||||
// return nullptr;
|
||||
// } else {
|
||||
// LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s) isHooked but not backup, fallback to system",
|
||||
// thiz, PrettyMethod(thiz).c_str());
|
||||
// }
|
||||
// }
|
||||
// return backup(thiz, pc);
|
||||
// });
|
||||
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
LOGD("art_method hook setup, handle=%p", handle);
|
||||
|
|
@ -84,7 +84,8 @@ namespace art {
|
|||
oat_header_code_length_offset = -4;
|
||||
break;
|
||||
}
|
||||
edxp::HookSyms(handle, hook_func, GetOatQuickMethodHeader);
|
||||
// edxp::HookSyms(handle, hook_func, GetOatQuickMethodHeader);
|
||||
|
||||
|
||||
RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by loves on 1/27/2021.
|
||||
//
|
||||
|
||||
#ifndef EDXPOSED_INSTRUMENTATION_H
|
||||
#define EDXPOSED_INSTRUMENTATION_H
|
||||
|
||||
#include "base/object.h"
|
||||
|
||||
namespace art {
|
||||
namespace instrumentation {
|
||||
|
||||
CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||
"_ZN3art15instrumentation15Instrumentation21UpdateMethodsCodeImplEPNS_9ArtMethodEPKv",
|
||||
void, UpdateMethodsCode, (void * thiz, void * art_method, const void *quick_code), {
|
||||
if (UNLIKELY(edxp::isHooked(art_method))) {
|
||||
LOGD("Skip update method code for hooked method %s",
|
||||
art_method::PrettyMethod(art_method).c_str());
|
||||
return;
|
||||
} else {
|
||||
backup(thiz, art_method, quick_code);
|
||||
}
|
||||
});
|
||||
|
||||
static void DisableUpdateHookedMethodsCode(void *handle, HookFunType hook_func) {
|
||||
edxp::HookSym(handle, hook_func, UpdateMethodsCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //EDXPOSED_INSTRUMENTATION_H
|
||||
|
|
@ -123,6 +123,7 @@ namespace edxp {
|
|||
|
||||
std::string ConfigManager::GetPackageNameFromBaseApkPath(const fs::path &path) {
|
||||
std::vector<std::string> paths(path.begin(), path.end());
|
||||
if (paths.empty()) return {};
|
||||
auto base_apk = paths.back(); // base.apk
|
||||
if (base_apk != "base.apk") return {};
|
||||
paths.pop_back();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "art/runtime/oat_file_manager.h"
|
||||
#include "art/runtime/jit/jit_code_cache.h"
|
||||
#include "art/runtime/art_method.h"
|
||||
#include "art/runtime/instrumentation.h"
|
||||
|
||||
std::vector<soinfo_t> linker_get_solist(); // Dobby but not in .h
|
||||
|
||||
|
|
@ -83,7 +84,8 @@ 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::jit::HookJitCacheCode(art_handle, hook_func);
|
||||
// art::jit::HookJitCacheCode(art_handle, hook_func);
|
||||
art::instrumentation::DisableUpdateHookedMethodsCode(art_handle, hook_func);
|
||||
|
||||
art_hooks_installed = true;
|
||||
LOGI("ART hooks installed");
|
||||
|
|
|
|||
Loading…
Reference in New Issue