Skip to content

Commit 3d79939

Browse files
committed
fix: linker64 static symbols lookup with suffix
On Android 15+ in some devices, the symbol names of some static variables such as `solist`, has a `llvm` suffix in its exported name. Current commit handles this case and close #63 as fixed.
1 parent 9bcbec9 commit 3d79939

3 files changed

Lines changed: 139 additions & 76 deletions

File tree

loader/src/common/elf_util.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,41 @@ ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
179179
}
180180
}
181181
}
182+
182183
if (auto i = symtabs_.find(name); i != symtabs_.end()) {
183184
return i->second->st_value;
184185
} else {
185186
return 0;
186187
}
187188
}
188189

190+
std::string_view ElfImg::LinearLookupByPrefix(std::string_view name) const {
191+
if (symtabs_.empty()) {
192+
symtabs_.reserve(symtab_count);
193+
if (symtab_start != nullptr && symstr_offset_for_symtab != 0) {
194+
for (ElfW(Off) i = 0; i < symtab_count; i++) {
195+
unsigned int st_type = ELF_ST_TYPE(symtab_start[i].st_info);
196+
const char *st_name = offsetOf<const char *>(header, symstr_offset_for_symtab +
197+
symtab_start[i].st_name);
198+
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && symtab_start[i].st_size) {
199+
symtabs_.emplace(st_name, &symtab_start[i]);
200+
}
201+
}
202+
}
203+
}
204+
205+
auto size = name.size();
206+
for (auto symtab : symtabs_) {
207+
if (symtab.first.size() < size) continue;
208+
209+
if (symtab.first.substr(0, size) == name) {
210+
return symtab.first;
211+
}
212+
}
213+
214+
return "";
215+
}
216+
189217

190218
ElfImg::~ElfImg() {
191219
//open elf file local

loader/src/include/elf_util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ namespace SandHook {
4848
}
4949
}
5050

51+
std::string_view findSymbolNameByPrefix(std::string_view prefix) const {
52+
return LinearLookupByPrefix(prefix);
53+
}
54+
5155
template<typename T>
5256
constexpr T getSymbAddress(std::string_view name) const {
5357
return reinterpret_cast<T>(getSymbAddress(name));
@@ -72,6 +76,8 @@ namespace SandHook {
7276

7377
ElfW(Addr) LinearLookup(std::string_view name) const;
7478

79+
std::string_view LinearLookupByPrefix(std::string_view name) const;
80+
7581
constexpr static uint32_t ElfHash(std::string_view name);
7682

7783
constexpr static uint32_t GnuHash(std::string_view name);

loader/src/include/solist.hpp

Lines changed: 105 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -6,98 +6,127 @@
66
#include <string>
77
#include "elf_util.h"
88

9-
namespace SoList
10-
{
11-
class SoInfo {
12-
public:
13-
#ifdef __LP64__
9+
namespace SoList {
10+
class SoInfo {
11+
public:
12+
#ifdef __LP64__
1413
inline static size_t solist_next_offset = 0x30;
1514
constexpr static size_t solist_realpath_offset = 0x1a8;
16-
#else
15+
#else
1716
inline static size_t solist_next_offset = 0xa4;
1817
constexpr static size_t solist_realpath_offset = 0x174;
19-
#endif
18+
#endif
2019

21-
inline static const char *(*get_realpath_sym)(SoInfo *) = nullptr;
22-
inline static const char *(*get_soname_sym)(SoInfo *) = nullptr;
20+
inline static const char *(*get_realpath_sym)(SoInfo *) = NULL;
21+
inline static const char *(*get_soname_sym)(SoInfo *) = NULL;
2322

24-
inline SoInfo *get_next() {
25-
return *(SoInfo **) ((uintptr_t) this + solist_next_offset);
26-
}
23+
inline SoInfo *get_next() {
24+
return *(SoInfo **) ((uintptr_t) this + solist_next_offset);
25+
}
2726

28-
inline const char *get_path() {
29-
return get_realpath_sym ? get_realpath_sym(this) : ((std::string *) ((uintptr_t) this + solist_realpath_offset))->c_str();
30-
}
27+
inline const char *get_path() {
28+
if (get_realpath_sym) return get_realpath_sym(this);
3129

32-
inline const char *get_name() {
33-
return get_soname_sym ? get_soname_sym(this) : *((const char **) ((uintptr_t) this + solist_realpath_offset - sizeof(void *)));
34-
}
30+
return ((std::string *) ((uintptr_t) this + solist_realpath_offset))->c_str();
31+
}
3532

36-
void nullify_name() {
37-
const char** name = (const char**)get_soname_sym(this);
33+
inline const char *get_name() {
34+
if (get_soname_sym) return get_soname_sym(this);
3835

39-
static const char* empty_string = "";
40-
*name = reinterpret_cast<const char *>(&empty_string);
41-
}
36+
return ((std::string *) ((uintptr_t) this + solist_realpath_offset - sizeof(void *)))->c_str();
37+
}
4238

43-
void nullify_path() {
44-
const char** name = (const char**)get_realpath_sym(this);
39+
void nullify_name() {
40+
const char **name = (const char**)get_soname_sym(this);
4541

46-
static const char* empty_string = "";
47-
*name = reinterpret_cast<const char *>(&empty_string);
48-
}
49-
};
42+
static const char *empty_string = "";
43+
*name = reinterpret_cast<const char *>(&empty_string);
44+
}
5045

51-
static SoInfo *solist = nullptr;
52-
static SoInfo *somain = nullptr;
46+
void nullify_path() {
47+
const char **name = (const char**)get_realpath_sym(this);
5348

54-
template<typename T>
55-
inline T *getStaticPointer(const SandHook::ElfImg &linker, const char* name)
56-
{
57-
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name));
58-
return addr == nullptr ? nullptr : *addr;
49+
static const char *empty_string = "";
50+
*name = reinterpret_cast<const char *>(&empty_string);
51+
}
52+
};
53+
54+
static SoInfo *solist = NULL;
55+
static SoInfo *somain = NULL;
56+
57+
template<typename T>
58+
inline T *getStaticPointer(const SandHook::ElfImg &linker, const char *name) {
59+
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name));
60+
61+
return addr == NULL ? NULL : *addr;
62+
}
63+
64+
static void NullifySoName(const char* target_name) {
65+
for (auto *iter = solist; iter; iter = iter->get_next()) {
66+
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
67+
iter->nullify_path();
68+
LOGI("Cleared SOList entry for %s", target_name);
69+
}
70+
}
71+
72+
for (auto *iter = somain; iter; iter = iter->get_next()) {
73+
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
74+
iter->nullify_path();
75+
76+
break;
77+
}
5978
}
79+
}
80+
81+
static bool Initialize() {
82+
SandHook::ElfImg linker("/linker");
83+
84+
/* INFO: Since Android 15, the symbol names for the linker have a suffix,
85+
this makes it impossible to hardcode the symbol names. To allow
86+
this to work on all versions, we need to iterate over the loaded
87+
symbols and find the correct ones.
88+
89+
See #63 for more information.
90+
*/
6091

61-
static void NullifySoName(const char* target_name) {
62-
for (auto *iter = solist; iter; iter = iter->get_next()) {
63-
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
64-
iter->nullify_path();
65-
LOGI("Cleared SOList entry for %s", target_name);
66-
}
67-
}
68-
69-
for (auto *iter = somain; iter; iter = iter->get_next()) {
70-
if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_name)) {
71-
iter->nullify_path();
72-
break;
73-
}
74-
}
92+
std::string_view solist_sym_name = linker.findSymbolNameByPrefix("__dl__ZL6solist");
93+
if (solist_sym_name.empty()) return false;
94+
95+
/* INFO: The size isn't a magic number, it's the size for the string: .llvm.7690929523238822858 */
96+
char llvm_sufix[25 + 1];
97+
98+
if (solist_sym_name.length() != strlen("__dl__ZL6solist")) {
99+
strncpy(llvm_sufix, solist_sym_name.data() + strlen("__dl__ZL6solist"), sizeof(llvm_sufix));
100+
} else {
101+
llvm_sufix[0] = '\0';
75102
}
76103

