You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
BlackDex/Bcore/src/main/cpp/jnihook/JniHook.cpp

115 lines
4.6 KiB

//
// Created by Milk on 3/8/21.
//
#include <jni.h>
#include "utils/Log.h"
#include "Art.h"
#include "ArtM.h"
#include "JniHook.h"
static struct {
int api_level;
jclass method_utils_class;
jmethodID get_method_desc_id;
jmethodID get_method_declaring_class_id;
jmethodID get_method_name_id;
} HookEnv;
static const char *GetMethodDesc(JNIEnv *env, jobject javaMethod) {
auto desc = reinterpret_cast<jstring>(env->CallStaticObjectMethod(HookEnv.method_utils_class,
HookEnv.get_method_desc_id,
javaMethod));
return env->GetStringUTFChars(desc, JNI_FALSE);
}
static const char *GetMethodDeclaringClass(JNIEnv *env, jobject javaMethod) {
auto desc = reinterpret_cast<jstring>(env->CallStaticObjectMethod(HookEnv.method_utils_class,
HookEnv.get_method_declaring_class_id,
javaMethod));
return env->GetStringUTFChars(desc, JNI_FALSE);
}
static const char *GetMethodName(JNIEnv *env, jobject javaMethod) {
auto desc = reinterpret_cast<jstring>(env->CallStaticObjectMethod(HookEnv.method_utils_class,
HookEnv.get_method_name_id,
javaMethod));
return env->GetStringUTFChars(desc, JNI_FALSE);
}
bool CheckFlags(void *artMethod) {
char *method = static_cast<char *>(artMethod);
if (!ArtM::HasAccessFlag(method, kAccNative)) {
ALOGE("not native method");
return false;
}
ArtM::ClearFastNativeFlag(method);
return true;
}
void JniHook::HookJniFun(JNIEnv *env, jobject java_method, void *new_fun,
void **orig_fun, bool is_static) {
const char *class_name = GetMethodDeclaringClass(env, java_method);
const char *method_name = GetMethodName(env, java_method);
const char *sign = GetMethodDesc(env, java_method);
HookJniFun(env, class_name, method_name, sign, new_fun, orig_fun, is_static);
}
void
JniHook::HookJniFun(JNIEnv *env, const char *class_name, const char *method_name, const char *sign,
void *new_fun, void **orig_fun, bool is_static) {
if (ArtM::GetArtMethodNativeOffset() == 0) {
return;
}
jclass clazz = env->FindClass(class_name);
if (!clazz) {
ALOGD("findClass fail: %s %s", class_name, method_name);
env->ExceptionClear();
return;
}
jmethodID method;
if (is_static) {
method = env->GetStaticMethodID(clazz, method_name, sign);
} else {
method = env->GetMethodID(clazz, method_name, sign);
}
if (!method) {
env->ExceptionClear();
ALOGD("get method id fail: %s %s", class_name, method_name);
return;
}
JNINativeMethod gMethods[] = {
{method_name, sign, (void *) new_fun},
};
auto artMethod = reinterpret_cast<uintptr_t *>(ArtM::GetArtMethod(env, clazz, method));
if (!CheckFlags(artMethod)) {
ALOGE("check flags error. class:%s, method:%s", class_name, method_name);
return;
}
*orig_fun = reinterpret_cast<void *>(artMethod[ArtM::GetArtMethodNativeOffset()]);
if (env->RegisterNatives(clazz, gMethods, 1) < 0) {
ALOGE("jni hook error. class:%s, method:%s", class_name, method_name);
return;
}
// FastNative
if (HookEnv.api_level == __ANDROID_API_O__ || HookEnv.api_level == __ANDROID_API_O_MR1__) {
ArtM::AddAccessFlag((char *) artMethod, kAccFastNative);
}
ALOGD("register class:%s, method:%s success!", class_name, method_name);
}
void JniHook::InitJniHook(JNIEnv *env, int api_level) {
HookEnv.api_level = api_level;
HookEnv.method_utils_class = env->FindClass("top/niunaijun/jnihook/MethodUtils");
HookEnv.get_method_desc_id = env->GetStaticMethodID(HookEnv.method_utils_class, "getDesc",
"(Ljava/lang/reflect/Method;)Ljava/lang/String;");
HookEnv.get_method_declaring_class_id = env->GetStaticMethodID(HookEnv.method_utils_class,
"getDeclaringClass",
"(Ljava/lang/reflect/Method;)Ljava/lang/String;");
HookEnv.get_method_name_id = env->GetStaticMethodID(HookEnv.method_utils_class, "getMethodName",
"(Ljava/lang/reflect/Method;)Ljava/lang/String;");
}