[core] Refactor Yahfa

This commit is contained in:
LoveSy 2021-03-20 15:10:55 +08:00 committed by LoveSy
parent 26a4decfeb
commit a6b4ed548e
5 changed files with 201 additions and 257 deletions

View File

@ -3,26 +3,18 @@
#include <jni.h> #include <jni.h>
#ifdef __cplusplus namespace yahfa {
extern "C" { void init(JNIEnv *env, jclass clazz, jint sdkVersion);
#endif
void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion); jobject findMethodNative(JNIEnv *env, jclass clazz,
jclass targetClass, jstring methodName,
jstring methodSig);
jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz, jboolean backupAndHookNative(JNIEnv *env, jclass clazz,
jclass targetClass, jstring methodName, jobject target, jobject hook,
jstring methodSig); jobject backup);
jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz, void *getArtMethod(JNIEnv *env, jobject jmethod);
jobject target, jobject hook,
jobject backup);
void setNonCompilable(void *method);
void *getArtMethodYahfa(JNIEnv *env, jobject jmethod);
#ifdef __cplusplus
} }
#endif
#endif // HOOK_MAIN_H #endif // HOOK_MAIN_H

View File

@ -8,255 +8,201 @@
#include "HookMain.h" #include "HookMain.h"
int SDKVersion; int SDKVersion;
static size_t OFFSET_entry_point_from_interpreter_in_ArtMethod;
size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
static size_t OFFSET_ArtMehod_in_Object; namespace {
static size_t OFFSET_access_flags_in_ArtMethod; size_t ArtMethodSize;
static size_t ArtMethodSize; constexpr size_t OFFSET_access_flags_in_ArtMethod = 4;
static uint32_t kAccCompileDontBother = 0x01000000; constexpr uint32_t kAccCompileDontBother = 0x02000000;
static uint32_t kAccPublic = 0x0001; // class, field, method, ic constexpr uint32_t kAccPreCompiled = 0x00100000 | 0x00200000;
static uint32_t kAccPrivate = 0x0002; // field, method, ic constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
static uint32_t kAccProtected = 0x0004; // field, method, ic constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
static uint32_t kAccStatic = 0x0008; // field, method, ic constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
static uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; constexpr uint32_t kAccStatic = 0x0008; // field, method, ic
constexpr uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000;
jfieldID fieldArtMethod = nullptr;
static jfieldID fieldArtMethod = nullptr; constexpr inline uint32_t read32(void *addr) {
return *((uint32_t *) addr);
static inline uint32_t read32(void *addr) {
return *((uint32_t *) addr);
}
static inline void write32(void *addr, uint32_t value) {
*((uint32_t *) addr) = value;
}
static inline void *readAddr(void *addr) {
return *((void **) addr);
}
static 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) {
SDKVersion = sdkVersion;
jclass classExecutable;
LOGI("init to SDK %d", sdkVersion);
switch (sdkVersion) {
case __ANDROID_API_S__:
classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
kAccCompileDontBother = 0x02000000;
OFFSET_ArtMehod_in_Object = 0;
OFFSET_access_flags_in_ArtMethod = 4;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 3 + 2 * 2) + pointer_size;
ArtMethodSize = roundUpToPtrSize(4 * 3 + 2 * 2) + pointer_size * 2;
break;
case __ANDROID_API_R__:
classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
case __ANDROID_API_Q__:
case __ANDROID_API_P__:
kAccCompileDontBother = 0x02000000;
OFFSET_ArtMehod_in_Object = 0;
OFFSET_access_flags_in_ArtMethod = 4;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size;
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
break;
case __ANDROID_API_O_MR1__:
kAccCompileDontBother = 0x02000000;
case __ANDROID_API_O__:
OFFSET_ArtMehod_in_Object = 0;
OFFSET_access_flags_in_ArtMethod = 4;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
break;
case __ANDROID_API_N_MR1__:
case __ANDROID_API_N__:
OFFSET_ArtMehod_in_Object = 0;
OFFSET_access_flags_in_ArtMethod = 4; // sizeof(GcRoot<mirror::Class>) = 4
// ptr_sized_fields_ is rounded up to pointer_size in ArtMethod
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 4;
break;
case __ANDROID_API_M__:
OFFSET_ArtMehod_in_Object = 0;
OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7);
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2;
ArtMethodSize = roundUpToPtrSize(4 * 7) + pointer_size * 3;
break;
case __ANDROID_API_L_MR1__:
OFFSET_ArtMehod_in_Object = 4 * 2;
OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(
OFFSET_ArtMehod_in_Object + 4 * 7);
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2;
ArtMethodSize = OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 3;
break;
case __ANDROID_API_L__:
OFFSET_ArtMehod_in_Object = 4 * 2;
OFFSET_entry_point_from_interpreter_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 4;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
OFFSET_entry_point_from_interpreter_in_ArtMethod + 8 * 2;
ArtMethodSize = OFFSET_ArtMehod_in_Object + 4 * 4 + 8 * 4 + 4 * 4;
break;
default:
LOGE("not compatible with SDK %d", sdkVersion);
break;
} }
setupTrampoline(); constexpr inline void write32(void *addr, uint32_t value) {
} *((uint32_t *) addr) = value;
void setNonCompilable(void *method) {
if (SDKVersion < __ANDROID_API_N__) {
return;
} }
uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod);
LOGI("setNonCompilable: access flags is 0x%x", access_flags);
access_flags |= kAccCompileDontBother;
write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags);
}
void setPrivate(void *method) { constexpr inline void *readAddr(void *addr) {
uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); return *((void **) addr);
if (!(access_flags & kAccStatic)) { }
LOGI("setPrivate: access flags is 0x%x", access_flags);
access_flags |= kAccPrivate; constexpr inline void writeAddr(void *addr, void *value) {
access_flags &= ~kAccProtected; *((void **) addr) = value;
access_flags &= ~kAccPublic; }
void setNonCompilable(void *method) {
if (SDKVersion < __ANDROID_API_N__) {
return;
}
uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod);
LOGI("setNonCompilable: access flags is 0x%x", access_flags);
access_flags |= kAccCompileDontBother;
access_flags &= ~kAccPreCompiled;
write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags);
} }
}
static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, void *backupMethod) { void setPrivate(void *method) {
if (hookCount >= hookCap) { uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod);
LOGI("not enough capacity. Allocating..."); if (!(access_flags & kAccStatic)) {
if (doInitHookCap(DEFAULT_CAP)) { LOGI("setPrivate: access flags is 0x%x", access_flags);
LOGE("cannot hook method"); access_flags |= kAccPrivate;
access_flags &= ~kAccProtected;
access_flags &= ~kAccPublic;
write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags);
}
}
int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) {
if (hookCount >= hookCap) {
LOGI("not enough capacity. Allocating...");
if (doInitHookCap(DEFAULT_CAP)) {
LOGE("cannot hook method");
return 1;
}
LOGI("Allocating done");
}
LOGI("target method is at %p, hook method is at %p, backup method is at %p",
targetMethod, hookMethod, backupMethod);
// set kAccCompileDontBother for a method we do not want the compiler to compile
// so that we don't need to worry about hotness_count_
if (SDKVersion >= __ANDROID_API_N__) {
setNonCompilable(targetMethod);
setNonCompilable(hookMethod);
}
if (backupMethod) {// do method backup
// have to copy the whole target ArtMethod here
// if the target method calls other methods which are to be resolved
// then ToDexPC would be invoked for the caller(origin method)
// in which case ToDexPC would use the entrypoint as a base for mapping pc to dex offset
// so any changes to the target method's entrypoint would result in a wrong dex offset
// and artQuickResolutionTrampoline would fail for methods called by the origin method
memcpy(backupMethod, targetMethod, ArtMethodSize);
setPrivate(backupMethod);
}
// replace entry point
void *newEntrypoint = genTrampoline(hookMethod);
LOGI("origin ep is %p, new ep is %p",
readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod),
newEntrypoint
);
if (newEntrypoint) {
writeAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod,
newEntrypoint);
} else {
LOGE("failed to allocate space for trampoline of target method");
return 1; return 1;
} }
LOGI("Allocating done");
if (SDKVersion >= __ANDROID_API_Q__) {
uint32_t access_flags = read32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod);
// On API 29 whether to use the fast path or not is cached in the ART method structure
access_flags &= ~kAccFastInterpreterToInterpreterInvoke;
write32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod, access_flags);
}
LOGI("hook and backup done");
hookCount += 1;
return 0;
} }
LOGI("target method is at %p, hook method is at %p, backup method is at %p",
targetMethod, hookMethod, backupMethod);
// set kAccCompileDontBother for a method we do not want the compiler to compile
// so that we don't need to worry about hotness_count_
if (SDKVersion >= __ANDROID_API_N__) {
setNonCompilable(targetMethod);
setNonCompilable(hookMethod);
}
if (backupMethod) {// do method backup
// have to copy the whole target ArtMethod here
// if the target method calls other methods which are to be resolved
// then ToDexPC would be invoked for the caller(origin method)
// in which case ToDexPC would use the entrypoint as a base for mapping pc to dex offset
// so any changes to the target method's entrypoint would result in a wrong dex offset
// and artQuickResolutionTrampoline would fail for methods called by the origin method
memcpy(backupMethod, targetMethod, ArtMethodSize);
setPrivate(backupMethod);
}
// replace entry point
void *newEntrypoint = genTrampoline(hookMethod);
LOGI("origin ep is %p, new ep is %p",
readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod),
newEntrypoint
);
if (newEntrypoint) {
writeAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod,
newEntrypoint);
} else {
LOGE("failed to allocate space for trampoline of target method");
return 1;
}
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
writeAddr((char *) targetMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
readAddr((char *) hookMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod));
}
if (SDKVersion >= __ANDROID_API_Q__) {
uint32_t access_flags = read32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod);
// On API 29 whether to use the fast path or not is cached in the ART method structure
access_flags &= ~kAccFastInterpreterToInterpreterInvoke;
write32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod, access_flags);
}
LOGI("hook and backup done");
hookCount += 1;
return 0;
} }
void *getArtMethodYahfa(JNIEnv *env, jobject jmethod) { namespace yahfa {
void *artMethod = nullptr;
if (jmethod == nullptr) { void init(JNIEnv *env, [[maybe_unused]] jclass clazz, jint sdkVersion) {
return artMethod; SDKVersion = sdkVersion;
jclass classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
LOGI("init to SDK %d", sdkVersion);
switch (sdkVersion) {
case __ANDROID_API_S__:
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 3 + 2 * 2) + pointer_size;
ArtMethodSize = roundUpToPtrSize(4 * 3 + 2 * 2) + pointer_size * 2;
break;
case __ANDROID_API_R__:
case __ANDROID_API_Q__:
case __ANDROID_API_P__:
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size;
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
break;
case __ANDROID_API_O_MR1__:
case __ANDROID_API_O__:
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
break;
default:
LOGE("not compatible with SDK %d", sdkVersion);
break;
}
setupTrampoline();
} }
if (SDKVersion >= __ANDROID_API_R__) { void *getArtMethod(JNIEnv *env, jobject jmethod) {
artMethod = (void *) env->GetLongField(jmethod, fieldArtMethod); if (jmethod == nullptr) {
} else { return nullptr;
artMethod = (void *) env->FromReflectedMethod(jmethod);
}
LOGI("ArtMethod: %p", artMethod);
return artMethod;
}
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(methodName, nullptr);
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
jobject ret = nullptr;
//Try both GetMethodID and GetStaticMethodID -- Whatever works :)
jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig);
if (!env->ExceptionCheck()) {
ret = env->ToReflectedMethod(targetClass, method, JNI_FALSE);
} else {
env->ExceptionClear();
method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig);
if (!env->ExceptionCheck()) {
ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE);
} else { } else {
env->ExceptionClear(); return (void *) env->GetLongField(jmethod, fieldArtMethod);
} }
} }
env->ReleaseStringUTFChars(methodName, c_methodName); jobject findMethodNative(JNIEnv *env, [[maybe_unused]] jclass clazz,
env->ReleaseStringUTFChars(methodSig, c_methodSig); jclass targetClass,
return ret; jstring methodName,
} jstring methodSig) {
const char *c_methodName = env->GetStringUTFChars(methodName, nullptr);
const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr);
jobject ret = nullptr;
extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz,
jobject target, jobject hook,
jobject backup) {
if (!doBackupAndHook(env, //Try both GetMethodID and GetStaticMethodID -- Whatever works :)
getArtMethodYahfa(env, target), jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig);
getArtMethodYahfa(env, hook), if (!env->ExceptionCheck()) {
getArtMethodYahfa(env, backup) ret = env->ToReflectedMethod(targetClass, method, JNI_FALSE);
)) { } else {
env->NewGlobalRef(hook); // keep a global ref so that the hook method would not be GCed env->ExceptionClear();
if (backup) env->NewGlobalRef(backup); method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig);
return JNI_TRUE; if (!env->ExceptionCheck()) {
} else { ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE);
return JNI_FALSE; } else {
env->ExceptionClear();
}
}
env->ReleaseStringUTFChars(methodName, c_methodName);
env->ReleaseStringUTFChars(methodSig, c_methodSig);
return ret;
}
jboolean backupAndHookNative(JNIEnv *env, [[maybe_unused]] jclass clazz,
jobject target, jobject hook,
jobject backup) {
if (!doBackupAndHook(getArtMethod(env, target),
getArtMethod(env, hook),
getArtMethod(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;
}
} }
} }

