Compare commits

...

5 Commits

Author SHA1 Message Date
topjohnwu
200665c48a Make jni_hooks.hpp a normal C++ header
[skip ci]
2025-12-07 02:44:19 -08:00
topjohnwu
dd42aa99ea Refactor gen_jni_hooks.py
[skip ci]
2025-12-07 02:25:50 -08:00
Wang Han
0936cdb192 Update nativeForkAndSpecialize signature for A16 QPR2
67a4b1b2fe
2025-12-07 00:18:50 -08:00
topjohnwu
871643dce2 Enable CI for API 36.1 2025-12-07 00:18:50 -08:00
topjohnwu
a510554b21 Disable Zygisk upon incomplete JNI hook
Do not enable Zygisk unless ALL replacements are hooked properly.
This allow Zygisk tests to fail when new signature is introduced.
2025-12-07 00:18:50 -08:00
5 changed files with 683 additions and 207 deletions

View File

@@ -82,7 +82,7 @@ jobs:
strategy:
fail-fast: false
matrix:
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, "CANARY"]
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36.1, "CANARY"]
type: [""]
include:
- version: "CANARY"

View File

@@ -1,238 +1,591 @@
#!/usr/bin/env python3
primitives = ['jint', 'jboolean', 'jlong']
primitives = ["jint", "jboolean", "jlong"]
class JType:
def __init__(self, cpp, jni):
def __init__(self, cpp: str, jni: str):
self.cpp = cpp
self.jni = jni
class JArray(JType):
def __init__(self, type):
def __init__(self, type: JType):
if type.cpp in primitives:
name = type.cpp + 'Array'
name = type.cpp + "Array"
else:
name = 'jobjectArray'
super().__init__(name, '[' + type.jni)
name = "jobjectArray"
super().__init__(name, "[" + type.jni)
class Argument:
def __init__(self, name, type, set_arg = False):
def __init__(self, name: str, type: JType, set_arg=False):
self.name = name
self.type = type
self.set_arg = set_arg
def cpp(self):
return f'{self.type.cpp} {self.name}'
def cpp(self) -> str:
return f"{self.type.cpp} {self.name}"
# Args we don't care, give it an auto generated name
class Anon(Argument):
cnt = 0
def __init__(self, type):
super().__init__(f'_{Anon.cnt}', type)
def __init__(self, type: JType):
super().__init__(f"_{Anon.cnt}", type)
Anon.cnt += 1
class Return:
def __init__(self, value, type):
def __init__(self, value: str, type: JType):
self.value = value
self.type = type
class Method:
def __init__(self, name, ret, args):
class JNIMethod:
def __init__(self, name: str, ret: Return, args: list[Argument]):
self.name = name
self.ret = ret
self.args = args
def cpp(self):
return ', '.join(map(lambda x: x.cpp(), self.args))
def arg_list_name(self) -> str:
return "env, clazz, " + ", ".join(map(lambda x: x.name, self.args))
def name_list(self):
return ', '.join(map(lambda x: x.name, self.args))
def arg_list_cpp(self) -> str:
return "JNIEnv *env, jclass clazz, " + ", ".join(
map(lambda x: x.cpp(), self.args)
)
def jni(self):
args = ''.join(map(lambda x: x.type.jni, self.args))
return f'({args}){self.ret.type.jni}'
def cpp_fn_type(self) -> str:
return f"{self.ret.type.cpp}(*)({self.arg_list_cpp()}"
def body(self, name, i):
return ''
def cpp_lambda_sig(self) -> str:
return f"[] [[clang::no_stack_protector]] ({self.arg_list_cpp()}) static -> {self.ret.type.cpp}"
class JNIHook(Method):
def __init__(self, ver, ret, args):
name = f'{self.base_name()}_{ver}'
def jni_sig(self):
args = "".join(map(lambda x: x.type.jni, self.args))
return f"({args}){self.ret.type.jni}"
class JNIHook(JNIMethod):
def __init__(self, ver: str, ret: Return, args: list[Argument]):
name = f"{self.hook_target()}_{ver}"
super().__init__(name, ret, args)
def base_name(self):
return ''
def hook_target(self):
return ""
def body(self, orig_fn_ptr: str):
return ""
def orig_method(self, name, i):
return f'reinterpret_cast<{self.ret.type.cpp}(*)(JNIEnv *env, jclass clazz, {self.cpp()})>(g_hook->{name}_methods[{i}].fnPtr)'
def ind(i):
return '\n' + ' ' * i
return "\n" + " " * i
# Common types
jint = JType('jint', 'I')
jint = JType("jint", "I")
jintArray = JArray(jint)
jstring = JType('jstring', 'Ljava/lang/String;')
jboolean = JType('jboolean', 'Z')
jlong = JType('jlong', 'J')
void = JType('void', 'V')
jstring = JType("jstring", "Ljava/lang/String;")
jboolean = JType("jboolean", "Z")
jlong = JType("jlong", "J")
void = JType("void", "V")
class ForkAndSpec(JNIHook):
class ForkApp(JNIHook):
def __init__(self, ver, args):
super().__init__(ver, Return('ctx.pid', jint), args)
super().__init__(ver, Return("ctx.pid", jint), args)
def base_name(self):
return 'nativeForkAndSpecialize'
def hook_target(self):
return "nativeForkAndSpecialize"
def init_args(self):
return 'AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);'
return "AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);"
def body(self, name, i):
decl = ''
def body(self, orig_fn_ptr: str):
decl = ""
decl += ind(3) + self.init_args()
for a in self.args:
if a.set_arg:
decl += ind(3) + f'args.{a.name} = &{a.name};'
decl += ind(3) + 'ZygiskContext ctx(env, &args);'
decl += ind(3) + f'ctx.{self.base_name()}_pre();'
decl += ind(3) + self.orig_method(name, i) + '('
decl += ind(4) + f'env, clazz, {self.name_list()}'
decl += ind(3) + ');'
decl += ind(3) + f'ctx.{self.base_name()}_post();'
decl += ind(3) + f"args.{a.name} = &{a.name};"
decl += ind(3) + "ZygiskContext ctx(env, &args);"
decl += ind(3) + f"ctx.{self.hook_target()}_pre();"
decl += ind(3) + f"reinterpret_cast<{self.cpp_fn_type()})>({orig_fn_ptr})("
decl += ind(4) + self.arg_list_name()
decl += ind(3) + ");"
decl += ind(3) + f"ctx.{self.hook_target()}_post();"
if self.ret.value:
decl += ind(3) + f"return {self.ret.value};"
return decl
class SpecApp(ForkAndSpec):
def __init__(self, ver, args):
class SpecializeApp(ForkApp):
def __init__(self, ver: str, args: list[Argument]):
super().__init__(ver, args)
self.ret = Return('', void)
self.ret = Return("", void)
def base_name(self):
return 'nativeSpecializeAppProcess'
def hook_target(self):
return "nativeSpecializeAppProcess"
class ForkServer(ForkAndSpec):
def base_name(self):
return 'nativeForkSystemServer'
class ForkServer(ForkApp):
def hook_target(self):
return "nativeForkSystemServer"
def init_args(self):
return 'ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);'
return "ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);"
# Common args
uid = Argument('uid', jint)
gid = Argument('gid', jint)
gids = Argument('gids', jintArray)
runtime_flags = Argument('runtime_flags', jint)
rlimits = Argument('rlimits', JArray(jintArray))
mount_external = Argument('mount_external', jint)
se_info = Argument('se_info', jstring)
nice_name = Argument('nice_name', jstring)
fds_to_close = Argument('fds_to_close', jintArray)
instruction_set = Argument('instruction_set', jstring)
app_data_dir = Argument('app_data_dir', jstring)
uid = Argument("uid", jint)
gid = Argument("gid", jint)
gids = Argument("gids", jintArray)
runtime_flags = Argument("runtime_flags", jint)
rlimits = Argument("rlimits", JArray(jintArray))
mount_external = Argument("mount_external", jint)
se_info = Argument("se_info", jstring)
nice_name = Argument("nice_name", jstring)
fds_to_close = Argument("fds_to_close", jintArray)
instruction_set = Argument("instruction_set", jstring)
app_data_dir = Argument("app_data_dir", jstring)
# o
fds_to_ignore = Argument('fds_to_ignore', jintArray, True)
fds_to_ignore = Argument("fds_to_ignore", jintArray, True)
# p
is_child_zygote = Argument('is_child_zygote', jboolean, True)
is_child_zygote = Argument("is_child_zygote", jboolean, True)
# q_alt
is_top_app = Argument('is_top_app', jboolean, True)
is_top_app = Argument("is_top_app", jboolean, True)
# r
pkg_data_info_list = Argument('pkg_data_info_list', JArray(jstring), True)
whitelisted_data_info_list = Argument('whitelisted_data_info_list', JArray(jstring), True)
mount_data_dirs = Argument('mount_data_dirs', jboolean, True)
mount_storage_dirs = Argument('mount_storage_dirs', jboolean, True)
pkg_data_info_list = Argument("pkg_data_info_list", JArray(jstring), True)
whitelisted_data_info_list = Argument(
"whitelisted_data_info_list", JArray(jstring), True
)
mount_data_dirs = Argument("mount_data_dirs", jboolean, True)
mount_storage_dirs = Argument("mount_storage_dirs", jboolean, True)
# u
mount_sysprop_overrides = Argument('mount_sysprop_overrides', jboolean, True)
mount_sysprop_overrides = Argument("mount_sysprop_overrides", jboolean, True)
# b
use_fifo_ui = Argument("use_fifo_ui", jboolean, False)
# server
permitted_capabilities = Argument('permitted_capabilities', jlong)
effective_capabilities = Argument('effective_capabilities', jlong)
permitted_capabilities = Argument("permitted_capabilities", jlong)
effective_capabilities = Argument("effective_capabilities", jlong)
# Method definitions
fas_l = ForkAndSpec('l', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, nice_name, fds_to_close, instruction_set, app_data_dir])
fas_l = ForkApp(
"l",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
instruction_set,
app_data_dir,
],
)
fas_o = ForkAndSpec('o', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir])
fas_o = ForkApp(
"o",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
instruction_set,
app_data_dir,
],
)
fas_p = ForkAndSpec('p', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir])
fas_p = ForkApp(
"p",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
],
)
fas_q_alt = ForkAndSpec('q_alt', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app])
fas_q_alt = ForkApp(
"q_alt",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
],
)
fas_r = ForkAndSpec('r', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app,
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs])
fas_r = ForkApp(
"r",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
pkg_data_info_list,
whitelisted_data_info_list,
mount_data_dirs,
mount_storage_dirs,
],
)
fas_u = ForkAndSpec('u', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app,
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides])
fas_u = ForkApp(
"u",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
pkg_data_info_list,
whitelisted_data_info_list,
mount_data_dirs,
mount_storage_dirs,
mount_sysprop_overrides,
],
)
fas_samsung_m = ForkAndSpec('samsung_m', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, fds_to_close, instruction_set, app_data_dir])
fas_b = ForkApp(
"b",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
use_fifo_ui,
pkg_data_info_list,
whitelisted_data_info_list,
mount_data_dirs,
mount_storage_dirs,
mount_sysprop_overrides,
],
)
fas_samsung_n = ForkAndSpec('samsung_n', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, fds_to_close, instruction_set, app_data_dir, Anon(jint)])
fas_samsung_m = ForkApp(
"samsung_m",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
Anon(jint),
Anon(jint),
nice_name,
fds_to_close,
instruction_set,
app_data_dir,
],
)
fas_samsung_o = ForkAndSpec('samsung_o', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir])
fas_samsung_n = ForkApp(
"samsung_n",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
Anon(jint),
Anon(jint),
nice_name,
fds_to_close,
instruction_set,
app_data_dir,
Anon(jint),
],
)
fas_samsung_p = ForkAndSpec('samsung_p', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, fds_to_close, fds_to_ignore, is_child_zygote,
instruction_set, app_data_dir])
fas_samsung_o = ForkApp(
"samsung_o",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
Anon(jint),
Anon(jint),
nice_name,
fds_to_close,
fds_to_ignore,
instruction_set,
app_data_dir,
],
)
spec_q = SpecApp('q', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, is_child_zygote, instruction_set, app_data_dir])
fas_samsung_p = ForkApp(
"samsung_p",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
Anon(jint),
Anon(jint),
nice_name,
fds_to_close,
fds_to_ignore,
is_child_zygote,
instruction_set,
app_data_dir,
],
)
spec_q_alt = SpecApp('q_alt', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app])
spec_q = SpecializeApp(
"q",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
is_child_zygote,
instruction_set,
app_data_dir,
],
)
spec_r = SpecApp('r', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name,
is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list,
whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs])
spec_q_alt = SpecializeApp(
"q_alt",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
],
)
spec_u = SpecApp('u', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name,
is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list,
whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides])
spec_r = SpecializeApp(
"r",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
pkg_data_info_list,
whitelisted_data_info_list,
mount_data_dirs,
mount_storage_dirs,
],
)
spec_samsung_q = SpecApp('samsung_q', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, is_child_zygote, instruction_set, app_data_dir])
spec_u = SpecializeApp(
"u",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
nice_name,
is_child_zygote,
instruction_set,
app_data_dir,
is_top_app,
pkg_data_info_list,
whitelisted_data_info_list,
mount_data_dirs,
mount_storage_dirs,
mount_sysprop_overrides,
],
)
server_l = ForkServer('l', [uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities])
spec_samsung_q = SpecializeApp(
"samsung_q",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
mount_external,
se_info,
Anon(jint),
Anon(jint),
nice_name,
is_child_zygote,
instruction_set,
app_data_dir,
],
)
server_samsung_q = ForkServer('samsung_q', [uid, gid, gids, runtime_flags, Anon(jint), Anon(jint), rlimits,
permitted_capabilities, effective_capabilities])
server_l = ForkServer(
"l",
[
uid,
gid,
gids,
runtime_flags,
rlimits,
permitted_capabilities,
effective_capabilities,
],
)
def gen_jni_def(name, methods):
decl = ''
decl += ind(0) + f'std::array<JNINativeMethod, {len(methods)}> {name}_methods = {{{{'
server_samsung_q = ForkServer(
"samsung_q",
[
uid,
gid,
gids,
runtime_flags,
Anon(jint),
Anon(jint),
rlimits,
permitted_capabilities,
effective_capabilities,
],
)
def gen_jni_def(field: str, methods: list[JNIHook]):
decl = ""
decl += ind(0) + f"std::array<JNINativeMethod, {len(methods)}> {field} = {{{{"
for i, m in enumerate(methods):
decl += ind(1) + '{'
decl += ind(2) + f'"{m.base_name()}",'
decl += ind(2) + f'"{m.jni()}",'
decl += ind(2) + f'(void *) +[] [[clang::no_stack_protector]] (JNIEnv *env, jclass clazz, {m.cpp()}) static -> {m.ret.type.cpp} {{'
decl += m.body(name, i)
if m.ret.value:
decl += ind(3) + f'return {m.ret.value};'
decl += ind(2) + '}'
decl += ind(1) + '},'
decl += ind(0) + '}};'
decl += ind(1) + f"// {m.name}"
decl += ind(1) + "{"
decl += ind(2) + f'"{m.hook_target()}",'
decl += ind(2) + f'"{m.jni_sig()}",'
decl += ind(2) + f"(void *) +{m.cpp_lambda_sig()} {{"
orig_fn_ptr = f"get_defs()->{field}[{i}].fnPtr"
decl += m.body(orig_fn_ptr)
decl += ind(2) + "}"
decl += ind(1) + "},"
decl += ind(0) + "}};"
decl += ind(0)
return decl
with open('jni_hooks.hpp', 'w') as f:
f.write('// Generated by gen_jni_hooks.py\n')
f.write(gen_jni_def('zygote', [
fas_l, fas_o, fas_p, fas_q_alt, fas_r, fas_u, fas_samsung_m, fas_samsung_n, fas_samsung_o,
fas_samsung_p, spec_q, spec_q_alt, spec_r, spec_u, spec_samsung_q, server_l, server_samsung_q]))
with open("jni_hooks.hpp", "w") as f:
f.write("// Generated by gen_jni_hooks.py\n")
f.write("#pragma once\n\n")
f.write("struct JniHookDefinitions;\n")
f.write("static JniHookDefinitions *get_defs();\n\n")
f.write("struct JniHookDefinitions {\n")
f.write(
gen_jni_def(
"fork_app_methods",
[
fas_l,
fas_o,
fas_p,
fas_q_alt,
fas_r,
fas_u,
fas_b,
fas_samsung_m,
fas_samsung_n,
fas_samsung_o,
fas_samsung_p,
],
)
)
f.write('\n')
f.write(
gen_jni_def(
"specialize_app_methods",
[spec_q, spec_q_alt, spec_r, spec_u, spec_samsung_q],
)
)
f.write(gen_jni_def("fork_server_methods", [server_l, server_samsung_q]))
f.write("\n};\n")

