Skip to content

Commit

Permalink
merge: Clean up injection traces of ReZygisk (PerformanC#101)
Browse files Browse the repository at this point in the history
This merge commit merges the Pull Request by JingMatrix that cleans up the rest of detection points of ReZygisk in non-KSU environments.
  • Loading branch information
ThePedroo authored Dec 18, 2024
2 parents 8fb5d91 + 0671f2e commit 4b7618d
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 126 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -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
107 changes: 85 additions & 22 deletions loader/src/include/solist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -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();

Expand All @@ -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;
return path_found;
}
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)) {
if (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("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;
}
LOGI("Dropped solist record for %s loaded at %s", iter->get_name(), iter->get_path());
}
prev = iter;
}
return path_found;
}

static void ResetCounters(size_t load, size_t unload) {
if (solist == NULL && !Initialize()) {
LOGE("Failed to initialize solist");
return;
}
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
Expand All @@ -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];
Expand All @@ -143,37 +183,60 @@ 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);

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;
}
}
12 changes: 7 additions & 5 deletions loader/src/injector/entry.cpp
Original file line number Diff line number Diff line change
@@ -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()) {
Expand All @@ -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);
}
Loading

0 comments on commit 4b7618d

Please sign in to comment.