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"]
|
||||
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;
|
||||
map<string, vector<JNINativeMethod>, StringCmp> *jni_hook_list;
|
||||
bool should_unmap_zygisk = false;
|
||||
std::vector<lsplt::MapInfo> cached_map_infos = {};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -187,6 +188,7 @@ DCL_HOOK_FUNC(int, pthread_attr_setstacksize, void *target, size_t size) {
|
||||
|
||||
if (should_unmap_zygisk) {
|
||||
unhook_functions();
|
||||
cached_map_infos.clear();
|
||||
if (should_unmap_zygisk) {
|
||||
// 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
|
||||
@@ -205,6 +207,8 @@ DCL_HOOK_FUNC(char *, strdup, const char *s) {
|
||||
if (strcmp(s, "com.android.internal.os.ZygoteInit") == 0) {
|
||||
LOGV("strdup %s", s);
|
||||
initialize_jni_hook();
|
||||
cached_map_infos = lsplt::MapInfo::Scan();
|
||||
LOGD("cached_map_infos updated");
|
||||
}
|
||||
|
||||
return old_strdup(s);
|
||||
@@ -268,7 +272,7 @@ void initialize_jni_hook() {
|
||||
auto get_created_java_vms = reinterpret_cast<jint (*)(JavaVM **, jsize, jsize *)>(
|
||||
dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"));
|
||||
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;
|
||||
void *h = dlopen(map.path.data(), RTLD_LAZY);
|
||||
if (!h) {
|
||||
@@ -349,7 +353,7 @@ bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
|
||||
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
||||
}
|
||||
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) {
|
||||
if (dev == 0 || inode == 0 || symbol == nullptr || fn == nullptr)
|
||||
return;
|
||||
@@ -383,7 +387,7 @@ void ZygiskContext::plt_hook_exclude(const char *regex, const char *symbol) {
|
||||
void ZygiskContext::plt_hook_process_regex() {
|
||||
if (register_info.empty())
|
||||
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;
|
||||
for (auto ®: register_info) {
|
||||
if (regexec(®.regex, map.path.data(), 0, nullptr, 0) != 0)
|
||||
@@ -411,7 +415,7 @@ bool ZygiskContext::plt_hook_commit() {
|
||||
register_info.clear();
|
||||
ignore_info.clear();
|
||||
}
|
||||
return lsplt::CommitHook();
|
||||
return lsplt::CommitHook(cached_map_infos);
|
||||
}
|
||||
|
||||
|
||||
@@ -719,8 +723,8 @@ ZygiskContext::~ZygiskContext() {
|
||||
|
||||
} // namespace
|
||||
|
||||
static bool hook_commit() {
|
||||
if (lsplt::CommitHook()) {
|
||||
static bool hook_commit(std::vector<lsplt::MapInfo> &map_infos = cached_map_infos) {
|
||||
if (lsplt::CommitHook(map_infos)) {
|
||||
return true;
|
||||
} else {
|
||||
LOGE("plt_hook failed");
|
||||
@@ -752,23 +756,23 @@ void clean_trace(const char* path, bool spoof_maps) {
|
||||
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
|
||||
for (auto &info : lsplt::MapInfo::Scan()) {
|
||||
if (strstr(info.path.c_str(), path))
|
||||
for (auto &map : lsplt::MapInfo::Scan()) {
|
||||
if (strstr(map.path.c_str(), path))
|
||||
{
|
||||
void *addr = (void *)info.start;
|
||||
size_t size = info.end - info.start;
|
||||
void *addr = (void *)map.start;
|
||||
size_t size = map.end - map.start;
|
||||
void *copy = mmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
if ((info.perms & PROT_READ) == 0) {
|
||||
if ((map.perms & PROT_READ) == 0) {
|
||||
mprotect(addr, size, PROT_READ);
|
||||
}
|
||||
memcpy(copy, addr, size);
|
||||
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;
|
||||
// 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")) {
|
||||
android_runtime_inode = map.inode;
|
||||
android_runtime_dev = map.dev;
|
||||
@@ -809,7 +814,7 @@ static void hook_unloader() {
|
||||
ino_t art_inode = 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")) {
|
||||
art_inode = map.inode;
|
||||
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);
|
||||
hook_commit();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user