77-
static bool Initialize() {
78-
SandHook::ElfImg linker("/linker");
79-
solist = getStaticPointer<SoInfo>(linker, "__dl__ZL6solist");
80-
somain = getStaticPointer<SoInfo>(linker, "__dl__ZL6somain");
81-
82-
if (solist != nullptr && somain != nullptr)
83-
{
84-
SoInfo::get_realpath_sym = reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
85-
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
86-
auto vsdo = getStaticPointer<SoInfo>(linker, "__dl__ZL4vdso");
87-
88-
for (size_t i = 0; i < 1024 / sizeof(void *); i++)
89-
{
90-
auto *possible_next = *(void **) ((uintptr_t) solist + i * sizeof(void *));
91-
if (possible_next == somain || (vsdo != nullptr && possible_next == vsdo))
92-
{
93-
SoInfo::solist_next_offset = i * sizeof(void *);
94-
break;
95-
}
96-
}
97-
98-
return (SoInfo::get_realpath_sym != nullptr && SoInfo::get_soname_sym != nullptr);
99-
}
100-
101-
return false;
104+
solist = getStaticPointer<SoInfo>(linker, solist_sym_name.data());
105+
if (solist == NULL) return false;
106+
107+
char somain_sym_name[sizeof("__dl__ZL6somain") + sizeof(llvm_sufix)];
108+
snprintf(somain_sym_name, sizeof(somain_sym_name), "__dl__ZL6somain%s", llvm_sufix);
109+
110+
char vsdo_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)];
111+
snprintf(vsdo_sym_name, sizeof(vsdo_sym_name), "__dl__ZL4vdso%s", llvm_sufix);
112+
113+
somain = getStaticPointer<SoInfo>(linker, somain_sym_name);
114+
if (somain == NULL) return false;
115+
116+
auto vsdo = getStaticPointer<SoInfo>(linker, vsdo_sym_name);
117+
118+
SoInfo::get_realpath_sym = reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
119+
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
120+
121+
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
122+
auto *possible_next = *(void **) ((uintptr_t) solist + i * sizeof(void *));
123+
if (possible_next == somain || (vsdo != NULL && possible_next == vsdo)) {
124+
SoInfo::solist_next_offset = i * sizeof(void *);
125+
126+
break;
127+
}
102128
}
103-
}
129+
130+
return (SoInfo::get_realpath_sym != NULL && SoInfo::get_soname_sym != NULL);
131+
}
132+
}

0 commit comments

Comments
 (0)