首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Android安全
发新帖
0
4
[原创][分享]某安全加固趣事分享
发表于: 2026-4-11 20:40
2012
[原创][分享]某安全加固趣事分享
嘎嘎真的很棒
2026-4-11 20:40
2012
该样本很早之前就分析了,前几天样本更新了,打开之后会直接闪退,这与之前所有版本都不太一样,猜测是更新了检测ROOT的方式,故又分析了一下。 该加固检测ROOT的方式是通过多次syscall调用__NR_faccessat和__NR_fchownat计算其差值判断是否处于ROOT环境的。 但是这种检测方式并不稳定,且在最新版的KernelSu中已经被修复了。 有趣的来了,4.2号的时候发布的版本是带有这个ROOT检测的,4.9号的时候APP更新了。 让我感到搞笑的是更新日志是这样写的: `修复部分设备进入闪退问题` 我一看到这个就猜到了绝对是因为ROOT检测,下载下来分析,果不其然,直接把加固SO文件换成旧版本的SO了。 检测代码AI复现如下 ``` #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sched.h> #include <stdint.h> #include <sys/utsname.h> #include <sys/syscall.h> /* ── ARM64 syscall numbers ── */ #ifndef __NR_faccessat #define __NR_faccessat 48 #endif #ifndef __NR_fchownat #define __NR_fchownat 54 #endif #ifndef __NR_gettid #define __NR_gettid 178 #endif /* ── 读取 ARM 硬件计数器 CNTVCT_EL0(纳秒级精度)── */ static inline uint64_t read_cntvct(void) { uint64_t val; __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(val)); return val; } /* ── 读取计数器频率 CNTFRQ_EL0(用于换算为时间)── */ static inline uint64_t read_cntfrq(void) { uint64_t val; __asm__ __volatile__("mrs %0, cntfrq_el0" : "=r"(val)); return val; } /* ── qsort 比较函数 ── */ static int cmp_u64(const void *a, const void *b) { uint64_t va = *(const uint64_t *)a; uint64_t vb = *(const uint64_t *)b; return (va > vb) - (va < vb); } /* ── 查找最快的 CPU 大核 ── */ static int find_fastest_core(void) { int num_cpus = (int)sysconf(_SC_NPROCESSORS_CONF); int best_core = 0; int best_freq = 0; for (int i = 0; i < num_cpus; i++) { char path[256]; snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i); FILE *f = fopen(path, "r"); int freq = -1; if (f) { fscanf(f, "%d", &freq); fclose(f); } if (freq > best_freq) { best_freq = freq; best_core = i; } } printf("[*] CPU cores: %d, fastest: CPU%d (%d KHz)\n", num_cpus, best_core, best_freq); return best_core; } /* ── 将当前线程绑定到指定 CPU 核心 ── */ static int pin_to_core(int core) { cpu_set_t set; CPU_ZERO(&set); CPU_SET(core, &set); pid_t tid = (pid_t)syscall(__NR_gettid); if (tid == -1) tid = getpid(); return sched_setaffinity(tid, sizeof(set), &set); } /** * detect_syscall_timing - 核心检测函数(复现 sub_301EC) * * @n: 采样次数 * @return: faccessat 比 fchownat 慢的次数 * 正常内核 → 返回值远小于 n*70% * hook内核 → 返回值接近 n(99%+) */ static int detect_syscall_timing(int n) { uint64_t *times_faccessat = (uint64_t *)calloc(n, sizeof(uint64_t)); uint64_t *times_fchownat = (uint64_t *)calloc(n, sizeof(uint64_t)); if (!times_faccessat || !times_fchownat) { free(times_faccessat); free(times_fchownat); return -1; } /* 保存原始 CPU 亲和性 */ cpu_set_t orig_set; int saved = sched_getaffinity(0, sizeof(orig_set), &orig_set); /* 绑定到最快的大核 */ int core = find_fastest_core(); pin_to_core(core); /* * 测量循环 1:faccessat(48) * 参数全部无效 → 内核立即返回错误 * 但如果 KernelSU hook 了这个 syscall,会有额外开销 */ for (int i = 0; i < n; i++) { uint64_t t0 = read_cntvct(); syscall(__NR_faccessat, 0xFFFFFFFF, NULL, 0xFFFFFFFF, 0); times_faccessat[i] = read_cntvct() - t0; } /* * 测量循环 2:fchownat(54) * 同样参数无效 → 立即返回错误 * 作为基准参照(通常不会被 hook 或 hook 开销更小) */ for (int i = 0; i < n; i++) { uint64_t t0 = read_cntvct(); syscall(__NR_fchownat, 0xFFFFFFFF, NULL, 0, 0, 0xFFFFFFFF); times_fchownat[i] = read_cntvct() - t0; } /* 恢复原始 CPU 亲和性 */ if (saved == 0) sched_setaffinity(0, sizeof(orig_set), &orig_set); /* 排序——消除偶发的调度噪声 */ qsort(times_faccessat, n, sizeof(uint64_t), cmp_u64); qsort(times_fchownat, n, sizeof(uint64_t), cmp_u64); /* 逐一对比:统计 faccessat 比 fchownat 慢超过 1 tick 的次数 */ int count = 0; for (int i = 0; i < n; i++) { if (times_faccessat[i] > times_fchownat[i] + 1) count++; } /* 输出前10个样本供参考 */ printf(" [samples] faccessat vs fchownat (first 10, sorted):\n"); for (int i = 0; i < 10 && i < n; i++) { printf(" [%d] %llu vs %llu %s\n", i, (unsigned long long)times_faccessat[i], (unsigned long long)times_fchownat[i], times_faccessat[i] > times_fchownat[i] + 1 ? "← SLOWER" : ""); } free(times_faccessat); free(times_fchownat); return count; } /* ── 检查内核版本是否 >= 4.14(原版条件)── */ static int check_kernel_version(void) { struct utsname uts; if (uname(&uts) != 0) return 1; /* uname 失败时仍然执行检测 */ printf("[*] Kernel: %s\n", uts.release); char *release = strdup(uts.release); char *saveptr; char *tok1 = strtok_r(release, ".", &saveptr); int major = tok1 ? atoi(tok1) : 0; char *tok2 = strtok_r(NULL, ".", &saveptr); int minor = tok2 ? atoi(tok2) : 0; /* 消费掉 "-xxx" 后缀 */ strtok_r(NULL, "-", &saveptr); free(release); printf("[*] Parsed version: %d.%d\n", major, minor); if (major > 4 || (major == 4 && minor >= 14)) return 1; printf("[!] Kernel < 4.14, original BangBang would skip this check\n"); return 0; } int main(int argc, char *argv[]) { int n = 10000; if (argc > 1) n = atoi(argv[1]); uint64_t freq = read_cntfrq(); printf("[*] Timer frequency: %llu Hz (%.1f MHz)\n\n", (unsigned long long)freq, freq / 1e6); if (!check_kernel_version()) { printf("[*] Running anyway for demonstration...\n\n"); } printf("\n"); /* 三轮测试*/ printf("── Test 1: n=%d ──\n", n); int r1 = detect_syscall_timing(n); printf("\n── Test 2: n=%d ──\n", n / 2); int r2 = detect_syscall_timing(n / 2); printf("\n── Test 3: n=%d ──\n", n / 2); int r3 = detect_syscall_timing(n / 2); /* ── 汇总结果 ── */ printf("\n╔══════════════════════════════════════════════════╗\n"); printf("║ Results ║\n"); printf("╠══════════════════════════════════════════════════╣\n"); printf("║ Test 1: %5d / %5d (%5.1f%%) ║\n", r1, n, r1 * 100.0 / n); printf("║ Test 2: %5d / %5d (%5.1f%%) ║\n", r2, n / 2, r2 * 100.0 / (n / 2)); printf("║ Test 3: %5d / %5d (%5.1f%%) ║\n", r3, n / 2, r3 * 100.0 / (n / 2)); printf("╚══════════════════════════════════════════════════╝\n\n"); /* * 按比例缩放到用户指定的 n */ int t1 = (int)((long long)n * 7001 / 10000); int t2 = (int)((long long)(n / 2) * 3500 / 5000); int t3 = (int)((long long)(n / 2) * 3501 / 5000); printf("── BangBang Detection Thresholds (~70%%) ──\n"); printf(" Test 1: %d >= %d ? %s\n", r1, t1, r1 >= t1 ? "⚠ TRIGGERED" : "✅ CLEAN"); printf(" Test 2: %d > %d ? %s\n", r2, t2, r2 > t2 ? "⚠ TRIGGERED" : "✅ CLEAN"); printf(" Test 3: %d >= %d ? %s\n", r3, t3, r3 >= t3 ? "⚠ TRIGGERED" : "✅ CLEAN"); printf("\n"); if (r1 >= t1 && r2 > t2 && r3 >= t3) { printf("╔══════════════════════════════════════════════════╗\n"); printf("║ ⚠ DETECTED: Kernel syscall table is hooked! ║\n"); printf("║ Possible: KernelSU / Magisk / other root ║\n"); printf("╚══════════════════════════════════════════════════╝\n"); } else { printf("╔══════════════════════════════════════════════════╗\n"); printf("║ ✅ CLEAN: No kernel syscall hook detected ║\n"); printf("╚══════════════════════════════════════════════════╝\n"); } return 0; } ```
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-4-11 20:44 被嘎嘎真的很棒编辑 ,原因: 增加代码
#逆向分析
#NDK分析
收藏
・
0
点赞
・
4
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
感谢你的贡献,论坛因你而更加精彩!
2026-7-16 05:55
熊趴趴来
为你点赞!
2026-4-14 00:52
下雨天sana
你的分享对大家帮助很大,非常感谢!
2026-4-12 14:25
东方玻璃
谢谢你的细致分析,受益匪浅!
2026-4-11 21:07
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
5
)
mb_cfjwplfo
雪 币:
284
能力值:
( LV1,RANK:0 )
在线值:
发帖
6
回帖
93
粉丝
20
关注
私信
mb_cfjwplfo
2
楼
太搞笑了,竟然真有安全人员敢用这种误杀的检测机制
2026-4-11 23:41
0
温泉划水鱼
雪 币:
84
能力值:
( LV1,RANK:0 )
在线值:
发帖
6
回帖
224
粉丝
28
关注
私信
温泉划水鱼
3
楼
草台班子
2026-4-12 02:52
0
墨穹呢
雪 币:
4706
活跃值:
(8132)
能力值:
( LV3,RANK:20 )
在线值:
发帖
2
回帖
225
粉丝
18
关注
私信
墨穹呢
4
楼
感谢分享
2026-4-12 15:47
0
Imxz
雪 币:
112
活跃值:
(9420)
能力值:
( LV2,RANK:10 )
在线值:
发帖
6
回帖
752
粉丝
9
关注
私信
Imxz
5
楼
tql
2026-4-13 09:43
0
iBa0
雪 币:
1560
活跃值:
(5833)
能力值:
( LV4,RANK:40 )
在线值:
发帖
6
回帖
482
粉丝
37
关注
私信
iBa0
6
楼
哈哈哈哈
2026-4-13 18:36
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
嘎嘎真的很棒
8
发帖
161
回帖
30
RANK
关注
私信
他的文章
[讨论][原创]frida检测分析感悟
968
[原创][分享]某安全加固趣事分享
2012
[原创]第六届金盾信安Reverse-WP
6793
[原创]2024网鼎-Reveres-WP
32015
[原创]DASCTF2024-金秋十月-REEZ-WP-特详细
6842
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部