You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
improve: cache scanned virtual maps
Reading the file `/proc/self/maps` is detectable by the target process. Hence, we should cache scanned virtual maps after `libart.so` is loaded for later plt hooks in the target process.
This commit is contained in:
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "loader/src/external/lsplt"]
|
[submodule "loader/src/external/lsplt"]
|
||||||
path = loader/src/external/lsplt
|
path = loader/src/external/lsplt
|
||||||
url = https://github.com/LSPosed/lsplt
|
url = https://github.com/JingMatrix/LSPlt
|
||||||
|
|||||||
2
loader/src/external/lsplt
vendored
2
loader/src/external/lsplt
vendored
Submodule loader/src/external/lsplt updated: 5d2b820cf9...984804293e
@@ -122,6 +122,7 @@ 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>, StringCmp> *jni_hook_list;
|
map<string, vector<JNINativeMethod>, StringCmp> *jni_hook_list;
|
||||||
bool should_unmap_zygisk = false;
|
bool should_unmap_zygisk = false;
|
||||||
|
std::vector<lsplt::MapInfo> cached_map_infos = {};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -187,6 +188,7 @@ DCL_HOOK_FUNC(int, pthread_attr_setstacksize, void *target, size_t size) {
|
|||||||
|
|
||||||
if (should_unmap_zygisk) {
|
if (should_unmap_zygisk) {
|
||||||
unhook_functions();
|
unhook_functions();
|
||||||
|
cached_map_infos.clear();
|
||||||
if (should_unmap_zygisk) {
|
if (should_unmap_zygisk) {
|
||||||
// Because both `pthread_attr_setstacksize` and `dlclose` have the same function signature,
|
// Because both `pthread_attr_setstacksize` and `dlclose` have the same function signature,
|
||||||
// we can use `musttail` to let the compiler reuse our stack frame and thus
|
// we can use `musttail` to let the compiler reuse our stack frame and thus
|
||||||
@@ -205,6 +207,8 @@ DCL_HOOK_FUNC(char *, strdup, const char *s) {
|
|||||||
if (strcmp(s, "com.android.internal.os.ZygoteInit") == 0) {
|
if (strcmp(s, "com.android.internal.os.ZygoteInit") == 0) {
|
||||||
LOGV("strdup %s", s);
|
LOGV("strdup %s", s);
|
||||||
initialize_jni_hook();
|
initialize_jni_hook();
|
||||||
|
cached_map_infos = lsplt::MapInfo::Scan();
|
||||||
|
LOGD("cached_map_infos updated");
|
||||||
}
|
}
|
||||||
|
|
||||||
return old_strdup(s);
|
return old_strdup(s);
|
||||||
@@ -268,7 +272,7 @@ void initialize_jni_hook() {
|
|||||||
auto get_created_java_vms = reinterpret_cast<jint (*)(JavaVM **, jsize, jsize *)>(
|
auto get_created_java_vms = reinterpret_cast<jint (*)(JavaVM **, jsize, jsize *)>(
|
||||||
dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"));
|
dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"));
|
||||||
if (!get_created_java_vms) {
|
if (!get_created_java_vms) {
|
||||||
for (auto &map: lsplt::MapInfo::Scan()) {
|
for (auto &map: cached_map_infos) {
|
||||||
if (!map.path.ends_with("/libnativehelper.so")) continue;
|
if (!map.path.ends_with("/libnativehelper.so")) continue;
|
||||||
void *h = dlopen(map.path.data(), RTLD_LAZY);
|
void *h = dlopen(map.path.data(), RTLD_LAZY);
|
||||||
if (!h) {
|
if (!h) {
|
||||||
@@ -349,7 +353,7 @@ bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
|
|||||||
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
||||||
}
|
}
|
||||||
if (api_version >= 4) {
|
if (api_version >= 4) {
|
||||||
api->v4.pltHookCommit = lsplt::CommitHook;
|
api->v4.pltHookCommit = []() { return lsplt::CommitHook(cached_map_infos); };
|
||||||
api->v4.pltHookRegister = [](dev_t dev, ino_t inode, const char *symbol, void *fn, void **backup) {
|
api->v4.pltHookRegister = [](dev_t dev, ino_t inode, const char *symbol, void *fn, void **backup) {
|
||||||
if (dev == 0 || inode == 0 || symbol == nullptr || fn == nullptr)
|
if (dev == 0 || inode == 0 || symbol == nullptr || fn == nullptr)
|
||||||
return;
|
return;
|
||||||
@@ -383,7 +387,7 @@ void ZygiskContext::plt_hook_exclude(const char *regex, const char *symbol) {
|
|||||||
void ZygiskContext::plt_hook_process_regex() {
|
void ZygiskContext::plt_hook_process_regex() {
|
||||||
if (register_info.empty())
|
if (register_info.empty())
|
||||||
return;
|
return;
|
||||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
for (auto &map : cached_map_infos) {
|
||||||
if (map.offset != 0 || !map.is_private || !(map.perms & PROT_READ)) continue;
|
if (map.offset != 0 || !map.is_private || !(map.perms & PROT_READ)) continue;
|
||||||
for (auto ®: register_info) {
|
for (auto ®: register_info) {
|
||||||
if (regexec(®.regex, map.path.data(), 0, nullptr, 0) != 0)
|
if (regexec(®.regex, map.path.data(), 0, nullptr, 0) != 0)
|
||||||
@@ -411,7 +415,7 @@ bool ZygiskContext::plt_hook_commit() {
|
|||||||
register_info.clear();
|
register_info.clear();
|
||||||
ignore_info.clear();
|
ignore_info.clear();
|
||||||
}
|
}
|
||||||
return lsplt::CommitHook();
|
return lsplt::CommitHook(cached_map_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -719,8 +723,8 @@ ZygiskContext::~ZygiskContext() {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static bool hook_commit() {
|
static bool hook_commit(std::vector<lsplt::MapInfo> &map_infos = cached_map_infos) {
|
||||||
if (lsplt::CommitHook()) {
|
if (lsplt::CommitHook(map_infos)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
LOGE("plt_hook failed");
|
LOGE("plt_hook failed");
|
||||||
@@ -752,23 +756,23 @@ void clean_trace(const char* path, bool spoof_maps) {
|
|||||||
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
|
// spoofing map names is futile in Android, we do it simply
|
||||||
// to avoid Zygisk detections based on string comparison
|
// to avoid Zygisk detections based on string comparison
|
||||||
for (auto &info : lsplt::MapInfo::Scan()) {
|
for (auto &map : lsplt::MapInfo::Scan()) {
|
||||||
if (strstr(info.path.c_str(), path))
|
if (strstr(map.path.c_str(), path))
|
||||||
{
|
{
|
||||||
void *addr = (void *)info.start;
|
void *addr = (void *)map.start;
|
||||||
size_t size = info.end - info.start;
|
size_t size = map.end - map.start;
|
||||||
void *copy = mmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
void *copy = mmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
||||||
if (copy == MAP_FAILED) {
|
if (copy == MAP_FAILED) {
|
||||||
LOGE("failed to backup block %s [%p, %p]", info.path.c_str(), addr, (void*)info.end);
|
LOGE("failed to backup block %s [%p, %p]", map.path.c_str(), addr, (void*)map.end);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((info.perms & PROT_READ) == 0) {
|
if ((map.perms & PROT_READ) == 0) {
|
||||||
mprotect(addr, size, PROT_READ);
|
mprotect(addr, size, PROT_READ);
|
||||||
}
|
}
|
||||||
memcpy(copy, addr, size);
|
memcpy(copy, addr, size);
|
||||||
mremap(copy, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, addr);
|
mremap(copy, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, addr);
|
||||||
mprotect(addr, size, info.perms);
|
mprotect(addr, size, map.perms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -783,7 +787,8 @@ void hook_functions() {
|
|||||||
// ino_t native_bridge_inode = 0;
|
// ino_t native_bridge_inode = 0;
|
||||||
// dev_t native_bridge_dev = 0;
|
// dev_t native_bridge_dev = 0;
|
||||||
|
|
||||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
cached_map_infos = lsplt::MapInfo::Scan();
|
||||||
|
for (auto &map : cached_map_infos) {
|
||||||
if (map.path.ends_with("libandroid_runtime.so")) {
|
if (map.path.ends_with("libandroid_runtime.so")) {
|
||||||
android_runtime_inode = map.inode;
|
android_runtime_inode = map.inode;
|
||||||
android_runtime_dev = map.dev;
|
android_runtime_dev = map.dev;
|
||||||
@@ -809,7 +814,7 @@ static void hook_unloader() {
|
|||||||
ino_t art_inode = 0;
|
ino_t art_inode = 0;
|
||||||
dev_t art_dev = 0;
|
dev_t art_dev = 0;
|
||||||
|
|
||||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
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;
|
||||||
art_dev = map.dev;
|
art_dev = map.dev;
|
||||||
@@ -817,6 +822,12 @@ static void hook_unloader() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (art_dev == 0 || art_inode == 0) {
|
||||||
|
LOGE("virtual map for libart.so is not cached");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
LOGD("hook_unloader called with libart.so [%zu:%lu]", art_dev, art_inode);
|
||||||
|
}
|
||||||
PLT_HOOK_REGISTER(art_dev, art_inode, pthread_attr_setstacksize);
|
PLT_HOOK_REGISTER(art_dev, art_inode, pthread_attr_setstacksize);
|
||||||
hook_commit();
|
hook_commit();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user