Hook UpdateMethodCode
This commit is contained in:
parent
f6da55411d
commit
0e2783f8e5
|
|
@ -5,34 +5,40 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "HookMain.h"
|
#include "HookMain.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "trampoline.h"
|
#include "trampoline.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDKVersion;
|
int SDKVersion;
|
||||||
static uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
namespace {
|
||||||
static uint32_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
||||||
static uint32_t OFFSET_ArtMehod_in_Object;
|
uint32_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||||
static uint32_t OFFSET_access_flags_in_ArtMethod;
|
uint32_t OFFSET_ArtMehod_in_Object;
|
||||||
static uint32_t kAccCompileDontBother = 0x01000000;
|
uint32_t OFFSET_access_flags_in_ArtMethod;
|
||||||
|
uint32_t kAccCompileDontBother = 0x01000000;
|
||||||
|
uint32_t kAccNative = 0x0100;
|
||||||
|
uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
||||||
|
|
||||||
static jfieldID fieldArtMethod = nullptr;
|
jfieldID fieldArtMethod = nullptr;
|
||||||
static std::unordered_map<void*, void*> replaced_entrypoint;
|
|
||||||
|
|
||||||
static inline uint32_t read32(void *addr) {
|
std::unordered_map<void *, void *> replaced_entrypoint;
|
||||||
return *((uint32_t *) addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write32(void *addr, uint32_t value) {
|
inline uint32_t read32(void *addr) {
|
||||||
*((uint32_t *) addr) = value;
|
return *((uint32_t *) addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *readAddr(void *addr) {
|
inline void write32(void *addr, uint32_t value) {
|
||||||
return *((void **) addr);
|
*((uint32_t *) addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writeAddr(void *addr, void *value) {
|
inline void *readAddr(void *addr) {
|
||||||
*((void **)addr) = value;
|
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) {
|
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_) {
|
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);
|
uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod);
|
||||||
return access_flags;
|
return access_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setFlags(void *method_, uint32_t 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);
|
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);
|
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);
|
return readAddr((char *) method + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = nullptr;
|
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) {
|
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
|
||||||
newEntrypoint = genTrampoline(toMethod, originEntrypoint);
|
newEntrypoint = genTrampoline(toMethod, originEntrypoint);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// entry point from ArtMethod struct
|
// entry point from ArtMethod struct
|
||||||
newEntrypoint = genTrampoline(toMethod, nullptr);
|
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.
|
// 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(fromEntrypoint, interpEntrypoint);
|
writeAddr(fromEntrypoint, interpEntrypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +173,7 @@ static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMet
|
||||||
if (SDKVersion >= __ANDROID_API_N__) {
|
if (SDKVersion >= __ANDROID_API_N__) {
|
||||||
setNonCompilable(targetMethod);
|
setNonCompilable(targetMethod);
|
||||||
// setNonCompilable(hookMethod);
|
// setNonCompilable(hookMethod);
|
||||||
if(backupMethod) setNonCompilable(backupMethod);
|
if (backupMethod) setNonCompilable(backupMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backupMethod) {// do method backup
|
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,
|
extern "C" jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz,
|
||||||
jclass targetClass, jstring methodName,
|
jclass targetClass,
|
||||||
jstring methodSig) {
|
jstring methodName,
|
||||||
|
jstring methodSig) {
|
||||||
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
|
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
|
||||||
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
|
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
|
||||||
jobject ret = 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,
|
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) {
|
||||||
|
|
||||||
if (!doBackupAndHook(getArtMethod(env, target),
|
if (!doBackupAndHook(getArtMethod(env, target),
|
||||||
getArtMethod(env, hook),
|
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];
|
return replaced_entrypoint[method];
|
||||||
}
|
}
|
||||||
|
|
@ -26,40 +26,40 @@ namespace art {
|
||||||
return PrettyMethod(thiz, true);
|
return PrettyMethod(thiz, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
CREATE_MEM_HOOK_STUB_ENTRIES(
|
// CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||||
LP_SELECT("_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj", "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"),
|
// LP_SELECT("_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj", "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"),
|
||||||
void *, GetOatQuickMethodHeader,
|
// void *, GetOatQuickMethodHeader,
|
||||||
(void * thiz, uintptr_t pc), {
|
// (void * thiz, uintptr_t pc), {
|
||||||
// This is a partial copy from AOSP. We only touch them if they are hooked.
|
// // This is a partial copy from AOSP. We only touch them if they are hooked.
|
||||||
if (UNLIKELY(edxp::isHooked(thiz))) {
|
// if (UNLIKELY(edxp::isHooked(thiz))) {
|
||||||
uintptr_t original_ep =
|
// uintptr_t original_ep =
|
||||||
reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
|
// reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
|
||||||
thiz)) & ~0x1;
|
// thiz)) & ~0x1;
|
||||||
if (original_ep) {
|
// if (original_ep) {
|
||||||
char *code_length_loc =
|
// char *code_length_loc =
|
||||||
reinterpret_cast<char *>(original_ep) +
|
// reinterpret_cast<char *>(original_ep) +
|
||||||
oat_header_code_length_offset;
|
// oat_header_code_length_offset;
|
||||||
uint32_t code_length =
|
// uint32_t code_length =
|
||||||
*reinterpret_cast<uint32_t *>(code_length_loc) &
|
// *reinterpret_cast<uint32_t *>(code_length_loc) &
|
||||||
~0x80000000u;
|
// ~0x80000000u;
|
||||||
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%zux, code_length=0x%x, pc=0x%zux",
|
// 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(),
|
// thiz, PrettyMethod(thiz).c_str(),
|
||||||
original_ep, code_length, pc);
|
// original_ep, code_length, pc);
|
||||||
if (original_ep <= pc &&
|
// if (original_ep <= pc &&
|
||||||
pc <= original_ep + code_length)
|
// pc <= original_ep + code_length)
|
||||||
return reinterpret_cast<void *>(
|
// return reinterpret_cast<void *>(
|
||||||
original_ep -
|
// original_ep -
|
||||||
oat_header_length);
|
// oat_header_length);
|
||||||
// If PC is not in range, we mark it as not found.
|
// // If PC is not in range, we mark it as not found.
|
||||||
LOGD("art_method::GetOatQuickMethodHeader: PC not found in current method.");
|
// LOGD("art_method::GetOatQuickMethodHeader: PC not found in current method.");
|
||||||
return nullptr;
|
// return nullptr;
|
||||||
} else {
|
// } else {
|
||||||
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s) isHooked but not backup, fallback to system",
|
// LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s) isHooked but not backup, fallback to system",
|
||||||
thiz, PrettyMethod(thiz).c_str());
|
// thiz, PrettyMethod(thiz).c_str());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return backup(thiz, pc);
|
// return backup(thiz, pc);
|
||||||
});
|
// });
|
||||||
|
|
||||||
static void Setup(void *handle, HookFunType hook_func) {
|
static void Setup(void *handle, HookFunType hook_func) {
|
||||||
LOGD("art_method hook setup, handle=%p", handle);
|
LOGD("art_method hook setup, handle=%p", handle);
|
||||||
|
|
@ -84,7 +84,8 @@ namespace art {
|
||||||
oat_header_code_length_offset = -4;
|
oat_header_code_length_offset = -4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
edxp::HookSyms(handle, hook_func, GetOatQuickMethodHeader);
|
// edxp::HookSyms(handle, hook_func, GetOatQuickMethodHeader);
|
||||||
|
|
||||||
|
|
||||||
RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb");
|
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::string ConfigManager::GetPackageNameFromBaseApkPath(const fs::path &path) {
|
||||||
std::vector<std::string> paths(path.begin(), path.end());
|
std::vector<std::string> paths(path.begin(), path.end());
|
||||||
|
if (paths.empty()) return {};
|
||||||
auto base_apk = paths.back(); // base.apk
|
auto base_apk = paths.back(); // base.apk
|
||||||
if (base_apk != "base.apk") return {};
|
if (base_apk != "base.apk") return {};
|
||||||
paths.pop_back();
|
paths.pop_back();
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "art/runtime/oat_file_manager.h"
|
#include "art/runtime/oat_file_manager.h"
|
||||||
#include "art/runtime/jit/jit_code_cache.h"
|
#include "art/runtime/jit/jit_code_cache.h"
|
||||||
#include "art/runtime/art_method.h"
|
#include "art/runtime/art_method.h"
|
||||||
|
#include "art/runtime/instrumentation.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
|
||||||
|
|
||||||
|
|
@ -83,7 +84,8 @@ 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::jit::HookJitCacheCode(art_handle, hook_func);
|
// art::jit::HookJitCacheCode(art_handle, hook_func);
|
||||||
|
art::instrumentation::DisableUpdateHookedMethodsCode(art_handle, hook_func);
|
||||||
|
|
||||||
art_hooks_installed = true;
|
art_hooks_installed = true;
|
||||||
LOGI("ART hooks installed");
|
LOGI("ART hooks installed");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue