Skip to content

Commit eb5e3ff

Browse files
committed
Fix symbol resolving of solist
Using heuristic methods adapted from JingMatrix/NeoZygisk.
1 parent 298bf39 commit eb5e3ff

File tree

2 files changed

+69
-46
lines changed

2 files changed

+69
-46
lines changed

app/src/main/cpp/include/solist.hpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ class SoInfo {
88
public:
99
#ifdef __LP64__
1010
inline static size_t solist_next_offset = 0x28;
11-
constexpr static size_t solist_realpath_offset = 0x1a8;
11+
inline static size_t solist_realpath_offset = 0x1a0;
1212
#else
1313
inline static size_t solist_next_offset = 0xa4;
14-
constexpr static size_t solist_realpath_offset = 0x174;
14+
inline static size_t solist_realpath_offset = 0x17c;
1515
#endif
1616

1717
inline static const char *(*get_realpath_sym)(SoInfo *) = NULL;
18-
inline static const char *(*get_soname_sym)(SoInfo *) = NULL;
1918

2019
inline SoInfo *get_next() {
2120
return *(SoInfo **)((uintptr_t)this + solist_next_offset);
@@ -29,11 +28,8 @@ class SoInfo {
2928
}
3029

3130
inline const char *get_name() {
32-
if (get_soname_sym)
33-
return get_soname_sym(this);
34-
3531
return ((std::string *)((uintptr_t)this + solist_realpath_offset -
36-
sizeof(void *)))
32+
sizeof(std::string)))
3733
->c_str();
3834
}
3935

@@ -86,7 +82,7 @@ class ProtectedDataGuard {
8682
};
8783
};
8884

89-
static SoInfo *solist = NULL;
85+
static SoInfo *solinker = NULL;
9086
static SoInfo *somain = NULL;
9187
static SoInfo **sonext = NULL;
9288
static uint64_t *g_module_unload_counter = NULL;
@@ -102,6 +98,7 @@ inline T *getStaticPointer(const SandHook::ElfImg &linker, const char *name) {
10298

10399
SoInfo *DetectInjection();
104100
size_t DetectModules();
101+
bool findHeuristicOffsets(std::string linker_name);
105102

106103
bool Initialize();
107104

app/src/main/cpp/solist.cpp

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ size_t DetectModules() {
1616
}
1717

1818
SoInfo *DetectInjection() {
19-
if (solist == NULL && !Initialize()) {
19+
if (solinker == NULL && !Initialize()) {
2020
LOGE("Failed to initialize solist");
2121
return NULL;
2222
}
23-
SoInfo *prev = solist;
23+
SoInfo *prev = solinker;
2424
size_t gap = 0;
2525
auto gap_repeated = 0;
2626
bool app_process_loaded = false;
@@ -30,7 +30,7 @@ SoInfo *DetectInjection() {
3030
bool nativehelper_loaded =
3131
false; // Not necessarily loaded after AppSpecialize
3232

33-
for (auto iter = solist; iter; iter = iter->get_next()) {
33+
for (auto iter = solinker; iter; iter = iter->get_next()) {
3434
// No soinfo has empty path name
3535
if (iter->get_path() == NULL || iter->get_path()[0] == '\0') {
3636
return iter;
@@ -69,7 +69,7 @@ SoInfo *DetectInjection() {
6969
} else {
7070
gap_repeated--;
7171
if (gap != 0)
72-
LOGD("Suspicious gap 0x%lx or 0x%lx != 0x%lx between %s and %s",
72+
LOGI("Suspicious gap 0x%lx or 0x%lx != 0x%lx between %s and %s",
7373
iter - prev, prev - iter, gap, prev->get_name(), iter->get_name());
7474
}
7575

@@ -97,67 +97,93 @@ bool Initialize() {
9797
SandHook::ElfImg linker("/linker");
9898
if (!ProtectedDataGuard::setup(linker))
9999
return false;
100+
LOGI("found symbol ProtectedDataGuard");
100101

101-
std::string_view solist_sym_name =
102-
linker.findSymbolNameByPrefix("__dl__ZL6solist");
103-
if (solist_sym_name.empty())
102+
std::string_view somain_sym_name =
103+
linker.findSymbolNameByPrefix("__dl__ZL6somain");
104+
if (somain_sym_name.empty())
104105
return false;
106+
LOGI("found symbol name %s", somain_sym_name.data());
105107

106108
/* INFO: The size isn't a magic number, it's the size for the string:
107109
* .llvm.7690929523238822858 */
108110
char llvm_sufix[25 + 1];
109111

110-
if (solist_sym_name.length() != strlen("__dl__ZL6solist")) {
111-
strncpy(llvm_sufix, solist_sym_name.data() + strlen("__dl__ZL6solist"),
112+
if (somain_sym_name.length() != strlen("__dl__ZL6somain")) {
113+
strncpy(llvm_sufix, somain_sym_name.data() + strlen("__dl__ZL6somain"),
112114
sizeof(llvm_sufix));
113115
} else {
114116
llvm_sufix[0] = '\0';
115117
}
116118

117-
solist = getStaticPointer<SoInfo>(linker, solist_sym_name.data());
118-
if (solist == NULL)
119-
return false;
119+
char solinker_sym_name[sizeof("__dl__ZL8solinker") + sizeof(llvm_sufix)];
120+
snprintf(solinker_sym_name, sizeof(solinker_sym_name), "__dl__ZL8solinker%s",
121+
llvm_sufix);
120122

121-
char somain_sym_name[sizeof("__dl__ZL6somain") + sizeof(llvm_sufix)];
122-
snprintf(somain_sym_name, sizeof(somain_sym_name), "__dl__ZL6somain%s",
123+
// for SDK < 36 (Android 16), the linker binary is loaded with name solist
124+
char solist_sym_name[sizeof("__dl__ZL6solist") + sizeof(llvm_sufix)];
125+
snprintf(solist_sym_name, sizeof(solist_sym_name), "__dl__ZL6solist%s",
123126
llvm_sufix);
124127

125128
char sonext_sym_name[sizeof("__dl__ZL6sonext") + sizeof(llvm_sufix)];
126-
snprintf(sonext_sym_name, sizeof(somain_sym_name), "__dl__ZL6sonext%s",
129+
snprintf(sonext_sym_name, sizeof(sonext_sym_name), "__dl__ZL6sonext%s",
127130
llvm_sufix);
128131

129-
char vdso_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)];
130-
snprintf(vdso_sym_name, sizeof(vdso_sym_name), "__dl__ZL4vdso%s", llvm_sufix);
131-
132-
somain = getStaticPointer<SoInfo>(linker, somain_sym_name);
133-
if (somain == NULL)
134-
return false;
135-
136-
sonext = linker.getSymbAddress<SoInfo **>(sonext_sym_name);
137-
if (sonext == NULL)
138-
return false;
139-
140-
SoInfo *vdso = getStaticPointer<SoInfo>(linker, vdso_sym_name);
132+
solinker = getStaticPointer<SoInfo>(linker, solinker_sym_name);
133+
if (solinker == nullptr) {
134+
solinker = getStaticPointer<SoInfo>(linker, solist_sym_name);
135+
if (solinker == nullptr)
136+
return false;
137+
LOGI("found symbol solist at %p", solinker);
138+
} else {
139+
LOGI("found symbol solinker at %p", solinker);
140+
}
141141

142142
SoInfo::get_realpath_sym =
143143
reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(
144144
linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
145-
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(
146-
linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
145+
if (SoInfo::get_realpath_sym != nullptr)
146+
LOGI("found symbol get_realpath_sym");
147147

148148
g_module_unload_counter = reinterpret_cast<decltype(g_module_unload_counter)>(
149149
linker.getSymbAddress("__dl__ZL23g_module_unload_counter"));
150-
if (g_module_unload_counter != NULL)
151-
LOGD("found symbol g_module_unload_counter");
152-
153-
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
154-
auto *possible_next = *(void **)((uintptr_t)solist + i * sizeof(void *));
155-
if (possible_next == somain || (vdso != NULL && possible_next == vdso)) {
156-
SoInfo::solist_next_offset = i * sizeof(void *);
157-
break;
150+
if (g_module_unload_counter != nullptr)
151+
LOGI("found symbol g_module_unload_counter");
152+
153+
somain = getStaticPointer<SoInfo>(linker, somain_sym_name.data());
154+
if (solinker == nullptr)
155+
return false;
156+
LOGI("found symbol somain at %p", somain);
157+
158+
return findHeuristicOffsets(linker.name());
159+
}
160+
161+
bool findHeuristicOffsets(std::string linker_name) {
162+
const size_t size_block_range = 1024;
163+
const size_t linker_realpath_size = linker_name.size();
164+
165+
bool field_realpath_found = false;
166+
for (size_t i = 0; i < size_block_range / sizeof(void *); i++) {
167+
auto field_of_solinker =
168+
reinterpret_cast<uintptr_t>(solinker) + i * sizeof(void *);
169+
auto size_of_somain = *reinterpret_cast<size_t *>(
170+
reinterpret_cast<uintptr_t>(somain) + i * sizeof(void *));
171+
172+
std::string *realpath_of_solinker =
173+
reinterpret_cast<std::string *>(field_of_solinker);
174+
if (realpath_of_solinker->size() == linker_realpath_size) {
175+
if (strcmp(linker_name.c_str(), realpath_of_solinker->c_str()) == 0) {
176+
SoInfo::solist_realpath_offset = i * sizeof(void *);
177+
LOGI("heuristic field_realpath_offset is %zu * %zu = %p", i,
178+
sizeof(void *),
179+
reinterpret_cast<void *>(SoInfo::solist_realpath_offset));
180+
field_realpath_found = true;
181+
break;
182+
}
158183
}
159184
}
160185

161-
return (SoInfo::get_realpath_sym != NULL && SoInfo::get_soname_sym != NULL);
186+
return field_realpath_found;
162187
}
188+
163189
} // namespace SoList

0 commit comments

Comments
 (0)