View File

@ -31,7 +31,7 @@ namespace lspd {
static std::unordered_set<void *> deopted_methods; static std::unordered_set<void *> deopted_methods;
LSP_DEF_NATIVE_METHOD(void, ClassLinker, setEntryPointsToInterpreter, jobject method) { LSP_DEF_NATIVE_METHOD(void, ClassLinker, setEntryPointsToInterpreter, jobject method) {
void *reflected_method = getArtMethodYahfa(env, method); void *reflected_method = yahfa::getArtMethod(env, method);
if (deopted_methods.contains(reflected_method)) { if (deopted_methods.contains(reflected_method)) {
LOGD("method %p has been deopted before, skip...", reflected_method); LOGD("method %p has been deopted before, skip...", reflected_method);
return; return;

View File

@ -65,7 +65,7 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(void, PendingHooks, recordPendingMethodNative, jobject method_ref, jclass class_ref){ LSP_DEF_NATIVE_METHOD(void, PendingHooks, recordPendingMethodNative, jobject method_ref, jclass class_ref){
auto *class_ptr = art::Thread::Current().DecodeJObject(class_ref); auto *class_ptr = art::Thread::Current().DecodeJObject(class_ref);
auto *method = getArtMethodYahfa(env, method_ref); auto *method = yahfa::getArtMethod(env, method_ref);
art::mirror::Class mirror_class(class_ptr); art::mirror::Class mirror_class(class_ptr);
if (auto def = mirror_class.GetClassDef(); LIKELY(def)) { if (auto def = mirror_class.GetClassDef(); LIKELY(def)) {
LOGD("record pending: %p (%s) with %p", class_ptr, mirror_class.GetDescriptor().c_str(), LOGD("record pending: %p (%s) with %p", class_ptr, mirror_class.GetDescriptor().c_str(),

View File

@ -32,13 +32,13 @@
namespace lspd { namespace lspd {
using namespace startop::dex; using namespace startop::dex;
LSP_DEF_NATIVE_METHOD(void, Yahfa, init, jint sdkVersion) { LSP_DEF_NATIVE_METHOD(void, Yahfa, init, jint sdkVersion) {
Java_lab_galaxy_yahfa_HookMain_init(env, clazz, sdkVersion); yahfa::init(env, clazz, sdkVersion);
} }
LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass, LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass,
jstring methodName, jstring methodSig) { jstring methodName, jstring methodSig) {
return Java_lab_galaxy_yahfa_HookMain_findMethodNative(env, clazz, targetClass, methodName, return yahfa::findMethodNative(env, clazz, targetClass, methodName,
methodSig); methodSig);
} }
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target, LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target,
@ -47,21 +47,23 @@ namespace lspd {
art::gc::kGcCauseDebugger, art::gc::kGcCauseDebugger,
art::gc::kCollectorTypeDebugger); art::gc::kCollectorTypeDebugger);
art::thread_list::ScopedSuspendAll suspend("Yahfa Hook", false); art::thread_list::ScopedSuspendAll suspend("Yahfa Hook", false);
return Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(env, clazz, target, hook, backup); return yahfa::backupAndHookNative(env, clazz, target, hook, backup);
} }
LSP_DEF_NATIVE_METHOD(void, Yahfa, recordHooked, jobject member) { LSP_DEF_NATIVE_METHOD(void, Yahfa, recordHooked, jobject member) {
lspd::recordHooked(getArtMethodYahfa(env, member)); lspd::recordHooked(yahfa::getArtMethod(env, member));
} }
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, isHooked, jobject member) { LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, isHooked, jobject member) {
return lspd::isHooked(getArtMethodYahfa(env, member)); return lspd::isHooked(yahfa::getArtMethod(env, member));
} }
LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class, jobjectArray classes, jstring method_name) { LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class,
static auto in_memory_classloader = (jclass)env->NewGlobalRef(env->FindClass( "dalvik/system/InMemoryDexClassLoader")); jobjectArray classes, jstring method_name) {
static auto in_memory_classloader = (jclass) env->NewGlobalRef(
env->FindClass("dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>", static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file; DexBuilder dex_file;
auto parameter_length = env->GetArrayLength(classes); auto parameter_length = env->GetArrayLength(classes);
@ -69,7 +71,9 @@ namespace lspd {
parameter_types.reserve(parameter_length); parameter_types.reserve(parameter_length);
std::string storage; std::string storage;
auto current_thread = art::Thread::Current(); auto current_thread = art::Thread::Current();
auto return_type = TypeDescriptor::FromDescriptor(art::mirror::Class(current_thread.DecodeJObject(return_class)).GetDescriptor(&storage)); auto return_type = TypeDescriptor::FromDescriptor(
art::mirror::Class(current_thread.DecodeJObject(return_class)).GetDescriptor(
&storage));
for (int i = 0; i < parameter_length; ++i) { for (int i = 0; i < parameter_length; ++i) {
auto param = (jclass) env->GetObjectArrayElement(classes, i); auto param = (jclass) env->GetObjectArrayElement(classes, i);
auto *param_ref = current_thread.DecodeJObject(param); auto *param_ref = current_thread.DecodeJObject(param);
@ -153,14 +157,15 @@ namespace lspd {
slicer::MemView image{dex_file.CreateImage()}; slicer::MemView image{dex_file.CreateImage()};
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void*>(image.ptr()), image.size()); auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, app_class_loader); dex_buffer, app_class_loader);
static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass", static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
if (!mid) { if (!mid) {
mid = JNI_GetMethodID(env, in_memory_classloader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); mid = JNI_GetMethodID(env, in_memory_classloader, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
} }
jobject target = env->CallObjectMethod(my_cl, mid, env->NewStringUTF("LspHooker_")); jobject target = env->CallObjectMethod(my_cl, mid, env->NewStringUTF("LspHooker_"));
// LOGD("Created %zd", image.size()); // LOGD("Created %zd", image.size());
@ -178,7 +183,8 @@ namespace lspd {
"(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"), "(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"),
LSP_NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Executable;)V"), LSP_NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Executable;)V"),
LSP_NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Executable;)Z"), LSP_NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Executable;)Z"),
LSP_NATIVE_METHOD(Yahfa, buildHooker, "(Ljava/lang/ClassLoader;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Class;"), LSP_NATIVE_METHOD(Yahfa, buildHooker,
"(Ljava/lang/ClassLoader;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Class;"),
}; };
void RegisterYahfa(JNIEnv *env) { void RegisterYahfa(JNIEnv *env) {