Skip to content

Commit 4469503

Browse files
committed
Add detection using module counter
Two counters for module loading and unloading are introduced in the commit https://cs.android.com/android/_/android/platform/bionic/+/a2e83ab34845759f0999d0ec88f4cdf558c0a9f5. Moreover, we remove detection using proc/self/smaps For projects using LSPlt as PLT hooks, the problem of dirty_page is avoided by restoring memory blocks.
1 parent d156f1c commit 4469503

File tree

4 files changed

+34
-19
lines changed

4 files changed

+34
-19
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ The following cases are considered as injections:
1616

1717
See blog [Android 用户态注入隐藏已死](https://nullptr.icu/index.php/archives/182/).
1818

19+
## Detection using `module counter`
20+
21+
A call to `dlclose` will increase the counter [g_module_unload_counter](https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker.cpp;l=1956).
22+
1923
## State of bypassing current test
2024

21-
- [x] [Zygisk of Magisk](https://github.com/topjohnwu/Magisk)
22-
- [x] [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) (since [v1.1.0](https://github.com/Dr-TSNG/ZygiskNext/releases/tag/v1.1.0))
25+
- [ ] [Zygisk of Magisk](https://github.com/topjohnwu/Magisk)
26+
- [ ] [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext)
2327
- [x] [ReZygisk](https://github.com/PerformanC/ReZygisk) (fixed by JingMatrix in https://github.com/PerformanC/ReZygisk/pull/101)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace SoList {
77
class SoInfo {
88
public:
99
#ifdef __LP64__
10-
inline static size_t solist_next_offset = 0x30;
10+
inline static size_t solist_next_offset = 0x28;
1111
constexpr static size_t solist_realpath_offset = 0x1a8;
1212
#else
1313
inline static size_t solist_next_offset = 0xa4;
@@ -89,6 +89,7 @@ class ProtectedDataGuard {
8989
static SoInfo *solist = NULL;
9090
static SoInfo *somain = NULL;
9191
static SoInfo **sonext = NULL;
92+
static uint64_t *g_module_unload_counter = NULL;
9293

9394
static bool Initialize();
9495

@@ -100,6 +101,7 @@ inline T *getStaticPointer(const SandHook::ElfImg &linker, const char *name) {
100101
}
101102

102103
SoInfo *DetectInjection();
104+
size_t DetectModules();
103105

104106
bool Initialize();
105107

app/src/main/cpp/native-lib.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ Java_org_matrix_demo_MainActivity_stringFromJNI(JNIEnv *env,
1212

1313
std::string solist_detection = "No injection found using solist";
1414
std::string vmap_detection = "No injection found using vitrual map";
15-
std::string smap_detection = "No injection found using stats map";
15+
std::string counter_detection = "No injection found using module counter";
1616
SoList::SoInfo *abnormal_soinfo = SoList::DetectInjection();
1717
VirtualMap::MapInfo *abnormal_vmap = VirtualMap::DetectInjection();
18-
/* StatsMap::SmapsEntry abnormal_smap = */
19-
/* StatsMap::DetectInjection(std::string("libharfbuzz_ng.so")); */
18+
size_t module_injected = SoList::DetectModules();
2019

2120
if (abnormal_soinfo != nullptr) {
2221
solist_detection =
@@ -32,13 +31,12 @@ Java_org_matrix_demo_MainActivity_stringFromJNI(JNIEnv *env,
3231
abnormal_vmap->start, abnormal_vmap->end);
3332
}
3433

35-
/* if (abnormal_smap.private_dirty_kb != -1) { */
36-
/* smap_detection = */
37-
/* std::format("Stats map: injection at {}", abnormal_smap.pathname); */
38-
/* LOGE("Abnormal smap %s", abnormal_smap.pathname.data()); */
39-
/* } */
34+
if (module_injected > 0) {
35+
counter_detection =
36+
std::format("Module counter: {} shared libraries injected", module_injected);
37+
}
4038

4139
return env->NewStringUTF(
42-
(solist_detection + "\n" + vmap_detection + "\n" + smap_detection)
40+
(solist_detection + "\n" + vmap_detection + "\n" + counter_detection)
4341
.c_str());
4442
}

app/src/main/cpp/solist.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ namespace SoList {
66
ProtectedDataGuard::FuncType ProtectedDataGuard::ctor = NULL;
77
ProtectedDataGuard::FuncType ProtectedDataGuard::dtor = NULL;
88

9+
size_t DetectModules() {
10+
if (g_module_unload_counter == NULL) {
11+
LOGI("g_module_unload_counter not found");
12+
return 0;
13+
} else {
14+
return *g_module_unload_counter;
15+
}
16+
}
17+
918
SoInfo *DetectInjection() {
1019
if (solist == NULL && !Initialize()) {
1120
LOGE("Failed to initialize solist");
@@ -117,8 +126,8 @@ bool Initialize() {
117126
snprintf(sonext_sym_name, sizeof(somain_sym_name), "__dl__ZL6sonext%s",
118127
llvm_sufix);
119128

120-
char vsdo_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)];
121-
snprintf(vsdo_sym_name, sizeof(vsdo_sym_name), "__dl__ZL4vdso%s", llvm_sufix);
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);
122131

123132
somain = getStaticPointer<SoInfo>(linker, somain_sym_name);
124133
if (somain == NULL)
@@ -128,21 +137,23 @@ bool Initialize() {
128137
if (sonext == NULL)
129138
return false;
130139

131-
SoInfo *vsdo = getStaticPointer<SoInfo>(linker, vsdo_sym_name);
132-
if (vsdo == NULL)
133-
return false;
140+
SoInfo *vdso = getStaticPointer<SoInfo>(linker, vdso_sym_name);
134141

135142
SoInfo::get_realpath_sym =
136143
reinterpret_cast<decltype(SoInfo::get_realpath_sym)>(
137144
linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv"));
138145
SoInfo::get_soname_sym = reinterpret_cast<decltype(SoInfo::get_soname_sym)>(
139146
linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv"));
140147

148+
g_module_unload_counter = reinterpret_cast<decltype(g_module_unload_counter)>(
149+
linker.getSymbAddress("__dl__ZL23g_module_unload_counter"));
150+
if (g_module_unload_counter != NULL)
151+
LOGD("found symbol g_module_unload_counter");
152+
141153
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
142154
auto *possible_next = *(void **)((uintptr_t)solist + i * sizeof(void *));
143-
if (possible_next == somain || (vsdo != NULL && possible_next == vsdo)) {
155+
if (possible_next == somain || (vdso != NULL && possible_next == vdso)) {
144156
SoInfo::solist_next_offset = i * sizeof(void *);
145-
146157
break;
147158
}
148159
}

0 commit comments

Comments
 (0)