0%

Android-Riru检测与对抗

记录对 riru (riru-hide) 注入 so 后的检测与对抗.

原理

被 riru-hide 隐藏的 so 是一段匿名内存,但与大部分匿名内存不同,他的权限位会出现 "x"(可执行).

通过检测 maps 文件中的匿名内存权限位是否有 "x" 来判断这段内存是不是 riru-hide 隐藏的 so.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char line[512];
FILE* fp;
fp = fopen("/proc/self/maps", "r");
if (fp) {
while (fgets(line, 512, fp)) {
char* part[6];
part[0] = strtok(line, " ");
int i=1;
while(i<6) {
part[i] = strtok(NULL, " ");
i++;
}
if (strcmp(part[5],"\n")==0){ //匿名内存
if (strstr(part[1],"x")){
LOGD("发现权限有x的匿名内存,地址:%s",part[0]);
}
}

}
LOGD("没有发现权限有x的匿名内存");
fclose(fp);
}

对抗

至于对抗,只需要把 Hook 逻辑直接写进 Riru 里就行,不要让 Riru 加载 so 模块.

1. 下载 Riru 源码

1
git clone https://github.com/RikkaApps/Riru.git

2. 修改 nativeForkAndSpecialize_pre 和 nativeForkAndSpecialize_post 函数代码

nativeForkAndSpecialize_post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static void
nativeForkAndSpecialize_post(JNIEnv *env, jclass clazz, jint uid, jboolean is_child_zygote,
jint res) {

// if (res == 0) jni::RestoreHooks(env);

// for (const auto &module : modules::Get()) {
// if (!module.hasForkAndSpecializePost())
// continue;

// if (module.apiVersion < 25) {
// if (module.hasShouldSkipUid() && module.shouldSkipUid(uid))
// continue;

// if (!module.hasShouldSkipUid() && shouldSkipUid(uid))
// continue;
// }

// if (res == 0) LOGD("%s: forkAndSpecializePost", module.id.data());

// module.forkAndSpecializePost(env, clazz, res);
// }

// if (res == 0) Entry::Unload(is_child_zygote);

// 这里直接写hook逻辑
LOGI("nativeForkAndSpecialize_post");
}

nativeSpecializeAppProcess_pre

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static void nativeSpecializeAppProcess_pre(
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtimeFlags,
jobjectArray &rlimits, jint &mountExternal, jstring &seInfo, jstring &niceName,
jboolean &startChildZygote, jstring &instructionSet, jstring &appDataDir,
jboolean &isTopApp, jobjectArray &pkgDataInfoList, jobjectArray &whitelistedDataInfoList,
jboolean &bindMountAppDataDirs, jboolean &bindMountAppStorageDirs) {

// for (auto &module : modules::Get()) {
// if (!module.hasSpecializeAppProcessPre())
// continue;

// module.resetAllowUnload();

// if (module.apiVersion < 25) {
// if (module.hasShouldSkipUid() && module.shouldSkipUid(uid))
// continue;

// if (!module.hasShouldSkipUid() && shouldSkipUid(uid))
// continue;
// }

// module.specializeAppProcessPre(
// env, clazz, &uid, &gid, &gids, &runtimeFlags, &rlimits, &mountExternal, &seInfo,
// &niceName, &startChildZygote, &instructionSet, &appDataDir, &isTopApp,
// &pkgDataInfoList, &whitelistedDataInfoList, &bindMountAppDataDirs,
// &bindMountAppStorageDirs);
// }

// 这里直接写hook逻辑
LOGI("nativeSpecializeAppProcess_pre");
}

3. 编译

1
gradlew :riru:assembleRelease

如果报错,看看是不是少了 local.properties 文件

4. 安装

略…

效果

最后效果如图