Hook UpdateMethodCode

This commit is contained in:
LoveSy 2021-01-27 19:03:05 +08:00
parent f6da55411d
commit 0e2783f8e5
5 changed files with 111 additions and 68 deletions

View File

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

View File

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

View File

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

View File

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

View File

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