Add JNI hooks to critical methods

This commit is contained in:
topjohnwu 2021-01-08 05:25:44 -08:00
parent a30d510eb1
commit 9ed110c91b
5 changed files with 700 additions and 5 deletions

View File

@ -33,7 +33,8 @@ LOCAL_SRC_FILES := \
su/su_daemon.cpp \
inject/entry.cpp \
inject/utils.cpp \
inject/hook.cpp
inject/hook.cpp \
inject/jni_hooks.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

View File

@ -42,6 +42,7 @@ static void inject_cleanup() {
}
void self_unload() {
LOGD("hook: Request to self unload\n");
// If unhook failed, do not unload or else it will cause SIGSEGV
if (!unhook_functions())
return;

View File

@ -8,20 +8,61 @@
using namespace std;
// Static vector won't work, use a pointer instead
static JavaVM *g_jvm;
// For some reason static vector won't work, use a pointer instead
static vector<tuple<const char *, const char *, void **>> *hook_list;
#define DEF_HOOK_FUNC(ret, func, ...) \
static ret (*old_##func)(__VA_ARGS__); \
static ret new_##func(__VA_ARGS__)
#define HOOK_JNI(clazz, method) \
if (newMethods[i].name == #method##sv) { \
JNI::clazz::method##_orig = new JNINativeMethod(); \
memcpy(JNI::clazz::method##_orig, &newMethods[i], sizeof(JNINativeMethod)); \
for (int j = 0; j < JNI::clazz::method##_methods_num; ++j) { \
if (strcmp(newMethods[i].signature, JNI::clazz::method##_methods[j].signature) == 0) { \
newMethods[i] = JNI::clazz::method##_methods[j]; \
LOGI("hook: replaced " #clazz "#" #method "\n"); \
++hooked; \
break; \
} \
} \
continue; \
}
#define clone_methods() \
newMethods = make_unique<JNINativeMethod[]>(numMethods); \
memcpy(newMethods.get(), methods, sizeof(JNINativeMethod) * numMethods)
DEF_HOOK_FUNC(int, jniRegisterNativeMethods,
JNIEnv *env, const char *className, const JNINativeMethod *methods, int numMethods) {
LOGD("hook: jniRegisterNativeMethods %s", className);
// TODO: actually do things like replacing JNI native methods
unique_ptr<JNINativeMethod[]> newMethods;
int hooked = 0;
return old_jniRegisterNativeMethods(env, className, methods, numMethods);
if (g_jvm == nullptr) {
// Save for later unhooking
env->GetJavaVM(&g_jvm);
}
if (className == "com/android/internal/os/Zygote"sv) {
clone_methods();
for (int i = 0; i < numMethods && hooked < 3; ++i) {
HOOK_JNI(Zygote, nativeForkAndSpecialize);
HOOK_JNI(Zygote, nativeSpecializeAppProcess);
HOOK_JNI(Zygote, nativeForkSystemServer);
}
} else if (className == "android/os/SystemProperties"sv) {
clone_methods();
for (int i = 0; i < numMethods && hooked < 1; ++i) {
HOOK_JNI(SystemProperties, native_set);
}
}
return old_jniRegisterNativeMethods(env, className, newMethods.get() ?: methods, numMethods);
}
static bool hook_refresh() {
@ -58,10 +99,40 @@ void hook_functions() {
hook_refresh();
}
#define push_method(clazz, method) \
if (JNI::clazz::method##_orig) methods.emplace_back(*JNI::clazz::method##_orig)
bool unhook_functions() {
JNIEnv* env;
if (g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
return false;
vector<JNINativeMethod> methods;
push_method(Zygote, nativeForkAndSpecialize);
push_method(Zygote, nativeSpecializeAppProcess);
push_method(Zygote, nativeForkSystemServer);
if (!methods.empty() && old_jniRegisterNativeMethods(env,
"com/android/internal/os/Zygote",
methods.data(), methods.size()) != 0) {
LOGE("hook: Failed to register JNI hook for Zygote\n");
return false;
}
methods.clear();
push_method(SystemProperties, native_set);
if (!methods.empty() && old_jniRegisterNativeMethods(env,
"android/os/SystemProperties",
methods.data(), methods.size()) != 0) {
LOGE("hook: Failed to register JNI hook for SystemProperties\n");
return false;
}
for (auto &[path, sym, old_func] : *hook_list) {
if (xhook_register(path, sym, *old_func, nullptr) != 0) {
LOGE("hook: Failed to register hook \"%s\"\n", sym); \
LOGE("hook: Failed to register hook \"%s\"\n", sym);
return false;
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include <jni.h>
#define INJECT_LIB_1 "/dev/tmp/magisk.1.so"
#define INJECT_LIB_2 "/dev/tmp/magisk.2.so"
@ -19,3 +20,28 @@ uintptr_t get_remote_lib(int pid, const char *lib);
void self_unload();
void hook_functions();
bool unhook_functions();
// JNI method declarations
namespace JNI {
namespace Zygote {
extern JNINativeMethod *nativeForkAndSpecialize_orig;
extern JNINativeMethod *nativeSpecializeAppProcess_orig;
extern JNINativeMethod *nativeForkSystemServer_orig;
extern const JNINativeMethod nativeForkAndSpecialize_methods[];
extern const int nativeForkAndSpecialize_methods_num;
extern const JNINativeMethod nativeSpecializeAppProcess_methods[];
extern const int nativeSpecializeAppProcess_methods_num;
extern const JNINativeMethod nativeForkSystemServer_methods[];
extern const int nativeForkSystemServer_methods_num;
}
namespace SystemProperties {
extern JNINativeMethod *native_set_orig;
extern const JNINativeMethod native_set_methods[];
constexpr int native_set_methods_num = 1;
}
}

View File

@ -0,0 +1,596 @@
/*
* Original code: https://github.com/RikkaApps/Riru/blob/master/riru/src/main/cpp/jni_native_method.cpp
* The code is modified and sublicensed to GPLv3 for incorporating into Magisk.
*
* Copyright (c) 2018-2021, RikkaW
* Copyright (c) 2021, John 'topjohnwu' Wu
*/
#include <jni.h>
#include <utils.hpp>
#include "inject.hpp"
#define ENABLE_LEGACY_DP 0 // Nobody should use outdated developer preview...
static void nativeForkAndSpecialize_pre(
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &se_name,
jintArray &fdsToClose, jintArray &fdsToIgnore, jboolean &is_child_zygote,
jstring &instructionSet, jstring &appDataDir, jboolean &isTopApp, jobjectArray &pkgDataInfoList,
jobjectArray &whitelistedDataInfoList, jboolean &bindMountAppDataDirs, jboolean &bindMountAppStorageDirs) {
LOGD("hook: %s\n", __FUNCTION__);
}
static void nativeForkAndSpecialize_post(JNIEnv *env, jclass clazz, jint uid, jint pid) {
LOGD("hook: %s\n", __FUNCTION__);
// Demonstrate self unload in child process
if (pid == 0)
self_unload();
}
// -----------------------------------------------------------------
static void nativeSpecializeAppProcess_pre(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir,
jboolean &isTopApp, jobjectArray &pkgDataInfoList, jobjectArray &whitelistedDataInfoList,
jboolean &bindMountAppDataDirs, jboolean &bindMountAppStorageDirs) {
LOGD("hook: %s\n", __FUNCTION__);
}
static void nativeSpecializeAppProcess_post(JNIEnv *env, jclass clazz) {
LOGD("hook: %s\n", __FUNCTION__);
}
// -----------------------------------------------------------------
static void nativeForkSystemServer_pre(
JNIEnv *env, jclass clazz, uid_t &uid, gid_t &gid, jintArray &gids, jint &debug_flags,
jobjectArray &rlimits, jlong &permittedCapabilities, jlong &effectiveCapabilities) {
LOGD("hook: %s\n", __FUNCTION__);
}
static void nativeForkSystemServer_post(JNIEnv *env, jclass clazz, jint res) {
LOGD("hook: %s\n", __FUNCTION__);
}
// -----------------------------------------------------------------
#define pre_fork() nativeForkAndSpecialize_pre( \
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, \
se_info, se_name, fdsToClose, fdsToIgnore, is_child_zygote, \
instructionSet, appDataDir, isTopApp, pkgDataInfoList, whitelistedDataInfoList, \
bindMountAppDataDirs, bindMountAppStorageDirs) \
template<typename T, typename ...Args>
static jint orig_fork(Args && ...args) {
return reinterpret_cast<T>(JNI::Zygote::nativeForkAndSpecialize_orig->fnPtr)(std::forward<Args>(args)...);
}
#define post_fork() nativeForkAndSpecialize_post(env, clazz, uid, pid)
const static char nativeForkAndSpecialize_m_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_m(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
jintArray fdsToIgnore = nullptr;
jboolean is_child_zygote = JNI_FALSE;
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_m)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, instructionSet, appDataDir);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_o_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_o(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jstring instructionSet, jstring appDataDir) {
jboolean is_child_zygote = JNI_FALSE;
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_o)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, instructionSet, appDataDir);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_p_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_p(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir) {
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_p)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, is_child_zygote, instructionSet, appDataDir);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_q_alt_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I";
static jint nativeForkAndSpecialize_q_alt(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir, jboolean isTopApp) {
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_q_alt)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, is_child_zygote, instructionSet, appDataDir, isTopApp);
post_fork();
return pid;
}
#if ENABLE_LEGACY_DP
const static char nativeForkAndSpecialize_r_dp2_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_r_dp2(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir, jboolean isTopApp, jobjectArray pkgDataInfoList) {
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_r_dp2)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, is_child_zygote, instructionSet, appDataDir, isTopApp,
pkgDataInfoList);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_r_dp3_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;Z)I";
static jint nativeForkAndSpecialize_r_dp3(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir, jboolean isTopApp, jobjectArray pkgDataInfoList,
jboolean bindMountAppStorageDirs) {
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_r_dp3)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, is_child_zygote, instructionSet, appDataDir, isTopApp,
pkgDataInfoList,
bindMountAppStorageDirs);
post_fork();
return pid;
}
#endif // ENABLE_LEGACY_DP
const static char *nativeForkAndSpecialize_r_sig =
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I";
static jint nativeForkAndSpecialize_r(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir, jboolean isTopApp, jobjectArray pkgDataInfoList,
jobjectArray whitelistedDataInfoList, jboolean bindMountAppDataDirs, jboolean bindMountAppStorageDirs) {
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_r)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, se_name,
fdsToClose, fdsToIgnore, is_child_zygote, instructionSet, appDataDir, isTopApp,
pkgDataInfoList,
whitelistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_samsung_m_sig[] =
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I";
jint nativeForkAndSpecialize_samsung_m(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
jstring se_name, jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
jintArray fdsToIgnore = nullptr;
jboolean is_child_zygote = JNI_FALSE;
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_samsung_m)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, category,
accessInfo, se_name, fdsToClose, instructionSet, appDataDir);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_samsung_n_sig[] =
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;I)I";
static jint nativeForkAndSpecialize_samsung_n(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
jstring se_name, jintArray fdsToClose, jstring instructionSet, jstring appDataDir,
jint a1) {
jintArray fdsToIgnore = nullptr;
jboolean is_child_zygote = JNI_FALSE;
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_samsung_n)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, category,
accessInfo, se_name, fdsToClose, instructionSet, appDataDir, a1);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_samsung_o_sig[] =
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_samsung_o(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
jstring se_name, jintArray fdsToClose, jintArray fdsToIgnore, jstring instructionSet,
jstring appDataDir) {
jboolean is_child_zygote = JNI_FALSE;
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_samsung_o)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, category,
accessInfo, se_name, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
post_fork();
return pid;
}
const static char nativeForkAndSpecialize_samsung_p_sig[] =
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I";
static jint nativeForkAndSpecialize_samsung_p(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
jstring se_name, jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir) {
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_fork();
jint pid = orig_fork<decltype(&nativeForkAndSpecialize_samsung_p)>(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, category,
accessInfo, se_name, fdsToClose, fdsToIgnore, is_child_zygote, instructionSet,
appDataDir);
post_fork();
return pid;
}
#define DCL_FORK(ver) { \
"nativeForkAndSpecialize", \
nativeForkAndSpecialize_##ver##_sig, \
(void *) &nativeForkAndSpecialize_##ver \
}
// -----------------------------------------------------------------
#define pre_spec() nativeSpecializeAppProcess_pre( \
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, \
startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, \
whitelistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs)
template<typename T, typename ...Args>
static void orig_spec(Args && ...args) {
reinterpret_cast<T>(JNI::Zygote::nativeSpecializeAppProcess_orig->fnPtr)(std::forward<Args>(args)...);
}
#define post_spec() nativeSpecializeAppProcess_post(env, clazz)
const static char nativeSpecializeAppProcess_q_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V";
static void nativeSpecializeAppProcess_q(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir) {
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_q)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
startChildZygote, instructionSet, appDataDir);
post_spec();
}
const static char nativeSpecializeAppProcess_q_alt_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V";
static void nativeSpecializeAppProcess_q_alt(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir,
jboolean isTopApp) {
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_q_alt)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
startChildZygote, instructionSet, appDataDir, isTopApp);
post_spec();
}
#if ENABLE_LEGACY_DP
const static char nativeSpecializeAppProcess_r_dp2_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)V";
static void nativeSpecializeAppProcess_r_dp2(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir,
jboolean isTopApp, jobjectArray pkgDataInfoList) {
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_r_dp2)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList);
post_spec();
}
const static char nativeSpecializeAppProcess_r_dp3_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;Z)V";
static void nativeSpecializeAppProcess_r_dp3(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir,
jboolean isTopApp, jobjectArray pkgDataInfoList, jboolean bindMountAppStorageDirs) {
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_r_dp3)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList,
bindMountAppStorageDirs);
post_spec();
}
#endif // ENABLE_LEGACY_DP
const static char nativeSpecializeAppProcess_r_sig[] =
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V";
static void nativeSpecializeAppProcess_r(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jstring niceName,
jboolean startChildZygote, jstring instructionSet, jstring appDataDir,
jboolean isTopApp, jobjectArray pkgDataInfoList, jobjectArray whitelistedDataInfoList,
jboolean bindMountAppDataDirs, jboolean bindMountAppStorageDirs) {
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_r)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList,
whitelistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs);
post_spec();
}
const static char nativeSpecializeAppProcess_samsung_q_sig[] =
"(II[II[[IILjava/lang/String;IILjava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V";
static void nativeSpecializeAppProcess_samsung_q(
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jint mountExternal, jstring seInfo, jint space, jint accessInfo,
jstring niceName, jboolean startChildZygote, jstring instructionSet, jstring appDataDir) {
jboolean isTopApp = JNI_FALSE;
jobjectArray pkgDataInfoList = nullptr;
jobjectArray whitelistedDataInfoList = nullptr;
jboolean bindMountAppDataDirs = JNI_FALSE;
jboolean bindMountAppStorageDirs = JNI_FALSE;
pre_spec();
orig_spec<decltype(&nativeSpecializeAppProcess_samsung_q)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, space,
accessInfo, niceName, startChildZygote, instructionSet, appDataDir);
post_spec();
}
#define DCL_SPEC(ver) { \
"nativeSpecializeAppProcess", \
nativeSpecializeAppProcess_##ver##_sig, \
(void *) &nativeSpecializeAppProcess_##ver \
}
// -----------------------------------------------------------------
#define pre_server() nativeForkSystemServer_pre( \
env, clazz, uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, \
effectiveCapabilities)
template<typename T, typename ...Args>
static jint orig_server(Args && ...args) {
return reinterpret_cast<T>(JNI::Zygote::nativeForkSystemServer_orig->fnPtr)(std::forward<Args>(args)...);
}
#define post_server() nativeForkSystemServer_post(env, clazz, pid)
const static char nativeForkSystemServer_m_sig[] = "(II[II[[IJJ)I";
static jint nativeForkSystemServer_m(
JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids, jint runtimeFlags,
jobjectArray rlimits, jlong permittedCapabilities, jlong effectiveCapabilities) {
pre_server();
jint pid = orig_server<decltype(&nativeForkSystemServer_m)>(
env, clazz, uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities,
effectiveCapabilities);
post_server();
return pid;
}
const static char nativeForkSystemServer_samsung_q_sig[] = "(II[IIII[[IJJ)I";
static jint nativeForkSystemServer_samsung_q(
JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids, jint runtimeFlags,
jint space, jint accessInfo, jobjectArray rlimits, jlong permittedCapabilities,
jlong effectiveCapabilities) {
pre_server();
jint pid = orig_server<decltype(&nativeForkSystemServer_samsung_q)>(
env, clazz, uid, gid, gids, runtimeFlags, space, accessInfo, rlimits,
permittedCapabilities,
effectiveCapabilities);
post_server();
return pid;
}
#define DCL_SERVER(ver) { \
"nativeForkSystemServer", \
nativeForkSystemServer_##ver##_sig, \
(void *) &nativeForkSystemServer_##ver \
}
/*
* On Android 9+, in very rare cases, SystemProperties.set("sys.user." + userId + ".ce_available", "true")
* will throw an exception (no idea if this is caused by hooking) and user data will be wiped.
* Hook it and clear the exception to prevent this problem from happening.
*
* https://cs.android.com/android/platform/superproject/+/android-9.0.0_r34:frameworks/base/services/core/java/com/android/server/pm/UserDataPreparer.java;l=107;bpv=0;bpt=0
*/
static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ) {
const char *key = env->GetStringUTFChars(keyJ, JNI_FALSE);
char user[16];
bool no_throw = sscanf(key, "sys.user.%[^.].ce_available", user) == 1;
env->ReleaseStringUTFChars(keyJ, key);
reinterpret_cast<decltype(&SystemProperties_set)>
(JNI::SystemProperties::native_set_orig->fnPtr)(env, clazz, keyJ, valJ);
jthrowable exception = env->ExceptionOccurred();
if (exception && no_throw) {
LOGW("prevented data destroy");
env->ExceptionDescribe();
env->ExceptionClear();
}
}
namespace JNI {
namespace Zygote {
JNINativeMethod *nativeForkAndSpecialize_orig = nullptr;
JNINativeMethod *nativeSpecializeAppProcess_orig = nullptr;
JNINativeMethod *nativeForkSystemServer_orig = nullptr;
const JNINativeMethod nativeForkAndSpecialize_methods[] = {
DCL_FORK(m), DCL_FORK(o), DCL_FORK(p),
DCL_FORK(q_alt), DCL_FORK(r),
DCL_FORK(samsung_m), DCL_FORK(samsung_n),
DCL_FORK(samsung_o), DCL_FORK(samsung_p),
#if ENABLE_LEGACY_DP
DCL_FORK(r_dp2), DCL_FORK(r_dp3)
#endif
};
const int nativeForkAndSpecialize_methods_num = std::size(nativeForkAndSpecialize_methods);
const JNINativeMethod nativeSpecializeAppProcess_methods[] = {
DCL_SPEC(q), DCL_SPEC(q_alt),
DCL_SPEC(r), DCL_SPEC(samsung_q),
#if ENABLE_LEGACY_DP
DCL_SPEC(r_dp2), DCL_SPEC(r_dp3)
#endif
};
const int nativeSpecializeAppProcess_methods_num = std::size(nativeSpecializeAppProcess_methods);
const JNINativeMethod nativeForkSystemServer_methods[] = {
DCL_SERVER(m), DCL_SERVER(samsung_q)
};
const int nativeForkSystemServer_methods_num = std::size(nativeForkSystemServer_methods);
}
namespace SystemProperties {
JNINativeMethod *native_set_orig = nullptr;
const JNINativeMethod native_set_methods[] = {{
"native_set",
"(Ljava/lang/String;Ljava/lang/String;)V",
(void *) &SystemProperties_set
}};
}
}