You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
merge: Clean up injection traces of ReZygisk (#101)
This merge commit merges the Pull Request by JingMatrix that cleans up the rest of detection points of ReZygisk in non-KSU environments.
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
@@ -11,20 +11,27 @@ namespace SoList {
|
||||
class SoInfo {
|
||||
public:
|
||||
#ifdef __LP64__
|
||||
inline static size_t solist_next_offset = 0x30;
|
||||
inline static size_t solist_size_offset = 0x18;
|
||||
inline static size_t solist_next_offset = 0x28;
|
||||
constexpr static size_t solist_realpath_offset = 0x1a8;
|
||||
#else
|
||||
inline static size_t solist_size_offset = 0x90;
|
||||
inline static size_t solist_next_offset = 0xa4;
|
||||
constexpr static size_t solist_realpath_offset = 0x174;
|
||||
#endif
|
||||
|
||||
inline static const char *(*get_realpath_sym)(SoInfo *) = NULL;
|
||||
inline static const char *(*get_soname_sym)(SoInfo *) = NULL;
|
||||
inline static void (*soinfo_free)(SoInfo *) = NULL;
|
||||
|
||||
inline SoInfo *get_next() {
|
||||
return *(SoInfo **) ((uintptr_t) this + solist_next_offset);
|
||||
}
|
||||
|
||||
inline size_t get_size() {
|
||||
return *(size_t *) ((uintptr_t) this + solist_size_offset);
|
||||
}
|
||||
|
||||
inline const char *get_path() {
|
||||
if (get_realpath_sym) return get_realpath_sym(this);
|
||||
|
||||
@@ -40,6 +47,10 @@ namespace SoList {
|
||||
void set_next(SoInfo *si) {
|
||||
*(SoInfo **) ((uintptr_t) this + solist_next_offset) = si;
|
||||
}
|
||||
|
||||
void set_size(size_t size) {
|
||||
*(size_t *) ((uintptr_t) this + solist_size_offset) = size;
|
||||
}
|
||||
};
|
||||
|
||||
class ProtectedDataGuard {
|
||||
@@ -69,8 +80,8 @@ namespace SoList {
|
||||
private:
|
||||
using FuncType = void (ProtectedDataGuard::*)();
|
||||
|
||||
static FuncType ctor;
|
||||
static FuncType dtor;
|
||||
inline static FuncType ctor = NULL;
|
||||
inline static FuncType dtor = NULL;
|
||||
|
||||
union MemFunc {
|
||||
FuncType f;
|
||||
@@ -86,8 +97,9 @@ namespace SoList {
|
||||
static SoInfo *solist = NULL;
|
||||
static SoInfo *somain = NULL;
|
||||
static SoInfo **sonext = NULL;
|
||||
ProtectedDataGuard::FuncType ProtectedDataGuard::ctor = NULL;
|
||||
ProtectedDataGuard::FuncType ProtectedDataGuard::dtor = NULL;
|
||||
|
||||
static uint64_t *g_module_load_counter = NULL;
|
||||
static uint64_t *g_module_unload_counter = NULL;
|
||||
|
||||
static bool Initialize();
|
||||
|
||||
@@ -98,28 +110,51 @@ namespace SoList {
|
||||
return addr == NULL ? NULL : *addr;
|
||||
}
|
||||
|
||||
static void DropSoPath(const char* target_path) {
|
||||
static bool DropSoPath(const char* target_path) {
|
||||
bool path_found = false;
|
||||
if (solist == NULL && !Initialize()) {
|
||||
LOGE("Failed to initialize solist");
|
||||
return path_found;
|
||||
}
|
||||
for (auto iter = solist; iter; iter = iter->get_next()) {
|
||||
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_path)) {
|
||||
SoList::ProtectedDataGuard guard;
|
||||
LOGI("dropping solist record for %s loaded at %s with size %zu", iter->get_name(), iter->get_path(), iter->get_size());
|
||||
if (iter->get_size() > 0) {
|
||||
iter->set_size(0);
|
||||
SoInfo::soinfo_free(iter);
|
||||
path_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return path_found;
|
||||
}
|
||||
|
||||
static void ResetCounters(size_t load, size_t unload) {
|
||||
if (solist == NULL && !Initialize()) {
|
||||
LOGE("Failed to initialize solist");
|
||||
return;
|
||||
}
|
||||
SoInfo *prev = NULL;
|
||||
for (auto iter = solist; iter; iter = iter->get_next()) {
|
||||
if (prev != NULL && iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_path)) {
|
||||
SoList::ProtectedDataGuard guard;
|
||||
prev->set_next(iter->get_next());
|
||||
if (iter == *sonext) {
|
||||
*sonext = prev;
|
||||
}
|
||||
LOGI("Dropped solist record for %s loaded at %s", iter->get_name(), iter->get_path());
|
||||
}
|
||||
prev = iter;
|
||||
if (g_module_load_counter == NULL || g_module_unload_counter == NULL) {
|
||||
LOGI("g_module counters not defined, skip reseting them");
|
||||
return;
|
||||
}
|
||||
auto loaded_modules = *g_module_load_counter;
|
||||
auto unloaded_modules = *g_module_unload_counter;
|
||||
if (loaded_modules >= load) {
|
||||
*g_module_load_counter = loaded_modules - load;
|
||||
LOGD("reset g_module_load_counter to %zu", (size_t) *g_module_load_counter);
|
||||
}
|
||||
if (unloaded_modules >= unload) {
|
||||
*g_module_unload_counter = unloaded_modules - unload;
|
||||
LOGD("reset g_module_unload_counter to %zu", (size_t) *g_module_unload_counter);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Initialize() {
|
||||
SandHook::ElfImg linker("/linker");
|
||||
if (!ProtectedDataGuard::setup(linker)) return false;
|
||||
LOGD("found symbol ProtectedDataGuard");
|
||||
|
||||
/* INFO: Since Android 15, the symbol names for the linker have a suffix,
|
||||
this makes it impossible to hardcode the symbol names. To allow
|
||||
@@ -131,6 +166,11 @@ namespace SoList {
|
||||
|
||||
std::string_view solist_sym_name = linker.findSymbolNameByPrefix("__dl__ZL6solist");
|
||||
if (solist_sym_name.empty()) return false;
|
||||
LOGD("found symbol name %s", solist_sym_name.data());
|
||||
|
||||
std::string_view soinfo_free_name = linker.findSymbolNameByPrefix("__dl__ZL11soinfo_freeP6soinfo");
|
||||
if (soinfo_free_name.empty()) return false;
|
||||
LOGD("found symbol name %s", soinfo_free_name.data());
|
||||
|
||||
/* INFO: The size isn't a magic number, it's the size for the string: .llvm.7690929523238822858 */
|
||||
char llvm_sufix[25 + 1];
|
||||
@@ -143,6 +183,7 @@ namespace SoList {
|
||||
|
||||
solist = getStaticPointer<SoInfo>(linker, solist_sym_name.data());
|
||||
if (solist == NULL) return false;
|
||||
LOGD("found symbol solist");
|
||||
|
||||
char somain_sym_name[sizeof("__dl__ZL6somain") + sizeof(llvm_sufix)];
|
||||
snprintf(somain_sym_name, sizeof(somain_sym_name), "__dl__ZL6somain%s", llvm_sufix);
|
||||
@@ -150,30 +191,52 @@ namespace SoList {
|
||||
char sonext_sym_name[sizeof("__dl__ZL6sonext") + sizeof(llvm_sufix)];
|
||||
snprintf(sonext_sym_name, sizeof(somain_sym_name), "__dl__ZL6sonext%s", llvm_sufix);
|
||||
|
||||
char vsdo_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)];
|
||||
snprintf(vsdo_sym_name, sizeof(vsdo_sym_name), "__dl__ZL4vdso%s", llvm_sufix);
|
||||
char vdso_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)];
|
||||
snprintf(vdso_sym_name, sizeof(vdso_sym_name), "__dl__ZL4vdso%s", llvm_sufix);
|
||||
|
||||
somain = getStaticPointer<SoInfo>(linker, somain_sym_name);
|
||||
if (somain == NULL) return false;
|
||||
LOGD("found symbol somain");
|
||||
|
||||
sonext = linker.getSymbAddress<SoInfo **>(sonext_sym_name);
|
||||
if (sonext == NULL) return false;
|
||||
LOGD("found symbol sonext");
|
||||
|
||||
SoInfo *vsdo = getStaticPointer<SoInfo>(linker, vsdo_sym_name);
|
||||
if (vsdo == NULL) return false;
|
||||
SoInfo *vdso = getStaticPointer<SoInfo>(linker, vdso_sym_name);
|
||||
if (vdso != NULL) LOGD("found symbol vdso");
|
||||
|
||||
SoInfo::get_realpath_sym = reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
|
||||
if (SoInfo::get_realpath_sym == NULL) return false;
|
||||
LOGD("found symbol get_realpath_sym");
|
||||
|
||||
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
|
||||
if (SoInfo::get_soname_sym == NULL) return false;
|
||||
LOGD("found symbol get_soname_sym");
|
||||
|
||||
SoInfo::soinfo_free = reinterpret_cast<decltype(SoInfo::soinfo_free)>(linker.getSymbAddress(soinfo_free_name));
|
||||
if (SoInfo::soinfo_free == NULL) return false;
|
||||
LOGD("found symbol soinfo_free");
|
||||
|
||||
g_module_load_counter = reinterpret_cast<decltype(g_module_load_counter)>(linker.getSymbAddress("__dl__ZL21g_module_load_counter"));
|
||||
if (g_module_load_counter != NULL) LOGD("found symbol g_module_load_counter");
|
||||
|
||||
g_module_unload_counter = reinterpret_cast<decltype(g_module_unload_counter)>(linker.getSymbAddress("__dl__ZL23g_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++) {
|
||||
auto *possible_next = *(void **) ((uintptr_t) solist + i * sizeof(void *));
|
||||
if (possible_next == somain || (vsdo != NULL && possible_next == vsdo)) {
|
||||
auto possible_field = (uintptr_t) solist + i * sizeof(void *);
|
||||
auto possible_size_of_somain = *(size_t *)((uintptr_t) somain + i * sizeof(void *));
|
||||
if (possible_size_of_somain < 0x100000 && possible_size_of_somain > 0x100) {
|
||||
SoInfo::solist_size_offset = i * sizeof(void *);
|
||||
LOGD("solist_size_offset is %zu * %zu = %p", i, sizeof(void *), (void*) SoInfo::solist_size_offset);
|
||||
}
|
||||
if (*(void **)possible_field == somain || (vdso != NULL && *(void **)possible_field == vdso)) {
|
||||
SoInfo::solist_next_offset = i * sizeof(void *);
|
||||
|
||||
LOGD("solist_next_offset is %zu * %zu = %p", i, sizeof(void *), (void*) SoInfo::solist_next_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (SoInfo::get_realpath_sym != NULL && SoInfo::get_soname_sym != NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "daemon.h"
|
||||
#include "logging.h"
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void *self_handle = nullptr;
|
||||
void *start_addr = nullptr;
|
||||
size_t block_size = 0;
|
||||
|
||||
extern "C" [[gnu::visibility("default")]]
|
||||
void entry(void* handle, const char* path) {
|
||||
void entry(void* addr, size_t size, const char* path) {
|
||||
LOGI("Zygisk library injected, version %s", ZKSU_VERSION);
|
||||
self_handle = handle;
|
||||
start_addr = addr;
|
||||
block_size = size;
|
||||
zygiskd::Init(path);
|
||||
|
||||
if (!zygiskd::PingHeartbeat()) {
|
||||
@@ -22,6 +23,7 @@ void entry(void* handle, const char* path) {
|
||||
logging::setfd(zygiskd::RequestLogcatFd());
|
||||
#endif
|
||||
|
||||
LOGI("Start hooking");
|
||||
LOGI("start plt hooking");
|
||||
hook_functions();
|
||||
clean_trace(path, 1, 0, false);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -176,22 +177,24 @@ DCL_HOOK_FUNC(void, android_log_close) {
|
||||
|
||||
// We cannot directly call `dlclose` to unload ourselves, otherwise when `dlclose` returns,
|
||||
// it will return to our code which has been unmapped, causing segmentation fault.
|
||||
// Instead, we hook `pthread_attr_destroy` which will be called when VM daemon threads start.
|
||||
DCL_HOOK_FUNC(int, pthread_attr_destroy, void *target) {
|
||||
int res = old_pthread_attr_destroy((pthread_attr_t *)target);
|
||||
// Instead, we hook `pthread_attr_setstacksize` which will be called when VM daemon threads start.
|
||||
DCL_HOOK_FUNC(int, pthread_attr_setstacksize, void *target, size_t size) {
|
||||
int res = old_pthread_attr_setstacksize((pthread_attr_t *)target, size);
|
||||
LOGV("Call pthread_attr_setstacksize in [tid, pid]: %d, %d", gettid(), getpid());
|
||||
|
||||
// Only perform unloading on the main thread
|
||||
if (gettid() != getpid())
|
||||
return res;
|
||||
|
||||
LOGV("pthread_attr_destroy");
|
||||
if (should_unmap_zygisk) {
|
||||
unhook_functions();
|
||||
cached_map_infos.clear();
|
||||
if (should_unmap_zygisk) {
|
||||
// Because both `pthread_attr_destroy` 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
|
||||
// `dlclose` will directly return to the caller of `pthread_attr_destroy`.
|
||||
[[clang::musttail]] return dlclose(self_handle);
|
||||
// `dlclose` will directly return to the caller of `pthread_attr_setstacksize`.
|
||||
LOGI("unmap libzygisk.so loaded at %p with size %zu", start_addr, block_size);
|
||||
[[clang::musttail]] return munmap(start_addr, block_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,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);
|
||||
@@ -267,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) {
|
||||
@@ -348,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;
|
||||
@@ -382,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)
|
||||
@@ -410,7 +415,7 @@ bool ZygiskContext::plt_hook_commit() {
|
||||
register_info.clear();
|
||||
ignore_info.clear();
|
||||
}
|
||||
return lsplt::CommitHook();
|
||||
return lsplt::CommitHook(cached_map_infos);
|
||||
}
|
||||
|
||||
|
||||
@@ -573,88 +578,20 @@ void ZygiskContext::run_modules_pre() {
|
||||
|
||||
void ZygiskContext::run_modules_post() {
|
||||
flags[POST_SPECIALIZE] = true;
|
||||
|
||||
size_t modules_unloaded = 0;
|
||||
for (const auto &m : modules) {
|
||||
if (flags[APP_SPECIALIZE]) {
|
||||
m.postAppSpecialize(args.app);
|
||||
} else if (flags[SERVER_FORK_AND_SPECIALIZE]) {
|
||||
m.postServerSpecialize(args.server);
|
||||
}
|
||||
m.tryUnload();
|
||||
if (m.tryUnload()) modules_unloaded++;
|
||||
}
|
||||
|
||||
SoList::DropSoPath("jit-cache");
|
||||
|
||||
// Remap as well to avoid checking of /memfd:jit-cache
|
||||
for (auto &info : lsplt::MapInfo::Scan()) {
|
||||
if (strstr(info.path.c_str(), "jit-cache-zygisk"))
|
||||
{
|
||||
void *addr = (void *)info.start;
|
||||
size_t size = info.end - info.start;
|
||||
// MAP_SHARED should fix the suspicious mapping.
|
||||
void *copy = mmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
||||
if (copy == MAP_FAILED) {
|
||||
LOGE("Failed to mmap jit-cache-zygisk");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((info.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);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't know if there's a header for things like this
|
||||
// so I just put it into a lambda
|
||||
auto generateRandomString = [](char *str, int length) {
|
||||
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
srand(time(NULL));
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int key = rand() % (sizeof(charset) - 1);
|
||||
str[i] = charset[key];
|
||||
}
|
||||
|
||||
str[length] = '\0';
|
||||
};
|
||||
|
||||
// Randomize name of anonymous mappings
|
||||
// We don't run this in the previous loop because LSPosed might also add
|
||||
// mappings that are not related to /memfd:jit-zygisk-cache
|
||||
//
|
||||
// Since we changed to MAP_SHARED, I don't think this is still needed but let's
|
||||
// leave it here just in case.
|
||||
for (auto info : lsplt::MapInfo::Scan()) {
|
||||
// I had some problems with info.perms & PROT_EXEC so I had to change lsplt source a bit.
|
||||
// If that problem occurs here, do strchr(info.perms_str.c_str(), 'x') instead and add perms_str
|
||||
// to the lsplt MapInfo struct and set it to the raw perms string in Scan();
|
||||
if (info.perms & PROT_EXEC && info.path.empty()) {
|
||||
// Generate Random Name
|
||||
char randomString[11];
|
||||
generateRandomString(randomString, 10);
|
||||
LOGI("Randomized Memory map name: %s", randomString);
|
||||
|
||||
// Memory address of random string
|
||||
uintptr_t strAddr = (uintptr_t)&randomString;
|
||||
|
||||
// https://lore.kernel.org/lkml/1383170047-21074-2-git-send-email-ccross@android.com/
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, info.start, info.end - info.start, strAddr);
|
||||
}
|
||||
|
||||
// Remap as MAP_SHARED
|
||||
if (info.perms & PROT_EXEC && info.dev == 0 && info.path.find("anon") != std::string::npos) {
|
||||
void *addr = reinterpret_cast<void *>(info.start);
|
||||
size_t size = info.end - info.start;
|
||||
void *copy = mmap(nullptr, size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
||||
if ((info.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);
|
||||
}
|
||||
if (modules.size() > 0) {
|
||||
LOGD("modules unloaded: %zu/%zu", modules_unloaded, modules.size());
|
||||
clean_trace("jit-cache-zygisk", modules.size(), modules_unloaded, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,8 +728,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");
|
||||
@@ -814,6 +751,37 @@ static void hook_register(dev_t dev, ino_t inode, const char *symbol, void *new_
|
||||
#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
|
||||
PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
|
||||
|
||||
void clean_trace(const char* path, size_t load, size_t unload, bool spoof_maps) {
|
||||
LOGD("cleaning trace for path %s", path);
|
||||
|
||||
if (load > 0 || unload >0) SoList::ResetCounters(load, unload);
|
||||
bool path_found = SoList::DropSoPath(path);
|
||||
if (!path_found || !spoof_maps) return;
|
||||
|
||||
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 &map : lsplt::MapInfo::Scan()) {
|
||||
if (strstr(map.path.c_str(), path))
|
||||
{
|
||||
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]", map.path.c_str(), addr, (void*)map.end);
|
||||
continue;
|
||||
}
|
||||
|
||||
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, map.perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hook_functions() {
|
||||
default_new(plt_hook_list);
|
||||
default_new(jni_hook_list);
|
||||
@@ -824,7 +792,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;
|
||||
@@ -850,7 +819,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;
|
||||
@@ -858,7 +827,13 @@ static void hook_unloader() {
|
||||
}
|
||||
}
|
||||
|
||||
PLT_HOOK_REGISTER(art_dev, art_inode, pthread_attr_destroy);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include "api.hpp"
|
||||
|
||||
@@ -209,7 +210,7 @@ case 5: \
|
||||
int getModuleDir() const;
|
||||
void setOption(zygisk::Option opt);
|
||||
static uint32_t getFlags();
|
||||
void tryUnload() const { if (unload) dlclose(handle); }
|
||||
bool tryUnload() const { return unload && dlclose(handle) == 0; };
|
||||
void clearApi() { memset(&api, 0, sizeof(api)); }
|
||||
int getId() const { return id; }
|
||||
|
||||
@@ -235,4 +236,4 @@ case 5: \
|
||||
} mod;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
extern void *self_handle;
|
||||
extern void *start_addr;
|
||||
extern size_t block_size;
|
||||
|
||||
void hook_functions();
|
||||
|
||||
void clean_trace(const char* path, size_t load = 1, size_t unload = 0, bool spoof_maps = false);
|
||||
|
||||
void revert_unmount_ksu();
|
||||
|
||||
void revert_unmount_magisk();
|
||||
|
||||
@@ -222,10 +222,24 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* call injector entry(handle, path) */
|
||||
/* record the address range of libzygisk.so */
|
||||
map = MapInfo::Scan(std::to_string(pid));
|
||||
void *start_addr = nullptr;
|
||||
size_t block_size = 0;
|
||||
for (auto &info : map) {
|
||||
if (strstr(info.path.c_str(), "libzygisk.so")) {
|
||||
void *addr = (void *)info.start;
|
||||
if (start_addr == nullptr) start_addr = addr;
|
||||
size_t size = info.end - info.start;
|
||||
block_size += size;
|
||||
LOGD("found block %s: [%p-%p] with size %zu", info.path.c_str(), addr, (void *)info.end, size);
|
||||
}
|
||||
}
|
||||
|
||||
/* call injector entry(start_addr, block_size, path) */
|
||||
args.clear();
|
||||
args.push_back(remote_handle);
|
||||
args.push_back((uintptr_t) start_addr);
|
||||
args.push_back(block_size);
|
||||
str = push_string(pid, regs, zygiskd::GetTmpPath().c_str());
|
||||
args.push_back((long) str);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user