From 45ab709bbd4ddf50b2c8fd05a6cbd048ed776f46 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Sat, 25 Sep 2021 15:36:02 +0200 Subject: [PATCH] Simplify hooking implementation --- linker/linker.cpp | 24 ++++++++++++++++++++++-- linker/linker_soinfo.cpp | 35 ++++++++++++++++++----------------- linker/linker_soinfo.h | 8 ++++++-- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index bc1759a09..869c2b2b4 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -663,7 +663,13 @@ class LoadTask { auto extinfo = this->get_extinfo(); if(extinfo && extinfo->flags & ANDROID_DLEXT_MCPELAUNCHER_HOOKS) { for(auto hook = extinfo->mcpelauncher_hooks; hook->name; hook++) { - (si_->symbols[hook->name] = std::make_shared())->st_value = (ElfW(Addr))hook->value - si_->load_bias; + auto entry = std::make_shared(); + entry->symbol.st_value = (ElfW(Addr))hook->value - si_->load_bias; + entry->symbol.st_info = STB_GLOBAL << 4; + entry->symbol.st_shndx = 1; + hook->value = nullptr; + entry->orig = &hook->value; + si_->symbols[hook->name] = std::move(entry); } } @@ -2278,6 +2284,16 @@ void* do_dlopen(const char* name, int flags, "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p", si->get_realpath(), si->get_soname(), handle); si->call_constructors(); + if(extinfo && extinfo->flags & ANDROID_DLEXT_MCPELAUNCHER_HOOKS) { + for(auto&& sym : si->symbols) { + // Check if this symbol isn't relocated do a fake lookup to enshure orig is set + if(sym.second->orig != nullptr && *sym.second->orig == 0) { + void* val; + do_dlsym(handle, sym.first.data(), nullptr, nullptr, &val); + } + sym.second->orig = nullptr; + } + } failure_guard.Disable(); LD_LOG(kLogDlopen, "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p", @@ -2858,7 +2874,11 @@ soinfo *soinfo::load_library(const char *name, const std::unordered_mapsymbols.reserve(symbols.size()); for (auto&& s : symbols) { if(s.second) { - (lib->symbols[s.first] = std::make_shared())->st_value = (ElfW(Addr))s.second; + auto entry = std::make_shared(); + entry->symbol.st_value = (ElfW(Addr))s.second; + entry->symbol.st_info = STB_GLOBAL << 4; + entry->symbol.st_shndx = 1; + lib->symbols[s.first] = std::move(entry); } else { async_safe_format_log(2, "load_library", "Undefined symbol %s", s.first.c_str()); } diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp index 6fffc4916..603480861 100644 --- a/linker/linker_soinfo.cpp +++ b/linker/linker_soinfo.cpp @@ -97,6 +97,10 @@ void SymbolLookupList::set_dt_symbolic_lib(soinfo* lib) { begin_ = lib ? &libs_[0] : &libs_[1]; } +bool SymbolLookupLib::needs_sysv_lookup() const { + return si_ != nullptr && (gnu_bloom_filter_ == nullptr || si_->symbols.size() > 0); +} + // Check whether a requested version matches the version on a symbol definition. There are a few // special cases: // - If the defining DSO has no version info at all, then any version matches. @@ -148,19 +152,6 @@ soinfo_do_lookup_impl(const char* name, const version_info* vi, name, lib->si_->get_realpath(), reinterpret_cast(lib->si_->base)); } - if (lib->si_->symbols.size()) { - // Custom overrides - auto sym = lib->si_->symbols.find(name); - if(sym != lib->si_->symbols.end()) { - // if(!strcmp("mcpelauncher_vlog", name)) { - // // throw 0; - // int i = 0; - // } - *si_found_in = lib->si_; - return sym->second.get(); - } - } - const uint32_t word_num = (hash / kBloomMaskBits) & lib->gnu_maskwords_; const ElfW(Addr) bloom_word = lib->gnu_bloom_filter_[word_num]; const uint32_t h1 = hash % kBloomMaskBits; @@ -338,19 +329,29 @@ SymbolLookupLib soinfo::get_lookup_lib() { const ElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name, const version_info* vi) const { + void** orig = nullptr; + ElfW(Sym)* ret = nullptr; if (this->symbols.size()) { // Custom Library auto sym = this->symbols.find(symbol_name.get_name()); if(sym != this->symbols.end()) { auto n = symbol_name.get_name(); - - return sym->second.get(); + orig = sym->second->orig; + ret = &sym->second->symbol; } } if(this->bucket_) { - return is_gnu_hash() ? gnu_lookup(symbol_name, vi) : elf_lookup(symbol_name, vi); + auto&& ret2 = is_gnu_hash() ? gnu_lookup(symbol_name, vi) : elf_lookup(symbol_name, vi); + if(!ret) { + return ret2; + } else { + if(orig != nullptr) { + *orig = ret2 ? (void*)(ret2->st_value + load_bias) : nullptr; + } + return ret; + } } - return (ElfW(Sym)*)nullptr; + return ret; } const ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name, const version_info* vi) const { diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h index bd8eb1367..f2525c2f2 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -91,7 +91,7 @@ struct SymbolLookupLib { soinfo* si_ = nullptr; - bool needs_sysv_lookup() const { return si_ != nullptr && gnu_bloom_filter_ == nullptr; } + bool needs_sysv_lookup() const; }; // A list of libraries to search for a symbol. @@ -442,7 +442,11 @@ struct soinfo { std::vector tlsdesc_args_; public: - std::unordered_map> symbols; + struct HookEntry { + ElfW(Sym) symbol; + void** orig; + }; + std::unordered_map> symbols; }; // This function is used by dlvsym() to calculate hash of sym_ver