You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Compare commits
33 Commits
rewrite/we
...
v1.0.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc1b757bb8 | ||
|
|
a0a54f2153 | ||
|
|
295a62b649 | ||
|
|
b6f02b39b3 | ||
|
|
e036b1f40a | ||
|
|
9a3b2f4a79 | ||
|
|
9810eb3974 | ||
|
|
823623a96f | ||
|
|
a75b2fe2b8 | ||
|
|
48238521df | ||
|
|
fa9adcf3b5 | ||
|
|
6c05527ffa | ||
|
|
aff2ad8d3c | ||
|
|
b7fe7b3dbe | ||
|
|
f432550f07 | ||
|
|
a0ab02cedc | ||
|
|
f9a23a2882 | ||
|
|
d111a2dfc5 | ||
|
|
cd4784376e | ||
|
|
c786790b0f | ||
|
|
4f35e06ac4 | ||
|
|
57f985292e | ||
|
|
34643c794f | ||
|
|
ec705fb260 | ||
|
|
c023da0fd6 | ||
|
|
63f29f0771 | ||
|
|
c975722795 | ||
|
|
2f589d0eda | ||
|
|
70697be9a5 | ||
|
|
6261466e44 | ||
|
|
d455117c49 | ||
|
|
6272e0a2ac | ||
|
|
62481ca2b6 |
2
.github/ISSUE_TEMPLATE/issue_template.yml
vendored
2
.github/ISSUE_TEMPLATE/issue_template.yml
vendored
@@ -59,7 +59,7 @@ body:
|
|||||||
id: code_of_conduct
|
id: code_of_conduct
|
||||||
attributes:
|
attributes:
|
||||||
label: Code of Conduct
|
label: Code of Conduct
|
||||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/PerformanC/voice/blob/main/CODE_OF_CONDUCT.md)
|
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/PerformanC/contributing/blob/main/CODE_OF_CONDUCT.md)
|
||||||
options:
|
options:
|
||||||
- label: I agree to follow this project's Code of Conduct
|
- label: I agree to follow this project's Code of Conduct
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/pull_request.yml
vendored
2
.github/ISSUE_TEMPLATE/pull_request.yml
vendored
@@ -35,7 +35,7 @@ body:
|
|||||||
id: code_of_conduct
|
id: code_of_conduct
|
||||||
attributes:
|
attributes:
|
||||||
label: Code of Conduct
|
label: Code of Conduct
|
||||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/PerformanC/voice/blob/main/CODE_OF_CONDUCT.md)
|
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/PerformanC/contributing/blob/main/CODE_OF_CONDUCT.md)
|
||||||
options:
|
options:
|
||||||
- label: I agree to follow this project's Code of Conduct
|
- label: I agree to follow this project's Code of Conduct
|
||||||
required: true
|
required: true
|
||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
java-version: "17"
|
java-version: "17"
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4.2.1
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
6
.github/workflows/trusted_ci.yml
vendored
6
.github/workflows/trusted_ci.yml
vendored
@@ -21,15 +21,19 @@ jobs:
|
|||||||
java-version: "17"
|
java-version: "17"
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4.2.1
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup keys
|
- name: Setup keys
|
||||||
env:
|
env:
|
||||||
private_key: ${{ secrets.ORG_PRIVATE_KEY }}
|
private_key: ${{ secrets.ORG_PRIVATE_KEY }}
|
||||||
public_key: ${{ secrets.ORG_PUBLIC_KEY }}
|
public_key: ${{ secrets.ORG_PUBLIC_KEY }}
|
||||||
run: |
|
run: |
|
||||||
|
if [ -z "$private_key" ] || [ -z "$public_key" ]; then
|
||||||
|
echo "Private or public key is not set."
|
||||||
|
else
|
||||||
echo "$private_key" | base64 -d > module/private_key
|
echo "$private_key" | base64 -d > module/private_key
|
||||||
echo "$public_key" | base64 -d > module/public_key
|
echo "$public_key" | base64 -d > module/public_key
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "loader/src/external/lsplt"]
|
[submodule "LSPlt"]
|
||||||
path = loader/src/external/lsplt
|
path = loader/src/external/lsplt
|
||||||
url = https://github.com/JingMatrix/LSPlt
|
url = https://github.com/PerformanC/LSPlt
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
- **es_ES** by [@LuchoModzzz](https://github.com/Lxchoooo)
|
- **es_ES** by [@LuchoModzzz](https://github.com/Lxchoooo)
|
||||||
- **es_MX** by [@LuchoModzzz](https://github.com/Lxchoooo)
|
- **es_MX** by [@LuchoModzzz](https://github.com/Lxchoooo)
|
||||||
- **fr_FR** by [@GhostFRR](https://github.com/GhostFRR)
|
- **fr_FR** by [@GhostFRR](https://github.com/GhostFRR)
|
||||||
- **ja_JP** by [@Fyphen1223](https://github.com/Fyphen1223)
|
- **ja_JP** by [@Fyphen1223](https://github.com/Fyphen1223) & [@reindex-ot](https://github.com/reindex-ot)
|
||||||
- **id_ID** by [@bpanca05](https://github.com/bpanca05) & [@LuckyKiddos](https://github.com/GuitarHeroStyles)
|
- **id_ID** by [@bpanca05](https://github.com/bpanca05) & [@LuckyKiddos](https://github.com/GuitarHeroStyles)
|
||||||
- **it_IT** by [@thasave14](https://github.com/thasave14)
|
- **it_IT** by [@thasave14](https://github.com/thasave14)
|
||||||
- **pt_BR** by [@ThePedroo](https://github.com/ThePedroo)
|
- **pt_BR** by [@ThePedroo](https://github.com/ThePedroo)
|
||||||
- **ro_RO** by [@ExtremeXT](https://github.com/ExtremeXT)
|
- **ro_RO** by [@ExtremeXT](https://github.com/ExtremeXT)
|
||||||
- **ru_RU** by [@Emulond](https://github.com/Emulond) & [@AJleKcAHgP68](https://github.com/AJleKcAHgP68)
|
- **ru_RU** by [@Emulond](https://github.com/Emulond) & [@AJleKcAHgP68](https://github.com/AJleKcAHgP68)
|
||||||
- **tr_TR** by [@dyingwillow](https://github.com/dyingwillow)
|
- **tr_TR** by [@witchfuneral](https://github.com/witchfuneral)
|
||||||
- **uk_UA** by [@Kittyskj](https://github.com/Kittyskj)
|
- **uk_UA** by [@Kittyskj](https://github.com/Kittyskj)
|
||||||
- **vi_VN** by [@RainyXeon](https://github.com/RainyXeon)
|
- **vi_VN** by [@RainyXeon](https://github.com/RainyXeon)
|
||||||
- **zh_CN** by [@Meltartica](https://github.com/Meltartica) & [@SheepChef](https://github.com/SheepChef)
|
- **zh_CN** by [@Meltartica](https://github.com/Meltartica) & [@SheepChef](https://github.com/SheepChef)
|
||||||
|
|||||||
@@ -38,19 +38,18 @@ val androidSourceCompatibility by extra(JavaVersion.VERSION_11)
|
|||||||
val androidTargetCompatibility by extra(JavaVersion.VERSION_11)
|
val androidTargetCompatibility by extra(JavaVersion.VERSION_11)
|
||||||
|
|
||||||
tasks.register("Delete", Delete::class) {
|
tasks.register("Delete", Delete::class) {
|
||||||
delete(rootProject.buildDir)
|
delete(layout.buildDirectory.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.configureBaseExtension() {
|
fun Project.configureBaseExtension() {
|
||||||
extensions.findByType(LibraryExtension::class)?.run {
|
extensions.findByType(LibraryExtension::class)?.run {
|
||||||
namespace = "icu.nullptr.zygisk.next"
|
namespace = "com.performanc.org.rezygisk"
|
||||||
compileSdk = androidCompileSdkVersion
|
compileSdk = androidCompileSdkVersion
|
||||||
ndkVersion = androidCompileNdkVersion
|
ndkVersion = androidCompileNdkVersion
|
||||||
buildToolsVersion = androidBuildToolsVersion
|
buildToolsVersion = androidBuildToolsVersion
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = androidMinSdkVersion
|
minSdk = androidMinSdkVersion
|
||||||
targetSdk = androidTargetSdkVersion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lint {
|
lint {
|
||||||
|
|||||||
@@ -535,8 +535,10 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
|||||||
((uintptr_t)1 << ((hash >> img->gnu_shift2_) % bloom_mask_bits));
|
((uintptr_t)1 << ((hash >> img->gnu_shift2_) % bloom_mask_bits));
|
||||||
|
|
||||||
if ((mask & bloom_word) != mask) {
|
if ((mask & bloom_word) != mask) {
|
||||||
LOGE("Symbol '%s' (hash %u) filtered out by GNU Bloom Filter (idx %zu, mask 0x%lx, word 0x%lx)",
|
/* INFO: Very loggy -- generates too much noise. GNU is rarely used for Zygisk context. */
|
||||||
|
/* LOGW("Symbol '%s' (hash %u) filtered out by GNU Bloom Filter (idx %zu, mask 0x%lx, word 0x%lx)",
|
||||||
name, hash, bloom_idx, (unsigned long)mask, (unsigned long)bloom_word);
|
name, hash, bloom_idx, (unsigned long)mask, (unsigned long)bloom_word);
|
||||||
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
2
loader/src/external/lsplt
vendored
2
loader/src/external/lsplt
vendored
Submodule loader/src/external/lsplt updated: 984804293e...dc62fbe05e
@@ -4,6 +4,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define IS_ISOLATED_SERVICE(uid) \
|
||||||
|
((uid) >= 90000 && (uid) < 1000000)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bionic's atoi runs through strtol().
|
* Bionic's atoi runs through strtol().
|
||||||
* Use our own implementation for faster conversion.
|
* Use our own implementation for faster conversion.
|
||||||
|
|||||||
97
loader/src/injector/clear.c
Normal file
97
loader/src/injector/clear.c
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <linux/seccomp.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <linux/audit.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
static bool seccomp_filters_visible() {
|
||||||
|
FILE *status_file = fopen("/proc/self/status", "r");
|
||||||
|
if (!status_file) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *needle = "Seccomp_filters:";
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), status_file)) {
|
||||||
|
if (strncmp(line, needle, strlen(needle)) == 0) {
|
||||||
|
fclose(status_file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(status_file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_seccomp_event() {
|
||||||
|
if (seccomp_filters_visible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 args[4] = {0};
|
||||||
|
|
||||||
|
int rnd_fd = open("/dev/urandom", O_RDONLY);
|
||||||
|
if (rnd_fd == -1) {
|
||||||
|
PLOGE("send_seccomp_event: open(/dev/urandom)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(rnd_fd, &args, sizeof(args)) != sizeof(args)) {
|
||||||
|
PLOGE("send_seccomp_event: read(rnd_fd)");
|
||||||
|
close(rnd_fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(rnd_fd);
|
||||||
|
|
||||||
|
args[0] |= 0x10000;
|
||||||
|
|
||||||
|
struct sock_filter filter[] = {
|
||||||
|
/* INFO: Check syscall number */
|
||||||
|
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit_group, 0, 9),
|
||||||
|
|
||||||
|
/* INFO: Load and check arg0 (lower 32 bits) */
|
||||||
|
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[0], 0, 7),
|
||||||
|
|
||||||
|
/* INFO: Load and check arg1 (lower 32 bits) */
|
||||||
|
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[1], 0, 5),
|
||||||
|
|
||||||
|
/* INFO: Load and check arg2 (lower 32 bits) */
|
||||||
|
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[2], 0, 3),
|
||||||
|
|
||||||
|
/* INFO: Load and check arg3 (lower 32 bits) */
|
||||||
|
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[3])),
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[3], 0, 1),
|
||||||
|
|
||||||
|
/* INFO: All match: return TRACE => will trigger PTRACE_EVENT_SECCOMP */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE),
|
||||||
|
|
||||||
|
/* INFO: Default: allow */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sock_fprog prog = {
|
||||||
|
.len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
|
||||||
|
.filter = filter,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
|
||||||
|
PLOGE("send_seccomp_event: prctl(SECCOMP)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFO: This will trigger a ptrace event, syscall will not execute due to tracee_skip_syscall */
|
||||||
|
syscall(__NR_exit_group, args[0], args[1], args[2], args[3]);
|
||||||
|
}
|
||||||
@@ -22,5 +22,8 @@ void entry(void* addr, size_t size, const char* path) {
|
|||||||
|
|
||||||
LOGD("start plt hooking");
|
LOGD("start plt hooking");
|
||||||
hook_functions();
|
hook_functions();
|
||||||
clean_trace(path, 1, 0, false);
|
|
||||||
|
void *module_addrs[1] = { addr };
|
||||||
|
clean_trace(path, module_addrs, 1, 1, 0, false);
|
||||||
|
send_seccomp_event();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ struct ZygiskContext {
|
|||||||
~ZygiskContext();
|
~ZygiskContext();
|
||||||
|
|
||||||
/* Zygisksu changed: Load module fds */
|
/* Zygisksu changed: Load module fds */
|
||||||
|
bool load_modules_only();
|
||||||
void run_modules_pre();
|
void run_modules_pre();
|
||||||
void run_modules_post();
|
void run_modules_post();
|
||||||
DCL_PRE_POST(fork)
|
DCL_PRE_POST(fork)
|
||||||
@@ -124,6 +125,8 @@ struct ZygiskContext {
|
|||||||
vector<tuple<dev_t, ino_t, const char *, void **>> *plt_hook_list;
|
vector<tuple<dev_t, ino_t, const char *, void **>> *plt_hook_list;
|
||||||
map<string, vector<JNINativeMethod>> *jni_hook_list;
|
map<string, vector<JNINativeMethod>> *jni_hook_list;
|
||||||
bool should_unmap_zygisk = false;
|
bool should_unmap_zygisk = false;
|
||||||
|
bool enable_unloader = false;
|
||||||
|
bool hooked_unloader = false;
|
||||||
std::vector<lsplt::MapInfo> cached_map_infos = {};
|
std::vector<lsplt::MapInfo> cached_map_infos = {};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -215,6 +218,9 @@ DCL_HOOK_FUNC(int, pthread_attr_setstacksize, void *target, size_t size) {
|
|||||||
int res = old_pthread_attr_setstacksize((pthread_attr_t *)target, size);
|
int res = old_pthread_attr_setstacksize((pthread_attr_t *)target, size);
|
||||||
LOGV("Call pthread_attr_setstacksize in [tid, pid]: %d, %d", gettid(), getpid());
|
LOGV("Call pthread_attr_setstacksize in [tid, pid]: %d, %d", gettid(), getpid());
|
||||||
|
|
||||||
|
if (!enable_unloader)
|
||||||
|
return res;
|
||||||
|
|
||||||
// Only perform unloading on the main thread
|
// Only perform unloading on the main thread
|
||||||
if (gettid() != getpid())
|
if (gettid() != getpid())
|
||||||
return res;
|
return res;
|
||||||
@@ -249,6 +255,27 @@ DCL_HOOK_FUNC(char *, strdup, const char *s) {
|
|||||||
return old_strdup(s);
|
return old_strdup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INFO: Our goal is to get called after libart.so is loaded, but before ART actually starts running.
|
||||||
|
* If we are too early, we won't find libart.so in maps, and if we are too late, we could make other
|
||||||
|
* threads crash if they try to use the PLT while we are in the process of hooking it.
|
||||||
|
* For this task, hooking property_get was chosen as there are lots of calls to this, so it's
|
||||||
|
* relatively unlikely to break.
|
||||||
|
*
|
||||||
|
* The line where libart.so is loaded is:
|
||||||
|
* https://github.com/aosp-mirror/platform_frameworks_base/blob/1cdfff555f4a21f71ccc978290e2e212e2f8b168/core/jni/AndroidRuntime.cpp#L1266
|
||||||
|
*
|
||||||
|
* And shortly after that, in the startVm method that is called right after, there are many calls to property_get:
|
||||||
|
* https://github.com/aosp-mirror/platform_frameworks_base/blob/1cdfff555f4a21f71ccc978290e2e212e2f8b168/core/jni/AndroidRuntime.cpp#L791
|
||||||
|
*
|
||||||
|
* After we succeed in getting called at a point where libart.so is already loaded, we will ignore
|
||||||
|
* the rest of the property_get calls.
|
||||||
|
*/
|
||||||
|
DCL_HOOK_FUNC(int, property_get, const char *key, char *value, const char *default_value) {
|
||||||
|
hook_unloader();
|
||||||
|
return old_property_get(key, value, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
#undef DCL_HOOK_FUNC
|
#undef DCL_HOOK_FUNC
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
@@ -601,9 +628,11 @@ void ZygiskContext::sanitize_fds() {
|
|||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
while ((entry = readdir(dir))) {
|
while ((entry = readdir(dir))) {
|
||||||
int fd = parse_int(entry->d_name);
|
int fd = parse_int(entry->d_name);
|
||||||
if (fd < 0 || fd < MAX_FD_SIZE || fd == dfd || allowed_fds[fd]) continue;
|
if (fd < 0 || fd > MAX_FD_SIZE || fd == dfd || allowed_fds[fd]) continue;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
LOGW("Closed leaked fd: %d", fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
@@ -615,13 +644,12 @@ void ZygiskContext::fork_post() {
|
|||||||
g_ctx = nullptr;
|
g_ctx = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zygisksu changed: Load module fds */
|
bool ZygiskContext::load_modules_only() {
|
||||||
void ZygiskContext::run_modules_pre() {
|
|
||||||
struct zygisk_modules ms;
|
struct zygisk_modules ms;
|
||||||
if (rezygiskd_read_modules(&ms) == false) {
|
if (rezygiskd_read_modules(&ms) == false) {
|
||||||
LOGE("Failed to read modules from zygiskd");
|
LOGE("Failed to read modules from zygiskd");
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < ms.modules_count; i++) {
|
for (size_t i = 0; i < ms.modules_count; i++) {
|
||||||
@@ -648,6 +676,11 @@ void ZygiskContext::run_modules_pre() {
|
|||||||
|
|
||||||
free_modules(&ms);
|
free_modules(&ms);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zygisksu changed: Load module fds */
|
||||||
|
void ZygiskContext::run_modules_pre() {
|
||||||
for (auto &m : modules) {
|
for (auto &m : modules) {
|
||||||
m.onLoad(env);
|
m.onLoad(env);
|
||||||
|
|
||||||
@@ -669,7 +702,19 @@ void ZygiskContext::run_modules_post() {
|
|||||||
|
|
||||||
if (modules.size() > 0) {
|
if (modules.size() > 0) {
|
||||||
LOGD("modules unloaded: %zu/%zu", modules_unloaded, modules.size());
|
LOGD("modules unloaded: %zu/%zu", modules_unloaded, modules.size());
|
||||||
clean_trace("/data/adb", modules.size(), modules_unloaded, true);
|
|
||||||
|
/* INFO: While Variable Length Arrays (VLAs) aren't usually
|
||||||
|
recommended due to the ease of using too much of the
|
||||||
|
stack, this should be fine since it should not be
|
||||||
|
possible to exhaust the stack with only a few addresses. */
|
||||||
|
void *module_addrs[modules.size() * sizeof(void *)];
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (const auto &m : modules) {
|
||||||
|
module_addrs[i++] = m.getEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_trace("/data/adb", module_addrs, modules.size(), modules.size(), modules_unloaded, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -677,7 +722,48 @@ void ZygiskContext::run_modules_post() {
|
|||||||
void ZygiskContext::app_specialize_pre() {
|
void ZygiskContext::app_specialize_pre() {
|
||||||
flags[APP_SPECIALIZE] = true;
|
flags[APP_SPECIALIZE] = true;
|
||||||
|
|
||||||
info_flags = rezygiskd_get_process_flags(g_ctx->args.app->uid, (const char *const)process);
|
/* INFO: Isolated services have different UIDs than the main apps. Because
|
||||||
|
numerous root implementations base themselves in the UID of the
|
||||||
|
app, we need to ensure that the UID sent to ReZygiskd to search
|
||||||
|
is the app's and not the isolated service, or else it will be
|
||||||
|
able to bypass DenyList.
|
||||||
|
|
||||||
|
All apps, and isolated processes, of *third-party* applications will
|
||||||
|
have their app_data_dir set. The system applications might not have
|
||||||
|
one, however it is unlikely they will create an isolated process,
|
||||||
|
and even if so, it should not impact in detections, performance or
|
||||||
|
any area.
|
||||||
|
*/
|
||||||
|
uid_t uid = args.app->uid;
|
||||||
|
if (IS_ISOLATED_SERVICE(uid) && args.app->app_data_dir) {
|
||||||
|
/* INFO: If the app is an isolated service, we use the UID of the
|
||||||
|
app's process data directory, which is the UID of the
|
||||||
|
app itself, which root implementations actually use.
|
||||||
|
*/
|
||||||
|
const char *data_dir = env->GetStringUTFChars(args.app->app_data_dir, NULL);
|
||||||
|
if (!data_dir) {
|
||||||
|
LOGE("Failed to get app data directory");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(data_dir, &st) == -1) {
|
||||||
|
PLOGE("Failed to stat app data directory [%s]", data_dir);
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(args.app->app_data_dir, data_dir);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = st.st_uid;
|
||||||
|
|
||||||
|
LOGD("Isolated service being related to UID %d, app data dir: %s", uid, data_dir);
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(args.app->app_data_dir, data_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
info_flags = rezygiskd_get_process_flags(uid, (const char *const)process);
|
||||||
if (info_flags & PROCESS_IS_FIRST_STARTED) {
|
if (info_flags & PROCESS_IS_FIRST_STARTED) {
|
||||||
/* INFO: To ensure we are really using a clean mount namespace, we use
|
/* INFO: To ensure we are really using a clean mount namespace, we use
|
||||||
the first process it as reference for clean mount namespace,
|
the first process it as reference for clean mount namespace,
|
||||||
@@ -687,24 +773,44 @@ void ZygiskContext::app_specialize_pre() {
|
|||||||
update_mnt_ns(Clean, true);
|
update_mnt_ns(Clean, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((info_flags & (PROCESS_IS_MANAGER | PROCESS_ROOT_IS_MAGISK)) == (PROCESS_IS_MANAGER | PROCESS_ROOT_IS_MAGISK)) {
|
if ((info_flags & PROCESS_IS_MANAGER) == PROCESS_IS_MANAGER) {
|
||||||
LOGD("Manager process detected. Notifying that Zygisk has been enabled.");
|
LOGD("Manager process detected. Notifying that Zygisk has been enabled.");
|
||||||
|
|
||||||
/* INFO: This environment variable is related to Magisk Zygisk/Manager. It
|
/* INFO: This environment variable is related to Magisk Zygisk/Manager. It
|
||||||
it used by Magisk's Zygisk to communicate to Magisk Manager whether
|
it used by Magisk's Zygisk to communicate to Magisk Manager whether
|
||||||
Zygisk is working or not.
|
Zygisk is working or not, allowing Zygisk modules to both work properly
|
||||||
|
and for the manager to mark Zygisk as enabled.
|
||||||
|
|
||||||
To allow Zygisk modules to both work properly and for the manager to
|
However, to enhance capabilities of root managers, it is also set for
|
||||||
identify Zygisk, being it not built-in, as working, we also set it. */
|
any other supported manager, so that, if they wish, they can recognize
|
||||||
|
if Zygisk is enabled.
|
||||||
|
*/
|
||||||
setenv("ZYGISK_ENABLED", "1", 1);
|
setenv("ZYGISK_ENABLED", "1", 1);
|
||||||
} else {
|
} else {
|
||||||
/* INFO: Modules only have two "start off" points from Zygisk, preSpecialize and
|
/* INFO: Because we load directly from the file, we need to do it before we umount
|
||||||
postSpecialize. While preSpecialie in fact runs with Zygote (not superuser)
|
the mounts, or else it won't have access to /data/adb anymore.
|
||||||
privileges, in postSpecialize it will now be with lower permission, in
|
|
||||||
the app's sandbox and therefore can move to a clean mount namespace after
|
|
||||||
executing the modules preSpecialize.
|
|
||||||
*/
|
*/
|
||||||
if ((info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST) {
|
if (!load_modules_only()) {
|
||||||
|
LOGE("Failed to load modules");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFO: Modules only have two "start off" points from Zygisk, preSpecialize and
|
||||||
|
postSpecialize. In preSpecialize, the process still has privileged
|
||||||
|
permissions, and therefore can execute mount/umount/setns functions.
|
||||||
|
If we update the mount namespace AFTER executing them, any mounts made
|
||||||
|
will be lost, and the process will not have access to them anymore.
|
||||||
|
|
||||||
|
In postSpecialize, while still could have its mounts modified with the
|
||||||
|
assistance of a Zygisk companion, it will already have the mount
|
||||||
|
namespace switched by then, so there won't be issues.
|
||||||
|
|
||||||
|
Knowing this, we update the mns before execution, so that they can still
|
||||||
|
make changes to mounts in DenyListed processes without being reverted.
|
||||||
|
*/
|
||||||
|
bool in_denylist = (info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST;
|
||||||
|
if (in_denylist) {
|
||||||
flags[DO_REVERT_UNMOUNT] = true;
|
flags[DO_REVERT_UNMOUNT] = true;
|
||||||
|
|
||||||
update_mnt_ns(Clean, false);
|
update_mnt_ns(Clean, false);
|
||||||
@@ -714,6 +820,17 @@ void ZygiskContext::app_specialize_pre() {
|
|||||||
application without worrying about it being overwritten by setns.
|
application without worrying about it being overwritten by setns.
|
||||||
*/
|
*/
|
||||||
run_modules_pre();
|
run_modules_pre();
|
||||||
|
|
||||||
|
/* INFO: The modules may request that although the process is NOT in
|
||||||
|
the DenyList, it has its mount namespace switched to the clean
|
||||||
|
one.
|
||||||
|
|
||||||
|
So to ensure this behavior happens, we must also check after the
|
||||||
|
modules are loaded and executed, so that the modules can have
|
||||||
|
the chance to request it.
|
||||||
|
*/
|
||||||
|
if (!in_denylist && flags[DO_REVERT_UNMOUNT])
|
||||||
|
update_mnt_ns(Clean, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,6 +876,7 @@ void ZygiskContext::nativeForkSystemServer_pre() {
|
|||||||
if (!is_child())
|
if (!is_child())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
load_modules_only();
|
||||||
run_modules_pre();
|
run_modules_pre();
|
||||||
rezygiskd_system_server_started();
|
rezygiskd_system_server_started();
|
||||||
|
|
||||||
@@ -821,7 +939,7 @@ ZygiskContext::~ZygiskContext() {
|
|||||||
m.clearApi();
|
m.clearApi();
|
||||||
}
|
}
|
||||||
|
|
||||||
hook_unloader();
|
enable_unloader = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -849,19 +967,35 @@ static void hook_register(dev_t dev, ino_t inode, const char *symbol, void *new_
|
|||||||
#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
|
#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
|
||||||
PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
|
PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
|
||||||
|
|
||||||
void clean_trace(const char* path, size_t load, size_t unload, bool spoof_maps) {
|
/* INFO: module_addrs_length is always the same as "load" */
|
||||||
|
void clean_trace(const char *path, void **module_addrs, size_t module_addrs_length, size_t load, size_t unload, bool spoof_maps) {
|
||||||
LOGD("cleaning trace for path %s", path);
|
LOGD("cleaning trace for path %s", path);
|
||||||
|
|
||||||
if (load > 0 || unload > 0) solist_reset_counters(load, unload);
|
if (load > 0 || unload > 0) solist_reset_counters(load, unload);
|
||||||
|
|
||||||
LOGD("Dropping solist record for %s", path);
|
LOGD("Dropping solist record for %s", path);
|
||||||
|
|
||||||
bool path_found = solist_drop_so_path(path);
|
bool any_dropped = false;
|
||||||
if (!path_found || !spoof_maps) return;
|
for (size_t i = 0; i < module_addrs_length; i++) {
|
||||||
|
bool local_any_dropped = solist_drop_so_path(module_addrs[i]);
|
||||||
|
if (!local_any_dropped) continue;
|
||||||
|
|
||||||
|
any_dropped = true;
|
||||||
|
|
||||||
|
LOGD("Dropped solist record for %p", module_addrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!any_dropped || !spoof_maps) return;
|
||||||
|
|
||||||
LOGD("spoofing virtual maps for %s", path);
|
LOGD("spoofing virtual maps for %s", path);
|
||||||
// spoofing map names is futile in Android, we do it simply
|
|
||||||
// to avoid Zygisk detections based on string comparison
|
/* INFO: Spoofing maps names is futile, after all it will
|
||||||
|
still show up in /proc/self/(s)maps but with a
|
||||||
|
different name, however still detectable by
|
||||||
|
checking the permissions. This, however, avoids
|
||||||
|
just checking for "zygisk". */
|
||||||
|
|
||||||
|
/* TODO: Use SoList to map through libraries to avoid open /proc/self/maps here */
|
||||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
for (auto &map : lsplt::MapInfo::Scan()) {
|
||||||
if (strstr(map.path.c_str(), path) && strstr(map.path.c_str(), "libzygisk") == 0)
|
if (strstr(map.path.c_str(), path) && strstr(map.path.c_str(), "libzygisk") == 0)
|
||||||
{
|
{
|
||||||
@@ -877,8 +1011,8 @@ void clean_trace(const char* path, size_t load, size_t unload, bool spoof_maps)
|
|||||||
mprotect(addr, size, PROT_READ);
|
mprotect(addr, size, PROT_READ);
|
||||||
}
|
}
|
||||||
memcpy(copy, addr, size);
|
memcpy(copy, addr, size);
|
||||||
|
mprotect(copy, size, map.perms);
|
||||||
mremap(copy, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, addr);
|
mremap(copy, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, addr);
|
||||||
mprotect(addr, size, map.perms);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -903,6 +1037,7 @@ void hook_functions() {
|
|||||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork);
|
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork);
|
||||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
|
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
|
||||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, strdup);
|
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, strdup);
|
||||||
|
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, property_get);
|
||||||
hook_commit();
|
hook_commit();
|
||||||
|
|
||||||
// Remove unhooked methods
|
// Remove unhooked methods
|
||||||
@@ -913,9 +1048,13 @@ void hook_functions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void hook_unloader() {
|
static void hook_unloader() {
|
||||||
|
if (hooked_unloader) return;
|
||||||
|
hooked_unloader = true;
|
||||||
|
|
||||||
ino_t art_inode = 0;
|
ino_t art_inode = 0;
|
||||||
dev_t art_dev = 0;
|
dev_t art_dev = 0;
|
||||||
|
|
||||||
|
cached_map_infos = lsplt::MapInfo::Scan();
|
||||||
for (auto &map : cached_map_infos) {
|
for (auto &map : cached_map_infos) {
|
||||||
if (map.path.ends_with("/libart.so")) {
|
if (map.path.ends_with("/libart.so")) {
|
||||||
art_inode = map.inode;
|
art_inode = map.inode;
|
||||||
@@ -925,7 +1064,16 @@ static void hook_unloader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (art_dev == 0 || art_inode == 0) {
|
if (art_dev == 0 || art_inode == 0) {
|
||||||
|
/*
|
||||||
|
* INFO: If we are here, it means we are too early and libart.so hasn't loaded yet when
|
||||||
|
* property_get was called. This doesn't normally happen, but we try again next time
|
||||||
|
* just to be safe.
|
||||||
|
*/
|
||||||
|
|
||||||
LOGE("virtual map for libart.so is not cached");
|
LOGE("virtual map for libart.so is not cached");
|
||||||
|
|
||||||
|
hooked_unloader = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOGD("hook_unloader called with libart.so [%zu:%lu]", art_dev, art_inode);
|
LOGD("hook_unloader called with libart.so [%zu:%lu]", art_dev, art_inode);
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ case 5: \
|
|||||||
bool tryUnload() const { return unload && dlclose(handle) == 0; };
|
bool tryUnload() const { return unload && dlclose(handle) == 0; };
|
||||||
void clearApi() { memset(&api, 0, sizeof(api)); }
|
void clearApi() { memset(&api, 0, sizeof(api)); }
|
||||||
int getId() const { return id; }
|
int getId() const { return id; }
|
||||||
|
void *getEntry() const { return entry.ptr; }
|
||||||
|
|
||||||
ZygiskModule(int id, void *handle, void *entry);
|
ZygiskModule(int id, void *handle, void *entry);
|
||||||
|
|
||||||
|
|||||||
@@ -2,27 +2,28 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <android/dlext.h>
|
||||||
|
|
||||||
|
#include <linux/limits.h>
|
||||||
|
|
||||||
#include "elf_util.h"
|
#include "elf_util.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
#include "solist.h"
|
#include "solist.h"
|
||||||
|
|
||||||
|
/* TODO: Is offset for realpath necessary? It seems to have the function
|
||||||
|
available anywhere. */
|
||||||
#ifdef __LP64__
|
#ifdef __LP64__
|
||||||
size_t solist_size_offset = 0x18;
|
size_t solist_size_offset = 0x18;
|
||||||
size_t solist_next_offset = 0x30;
|
|
||||||
size_t solist_realpath_offset = 0x1a8;
|
size_t solist_realpath_offset = 0x1a8;
|
||||||
#else
|
#else
|
||||||
size_t solist_size_offset = 0x90;
|
size_t solist_size_offset = 0x90;
|
||||||
size_t solist_next_offset = 0xa4;
|
|
||||||
size_t solist_realpath_offset = 0x174;
|
size_t solist_realpath_offset = 0x174;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *(*get_realpath_sym)(SoInfo *) = NULL;
|
static const char *(*get_realpath_sym)(SoInfo *) = NULL;
|
||||||
static void (*soinfo_free)(SoInfo *) = NULL;
|
static void (*soinfo_free)(SoInfo *) = NULL;
|
||||||
|
static SoInfo *(*find_containing_library)(const void *p) = NULL;
|
||||||
static inline SoInfo *get_next(SoInfo *self) {
|
|
||||||
return *(SoInfo **)((uintptr_t)self + solist_next_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const char *get_path(SoInfo *self) {
|
static inline const char *get_path(SoInfo *self) {
|
||||||
if (get_realpath_sym)
|
if (get_realpath_sym)
|
||||||
@@ -35,11 +36,7 @@ static inline void set_size(SoInfo *self, size_t size) {
|
|||||||
*(size_t *) ((uintptr_t)self + solist_size_offset) = size;
|
*(size_t *) ((uintptr_t)self + solist_size_offset) = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t get_size(SoInfo *self) {
|
struct pdg ppdg = { 0 };
|
||||||
return *(size_t *) ((uintptr_t)self + solist_size_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pdg ppdg;
|
|
||||||
|
|
||||||
static bool pdg_setup(ElfImg *img) {
|
static bool pdg_setup(ElfImg *img) {
|
||||||
ppdg.ctor = (void *(*)())getSymbAddress(img, "__dl__ZN18ProtectedDataGuardC2Ev");
|
ppdg.ctor = (void *(*)())getSymbAddress(img, "__dl__ZN18ProtectedDataGuardC2Ev");
|
||||||
@@ -48,22 +45,20 @@ static bool pdg_setup(ElfImg *img) {
|
|||||||
return ppdg.ctor != NULL && ppdg.dtor != NULL;
|
return ppdg.ctor != NULL && ppdg.dtor != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pdg_protect() {
|
/* INFO: Allow data to be written to the areas. */
|
||||||
if (ppdg.ctor != NULL)
|
|
||||||
(*(ppdg.ctor))();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pdg_unprotect() {
|
static void pdg_unprotect() {
|
||||||
if (ppdg.dtor != NULL)
|
(*ppdg.ctor)();
|
||||||
(*(ppdg.dtor))();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoInfo *solist = NULL;
|
/* INFO: Block write and only allow read access to the areas. */
|
||||||
static SoInfo *somain = NULL;
|
static void pdg_protect() {
|
||||||
static SoInfo **sonext = NULL;
|
(*ppdg.dtor)();
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t *g_module_load_counter = NULL;
|
static SoInfo *somain = NULL;
|
||||||
static uint64_t *g_module_unload_counter = NULL;
|
|
||||||
|
static size_t *g_module_load_counter = NULL;
|
||||||
|
static size_t *g_module_unload_counter = NULL;
|
||||||
|
|
||||||
static bool solist_init() {
|
static bool solist_init() {
|
||||||
#ifdef __LP64__
|
#ifdef __LP64__
|
||||||
@@ -77,10 +72,6 @@ static bool solist_init() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppdg = (struct pdg) {
|
|
||||||
.ctor = NULL,
|
|
||||||
.dtor = NULL
|
|
||||||
};
|
|
||||||
if (!pdg_setup(linker)) {
|
if (!pdg_setup(linker)) {
|
||||||
LOGE("Failed to setup pdg");
|
LOGE("Failed to setup pdg");
|
||||||
|
|
||||||
@@ -96,17 +87,6 @@ static bool solist_init() {
|
|||||||
|
|
||||||
See #63 for more information.
|
See #63 for more information.
|
||||||
*/
|
*/
|
||||||
solist = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL6solist");
|
|
||||||
if ((void *)solist == NULL) {
|
|
||||||
LOGE("Failed to find solist __dl__ZL6solist*");
|
|
||||||
|
|
||||||
ElfImg_destroy(linker);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGD("%p is solist", (void *)solist);
|
|
||||||
|
|
||||||
somain = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL6somain");
|
somain = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL6somain");
|
||||||
if (somain == NULL) {
|
if (somain == NULL) {
|
||||||
LOGE("Failed to find somain __dl__ZL6somain*");
|
LOGE("Failed to find somain __dl__ZL6somain*");
|
||||||
@@ -118,20 +98,6 @@ static bool solist_init() {
|
|||||||
|
|
||||||
LOGD("%p is somain", (void *)somain);
|
LOGD("%p is somain", (void *)somain);
|
||||||
|
|
||||||
sonext = (SoInfo **)getSymbAddressByPrefix(linker, "__dl__ZL6sonext");
|
|
||||||
if (sonext == NULL) {
|
|
||||||
LOGE("Failed to find sonext __dl__ZL6sonext*");
|
|
||||||
|
|
||||||
ElfImg_destroy(linker);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGD("%p is sonext", (void *)sonext);
|
|
||||||
|
|
||||||
SoInfo *vdso = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL4vdso");
|
|
||||||
if (vdso != NULL) LOGD("%p is vdso", (void *)vdso);
|
|
||||||
|
|
||||||
get_realpath_sym = (const char *(*)(SoInfo *))getSymbAddress(linker, "__dl__ZNK6soinfo12get_realpathEv");
|
get_realpath_sym = (const char *(*)(SoInfo *))getSymbAddress(linker, "__dl__ZNK6soinfo12get_realpathEv");
|
||||||
if (get_realpath_sym == NULL) {
|
if (get_realpath_sym == NULL) {
|
||||||
LOGE("Failed to find get_realpath __dl__ZNK6soinfo12get_realpathEv");
|
LOGE("Failed to find get_realpath __dl__ZNK6soinfo12get_realpathEv");
|
||||||
@@ -154,25 +120,28 @@ static bool solist_init() {
|
|||||||
|
|
||||||
LOGD("%p is soinfo_free", (void *)soinfo_free);
|
LOGD("%p is soinfo_free", (void *)soinfo_free);
|
||||||
|
|
||||||
g_module_load_counter = (uint64_t *)getSymbAddress(linker, "__dl__ZL21g_module_load_counter");
|
find_containing_library = (SoInfo *(*)(const void *))getSymbAddress(linker, "__dl__Z23find_containing_libraryPKv");
|
||||||
|
if (find_containing_library == NULL) {
|
||||||
|
LOGE("Failed to find find_containing_library __dl__Z23find_containing_libraryPKv");
|
||||||
|
|
||||||
|
ElfImg_destroy(linker);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_module_load_counter = (size_t *)getSymbAddress(linker, "__dl__ZL21g_module_load_counter");
|
||||||
if (g_module_load_counter != NULL) LOGD("found symbol g_module_load_counter");
|
if (g_module_load_counter != NULL) LOGD("found symbol g_module_load_counter");
|
||||||
|
|
||||||
g_module_unload_counter = (uint64_t *)getSymbAddress(linker, "__dl__ZL23g_module_unload_counter");
|
g_module_unload_counter = (size_t *)getSymbAddress(linker, "__dl__ZL23g_module_unload_counter");
|
||||||
if (g_module_unload_counter != NULL) LOGD("found symbol g_module_unload_counter");
|
if (g_module_unload_counter != NULL) LOGD("found symbol g_module_unload_counter");
|
||||||
|
|
||||||
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
|
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
|
||||||
uintptr_t possible_field = (uintptr_t)solist + i * sizeof(void *);
|
|
||||||
size_t possible_size_of_somain = *(size_t *)((uintptr_t)somain + i * sizeof(void *));
|
size_t possible_size_of_somain = *(size_t *)((uintptr_t)somain + i * sizeof(void *));
|
||||||
|
|
||||||
if (possible_size_of_somain < 0x100000 && possible_size_of_somain > 0x100) {
|
if (possible_size_of_somain < 0x100000 && possible_size_of_somain > 0x100) {
|
||||||
solist_size_offset = i * sizeof(void *);
|
solist_size_offset = i * sizeof(void *);
|
||||||
|
|
||||||
LOGD("solist_size_offset is %zu * %zu = %p", i, sizeof(void *), (void *)solist_size_offset);
|
LOGD("solist_size_offset is %zu * %zu = %p", i, sizeof(void *), (void *)solist_size_offset);
|
||||||
}
|
|
||||||
|
|
||||||
if (*(void **)possible_field == somain || (vdso != NULL && *(void **)possible_field == vdso)) {
|
|
||||||
solist_next_offset = i * sizeof(void *);
|
|
||||||
LOGD("solist_next_offset is %zu * %zu = %p", i, sizeof(void *), (void *)solist_next_offset);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -183,36 +152,49 @@ static bool solist_init() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solist_drop_so_path(const char *target_path) {
|
/* INFO: find_containing_library returns the SoInfo for the library that contains
|
||||||
if (solist == NULL && !solist_init()) {
|
that memory inside its limits, hence why named "lib_memory" in ReZygisk. */
|
||||||
|
bool solist_drop_so_path(void *lib_memory) {
|
||||||
|
if (somain == NULL && !solist_init()) {
|
||||||
LOGE("Failed to initialize solist");
|
LOGE("Failed to initialize solist");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SoInfo *iter = solist; iter; iter = get_next(iter)) {
|
SoInfo *found = (*find_containing_library)(lib_memory);
|
||||||
if (get_path(iter) && strstr(get_path(iter), target_path)) {
|
if (found == NULL) {
|
||||||
pdg_protect();
|
LOGD("Could not find containing library for %p", lib_memory);
|
||||||
|
|
||||||
LOGV("dropping solist record loaded at %s with size %zu", get_path(iter), get_size(iter));
|
|
||||||
if (get_size(iter) > 0) {
|
|
||||||
set_size(iter, 0);
|
|
||||||
soinfo_free(iter);
|
|
||||||
|
|
||||||
pdg_unprotect();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdg_unprotect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGD("Found so path for %p: %s", lib_memory, get_path(found));
|
||||||
|
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if (get_path(found) == NULL) {
|
||||||
|
LOGE("Failed to get path for %p", found);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strcpy(path, get_path(found));
|
||||||
|
|
||||||
|
pdg_unprotect();
|
||||||
|
|
||||||
|
set_size(found, 0);
|
||||||
|
soinfo_free(found);
|
||||||
|
|
||||||
|
pdg_protect();
|
||||||
|
|
||||||
|
LOGD("Successfully dropped so path for: %s", path);
|
||||||
|
|
||||||
|
/* INFO: Let's avoid trouble regarding detections */
|
||||||
|
memset(path, strlen(path), 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void solist_reset_counters(size_t load, size_t unload) {
|
void solist_reset_counters(size_t load, size_t unload) {
|
||||||
if (solist == NULL && !solist_init()) {
|
if (somain == NULL && !solist_init()) {
|
||||||
LOGE("Failed to initialize solist");
|
LOGE("Failed to initialize solist");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -224,18 +206,18 @@ void solist_reset_counters(size_t load, size_t unload) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t loaded_modules = *g_module_load_counter;
|
size_t loaded_modules = *g_module_load_counter;
|
||||||
uint64_t unloaded_modules = *g_module_unload_counter;
|
size_t unloaded_modules = *g_module_unload_counter;
|
||||||
|
|
||||||
if (loaded_modules >= load) {
|
if (loaded_modules >= load) {
|
||||||
*g_module_load_counter = loaded_modules - load;
|
*g_module_load_counter -= load;
|
||||||
|
|
||||||
LOGD("reset g_module_load_counter to %zu", (size_t) *g_module_load_counter);
|
LOGD("reset g_module_load_counter to %zu", *g_module_load_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unloaded_modules >= unload) {
|
if (unloaded_modules >= unload) {
|
||||||
*g_module_unload_counter = unloaded_modules - unload;
|
*g_module_unload_counter -= unload;
|
||||||
|
|
||||||
LOGD("reset g_module_unload_counter to %zu", (size_t) *g_module_unload_counter);
|
LOGD("reset g_module_unload_counter to %zu", *g_module_unload_counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct pdg {
|
|||||||
SOURCES:
|
SOURCES:
|
||||||
- https://android.googlesource.com/platform/bionic/+/refs/heads/android15-release/linker/linker.cpp#1712
|
- https://android.googlesource.com/platform/bionic/+/refs/heads/android15-release/linker/linker.cpp#1712
|
||||||
*/
|
*/
|
||||||
bool solist_drop_so_path(const char *target_path);
|
bool solist_drop_so_path(void *lib_memory);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
INFO: When dlopen'ing a library, the system will increment 1 to a global
|
INFO: When dlopen'ing a library, the system will increment 1 to a global
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ extern size_t block_size;
|
|||||||
|
|
||||||
void hook_functions();
|
void hook_functions();
|
||||||
|
|
||||||
void clean_trace(const char* path, size_t load = 1, size_t unload = 0, bool spoof_maps = false);
|
void clean_trace(const char *path, void **module_addrs, size_t module_addrs_length, size_t load, size_t unload, bool spoof_maps);
|
||||||
|
|
||||||
|
extern "C" void send_seccomp_event();
|
||||||
|
|||||||
@@ -159,17 +159,43 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
void *libc_return_addr = find_module_return_addr(map, "libc.so");
|
void *libc_return_addr = find_module_return_addr(map, "libc.so");
|
||||||
LOGD("libc return addr %p", libc_return_addr);
|
LOGD("libc return addr %p", libc_return_addr);
|
||||||
|
|
||||||
|
const char *libdl_path = NULL;
|
||||||
|
const char *libc_path = NULL;
|
||||||
|
for (size_t i = 0; i < local_map->size; i++) {
|
||||||
|
if (local_map->maps[i].path == NULL) continue;
|
||||||
|
|
||||||
|
const char *filename = position_after(local_map->maps[i].path, '/');
|
||||||
|
|
||||||
|
if (strcmp(filename, "libdl.so") == 0) {
|
||||||
|
libdl_path = local_map->maps[i].path;
|
||||||
|
|
||||||
|
/* INFO: If we had found libc.so too, no need to continue searching */
|
||||||
|
if (libc_path) break;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(filename, "libc.so") == 0) {
|
||||||
|
libc_path = local_map->maps[i].path;
|
||||||
|
|
||||||
|
/* INFO: If we had found libdl.so too, no need to continue searching */
|
||||||
|
if (libdl_path) break;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* call dlopen */
|
/* call dlopen */
|
||||||
#ifdef __LP64__
|
void *dlopen_addr = NULL;
|
||||||
void *dlopen_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlopen");
|
if (!libdl_path || (dlopen_addr = find_func_addr(local_map, map, libdl_path, "dlopen")) == NULL) {
|
||||||
#else
|
|
||||||
void *dlopen_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlopen");
|
|
||||||
#endif
|
|
||||||
if (dlopen_addr == NULL) {
|
|
||||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||||
LOGW("Failed to find dlopen from libdl.so, will load from linker");
|
LOGW("Failed to find dlopen from libdl.so, will load from linker");
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
dlopen_addr = find_func_addr(local_map, map, "/system/bin/linker64", "__dl_dlopen");
|
||||||
|
#else
|
||||||
dlopen_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlopen");
|
dlopen_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlopen");
|
||||||
|
#endif
|
||||||
if (dlopen_addr == NULL) {
|
if (dlopen_addr == NULL) {
|
||||||
PLOGE("Find __dl_dlopen");
|
PLOGE("Find __dl_dlopen");
|
||||||
|
|
||||||
@@ -198,16 +224,16 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
LOGE("handle is null");
|
LOGE("handle is null");
|
||||||
|
|
||||||
/* call dlerror */
|
/* call dlerror */
|
||||||
#ifdef __LP64__
|
void *dlerror_addr = NULL;
|
||||||
void *dlerror_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlerror");
|
if (!libdl_path || (dlerror_addr = find_func_addr(local_map, map, libdl_path, "dlerror")) == NULL) {
|
||||||
#else
|
|
||||||
void *dlerror_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlerror");
|
|
||||||
#endif
|
|
||||||
if (dlerror_addr == NULL) {
|
|
||||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||||
LOGW("Failed to find dlerror from libdl.so, will load from linker");
|
LOGW("Failed to find dlerror from libdl.so, will load from linker");
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
dlerror_addr = find_func_addr(local_map, map, "/system/bin/linker64", "__dl_dlerror");
|
||||||
|
#else
|
||||||
dlerror_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlerror");
|
dlerror_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlerror");
|
||||||
|
#endif
|
||||||
if (dlerror_addr == NULL) {
|
if (dlerror_addr == NULL) {
|
||||||
LOGE("Find __dl_dlerror");
|
LOGE("Find __dl_dlerror");
|
||||||
|
|
||||||
@@ -225,19 +251,19 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
LOGE("dlerror str is null");
|
LOGE("dlerror str is null");
|
||||||
|
|
||||||
free(args);
|
free(args);
|
||||||
|
free_maps(local_map);
|
||||||
|
free_maps(map);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __LP64__
|
void *strlen_addr = find_func_addr(local_map, map, libc_path, "strlen");
|
||||||
void *strlen_addr = find_func_addr(local_map, map, "/system/lib64/libc.so", "strlen");
|
|
||||||
#else
|
|
||||||
void *strlen_addr = find_func_addr(local_map, map, "/system/lib/libc.so", "strlen");
|
|
||||||
#endif
|
|
||||||
if (strlen_addr == NULL) {
|
if (strlen_addr == NULL) {
|
||||||
LOGE("find strlen");
|
LOGE("find strlen");
|
||||||
|
|
||||||
free(args);
|
free(args);
|
||||||
|
free_maps(local_map);
|
||||||
|
free_maps(map);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -249,6 +275,8 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
LOGE("dlerror len <= 0");
|
LOGE("dlerror len <= 0");
|
||||||
|
|
||||||
free(args);
|
free(args);
|
||||||
|
free_maps(local_map);
|
||||||
|
free_maps(map);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -258,6 +286,8 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
LOGE("malloc err");
|
LOGE("malloc err");
|
||||||
|
|
||||||
free(args);
|
free(args);
|
||||||
|
free_maps(local_map);
|
||||||
|
free_maps(map);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -269,20 +299,23 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
free(err);
|
free(err);
|
||||||
free(args);
|
free(args);
|
||||||
|
|
||||||
|
free_maps(local_map);
|
||||||
|
free_maps(map);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call dlsym(handle, "entry") */
|
/* call dlsym(handle, "entry") */
|
||||||
#ifdef __LP64__
|
void *dlsym_addr = NULL;
|
||||||
void *dlsym_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlsym");
|
if (!libdl_path || (dlsym_addr = find_func_addr(local_map, map, libdl_path, "dlsym")) == NULL) {
|
||||||
#else
|
|
||||||
void *dlsym_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlsym");
|
|
||||||
#endif
|
|
||||||
if (dlsym_addr == NULL) {
|
|
||||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||||
LOGW("Failed to find dlsym from libdl.so, will load from linker");
|
LOGW("Failed to find dlsym from libdl.so, will load from linker");
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
dlsym_addr = find_func_addr(local_map, map, "/system/bin/linker64", "__dl_dlsym");
|
||||||
|
#else
|
||||||
dlsym_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlsym");
|
dlsym_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlsym");
|
||||||
|
#endif
|
||||||
if (dlsym_addr == NULL) {
|
if (dlsym_addr == NULL) {
|
||||||
LOGE("find __dl_dlsym");
|
LOGE("find __dl_dlsym");
|
||||||
|
|
||||||
@@ -370,7 +403,7 @@ bool trace_zygote(int pid) {
|
|||||||
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_EXITKILL) == -1) {
|
if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACESECCOMP) == -1) {
|
||||||
PLOGE("seize");
|
PLOGE("seize");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -405,6 +438,16 @@ bool trace_zygote(int pid) {
|
|||||||
if (STOPPED_WITH(SIGCONT, 0)) {
|
if (STOPPED_WITH(SIGCONT, 0)) {
|
||||||
LOGD("received SIGCONT");
|
LOGD("received SIGCONT");
|
||||||
|
|
||||||
|
/* INFO: Due to kernel bugs, fixed in 5.16+, ptrace_message (msg of
|
||||||
|
PTRACE_GETEVENTMSG) may not represent the current state of
|
||||||
|
the process. Because we set some options, which alters the
|
||||||
|
ptrace_message, we need to call PTRACE_SYSCALL to reset the
|
||||||
|
ptrace_message to 0, the default/normal state.
|
||||||
|
*/
|
||||||
|
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||||
|
|
||||||
|
WAIT_OR_DIE
|
||||||
|
|
||||||
ptrace(PTRACE_DETACH, pid, 0, SIGCONT);
|
ptrace(PTRACE_DETACH, pid, 0, SIGCONT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -313,20 +313,12 @@ void *find_module_return_addr(struct maps *map, const char *suffix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *find_module_base(struct maps *map, const char *file) {
|
void *find_module_base(struct maps *map, const char *file) {
|
||||||
const char *suffix = position_after(file, '/');
|
|
||||||
if (!suffix) {
|
|
||||||
LOGE("failed to find suffix in %s", file);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < map->size; i++) {
|
for (size_t i = 0; i < map->size; i++) {
|
||||||
if (map->maps[i].path == NULL) continue;
|
if (map->maps[i].path == NULL) continue;
|
||||||
|
|
||||||
const char *file_name = position_after(map->maps[i].path, '/');
|
const char *file_path = map->maps[i].path;
|
||||||
if (!file_name) continue;
|
|
||||||
|
|
||||||
if (strlen(file_name) < strlen(suffix) || map->maps[i].offset != 0 || strncmp(file_name, suffix, strlen(suffix)) != 0) continue;
|
if (strlen(file_path) != strlen(file) || map->maps[i].offset != 0 || strncmp(file_path, file, strlen(file)) != 0) continue;
|
||||||
|
|
||||||
return (void *)map->maps[i].start;
|
return (void *)map->maps[i].start;
|
||||||
}
|
}
|
||||||
@@ -530,6 +522,32 @@ int fork_dont_care() {
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tracee_skip_syscall(int pid) {
|
||||||
|
struct user_regs_struct regs;
|
||||||
|
if (!get_regs(pid, ®s)) {
|
||||||
|
LOGE("failed to get seccomp regs");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
regs.REG_SYSNR = -1;
|
||||||
|
if (!set_regs(pid, ®s)) {
|
||||||
|
LOGE("failed to set seccomp regs");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFO: It might not work, don't check for error */
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
int sysnr = -1;
|
||||||
|
struct iovec iov = {
|
||||||
|
.iov_base = &sysnr,
|
||||||
|
.iov_len = sizeof (int),
|
||||||
|
};
|
||||||
|
ptrace(PTRACE_SETREGSET, pid, NT_ARM_SYSTEM_CALL, &iov);
|
||||||
|
#elif defined(__arm__)
|
||||||
|
ptrace(PTRACE_SET_SYSCALL, pid, 0, (void*) -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void wait_for_trace(int pid, int *status, int flags) {
|
void wait_for_trace(int pid, int *status, int flags) {
|
||||||
while (1) {
|
while (1) {
|
||||||
pid_t result = waitpid(pid, status, flags);
|
pid_t result = waitpid(pid, status, flags);
|
||||||
@@ -540,7 +558,13 @@ void wait_for_trace(int pid, int *status, int flags) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WIFSTOPPED(*status)) {
|
if (*status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
|
||||||
|
tracee_skip_syscall(pid);
|
||||||
|
|
||||||
|
ptrace(PTRACE_CONT, pid, 0, 0);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if (!WIFSTOPPED(*status)) {
|
||||||
char status_str[64];
|
char status_str[64];
|
||||||
parse_status(*status, status_str, sizeof(status_str));
|
parse_status(*status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
|||||||
@@ -37,18 +37,22 @@ void free_maps(struct maps *maps);
|
|||||||
#define REG_SP rsp
|
#define REG_SP rsp
|
||||||
#define REG_IP rip
|
#define REG_IP rip
|
||||||
#define REG_RET rax
|
#define REG_RET rax
|
||||||
|
#define REG_SYSNR orig_rax
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
#define REG_SP esp
|
#define REG_SP esp
|
||||||
#define REG_IP eip
|
#define REG_IP eip
|
||||||
#define REG_RET eax
|
#define REG_RET eax
|
||||||
|
#define REG_SYSNR orig_eax
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define REG_SP sp
|
#define REG_SP sp
|
||||||
#define REG_IP pc
|
#define REG_IP pc
|
||||||
#define REG_RET regs[0]
|
#define REG_RET regs[0]
|
||||||
|
#define REG_SYSNR regs[8]
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
#define REG_SP uregs[13]
|
#define REG_SP uregs[13]
|
||||||
#define REG_IP uregs[15]
|
#define REG_IP uregs[15]
|
||||||
#define REG_RET uregs[0]
|
#define REG_RET uregs[0]
|
||||||
|
#define REG_SYSNR uregs[7]
|
||||||
#define user_regs_struct user_regs
|
#define user_regs_struct user_regs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -62,6 +66,8 @@ bool set_regs(int pid, struct user_regs_struct *regs);
|
|||||||
|
|
||||||
void get_addr_mem_region(struct maps *map, uintptr_t addr, char *buf, size_t buf_size);
|
void get_addr_mem_region(struct maps *map, uintptr_t addr, char *buf, size_t buf_size);
|
||||||
|
|
||||||
|
const char *position_after(const char *str, const char needle);
|
||||||
|
|
||||||
void *find_module_return_addr(struct maps *map, const char *suffix);
|
void *find_module_return_addr(struct maps *map, const char *suffix);
|
||||||
|
|
||||||
void *find_func_addr(struct maps *local_info, struct maps *remote_info, const char *module, const char *func);
|
void *find_func_addr(struct maps *local_info, struct maps *remote_info, const char *module, const char *func);
|
||||||
|
|||||||
93
webroot/lang/ja_JP.json
Normal file
93
webroot/lang/ja_JP.json
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"langName": "日本語",
|
||||||
|
"global": {
|
||||||
|
"unknown": "不明"
|
||||||
|
},
|
||||||
|
"smallPage": {
|
||||||
|
"language": {
|
||||||
|
"header": "言語を選択してください"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"header": "テーマを選択してください",
|
||||||
|
"dark": "ダーク",
|
||||||
|
"light": "ライト",
|
||||||
|
"system": "システムベース"
|
||||||
|
},
|
||||||
|
"errorh": {
|
||||||
|
"buttons": {
|
||||||
|
"copy": "コピー",
|
||||||
|
"clear": "すべてのログを消去"
|
||||||
|
},
|
||||||
|
"header": "エラーの履歴",
|
||||||
|
"placeholder": "エラーログは記録されていません!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"home": {
|
||||||
|
"header": "ホーム",
|
||||||
|
"status": {
|
||||||
|
"notWorking": "動作していません",
|
||||||
|
"ok": "動作中",
|
||||||
|
"partially": "部分的に動作中"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "バージョン",
|
||||||
|
"root": "Root の実装",
|
||||||
|
"zygote": {
|
||||||
|
"injected": "インジェクト済み",
|
||||||
|
"notInjected": "未インジェクト",
|
||||||
|
"unknown": "不明"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modules": {
|
||||||
|
"header": "モジュール",
|
||||||
|
"notAvaliable": "Zygisk を使用するモジュールはありません。",
|
||||||
|
"arch": "アーキテクチャ: "
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"header": "アクション",
|
||||||
|
"monitorButton": {
|
||||||
|
"start": "開始",
|
||||||
|
"stop": "停止",
|
||||||
|
"pause": "一時停止"
|
||||||
|
},
|
||||||
|
"monitor": "監視",
|
||||||
|
"status": {
|
||||||
|
"tracing": "トレース中",
|
||||||
|
"stopping": "停止中",
|
||||||
|
"stopped": "停止済み",
|
||||||
|
"exiting": "終了中",
|
||||||
|
"unknown": "不明"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"header": "設定",
|
||||||
|
"font": {
|
||||||
|
"header": "システムフォントを有効化",
|
||||||
|
"description": "現在の WebUI でシステムフォントの使用を有効化します。注意: FlipFont との互換性がない場合があります"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"header": "システムテーマ",
|
||||||
|
"description": "WebUI のシステムテーマを変更します"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"header": "言語の変更",
|
||||||
|
"description": "言語を変更します"
|
||||||
|
},
|
||||||
|
"logs": {
|
||||||
|
"header": "エラーの履歴",
|
||||||
|
"description": "すべてのエラーログを表示します"
|
||||||
|
},
|
||||||
|
"credits": {
|
||||||
|
"module": "モジュールの開発者",
|
||||||
|
"original": "オリジナルの開発者",
|
||||||
|
"web": "WebUI の開発者"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"module": "モジュールのライセンス",
|
||||||
|
"web": "WebUI のライセンス"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -121,11 +121,7 @@ void companion_entry(int fd) {
|
|||||||
ASSURE_SIZE_WRITE("ZygiskdCompanion", "module_entry", ret, sizeof(uint8_t));
|
ASSURE_SIZE_WRITE("ZygiskdCompanion", "module_entry", ret, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa = { .sa_handler = SIG_IGN };
|
||||||
memset(&sa, 0, sizeof(sa));
|
|
||||||
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_handler = SIG_IGN;
|
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ void apatch_get_existence(struct root_impl_state *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct package_config {
|
struct package_config {
|
||||||
|
char *process;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
bool root_granted;
|
bool root_granted;
|
||||||
bool umount_needed;
|
bool umount_needed;
|
||||||
@@ -104,7 +105,7 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
strtok(line, ",");
|
config->configs[config->size].process = strdup(strtok(line, ","));
|
||||||
|
|
||||||
char *exclude_str = strtok(NULL, ",");
|
char *exclude_str = strtok(NULL, ",");
|
||||||
if (exclude_str == NULL) continue;
|
if (exclude_str == NULL) continue;
|
||||||
@@ -128,6 +129,10 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _apatch_free_package_config(struct packages_config *restrict config) {
|
void _apatch_free_package_config(struct packages_config *restrict config) {
|
||||||
|
for (size_t i = 0; i < config->size; i++) {
|
||||||
|
free(config->configs[i].process);
|
||||||
|
}
|
||||||
|
|
||||||
free(config->configs);
|
free(config->configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +160,7 @@ bool apatch_uid_granted_root(uid_t uid) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool apatch_uid_should_umount(uid_t uid) {
|
bool apatch_uid_should_umount(uid_t uid, const char *const process) {
|
||||||
struct packages_config config;
|
struct packages_config config;
|
||||||
if (!_apatch_get_package_config(&config)) {
|
if (!_apatch_get_package_config(&config)) {
|
||||||
_apatch_free_package_config(&config);
|
_apatch_free_package_config(&config);
|
||||||
@@ -174,6 +179,29 @@ bool apatch_uid_should_umount(uid_t uid) {
|
|||||||
return umount_needed;
|
return umount_needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* INFO: Isolated services have different UIDs than the main app, and
|
||||||
|
while libzygisk.so has code to send the UID of the app related
|
||||||
|
to the isolated service, we add this so that in case it fails,
|
||||||
|
this should avoid it pass through as Mounted.
|
||||||
|
*/
|
||||||
|
if (IS_ISOLATED_SERVICE(uid)) {
|
||||||
|
size_t targeted_process_length = strlen(process);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < config.size; i++) {
|
||||||
|
size_t config_process_length = strlen(config.configs[i].process);
|
||||||
|
size_t smallest_process_length = targeted_process_length < config_process_length ? targeted_process_length : config_process_length;
|
||||||
|
|
||||||
|
if (strncmp(config.configs[i].process, process, smallest_process_length) != 0) continue;
|
||||||
|
|
||||||
|
/* INFO: This allow us to copy the information to avoid use-after-free */
|
||||||
|
bool umount_needed = config.configs[i].umount_needed;
|
||||||
|
|
||||||
|
_apatch_free_package_config(&config);
|
||||||
|
|
||||||
|
return umount_needed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_apatch_free_package_config(&config);
|
_apatch_free_package_config(&config);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ void apatch_get_existence(struct root_impl_state *state);
|
|||||||
|
|
||||||
bool apatch_uid_granted_root(uid_t uid);
|
bool apatch_uid_granted_root(uid_t uid);
|
||||||
|
|
||||||
bool apatch_uid_should_umount(uid_t uid);
|
bool apatch_uid_should_umount(uid_t uid, const char *const process);
|
||||||
|
|
||||||
bool apatch_uid_is_manager(uid_t uid);
|
bool apatch_uid_is_manager(uid_t uid);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ void root_impls_setup(void) {
|
|||||||
impl.impl = Multiple;
|
impl.impl = Multiple;
|
||||||
} else if (state_ksu.state == Supported) {
|
} else if (state_ksu.state == Supported) {
|
||||||
impl.impl = KernelSU;
|
impl.impl = KernelSU;
|
||||||
|
impl.variant = state_ksu.variant;
|
||||||
} else if (state_apatch.state == Supported) {
|
} else if (state_apatch.state == Supported) {
|
||||||
impl.impl = APatch;
|
impl.impl = APatch;
|
||||||
} else if (state_magisk.state == Supported) {
|
} else if (state_magisk.state == Supported) {
|
||||||
@@ -100,7 +101,7 @@ bool uid_should_umount(uid_t uid, const char *const process) {
|
|||||||
return ksu_uid_should_umount(uid);
|
return ksu_uid_should_umount(uid);
|
||||||
}
|
}
|
||||||
case APatch: {
|
case APatch: {
|
||||||
return apatch_uid_should_umount(uid);
|
return apatch_uid_should_umount(uid, process);
|
||||||
}
|
}
|
||||||
case Magisk: {
|
case Magisk: {
|
||||||
return magisk_uid_should_umount(process);
|
return magisk_uid_should_umount(process);
|
||||||
|
|||||||
@@ -19,6 +19,12 @@
|
|||||||
#define CMD_GET_VERSION 2
|
#define CMD_GET_VERSION 2
|
||||||
#define CMD_UID_GRANTED_ROOT 12
|
#define CMD_UID_GRANTED_ROOT 12
|
||||||
#define CMD_UID_SHOULD_UMOUNT 13
|
#define CMD_UID_SHOULD_UMOUNT 13
|
||||||
|
#define CMD_GET_MANAGER_UID 16
|
||||||
|
#define CMD_HOOK_MODE 0xC0DEAD1A
|
||||||
|
|
||||||
|
static enum kernelsu_variants variant = KOfficial;
|
||||||
|
|
||||||
|
static bool supports_manager_uid_retrieval = false;
|
||||||
|
|
||||||
void ksu_get_existence(struct root_impl_state *state) {
|
void ksu_get_existence(struct root_impl_state *state) {
|
||||||
int version = 0;
|
int version = 0;
|
||||||
@@ -42,6 +48,26 @@ void ksu_get_existence(struct root_impl_state *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->state = Supported;
|
state->state = Supported;
|
||||||
|
|
||||||
|
char mode[16] = { 0 };
|
||||||
|
prctl((signed int)KERNEL_SU_OPTION, CMD_HOOK_MODE, mode, 0, 0);
|
||||||
|
|
||||||
|
if (mode[0] != '\0') state->variant = KNext;
|
||||||
|
else state->variant = KOfficial;
|
||||||
|
|
||||||
|
variant = state->variant;
|
||||||
|
|
||||||
|
/* INFO: CMD_GET_MANAGER_UID is a KernelSU Next feature, however we won't
|
||||||
|
limit to KernelSU Next only in case other forks wish to implement
|
||||||
|
it. */
|
||||||
|
int reply_ok = 0;
|
||||||
|
prctl((signed int)KERNEL_SU_OPTION, CMD_GET_MANAGER_UID, 0, 0, &reply_ok);
|
||||||
|
|
||||||
|
if (reply_ok == KERNEL_SU_OPTION) {
|
||||||
|
LOGI("KernelSU implementation supports CMD_GET_MANAGER_UID.\n");
|
||||||
|
|
||||||
|
supports_manager_uid_retrieval = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (version >= 1 && version <= MIN_KSU_VERSION - 1) state->state = TooOld;
|
else if (version >= 1 && version <= MIN_KSU_VERSION - 1) state->state = TooOld;
|
||||||
else state->state = Abnormal;
|
else state->state = Abnormal;
|
||||||
@@ -68,8 +94,24 @@ bool ksu_uid_should_umount(uid_t uid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_uid_is_manager(uid_t uid) {
|
bool ksu_uid_is_manager(uid_t uid) {
|
||||||
|
/* INFO: If the manager UID is set, we can use it to check if the UID
|
||||||
|
is the manager UID, which is more reliable than checking
|
||||||
|
the KSU manager data directory, as spoofed builds of
|
||||||
|
KernelSU Next have different package names.
|
||||||
|
*/
|
||||||
|
if (supports_manager_uid_retrieval) {
|
||||||
|
uid_t manager_uid = 0;
|
||||||
|
prctl(KERNEL_SU_OPTION, CMD_GET_MANAGER_UID, &manager_uid, NULL, NULL);
|
||||||
|
|
||||||
|
return uid == manager_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *manager_path = NULL;
|
||||||
|
if (variant == KOfficial) manager_path = "/data/user_de/0/me.weishu.kernelsu";
|
||||||
|
else if (variant == KNext) manager_path = "/data/user_de/0/com.rifsxd.ksunext";
|
||||||
|
|
||||||
struct stat s;
|
struct stat s;
|
||||||
if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == -1) {
|
if (stat(manager_path, &s) == -1) {
|
||||||
if (errno != ENOENT) {
|
if (errno != ENOENT) {
|
||||||
LOGE("Failed to stat KSU manager data directory: %s\n", strerror(errno));
|
LOGE("Failed to stat KSU manager data directory: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
#include "../constants.h"
|
#include "../constants.h"
|
||||||
|
|
||||||
|
enum kernelsu_variants {
|
||||||
|
KOfficial,
|
||||||
|
KNext
|
||||||
|
};
|
||||||
|
|
||||||
void ksu_get_existence(struct root_impl_state *state);
|
void ksu_get_existence(struct root_impl_state *state);
|
||||||
|
|
||||||
bool ksu_uid_granted_root(uid_t uid);
|
bool ksu_uid_granted_root(uid_t uid);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ char *magisk_managers[] = {
|
|||||||
#define DEBUG_RAMDISK_MAGISK lp_select("/debug_ramdisk/magisk32", "/debug_ramdisk/magisk64")
|
#define DEBUG_RAMDISK_MAGISK lp_select("/debug_ramdisk/magisk32", "/debug_ramdisk/magisk64")
|
||||||
#define BITLESS_DEBUG_RAMDISK_MAGISK "/debug_ramdisk/magisk"
|
#define BITLESS_DEBUG_RAMDISK_MAGISK "/debug_ramdisk/magisk"
|
||||||
|
|
||||||
enum magisk_variants variant = Official;
|
static enum magisk_variants variant = MOfficial;
|
||||||
/* INFO: Longest path */
|
/* INFO: Longest path */
|
||||||
static char path_to_magisk[sizeof(DEBUG_RAMDISK_MAGISK)] = { 0 };
|
static char path_to_magisk[sizeof(DEBUG_RAMDISK_MAGISK)] = { 0 };
|
||||||
bool is_using_sulist = false;
|
bool is_using_sulist = false;
|
||||||
@@ -74,7 +74,7 @@ void magisk_get_existence(struct root_impl_state *state) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->variant = (uint8_t)Official;
|
state->variant = (uint8_t)MOfficial;
|
||||||
|
|
||||||
for (unsigned long i = 0; i < sizeof(supported_variants) / sizeof(supported_variants[0]); i++) {
|
for (unsigned long i = 0; i < sizeof(supported_variants) / sizeof(supported_variants[0]); i++) {
|
||||||
if (strstr(magisk_info, supported_variants[i])) {
|
if (strstr(magisk_info, supported_variants[i])) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#include "../constants.h"
|
#include "../constants.h"
|
||||||
|
|
||||||
enum magisk_variants {
|
enum magisk_variants {
|
||||||
Official,
|
MOfficial,
|
||||||
Kitsune
|
MKitsune
|
||||||
};
|
};
|
||||||
|
|
||||||
void magisk_get_existence(struct root_impl_state *state);
|
void magisk_get_existence(struct root_impl_state *state);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "root_impl/common.h"
|
#include "root_impl/common.h"
|
||||||
|
#include "root_impl/kernelsu.h"
|
||||||
#include "root_impl/magisk.h"
|
#include "root_impl/magisk.h"
|
||||||
|
|
||||||
int clean_namespace_fd = 0;
|
int clean_namespace_fd = 0;
|
||||||
@@ -436,7 +437,8 @@ void stringify_root_impl_name(struct root_impl impl, char *restrict output) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KernelSU: {
|
case KernelSU: {
|
||||||
strcpy(output, "KernelSU");
|
if (impl.variant == KOfficial) strcpy(output, "KernelSU");
|
||||||
|
else strcpy(output, "KernelSU Next");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -446,11 +448,8 @@ void stringify_root_impl_name(struct root_impl impl, char *restrict output) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Magisk: {
|
case Magisk: {
|
||||||
if (impl.variant == 0) {
|
if (impl.variant == MOfficial) strcpy(output, "Magisk Official");
|
||||||
strcpy(output, "Magisk Official");
|
else strcpy(output, "Magisk Kitsune");
|
||||||
} else {
|
|
||||||
strcpy(output, "Magisk Kitsune");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -603,15 +602,11 @@ bool umount_root(struct root_impl impl) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (impl.impl) {
|
/* INFO: "Magisk" is the longest word that will ever be put in source_name */
|
||||||
case None: { break; }
|
char source_name[sizeof("magisk")];
|
||||||
case Multiple: { break; }
|
|
||||||
|
|
||||||
case KernelSU:
|
|
||||||
case APatch: {
|
|
||||||
char source_name[LONGEST_ROOT_IMPL_NAME];
|
|
||||||
if (impl.impl == KernelSU) strcpy(source_name, "KSU");
|
if (impl.impl == KernelSU) strcpy(source_name, "KSU");
|
||||||
else strcpy(source_name, "APatch");
|
else if (impl.impl == APatch) strcpy(source_name, "APatch");
|
||||||
|
else strcpy(source_name, "magisk");
|
||||||
|
|
||||||
LOGI("[%s] Unmounting root", source_name);
|
LOGI("[%s] Unmounting root", source_name);
|
||||||
|
|
||||||
@@ -622,16 +617,16 @@ bool umount_root(struct root_impl impl) {
|
|||||||
struct mountinfo mount = mounts.mounts[i];
|
struct mountinfo mount = mounts.mounts[i];
|
||||||
|
|
||||||
bool should_unmount = false;
|
bool should_unmount = false;
|
||||||
|
/* INFO: The root implementations have their own /system mounts, so we
|
||||||
/* INFO: KernelSU has its own /system mounts, so we only skip the mount
|
only skip the mount if they are from a module, not Magisk itself.
|
||||||
if they are from a module, not KSU itself.
|
|
||||||
*/
|
*/
|
||||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0 &&
|
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0 &&
|
||||||
strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) continue;
|
strncmp(mount.root, "/adb/modules/", strlen("/adb/modules/")) == 0 &&
|
||||||
|
strncmp(mount.target, "/system/etc/", strlen("/system/etc/")) != 0) continue;
|
||||||
|
|
||||||
if (strcmp(mount.source, source_name) == 0) should_unmount = true;
|
if (strcmp(mount.source, source_name) == 0) should_unmount = true;
|
||||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
|
||||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
||||||
|
if (strncmp(mount.root, "/adb/modules/", strlen("/adb/modules/")) == 0) should_unmount = true;
|
||||||
|
|
||||||
if (!should_unmount) continue;
|
if (!should_unmount) continue;
|
||||||
|
|
||||||
@@ -651,7 +646,6 @@ bool umount_root(struct root_impl impl) {
|
|||||||
|
|
||||||
for (size_t i = num_targets; i > 0; i--) {
|
for (size_t i = num_targets; i > 0; i--) {
|
||||||
const char *target = targets_to_unmount[i - 1];
|
const char *target = targets_to_unmount[i - 1];
|
||||||
|
|
||||||
if (umount2(target, MNT_DETACH) == -1) {
|
if (umount2(target, MNT_DETACH) == -1) {
|
||||||
LOGE("[%s] Failed to unmount %s: %s\n", source_name, target, strerror(errno));
|
LOGE("[%s] Failed to unmount %s: %s\n", source_name, target, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
@@ -660,59 +654,6 @@ bool umount_root(struct root_impl impl) {
|
|||||||
}
|
}
|
||||||
free(targets_to_unmount);
|
free(targets_to_unmount);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Magisk: {
|
|
||||||
LOGI("[Magisk] Unmounting root");
|
|
||||||
|
|
||||||
const char **targets_to_unmount = NULL;
|
|
||||||
size_t num_targets = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < mounts.length; i++) {
|
|
||||||
struct mountinfo mount = mounts.mounts[i];
|
|
||||||
|
|
||||||
bool should_unmount = false;
|
|
||||||
/* INFO: Magisk has its own /system mounts, so we only skip the mount
|
|
||||||
if they are from a module, not Magisk itself.
|
|
||||||
*/
|
|
||||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0 &&
|
|
||||||
strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) continue;
|
|
||||||
|
|
||||||
if (strcmp(mount.source, "magisk") == 0) should_unmount = true;
|
|
||||||
if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0) should_unmount = true;
|
|
||||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
|
||||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
|
||||||
|
|
||||||
if (!should_unmount) continue;
|
|
||||||
|
|
||||||
num_targets++;
|
|
||||||
targets_to_unmount = realloc(targets_to_unmount, num_targets * sizeof(char*));
|
|
||||||
if (targets_to_unmount == NULL) {
|
|
||||||
LOGE("[Magisk] Failed to allocate memory for targets_to_unmount\n");
|
|
||||||
|
|
||||||
free(targets_to_unmount);
|
|
||||||
free_mounts(&mounts);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets_to_unmount[num_targets - 1] = mount.target;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = num_targets; i > 0; i--) {
|
|
||||||
const char *target = targets_to_unmount[i - 1];
|
|
||||||
if (umount2(target, MNT_DETACH) == -1) {
|
|
||||||
LOGE("[Magisk] Failed to unmount %s: %s\n", target, strerror(errno));
|
|
||||||
} else {
|
|
||||||
LOGI("[Magisk] Unmounted %s\n", target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(targets_to_unmount);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_mounts(&mounts);
|
free_mounts(&mounts);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -844,7 +785,7 @@ int save_mns_fd(int pid, enum MountNamespaceState mns_state, struct root_impl im
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl.impl == Magisk && impl.variant == Kitsune && mns_state == Clean) {
|
if (impl.impl == Magisk && impl.variant == MKitsune && mns_state == Clean) {
|
||||||
LOGI("[Magisk] Magisk Kitsune detected, will skip cache first.");
|
LOGI("[Magisk] Magisk Kitsune detected, will skip cache first.");
|
||||||
|
|
||||||
/* INFO: MagiskSU of Kitsune has a special behavior: It is only mounted
|
/* INFO: MagiskSU of Kitsune has a special behavior: It is only mounted
|
||||||
|
|||||||
@@ -65,6 +65,9 @@
|
|||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_ISOLATED_SERVICE(uid) \
|
||||||
|
((uid) >= 90000 && (uid) < 1000000)
|
||||||
|
|
||||||
#define write_func_def(type) \
|
#define write_func_def(type) \
|
||||||
ssize_t write_## type(int fd, type val)
|
ssize_t write_## type(int fd, type val)
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,14 @@ enum Architecture {
|
|||||||
#define ZYGISKD_PATH "/data/adb/modules/rezygisk/bin/zygiskd" lp_select("32", "64")
|
#define ZYGISKD_PATH "/data/adb/modules/rezygisk/bin/zygiskd" lp_select("32", "64")
|
||||||
|
|
||||||
static enum Architecture get_arch(void) {
|
static enum Architecture get_arch(void) {
|
||||||
char system_arch[32];
|
char system_arch[64];
|
||||||
get_property("ro.product.cpu.abilist", system_arch);
|
get_property("ro.product.cpu.abilist", system_arch);
|
||||||
|
|
||||||
if (strstr(system_arch, "arm") != NULL) return lp_select(ARM32, ARM64);
|
/* INFO: "PC" architectures should have priority because in an emulator
|
||||||
|
the native architecture should have priority over the emulated
|
||||||
|
architecture for "native" reasons. */
|
||||||
if (strstr(system_arch, "x86") != NULL) return lp_select(X86, X86_64);
|
if (strstr(system_arch, "x86") != NULL) return lp_select(X86, X86_64);
|
||||||
|
if (strstr(system_arch, "arm") != NULL) return lp_select(ARM32, ARM64);
|
||||||
|
|
||||||
LOGE("Unsupported system architecture: %s\n", system_arch);
|
LOGE("Unsupported system architecture: %s\n", system_arch);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -130,6 +133,8 @@ static void load_modules(enum Architecture arch, struct Context *restrict contex
|
|||||||
context->modules[context->len].companion = -1;
|
context->modules[context->len].companion = -1;
|
||||||
context->len++;
|
context->len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_modules(struct Context *restrict context) {
|
static void free_modules(struct Context *restrict context) {
|
||||||
@@ -355,6 +360,9 @@ void zygiskd_start(char *restrict argv[]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sigaction sa = { .sa_handler = SIG_IGN };
|
||||||
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
|
||||||
bool first_process = true;
|
bool first_process = true;
|
||||||
while (1) {
|
while (1) {
|
||||||
int client_fd = accept(socket_fd, NULL, NULL);
|
int client_fd = accept(socket_fd, NULL, NULL);
|
||||||
|
|||||||
Reference in New Issue
Block a user