View File

@@ -8,10 +8,10 @@
#include <lsplt.hpp>
#include <base.hpp>
#include <consts.hpp>
#include "zygisk.hpp"
#include "module.hpp"
#include "jni_hooks.hpp"
using namespace std;
@@ -90,25 +90,15 @@ using namespace std;
constexpr const char *kZygoteInit = "com.android.internal.os.ZygoteInit";
constexpr const char *kZygote = "com/android/internal/os/Zygote";
// Global contexts:
//
// HookContext lives as long as Zygisk is loaded in memory. It tracks the process's function
// hooking state and bootstraps code injection until we replace the process specialization methods.
//
// ZygiskContext lives during the process specialization process. It implements Zygisk
// features, such as loading modules and customizing process fork/specialization.
ZygiskContext *g_ctx;
struct HookContext;
static HookContext *g_hook;
constexpr const char *kForkApp = "nativeForkAndSpecialize";
constexpr const char *kSpecializeApp = "nativeSpecializeAppProcess";
constexpr const char *kForkServer = "nativeForkSystemServer";
using JNIMethods = std::span<JNINativeMethod>;
using JNIMethodsDyn = std::pair<unique_ptr<JNINativeMethod[]>, size_t>;
struct HookContext {
#include "jni_hooks.hpp"
struct HookContext : JniHookDefinitions {
// std::array<JNINativeMethod> zygote_methods
vector<tuple<dev_t, ino_t, const char *, void **>> plt_backup;
const NativeBridgeRuntimeCallbacks *runtime_callbacks = nullptr;
void *self_handle = nullptr;
@@ -119,15 +109,34 @@ struct HookContext {
void restore_plt_hook();
void hook_zygote_jni();
void restore_zygote_hook(JNIEnv *env);
void hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods methods);
void hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods methods) const;
void post_native_bridge_load(void *handle);
private:
void register_hook(dev_t dev, ino_t inode, const char *symbol, void *new_func, void **old_func);
int hook_jni_methods(JNIEnv *env, jclass clazz, JNIMethods methods) const;
JNIMethodsDyn get_jni_methods(JNIEnv *env, jclass clazz) const;
};
// -----------------------------------------------------------------
// Global contexts:
//
// HookContext lives as long as Zygisk is loaded in memory. It tracks the process's function
// hooking state and bootstraps code injection until we replace the process specialization methods.
//
// ZygiskContext lives during the process specialization process. It implements Zygisk
// features, such as loading modules and customizing process fork/specialization.
ZygiskContext *g_ctx;
static HookContext *g_hook;
static JniHookDefinitions *get_defs() {
return g_hook;
}
// -----------------------------------------------------------------
#define DCL_HOOK_FUNC(ret, func, ...) \
ret (*old_##func)(__VA_ARGS__); \
ret new_##func(__VA_ARGS__)
@@ -452,56 +461,74 @@ void HookContext::restore_plt_hook() {
// -----------------------------------------------------------------
void HookContext::hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods methods) {
jclass clazz;
if (!runtime_callbacks || !env || !clz || !(clazz = env->FindClass(clz))) {
for (auto &method : methods) {
method.fnPtr = nullptr;
}
return;
}
JNIMethodsDyn HookContext::get_jni_methods(JNIEnv *env, jclass clazz) const {
size_t total = runtime_callbacks->getNativeMethodCount(env, clazz);
auto methods = std::make_unique_for_overwrite<JNINativeMethod[]>(total);
runtime_callbacks->getNativeMethods(env, clazz, methods.get(), total);
return std::make_pair(std::move(methods), total);
}
// Backup existing methods
auto total = runtime_callbacks->getNativeMethodCount(env, clazz);
auto old_methods = std::make_unique_for_overwrite<JNINativeMethod[]>(total);
runtime_callbacks->getNativeMethods(env, clazz, old_methods.get(), total);
// WARNING: the signature field returned from getNativeMethods is in a non-standard format.
// DO NOT TRY TO USE IT. This is the reason why we try to call RegisterNatives on every single
// provided JNI methods directly to be 100% sure about whether a signature matches or not.
// Replace methods
static void register_jni_methods(JNIEnv *env, jclass clazz, JNIMethods methods) {
for (auto &method : methods) {
// It's useful to allow nullptr function pointer for restoring hook
if (!method.fnPtr) continue;
// It's normal that the method is not found
if (env->RegisterNatives(clazz, &method, 1) == JNI_ERR || env->ExceptionCheck() == JNI_TRUE) {
if (auto exception = env->ExceptionOccurred()) {
env->DeleteLocalRef(exception);
}
env->ExceptionClear();
method.fnPtr = nullptr;
}
}
}
int HookContext::hook_jni_methods(JNIEnv *env, jclass clazz, JNIMethods methods) const {
// Backup existing methods
auto o = get_jni_methods(env, clazz);
const auto old_methods = span(o.first.get(), o.second);
// WARNING: the signature field returned from getNativeMethods is in a non-standard format.
// DO NOT TRY TO USE IT. This is the reason why we try to call RegisterNatives on every single
// provided JNI methods directly to be 100% sure about whether a signature matches or not.
// Replace methods
register_jni_methods(env, clazz, methods);
// Fetch the new set of native methods
auto new_methods = std::make_unique_for_overwrite<JNINativeMethod[]>(total);
runtime_callbacks->getNativeMethods(env, clazz, new_methods.get(), total);
auto n = get_jni_methods(env, clazz);
const auto new_methods = span(n.first.get(), n.second);
// Find the old function pointer and return to caller
int hook_count = 0;
for (auto &method : methods) {
if (!method.fnPtr) continue;
for (auto i = 0; i < total; ++i) {
auto &new_method = new_methods[i];
for (const auto &new_method : new_methods) {
if (new_method.fnPtr == method.fnPtr) {
auto &old_method = old_methods[i];
ZLOGV("replace %s#%s%s %p -> %p\n", clz, method.name, method.signature, old_method.fnPtr, method.fnPtr);
method.fnPtr = old_method.fnPtr;
break;
for (const auto &old_method : old_methods) {
if (strcmp(old_method.name, new_method.name) == 0 &&
strcmp(old_method.signature, new_method.signature) == 0) {
ZLOGV("replace %s %s %p -> %p\n",
method.name, method.signature, old_method.fnPtr, method.fnPtr);
method.fnPtr = old_method.fnPtr;
++hook_count;
// Break 2 levels of for loop
goto next_method;
}
}
}
}
next_method:
}
return hook_count;
}
void HookContext::hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods methods) const {
jclass clazz;
if (!runtime_callbacks || !env || !clz || !((clazz = env->FindClass(clz)))) {
ranges::for_each(methods, [](auto &m) { m.fnPtr = nullptr; });
return;
}
hook_jni_methods(env, clazz, methods);
}
void HookContext::hook_zygote_jni() {
@@ -538,11 +565,54 @@ void HookContext::hook_zygote_jni() {
if (res != JNI_OK || env == nullptr) {
ZLOGW("JNIEnv not found\n");
}
hook_jni_methods(env, kZygote, zygote_methods);
JNINativeMethod missing_method{};
bool replaced_fork_app = false;
bool replaced_specialize_app = false;
bool replaced_fork_server = false;
jclass clazz = env->FindClass(kZygote);
auto [ptr, count] = get_jni_methods(env, clazz);
for (const auto methods = span(ptr.get(), count); const auto &method : methods) {
if (strcmp(method.name, kForkApp) == 0) {
if (hook_jni_methods(env, clazz, fork_app_methods) == 0) {
missing_method = method;
break;
}
replaced_fork_app = true;
} else if (strcmp(method.name, kSpecializeApp) == 0) {
if (hook_jni_methods(env, clazz, specialize_app_methods) == 0) {
missing_method = method;
break;
}
replaced_specialize_app = true;
} else if (strcmp(method.name, kForkServer) == 0) {
if (hook_jni_methods(env, clazz, fork_server_methods) == 0) {
missing_method = method;
break;
}
replaced_fork_server = true;
}
}
if (missing_method.name != nullptr) {
ZLOGE("Cannot hook method: %s %s\n", missing_method.name, missing_method.signature);
// Restore methods that were already replaced
if (replaced_fork_app) register_jni_methods(env, clazz, fork_app_methods);
if (replaced_specialize_app) register_jni_methods(env, clazz, specialize_app_methods);
if (replaced_fork_server) register_jni_methods(env, clazz, fork_server_methods);
// Clear the method lists just in case
ranges::for_each(fork_app_methods, [](auto &m) { m.fnPtr = nullptr; });
ranges::for_each(specialize_app_methods, [](auto &m) { m.fnPtr = nullptr; });
ranges::for_each(fork_server_methods, [](auto &m) { m.fnPtr = nullptr; });
}
}
void HookContext::restore_zygote_hook(JNIEnv *env) {
hook_jni_methods(env, kZygote, zygote_methods);
jclass clazz = env->FindClass(kZygote);
register_jni_methods(env, clazz, fork_app_methods);
register_jni_methods(env, clazz, specialize_app_methods);
register_jni_methods(env, clazz, fork_server_methods);
}
// -----------------------------------------------------------------
@@ -553,5 +623,5 @@ void hook_entry() {
}
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods) {
g_hook->hook_jni_methods(env, clz, { methods, (size_t) numMethods });
g_hook->hook_jni_methods(env, clz, { methods, static_cast<size_t>(numMethods) });
}

View File

@@ -1,6 +1,13 @@
// Generated by gen_jni_hooks.py
#pragma once
std::array<JNINativeMethod, 17> zygote_methods = {{
struct JniHookDefinitions;
static JniHookDefinitions *get_defs();
struct JniHookDefinitions {
std::array<JNINativeMethod, 11> fork_app_methods = {{
// nativeForkAndSpecialize_l
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
@@ -8,13 +15,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[0].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[0].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_o
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
@@ -23,13 +31,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.fds_to_ignore = &fds_to_ignore;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[1].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[1].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_p
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
@@ -39,13 +48,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_child_zygote = &is_child_zygote;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[2].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[2].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_q_alt
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
@@ -56,13 +66,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_top_app = &is_top_app;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app)>(g_hook->zygote_methods[3].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app)>(get_defs()->fork_app_methods[3].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_r
{
"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",
@@ -77,13 +88,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.mount_storage_dirs = &mount_storage_dirs;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs)>(g_hook->zygote_methods[4].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs)>(get_defs()->fork_app_methods[4].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_u
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)I",
@@ -99,13 +111,37 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.mount_sysprop_overrides = &mount_sysprop_overrides;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides)>(g_hook->zygote_methods[5].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides)>(get_defs()->fork_app_methods[5].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_b
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;ZZ[Ljava/lang/String;[Ljava/lang/String;ZZZ)I",
(void *) +[] [[clang::no_stack_protector]] (JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jboolean use_fifo_ui, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) static -> jint {
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
args.pkg_data_info_list = &pkg_data_info_list;
args.whitelisted_data_info_list = &whitelisted_data_info_list;
args.mount_data_dirs = &mount_data_dirs;
args.mount_storage_dirs = &mount_storage_dirs;
args.mount_sysprop_overrides = &mount_sysprop_overrides;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jboolean use_fifo_ui, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides)>(get_defs()->fork_app_methods[6].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, use_fifo_ui, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_samsung_m
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
@@ -113,13 +149,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _0, jint _1, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[6].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _0, jint _1, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[7].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _0, _1, nice_name, fds_to_close, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_samsung_n
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;I)I",
@@ -127,13 +164,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _2, jint _3, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir, jint _4)>(g_hook->zygote_methods[7].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _2, jint _3, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir, jint _4)>(get_defs()->fork_app_methods[8].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _2, _3, nice_name, fds_to_close, instruction_set, app_data_dir, _4
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_samsung_o
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
@@ -142,13 +180,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.fds_to_ignore = &fds_to_ignore;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _5, jint _6, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[8].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _5, jint _6, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[9].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _5, _6, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
// nativeForkAndSpecialize_samsung_p
{
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
@@ -158,13 +197,17 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_child_zygote = &is_child_zygote;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _7, jint _8, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[9].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _7, jint _8, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(get_defs()->fork_app_methods[10].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _7, _8, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
},
}};
std::array<JNINativeMethod, 5> specialize_app_methods = {{
// nativeSpecializeAppProcess_q
{
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
@@ -173,12 +216,13 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_child_zygote = &is_child_zygote;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<void(*)(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)>(g_hook->zygote_methods[10].fnPtr)(
reinterpret_cast<void(*)(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)>(get_defs()->specialize_app_methods[0].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir
);
ctx.nativeSpecializeAppProcess_post();
}
},
// nativeSpecializeAppProcess_q_alt
{
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
@@ -188,12 +232,13 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_top_app = &is_top_app;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<void(*)(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, jboolean is_top_app)>(g_hook->zygote_methods[11].fnPtr)(
reinterpret_cast<void(*)(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, jboolean is_top_app)>(get_defs()->specialize_app_methods[1].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app
);
ctx.nativeSpecializeAppProcess_post();
}
},
// nativeSpecializeAppProcess_r
{
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
@@ -207,12 +252,13 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.mount_storage_dirs = &mount_storage_dirs;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<void(*)(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, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs)>(g_hook->zygote_methods[12].fnPtr)(
reinterpret_cast<void(*)(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, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs)>(get_defs()->specialize_app_methods[2].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs
);
ctx.nativeSpecializeAppProcess_post();
}
},
// nativeSpecializeAppProcess_u
{
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)V",
@@ -227,12 +273,13 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.mount_sysprop_overrides = &mount_sysprop_overrides;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<void(*)(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, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides)>(g_hook->zygote_methods[13].fnPtr)(
reinterpret_cast<void(*)(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, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides)>(get_defs()->specialize_app_methods[3].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides
);
ctx.nativeSpecializeAppProcess_post();
}
},
// nativeSpecializeAppProcess_samsung_q
{
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;IILjava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
@@ -241,12 +288,16 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
args.is_child_zygote = &is_child_zygote;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<void(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _9, jint _10, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(g_hook->zygote_methods[14].fnPtr)(
reinterpret_cast<void(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _9, jint _10, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir)>(get_defs()->specialize_app_methods[4].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _9, _10, nice_name, is_child_zygote, instruction_set, app_data_dir
);
ctx.nativeSpecializeAppProcess_post();
}
},
}};
std::array<JNINativeMethod, 2> fork_server_methods = {{
// nativeForkSystemServer_l
{
"nativeForkSystemServer",
"(II[II[[IJJ)I",
@@ -254,13 +305,14 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);
ZygiskContext ctx(env, &args);
ctx.nativeForkSystemServer_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities)>(g_hook->zygote_methods[15].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities)>(get_defs()->fork_server_methods[0].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities
);
ctx.nativeForkSystemServer_post();
return ctx.pid;
}
},
// nativeForkSystemServer_samsung_q
{
"nativeForkSystemServer",
"(II[IIII[[IJJ)I",
@@ -268,7 +320,7 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);
ZygiskContext ctx(env, &args);
ctx.nativeForkSystemServer_pre();
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jint _11, jint _12, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities)>(g_hook->zygote_methods[16].fnPtr)(
reinterpret_cast<jint(*)(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jint _11, jint _12, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities)>(get_defs()->fork_server_methods[1].fnPtr)(
env, clazz, uid, gid, gids, runtime_flags, _11, _12, rlimits, permitted_capabilities, effective_capabilities
);
ctx.nativeForkSystemServer_post();
@@ -277,3 +329,4 @@ std::array<JNINativeMethod, 17> zygote_methods = {{
},
}};
};

View File

@@ -19,7 +19,7 @@
#endif
// Extreme verbose logging
//#define ZLOGV(...) ZLOGD(__VA_ARGS__)
// #define ZLOGV(...) ZLOGD(__VA_ARGS__)
#define ZLOGV(...) (void*)0
void hook_entry();