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

View File

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

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

View File

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