Skip to content

Commit

Permalink
improve: drop soinfo records of loaded modules
Browse files Browse the repository at this point in the history
In Bionic linker, the `soinfo` structure has a field `next`, which points to the next loaded library in a linked list consisting of all loaded libraries.
Hence, an injected process can easily find all loaded libraries.
Previously in ReZygisk, module library records are hidden by setting the `pathname` field to be empty, which is futile but easier to detect.
Current idea of dropping record can be found in the following commit:
RikkaApps/Riru@5d635e8
  • Loading branch information
JingMatrix committed Nov 29, 2024
1 parent fade354 commit e3cb1fb
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 23 deletions.
84 changes: 62 additions & 22 deletions loader/src/include/solist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,57 @@ namespace SoList {
return ((std::string *) ((uintptr_t) this + solist_realpath_offset - sizeof(void *)))->c_str();
}

void nullify_name() {
const char **name = (const char**)get_soname_sym(this);
void set_next(SoInfo *si) {
*(SoInfo **) ((uintptr_t) this + solist_next_offset) = si;
}
};

static const char *empty_string = "";
*name = reinterpret_cast<const char *>(&empty_string);
class ProtectedDataGuard {
public:
ProtectedDataGuard() {
if (ctor != nullptr)
(this->*ctor)();
}

void nullify_path() {
const char **name = (const char**)get_realpath_sym(this);
~ProtectedDataGuard() {
if (dtor != nullptr)
(this->*dtor)();
}

static const char *empty_string = "";
*name = reinterpret_cast<const char *>(&empty_string);
static bool setup(const SandHook::ElfImg &linker) {
ctor = MemFunc{.data = {.p = reinterpret_cast<void *>(linker.getSymbAddress(
"__dl__ZN18ProtectedDataGuardC2Ev")), .adj = 0}}.f;
dtor = MemFunc{.data = {.p = reinterpret_cast<void *>(linker.getSymbAddress(
"__dl__ZN18ProtectedDataGuardD2Ev")), .adj = 0}}.f;
return ctor != nullptr && dtor != nullptr;
}

ProtectedDataGuard(const ProtectedDataGuard &) = delete;

void operator=(const ProtectedDataGuard &) = delete;

private:
using FuncType = void (ProtectedDataGuard::*)();

static FuncType ctor;
static FuncType dtor;

union MemFunc {
FuncType f;

struct {
void *p;
std::ptrdiff_t adj;
} data;
};
};


static SoInfo *solist = NULL;
static SoInfo *somain = NULL;
static SoInfo **sonext = NULL;
ProtectedDataGuard::FuncType ProtectedDataGuard::ctor = NULL;
ProtectedDataGuard::FuncType ProtectedDataGuard::dtor = NULL;

template<typename T>
inline T *getStaticPointer(const SandHook::ElfImg &linker, const char *name) {
Expand All @@ -61,25 +95,24 @@ namespace SoList {
return addr == NULL ? NULL : *addr;
}

static void NullifySoName(const char* target_name) {
for (auto *iter = solist; iter; iter = iter->get_next()) {
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
iter->nullify_path();
LOGI("Cleared SOList entry for %s", target_name);
}
}

for (auto *iter = somain; iter; iter = iter->get_next()) {
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
iter->nullify_path();

break;
static void DropSoPath(const char* target_path) {
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;
}
}

static bool Initialize() {
SandHook::ElfImg linker("/linker");
if (!ProtectedDataGuard::setup(linker)) return false;

/* 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 Down Expand Up @@ -107,13 +140,20 @@ namespace 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);

somain = getStaticPointer<SoInfo>(linker, somain_sym_name);
if (somain == NULL) return false;

auto vsdo = getStaticPointer<SoInfo>(linker, vsdo_sym_name);
sonext = linker.getSymbAddress<SoInfo **>(sonext_sym_name);
if (sonext == NULL) return false;

SoInfo *vsdo = getStaticPointer<SoInfo>(linker, vsdo_sym_name);
if (vsdo == NULL) return false;

SoInfo::get_realpath_sym = reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
Expand Down
2 changes: 1 addition & 1 deletion loader/src/injector/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ void ZygiskContext::run_modules_post() {
if (!solist_res) {
LOGE("Failed to initialize SoList");
} else {
SoList::NullifySoName("jit-cache");
SoList::DropSoPath("jit-cache");
}

// Remap as well to avoid checking of /memfd:jit-cache
Expand Down

0 comments on commit e3cb1fb

Please sign in to comment.