mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Refactor hookJniNativeMethods
Utilize NativeBridgeRuntimeCallbacks we obtained from native bridge to directly fetch and modify registered native JNI methods. By doing so, we do not need to keep a copy of every single JNINativeMethod registered in order to provide JNI hooking functionality. Co-authored-by: LoveSy <shana@zju.edu.cn>
This commit is contained in:
parent
fce1bf2365
commit
a80cadf587
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -22,9 +22,6 @@
|
||||
[submodule "zlib"]
|
||||
path = native/src/external/zlib
|
||||
url = https://android.googlesource.com/platform/external/zlib
|
||||
[submodule "parallel-hashmap"]
|
||||
path = native/src/external/parallel-hashmap
|
||||
url = https://github.com/greg7mdp/parallel-hashmap.git
|
||||
[submodule "zopfli"]
|
||||
path = native/src/external/zopfli
|
||||
url = https://github.com/google/zopfli.git
|
||||
|
@ -11,7 +11,6 @@ LOCAL_MODULE := magisk
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libsystemproperties \
|
||||
libphmap \
|
||||
liblsplt \
|
||||
libmagisk-rs
|
||||
|
||||
@ -36,7 +35,6 @@ LOCAL_SRC_FILES := \
|
||||
zygisk/entry.cpp \
|
||||
zygisk/main.cpp \
|
||||
zygisk/hook.cpp \
|
||||
zygisk/memory.cpp \
|
||||
zygisk/native_bridge.cpp \
|
||||
zygisk/deny/cli.cpp \
|
||||
zygisk/deny/utils.cpp \
|
||||
|
6
native/src/external/Android.mk
vendored
6
native/src/external/Android.mk
vendored
@ -1,11 +1,5 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Header only library
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libphmap
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/parallel-hashmap
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libxz.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libxz
|
||||
|
1
native/src/external/parallel-hashmap
vendored
1
native/src/external/parallel-hashmap
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 7684faf186806e2c88554a78188c18185b21f127
|
@ -213,60 +213,21 @@ def gen_jni_def(clz, methods):
|
||||
decl += ind(1) + f'return {m.ret.value};'
|
||||
decl += ind(0) + '}'
|
||||
|
||||
decl += ind(0) + f'const JNINativeMethod {m.base_name()}_methods[] = {{'
|
||||
decl += ind(0) + f'std::array {m.base_name()}_methods = {{'
|
||||
for m in methods:
|
||||
decl += ind(1) + '{'
|
||||
decl += ind(1) + 'JNINativeMethod {'
|
||||
decl += ind(2) + f'"{m.base_name()}",'
|
||||
decl += ind(2) + f'"{m.jni()}",'
|
||||
decl += ind(2) + f'(void *) &{m.name}'
|
||||
decl += ind(1) + '},'
|
||||
decl += ind(0) + '};'
|
||||
decl = ind(0) + f'void *{m.base_name()}_orig = nullptr;' + decl
|
||||
decl += ind(0) + f'constexpr int {m.base_name()}_methods_num = std::size({m.base_name()}_methods);'
|
||||
decl += ind(0)
|
||||
|
||||
hook_map[clz].append(m.base_name())
|
||||
|
||||
return decl
|
||||
|
||||
def gen_jni_hook():
|
||||
decl = ''
|
||||
decl += ind(0) + 'static JNINativeMethod *hookAndSaveJNIMethods(const char *className, const JNINativeMethod *methods, int numMethods) {'
|
||||
decl += ind(1) + 'JNINativeMethod *newMethods = nullptr;'
|
||||
decl += ind(1) + 'int clz_id = -1;'
|
||||
decl += ind(1) + 'int hook_cnt = 0;'
|
||||
decl += ind(1) + 'do {'
|
||||
|
||||
for index, (clz, methods) in enumerate(hook_map.items()):
|
||||
decl += ind(2) + f'if (className == "{clz}"sv) {{'
|
||||
decl += ind(3) + f'clz_id = {index};'
|
||||
decl += ind(3) + f'hook_cnt = {len(methods)};'
|
||||
decl += ind(3) + 'break;'
|
||||
decl += ind(2) + '}'
|
||||
|
||||
decl += ind(1) + '} while (false);'
|
||||
|
||||
decl += ind(1) + 'if (hook_cnt) {'
|
||||
decl += ind(2) + 'newMethods = new JNINativeMethod[numMethods];'
|
||||
decl += ind(2) + 'memcpy(newMethods, methods, sizeof(JNINativeMethod) * numMethods);'
|
||||
decl += ind(1) + '}'
|
||||
|
||||
decl += ind(1) + 'auto &class_map = (*jni_method_map)[className];'
|
||||
decl += ind(1) + 'for (int i = 0; i < numMethods; ++i) {'
|
||||
|
||||
for index, methods in enumerate(hook_map.values()):
|
||||
decl += ind(2) + f'if (hook_cnt && clz_id == {index}) {{'
|
||||
for m in methods:
|
||||
decl += ind(3) + f'HOOK_JNI({m})'
|
||||
decl += ind(2) + '}'
|
||||
|
||||
decl += ind(2) + 'class_map[methods[i].name][methods[i].signature] = methods[i].fnPtr;'
|
||||
decl += ind(1) + '}'
|
||||
|
||||
decl += ind(1) + 'return newMethods;'
|
||||
decl += ind(0) + '}'
|
||||
return decl
|
||||
|
||||
with open('jni_hooks.hpp', 'w') as f:
|
||||
f.write('// Generated by gen_jni_hooks.py\n')
|
||||
f.write('\nnamespace {\n')
|
||||
@ -283,6 +244,3 @@ with open('jni_hooks.hpp', 'w') as f:
|
||||
f.write(gen_jni_def(zygote, methods))
|
||||
|
||||
f.write('\n} // namespace\n')
|
||||
|
||||
f.write(gen_jni_hook())
|
||||
f.write('\n')
|
||||
|
@ -12,14 +12,10 @@
|
||||
#include <magisk.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "module.hpp"
|
||||
#include "deny/deny.hpp"
|
||||
|
||||
using namespace std;
|
||||
using jni_hook::hash_map;
|
||||
using jni_hook::tree_map;
|
||||
using xstring = jni_hook::string;
|
||||
|
||||
// Extreme verbose logging
|
||||
#define ZLOGV(...) ZLOGD(__VA_ARGS__)
|
||||
@ -28,7 +24,6 @@ using xstring = jni_hook::string;
|
||||
static void hook_unloader();
|
||||
static void unhook_functions();
|
||||
static void hook_jni_env();
|
||||
static void restore_jni_env(JNIEnv *env);
|
||||
static void reload_native_bridge(const string &nb);
|
||||
|
||||
namespace {
|
||||
@ -49,7 +44,6 @@ enum {
|
||||
// Global variables
|
||||
vector<tuple<dev_t, ino_t, const char *, void **>> *plt_hook_list;
|
||||
map<string, vector<JNINativeMethod>, StringCmp> *jni_hook_list;
|
||||
hash_map<xstring, tree_map<xstring, tree_map<xstring, void *>>> *jni_method_map;
|
||||
bool should_unmap_zygisk = false;
|
||||
|
||||
// Current context
|
||||
@ -97,14 +91,7 @@ struct HookContext {
|
||||
|
||||
HookContext(JNIEnv *env, void *args) :
|
||||
env(env), args{args}, process(nullptr), pid(-1), info_flags(0),
|
||||
hook_info_lock(PTHREAD_MUTEX_INITIALIZER) {
|
||||
static bool restored_env = false;
|
||||
if (!restored_env) {
|
||||
restore_jni_env(env);
|
||||
restored_env = true;
|
||||
}
|
||||
g_ctx = this;
|
||||
}
|
||||
hook_info_lock(PTHREAD_MUTEX_INITIALIZER) { g_ctx = this; }
|
||||
|
||||
~HookContext();
|
||||
|
||||
@ -224,38 +211,41 @@ DCL_HOOK_FUNC(int, dlclose, void *handle) {
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods) {
|
||||
auto class_map = jni_method_map->find(clz);
|
||||
if (class_map == jni_method_map->end()) {
|
||||
for (int i = 0; i < numMethods; ++i) {
|
||||
jclass clazz;
|
||||
if (!runtime_callbacks || !env || !clz || !(clazz = env->FindClass(clz))) {
|
||||
for (auto i = 0; i < numMethods; ++i) {
|
||||
methods[i].fnPtr = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
vector<JNINativeMethod> hooks;
|
||||
for (int i = 0; i < numMethods; ++i) {
|
||||
auto method_map = class_map->second.find(methods[i].name);
|
||||
if (method_map != class_map->second.end()) {
|
||||
auto it = method_map->second.find(methods[i].signature);
|
||||
if (it != method_map->second.end()) {
|
||||
// Copy the JNINativeMethod
|
||||
hooks.push_back(methods[i]);
|
||||
// Save the original function pointer
|
||||
methods[i].fnPtr = it->second;
|
||||
// Do not allow double hook, remove method from map
|
||||
method_map->second.erase(it);
|
||||
continue;
|
||||
// Backup existing methods
|
||||
auto total = runtime_callbacks->getNativeMethodCount(env, clazz);
|
||||
vector<JNINativeMethod> old_methods(total);
|
||||
runtime_callbacks->getNativeMethods(env, clazz, old_methods.data(), total);
|
||||
|
||||
// Replace the method
|
||||
for (auto i = 0; i < numMethods; ++i) {
|
||||
auto &method = methods[i];
|
||||
auto res = env->RegisterNatives(clazz, &method, 1);
|
||||
// It's normal that the method is not found
|
||||
if (res == JNI_ERR || env->ExceptionCheck()) {
|
||||
auto exception = env->ExceptionOccurred();
|
||||
if (exception) env->DeleteLocalRef(exception);
|
||||
env->ExceptionClear();
|
||||
method.fnPtr = nullptr;
|
||||
} else {
|
||||
// Find the old function pointer and return to caller
|
||||
for (const auto &old_method : old_methods) {
|
||||
if (strcmp(method.name, old_method.name) == 0 &&
|
||||
strcmp(method.signature, old_method.signature) == 0) {
|
||||
ZLOGD("replace %s#%s%s %p -> %p\n", clz,
|
||||
method.name, method.signature, old_method.fnPtr, method.fnPtr);
|
||||
method.fnPtr = old_method.fnPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
// No matching method found, set fnPtr to null
|
||||
methods[i].fnPtr = nullptr;
|
||||
}
|
||||
|
||||
if (hooks.empty())
|
||||
return;
|
||||
|
||||
old_functions->RegisterNatives(
|
||||
env, env->FindClass(clz), hooks.data(), static_cast<int>(hooks.size()));
|
||||
}
|
||||
|
||||
ZygiskModule::ZygiskModule(int id, void *handle, void *entry)
|
||||
@ -643,12 +633,6 @@ HookContext::~HookContext() {
|
||||
delete jni_hook_list;
|
||||
jni_hook_list = nullptr;
|
||||
|
||||
// Do NOT directly call delete
|
||||
operator delete(jni_method_map);
|
||||
// Directly unmap the whole memory block
|
||||
jni_hook::memory_block::release();
|
||||
jni_method_map = nullptr;
|
||||
|
||||
// Strip out all API function pointers
|
||||
for (auto &m : modules) {
|
||||
m.clearApi();
|
||||
@ -844,7 +828,6 @@ static void hook_commit() {
|
||||
void hook_functions() {
|
||||
default_new(plt_hook_list);
|
||||
default_new(jni_hook_list);
|
||||
default_new(jni_method_map);
|
||||
|
||||
ino_t android_runtime_inode = 0;
|
||||
dev_t android_runtime_dev = 0;
|
||||
@ -910,7 +893,8 @@ static void unhook_functions() {
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
static JNINativeMethod *hookAndSaveJNIMethods(const char *, const JNINativeMethod *, int);
|
||||
// JNI method hook definitions, auto generated
|
||||
#include "jni_hooks.hpp"
|
||||
|
||||
static string get_class_name(JNIEnv *env, jclass clazz) {
|
||||
static auto class_getName = env->GetMethodID(
|
||||
@ -923,13 +907,46 @@ static string get_class_name(JNIEnv *env, jclass clazz) {
|
||||
return className;
|
||||
}
|
||||
|
||||
static void replace_jni_methods(
|
||||
vector<JNINativeMethod> &methods,
|
||||
JNINativeMethod *hook_methods, size_t hook_methods_size,
|
||||
void **orig_function) {
|
||||
for (auto &method : methods) {
|
||||
if (strcmp(method.name, hook_methods[0].name) == 0) {
|
||||
for (auto i = 0; i < hook_methods_size; ++i) {
|
||||
const auto &hook = hook_methods[i];
|
||||
if (strcmp(method.signature, hook.signature) == 0) {
|
||||
*orig_function = method.fnPtr;
|
||||
method.fnPtr = hook.fnPtr;
|
||||
ZLOGI("replace %s\n", method.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ZLOGE("unknown signature of %s%s\n", method.name, method.signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define HOOK_JNI(method) \
|
||||
replace_jni_methods(newMethods, method##_methods.data(), method##_methods.size(), &method##_orig)
|
||||
|
||||
static jint env_RegisterNatives(
|
||||
JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint numMethods) {
|
||||
auto className = get_class_name(env, clazz);
|
||||
ZLOGV("JNIEnv->RegisterNatives [%s]\n", className.data());
|
||||
auto newMethods = unique_ptr<JNINativeMethod[]>(
|
||||
hookAndSaveJNIMethods(className.data(), methods, numMethods));
|
||||
return old_functions->RegisterNatives(env, clazz, newMethods.get() ?: methods, numMethods);
|
||||
if (className == "com/android/internal/os/Zygote") {
|
||||
// Restore JNIEnv as we no longer need to replace anything
|
||||
env->functions = old_functions;
|
||||
delete new_functions;
|
||||
new_functions = nullptr;
|
||||
|
||||
vector<JNINativeMethod> newMethods(methods, methods + numMethods);
|
||||
HOOK_JNI(nativeForkAndSpecialize);
|
||||
HOOK_JNI(nativeSpecializeAppProcess);
|
||||
HOOK_JNI(nativeForkSystemServer);
|
||||
return old_functions->RegisterNatives(env, clazz, newMethods.data(), numMethods);
|
||||
} else {
|
||||
return old_functions->RegisterNatives(env, clazz, methods, numMethods);
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_jni_env() {
|
||||
@ -975,31 +992,3 @@ static void hook_jni_env() {
|
||||
old_functions = env->functions;
|
||||
env->functions = new_functions;
|
||||
}
|
||||
|
||||
static void restore_jni_env(JNIEnv *env) {
|
||||
env->functions = old_functions;
|
||||
delete new_functions;
|
||||
new_functions = nullptr;
|
||||
}
|
||||
|
||||
#define HOOK_JNI(method) \
|
||||
if (methods[i].name == #method##sv) { \
|
||||
int j = 0; \
|
||||
for (; j < method##_methods_num; ++j) { \
|
||||
if (strcmp(methods[i].signature, method##_methods[j].signature) == 0) { \
|
||||
jni_hook_list->try_emplace(className).first->second.push_back(methods[i]); \
|
||||
method##_orig = methods[i].fnPtr; \
|
||||
newMethods[i] = method##_methods[j]; \
|
||||
ZLOGI("replaced %s#" #method "\n", className); \
|
||||
--hook_cnt; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (j == method##_methods_num) { \
|
||||
ZLOGE("unknown signature of %s#" #method ": %s\n", className, methods[i].signature); \
|
||||
} \
|
||||
continue; \
|
||||
}
|
||||
|
||||
// JNI method hook definitions, auto generated
|
||||
#include "jni_hooks.hpp"
|
||||
|
@ -109,54 +109,53 @@ void *nativeForkAndSpecialize_orig = nullptr;
|
||||
ctx.nativeForkAndSpecialize_post();
|
||||
return ctx.pid;
|
||||
}
|
||||
const JNINativeMethod nativeForkAndSpecialize_methods[] = {
|
||||
{
|
||||
std::array nativeForkAndSpecialize_methods = {
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_l
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_o
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_p
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
|
||||
(void *) &nativeForkAndSpecialize_q_alt
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
|
||||
(void *) &nativeForkAndSpecialize_r
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_samsung_m
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;I)I",
|
||||
(void *) &nativeForkAndSpecialize_samsung_n
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_samsung_o
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkAndSpecialize",
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
||||
(void *) &nativeForkAndSpecialize_samsung_p
|
||||
},
|
||||
};
|
||||
constexpr int nativeForkAndSpecialize_methods_num = std::size(nativeForkAndSpecialize_methods);
|
||||
|
||||
void *nativeSpecializeAppProcess_orig = nullptr;
|
||||
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
|
||||
@ -205,29 +204,28 @@ void *nativeSpecializeAppProcess_orig = nullptr;
|
||||
);
|
||||
ctx.nativeSpecializeAppProcess_post();
|
||||
}
|
||||
const JNINativeMethod nativeSpecializeAppProcess_methods[] = {
|
||||
{
|
||||
std::array nativeSpecializeAppProcess_methods = {
|
||||
JNINativeMethod {
|
||||
"nativeSpecializeAppProcess",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||
(void *) &nativeSpecializeAppProcess_q
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeSpecializeAppProcess",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
|
||||
(void *) &nativeSpecializeAppProcess_q_alt
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeSpecializeAppProcess",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
|
||||
(void *) &nativeSpecializeAppProcess_r
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeSpecializeAppProcess",
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||
(void *) &nativeSpecializeAppProcess_samsung_q
|
||||
},
|
||||
};
|
||||
constexpr int nativeSpecializeAppProcess_methods_num = std::size(nativeSpecializeAppProcess_methods);
|
||||
|
||||
void *nativeForkSystemServer_orig = nullptr;
|
||||
[[clang::no_stack_protector]] jint nativeForkSystemServer_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) {
|
||||
@ -250,45 +248,17 @@ void *nativeForkSystemServer_orig = nullptr;
|
||||
ctx.nativeForkSystemServer_post();
|
||||
return ctx.pid;
|
||||
}
|
||||
const JNINativeMethod nativeForkSystemServer_methods[] = {
|
||||
{
|
||||
std::array nativeForkSystemServer_methods = {
|
||||
JNINativeMethod {
|
||||
"nativeForkSystemServer",
|
||||
"(II[II[[IJJ)I",
|
||||
(void *) &nativeForkSystemServer_l
|
||||
},
|
||||
{
|
||||
JNINativeMethod {
|
||||
"nativeForkSystemServer",
|
||||
"(II[IIII[[IJJ)I",
|
||||
(void *) &nativeForkSystemServer_samsung_q
|
||||
},
|
||||
};
|
||||
constexpr int nativeForkSystemServer_methods_num = std::size(nativeForkSystemServer_methods);
|
||||
|
||||
} // namespace
|
||||
|
||||
static JNINativeMethod *hookAndSaveJNIMethods(const char *className, const JNINativeMethod *methods, int numMethods) {
|
||||
JNINativeMethod *newMethods = nullptr;
|
||||
int clz_id = -1;
|
||||
int hook_cnt = 0;
|
||||
do {
|
||||
if (className == "com/android/internal/os/Zygote"sv) {
|
||||
clz_id = 0;
|
||||
hook_cnt = 3;
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
if (hook_cnt) {
|
||||
newMethods = new JNINativeMethod[numMethods];
|
||||
memcpy(newMethods, methods, sizeof(JNINativeMethod) * numMethods);
|
||||
}
|
||||
auto &class_map = (*jni_method_map)[className];
|
||||
for (int i = 0; i < numMethods; ++i) {
|
||||
if (hook_cnt && clz_id == 0) {
|
||||
HOOK_JNI(nativeForkAndSpecialize)
|
||||
HOOK_JNI(nativeSpecializeAppProcess)
|
||||
HOOK_JNI(nativeForkSystemServer)
|
||||
}
|
||||
class_map[methods[i].name][methods[i].signature] = methods[i].fnPtr;
|
||||
}
|
||||
return newMethods;
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
#include <sys/mman.h>
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace jni_hook {
|
||||
|
||||
// We know our minimum alignment is WORD size (size of pointer)
|
||||
static constexpr size_t ALIGN = sizeof(long);
|
||||
|
||||
// 4MB is more than enough
|
||||
static constexpr size_t CAPACITY = (1 << 22);
|
||||
|
||||
// No need to be thread safe as the initial mmap always happens on the main thread
|
||||
static uint8_t *_area = nullptr;
|
||||
|
||||
static std::atomic<uint8_t *> _curr = nullptr;
|
||||
|
||||
void *memory_block::allocate(size_t sz) {
|
||||
if (!_area) {
|
||||
// Memory will not actually be allocated because physical pages are mapped in on-demand
|
||||
_area = static_cast<uint8_t *>(xmmap(
|
||||
nullptr, CAPACITY, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
_curr = _area;
|
||||
}
|
||||
return _curr.fetch_add(align_to(sz, ALIGN));
|
||||
}
|
||||
|
||||
void memory_block::release() {
|
||||
if (_area)
|
||||
munmap(_area, CAPACITY);
|
||||
}
|
||||
|
||||
} // namespace jni_hook
|
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-builtins"
|
||||
#include <parallel_hashmap/phmap.h>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#include <base.hpp>
|
||||
|
||||
namespace jni_hook {
|
||||
|
||||
struct memory_block {
|
||||
static void *allocate(size_t sz);
|
||||
static void deallocate(void *, size_t) { /* Monotonic increase */ }
|
||||
static void release();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using allocator = stateless_allocator<T, memory_block>;
|
||||
|
||||
using string = std::basic_string<char, std::char_traits<char>, allocator<char>>;
|
||||
|
||||
// Use node_hash_map since it will use less memory because we are using a monotonic allocator
|
||||
template<class K, class V>
|
||||
using hash_map = phmap::node_hash_map<K, V,
|
||||
phmap::priv::hash_default_hash<K>,
|
||||
phmap::priv::hash_default_eq<K>,
|
||||
allocator<std::pair<const K, V>>
|
||||
>;
|
||||
|
||||
template<class K, class V>
|
||||
using tree_map = std::map<K, V,
|
||||
std::less<K>,
|
||||
allocator<std::pair<const K, V>>
|
||||
>;
|
||||
|
||||
} // namespace jni_hook
|
||||
|
||||
// Provide heterogeneous lookup for jni_hook::string
|
||||
namespace phmap::priv {
|
||||
template <> struct HashEq<jni_hook::string> : StringHashEqT<char> {};
|
||||
} // namespace phmap::priv
|
Loading…
x
Reference in New Issue
Block a user