S24 为什么跑不了 DirtyFrag

——把结论钉死在一个可证伪的预测上

这篇讲一件有点扫兴的事:DirtyFrag(CVE-2026-43284)这套 2026 年最香的免解锁 root 方案,
在 Galaxy S25(6.6 内核)和 S23(5.15 内核)上都能跑通,在 Galaxy S24 全系上却怎么都跑不了,
而且不是”没调好”——是结构性不通。

我不想写”因为我们安全补丁比它新”,那句话既不解释也不可信。下面是我怎么把这件事钉死的:
从内核源码推出一个能算出具体整数的预测,然后在真机上数出那个整数。


0x00 开场:别人能跑,为什么我这里不行

事情的起点是一个很朴素的对比:

设备内核DirtyFrag
Galaxy S23 系列5.15✅ 机主实测能跑
Galaxy S25 Ultra(SM-S938B)6.6.98✅ 有公开移植,还能开机自动恢复 root
Galaxy S24 全系(SM-S9280…)6.1.x❌ 我们实测跑不了

DirtyFrag 的吸引力在于它的性质:确定性(不靠竞态)、失败不 panic、只改内存里的 page cache、
重启即还原——对 bootloader 已锁定、又不想每次手动跑一遍工具的人来说,这几乎是理想解。

所以当自研的移植在我们手上失败时,第一反应一定是”我们哪里写错了”:
IV 算错了?HMAC 算错了?ICV 长度猜错了?SA 没建起来?包没发出去?

这些怀疑最后全部被排除。而排除它们靠的不是反复试参数,而是一条能算出整数的判据。


0x01 先把链条拆开

0x01-1 完整链条长什么样

有公开移植把它串成这样(我对着源码逐条核过,机主的描述和实现是对得上的):

① 借 crash_dump64 突破沙盒  →  获得 vendor 读权限
② 用 DirtyFrag 篡改只读文件的页缓存        ← 全链唯一的写原语
③ 把内核模块注入厂商库(libstagefrighthw.so)的页缓存
④ 挂钩 libc / libc++,等触发
⑤ modprobe 加载模块时触发钩子
⑥ 加载 dirtyfrag.ko 进内核
⑦ 关闭 SELinux
⑧ bind mount logcat,启动 KernelSU
⑨ 完成无痕迹临时 root

0x01-2 谁是支点

这里有件事必须先说清楚:这条链只有一把钥匙。

③ 需要 ②(把模块写进只读的厂商库)+ ① (读 vendor 文件算 IV);
④ 需要 ②;⑤ 依赖 ④;⑥ 依赖 ⑤。

也就是说,② 一旦不成立,后面全是空谈——换 ksud、补参数槽、改 LKM、调 SELinux,
这些”下游工作”做得再漂亮都没用,因为根本走不到那一步。

我们后来确实在真机上看到它死在 ②:目标文件 crash_dump64 的 md5 前后一字未变。
(顺便,这一条也说明:有人反馈”我在 S23U 上用的是 ROOT_s23 那套 ksud,打了个跳转槽补丁就好了”——
那是链条 ⑥⑦⑧ 段的活,属于”拿到写原语之后”,在 S24 上不解决任何问题。)


0x02 原理:拆到能自己写出来

这一节是全文的地基。要看懂后面为什么”构造是对的但还是写不进去”,得先知道内核到底认什么。

0x02-1 报文长什么样

[ ESP 头 8 ][ IV 16 ][ 密文 = 文件页 16 ][ ICV A ]
     ↑ SPI+Seq    ↑ 网络序     ↑ 这段来自页缓存      ↑ 长度 A = authsize

套路是:把目标文件的页缓存页用 splice() 送进管道,再 splice() 到 UDP socket。
如果内核在这条发送路径上是零拷贝的,那么这一页就会被原样挂进 skb 的 frag;
之后 ESP 输入路径在这个 frag 上做就地解密,写出来的明文就直接落在文件的页缓存里——
不需要写权限、绕过 COW、绕过只读挂载。

0x02-2 内核是”先验 ICV,再解密”

crypto/authenc.c:

/* authenc = auth + crypt 的组合。解密路径先算 ICV 并比对,
   验过了才真正调用 skcipher 解密 —— 顺序很关键:
   认证不过,解密根本不会发生,也就没有任何写入。 */
ahash_request_set_crypt(ahreq, req->src, hash,
                        req->assoclen + req->cryptlen - authsize);
err = crypto_ahash_digest(ahreq);
...
return crypto_authenc_decrypt_tail(req, ...);   /* 验过了才到这里 */

net/ipv4/esp4.c 的输入侧:

int ivlen = crypto_aead_ivsize(aead);                        /* 16 */
int elen  = skb->len - sizeof(struct ip_esp_hdr) - ivlen;
int assoclen = sizeof(struct ip_esp_hdr);                    /* 8 */

/* src == dst:这就是"就地"的意思 —— 解密结果覆盖在原文所在的内存上 */
aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
aead_request_set_ad(req, assoclen);

0x02-3 覆盖范围其实是个恒等式

把上面两段拼起来,ICV 的覆盖长度是:

assoclen + cryptlen - authsize
  = 8 + (skb->len - 8) - authsize
  = skb->len - authsize

对本文的布局,skb->len = 40 + A(A = 随包附加的 ICV 字节数),所以:

ICV 的覆盖范围恒为 ESP头 + IV + 文件页 = 40 字节,跟 authsize 无关。

这句话的价值在于:它把”HMAC 该覆盖哪 40 个字节”这件事变成确定的,
于是整条链上真正未知的量只剩一个:

随包附加的 ICV 字节数 A,必须恰好等于内核 SA 的 authsize。

0x02-4 IV 怎么算

CBC 解密是 P = DEC(C) ⊕ IV。我们希望解出来的明文就是想要的新内容,于是:

IV = AES_ECB_DEC(key, C_old) ⊕ C_new

代入:P = DEC(C_old) ⊕ IV
        = DEC(C_old) ⊕ DEC(C_old) ⊕ C_new
        = C_new      ✓

而 C_old 就是目标页的当前内容——pread() 读出来,splice() 送出去,读和写用的是同一页。

/* 只写 16 字节整数倍:密文块必须是完整的 CBC 块 */
static void compute_iv(const uint8_t old_content[16],
                       const uint8_t desired[16], uint8_t iv[16]) {
    uint8_t dec[16];
    aes256_ecb_decrypt(g_aes_key, old_content, dec);   /* DEC(C_old) */
    for (int i = 0; i < 16; i++)
        iv[i] = dec[i] ^ desired[i];                   /* 再异或目标内容 */
}

0x02-5 trailer 判据:把密码学断言变成能数的整数 ★

ESP 解密之后内核要校验 trailer(padding 长度 + next header):

static inline int esp_remove_trailer(struct sk_buff *skb) {
    alen = crypto_aead_authsize(aead);
    hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);   /* 24 */
    elen = skb->len - hlen;

    /* 从"密文末尾往前数 alen,再往前 2 字节"读 trailer ——
       这个位置恰好等于【解密后明文的最后两字节】 */
    skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2);

    padlen = nexthdr[0];
    if (padlen + 2 + alen >= elen)
        return -EINVAL;          /* 调用方会把它计成 XfrmInStateProtoError */
    ...
}

划重点:skb->len - alen - 2 正好落在解密后明文的最后两字节。

于是我们得到一个可证伪的推论:

如果报文被正确解密,那么报错与否完全由我们自己构造的第 15 字节决定。
换句话说:/proc/net/xfrm_stat 里那个计数器应该增加多少,是可以算出来的。

这就是后文一切的支点。


0x03 怎么验的:五条判据

0x03-1 判据一:一个能算出来的整数(31 / 62)

我们的写入目标是 /apex/com.android.runtime/bin/crash_dump64,往它里面写一个 1392 字节的
静态 helper(用来读 vendor 文件),也就是 87 个 16 字节块。加 6 个探针包,一共 93 个包。

按 0x02-5 的判据:alen = 16、elen = 32,报错条件是 padlen + 18 >= 32,即
desired[14] >= 14。

数一遍 splicehelper 的 87 个块,其中 25 个满足这个条件(另有 1 个补零块必然通过):

预测实测
XfrmInStateProtoError 增量6 + 25 = 3131
无声通过(认证+解密+trailer 都过)61 + 1 = 6262

逐数字吻合。 这说明:

  • 内核 SA 的 authsize 就是 16(Android 确实把 truncLen=128 传下去了);
  • 我们的 HMAC 输入、密钥、IV 数学、报文布局全部正确;
  • 包确实被内核解密了,而且解密出的明文就是我们的 desired——因为 trailer 判据
    恰好命中了我们构造的图案。

可是页缓存一个字节都没变:目标文件 md5 = 5f6d588628f5a69423d435419eae2191 前后一致,
ELF 头仍是 e_type=3 / 14 个 program header / 带 PT_INTERP
(如果被写进去,这里已经变成我们那个静态 helper 了)。

这一条一次性排除了整整一类怀疑:ICV 长度猜错(6 种候选全试过 0/12/16/20/24/32)、
密钥不匹配、算法不对、IV 算错、布局写错、SA 没建起来、包没到内核。
剩下的唯一可能:解密作用在载荷的副本上,页缓存页压根没进 skb。

0x03-2 判据二:七形态探针(以及我差点被骗的那个坑)

最快的验证办法是把 IPsec 整个剥掉,只用普通 UDP socket 测同一件事:

把源页发出去之后立刻原地改写这一页,然后才收包。
收到旧值 = 发送路径做了拷贝;收到新值 = 页被共享进了 skb frag。

但这里有个坑,我第一版就被它骗了:探针文件放在 /data(Android 的 FBE 加密盘),
万一内核在 splice() 读路径上就拷贝了,那”拷贝”的结论就不能算在发送路径头上。
所以先加一条探针有效性校验:

内核: 6.1.145-android14-11-3254743-abS9280ZCS6DZH3
测试目录: /data/local/tmp        文件系统: /data(f2fs)
* 管道页身份校验: 管道内是新值 -> splice 挂的就是页缓存页

splice(file→pipe) 走 generic_file_splice_read,不经 GUP,管道缓冲直接引用页缓存页,
所以改文件就等于改管道里那一页。校验通过,后面才能算数。结果:

形态结果
A splice(file 16B) → pipe → UDP拷贝
B splice(file 整页 4096B) → pipe → UDP拷贝
C sendfile(UDP ← file)拷贝
D mmap(RO) → vmsplice → pipe → UDP拷贝(受 GUP 的 FOLL_WRITE→COW 干扰,仅参考)
E1 mmap(RO) + MSG_ZEROCOPY拷贝(同上)
E2 三段 ESP 形态 + MSG_ZEROCOPY拷贝(同上)
F mmap(RW) + MSG_ZEROCOPY拷贝

F 组是决定性的那一格:可写 MAP_SHARED 映射下 GUP 不可能触发 COW,
它照样拷贝 —— 所以”拷贝”是发送路径自己的行为,和 COW 无关,也不是文件系统的锅。

0x03-3 判据三:反汇编设备自己的内核

对着机型固件抽出来的 vmlinux_dzh3.elf 看:

目标看到什么含义
udp_sendpage调用 iov_iter_bvec + udp_sendmsg是新写法,不是老式 ip_append_page
__ip_append_data无任何 MSG_SPLICE_PAGES(BIT 27)判定;0 次调用 skb_append_pagefrags;分片走 sk_alloc_send_pskb + sk_page_frag_refill它只会自己分配 frag 页再拷进去,从不把”来源页”挂上去
esp_input全文只有 skb_cloned() 的两个判定,没有任何 skb_shinfo->flags 位测试修复版应有的 tbnz w?, #0x1 不存在 ⇒ 未修补
ip_append_page全文 0 处 SKBFL_SHARED_FRAG 写入6.1 分支的修复点也是空的,而且这个函数在 6.1 的 UDP 路径上已经是死代码

“未修补”这个结论很重要:它把”漏洞已经被厂商修掉了”这个解释也排除了,
把结论唯一地钉在”页缓存页从来没进过 skb“上。

0x03-4 判据四:内核配置(设备自报)

# Linux/arm64 6.1.145 Kernel Configuration      ← 7694 行完整 config
# CONFIG_AF_RXRPC is not set                   ← CVE-2026-43500 这条备选路没有
# CONFIG_CRYPTO_USER is not set
# CONFIG_CRYPTO_USER_API_AEAD is not set       ← Copy Fail(AF_ALG) 那条路也没有
# CONFIG_USER_NS is not set                    ← 原 PoC 靠 userns 自建 SA 也没门
CONFIG_NET_NS=y

旁证:nm vmlinux_dzh3.elf | grep -icE 'af_alg|algif|rxrpc' = 0;
/vendor/lib/modules(357 个模块)里没有 af_alg.ko / algif_aead.ko;
真机 socket(AF_ALG, SOCK_SEQPACKET, 0) → EACCES(SELinux 在家族查找之前就拦),
unshare(CLONE_NEWUSER) → EINVAL。

0x03-5 判据五:stable 6.1.y 的分界线

把 net/ipv4/udp.c 的 udp_sendpage() 逐版本翻出来:

5.15.204  udp_sendpage → ip_append_page                  ✅ 共享(S23 可用)
6.1.25    udp_sendpage → ip_append_page                  ✅ 共享
6.1.50    udp_sendpage → ip_append_page                  ✅ 共享
6.1.75    iov_iter_bvec + MSG_SPLICE_PAGES               ❌ 拷贝   ← 断点在这里
6.1.100   同上                                            ❌
6.1.128(CZB2)                                           ❌
6.1.145(DZH3)                                           ❌
6.6.98    没有 udp_sendpage,走 splice_to_socket          ✅ 共享

再把本机所有机型内核镜像普查一遍(取 udp_sendpage 的 callee):

镜像callee结论
vmlinux_pixel6ip_append_page✅ 老内核
CZB2/dzf2/dzh3/cza1/cza1_chc/dze2/dzg1/byh7iov_iter_bvec + udp_sendmsg❌ 全是拷贝
vmlinux_czg1(S25 / 6.6)没有这个函数✅

0x04 根因:一次”半截回移”

结论一句话:

stable 6.1.y 把 udp_sendpage() 回移成了新写法(构造 bvec 迭代器并置 MSG_SPLICE_PAGES),
但同一分支的 __ip_append_data() 没有同步获得对 MSG_SPLICE_PAGES 的处理。
于是这个标志被静默忽略,数据被 copy_from_iter 拷进内核自己分配的 frag 页——
页缓存页从未进入 skb,就地解密自然写不到目标文件。

“把来源页原样挂进 skb”这个能力是 Linux 6.5 才引入的语义(7da0dde68486)。
5.10/5.15 用的是老式 ip_append_page()(它会直接挂页,所以 S23 能跑);
6.5/6.6 起新路径完整(所以 S25 能跑);
6.1.75~6.1.14x 这一小段,恰好卡在”新写法已经进来、底层能力还没来”的裂缝里。

这件事在 Linux 内核邮件列表上有独立佐证。在 CVE-2026-43284 的修复讨论里,内核开发者写道:

“I don’t see the support for MSG_SPLICE_PAGES present in kernels 6.1 and older
(i.e. 7da0dde68486 (“ip, udp: Support MSG_SPLICE_PAGES”) is not there in 6.1.y and older
stable branches). Are you sure the PoC didn’t fall back to the RxRPC Page-Cache Write
vulnerability in your case?
“

更妙的是:6.1 分支的官方修复(f4c50a4034e6)被打在 ip_append_page() 上——
而那正是 6.1 上已经不可达的函数。也就是说,6.1 的”修复”打在了一条死路径上,
真正决定可达性的那条路径(新式 udp_sendpage)根本没有对应的共享能力。


0x05 那能不能自己改一下利用?

这是我被问得最多的问题,值得逐层回答。

层现状能改吗
报文层authsize=16、HMAC 覆盖 40 字节、IV 构造全部验证正确(0x03-1)改不出更好的
发送层splice / sendfile / vmsplice / MSG_ZEROCOPY(只读与可写映射)全拷贝;raw / AF_PACKET 之类最终都汇进同一个 ip_append_data否
内核层需要 __ip_append_data 认识 MSG_SPLICE_PAGES(6.5 语义)用户态无法补
目标层换目标文件没用(不是权限或文件系统问题,0x03-2 已证)否
旁路层RxRPC 未编、AF_ALG 未编、user namespace 未开否

一句话:缺的那一环在内核里,用户态无论怎么改报文、换发送 API、换目标文件都绕不过去。

0x05-1 被排除的替代解释(汇总表)

排查一个”应该能跑却跑不了”的问题,最怕的是自己骗自己。这是我逐条打掉的清单:

替代解释怎么验的结果
ICV / authsize 猜错trailer 判据的可证伪预测✗ 预测 31 = 实测 31
密钥 / 算法不匹配同上(HMAC 过了才可能解密、才会触发 trailer 判据)✗
IV 数学写错同上(解出来的必须是我们的 desired)✗
SA 没建起来 / 包没到内核XfrmIn* 计数器✗ 只有 ProtoError 在涨,SA 命中
内核已打修复反汇编 esp_input / ip_append_page✗ 未修补
文件系统不让 splice 挂页(EROFS / FBE)管道页身份校验✗ 管道里就是页缓存页
zerocopy 被 FOLL_WRITE 的 COW 打断F 组:可写映射✗ 照样拷贝
原 PoC 的 userns 路径unshare(CLONE_NEWUSER)✗ EINVAL
RxRPC 备选路CONFIG_AF_RXRPC + 符号✗ 未编译
AF_ALG(Copy Fail)备选路CONFIG_CRYPTO_USER_API_AEAD + 真机 socket()✗ 未编译且 SELinux 拦
6.1 的 UDP 拼接路径不做页共享七形态矩阵✅ 成立

0x06 副产品与几个教训

这次排查本身也产出了一些能复用的东西,顺便记几个教训。

0x06-1 一个自研的”能不能用”探针

以后遇到任何机型、任何内核,都可以几百毫秒内回答”DirtyFrag 这类页缓存写原语可不可达”。
它是自研的(不依赖 app、不依赖 IPsec),NDK 一条命令编译成静态二进制,adb push 就能跑:

/* 核心判据:把源页发出去之后**立刻原地改写这一页**,再收包看新值还是旧值。
   旧值 = 发送路径拷贝(不可达);新值 = 页被共享进 skb frag(可达)。 */
static int try_send(int kind, int fd, const char *path, int sfd, int rfd) {
    ...
    if (kind == 0) {                       /* A: splice(file->pipe) -> UDP */
        pipe(pfd);
        ffd = open(path, O_RDONLY);
        off_t off = 0;
        /* 第一步:把文件页挂进管道(这一步不经 GUP,管道里就是页缓存页) */
        if (splice(ffd, &off, pfd[1], NULL, 16, SPLICE_F_MOVE) == 16)
            /* 第二步:管道 -> UDP socket。能不能"原样挂进 skb"全看这一步 */
            sent = splice(pfd[0], NULL, sfd, NULL, 16, 0);
    }
    if (sent > 0) {
        pwrite(fd, pageB, 16, 0);          /* 关键时序:先改源页,再收包 */
        ...
    }
}
# 编译 + 推送 + 运行(建议同时跑 /dev 与 /data,两边对比排除加密盘干扰)
$CC -O2 -static -Wall -o psp psp.c
adb push psp /data/local/tmp/ && adb shell chmod 755 /data/local/tmp/psp
adb shell /data/local/tmp/psp /data/local/tmp

输出直接给结论,附带”管道页身份校验”作为有效性背书:

* 管道页身份校验: 管道内是新值 -> splice 挂的就是页缓存页
  A splice(file 16B)->pipe->UDP            【拷贝】收到旧值
  ...
  F  mmap(RW)+MSG_ZEROCOPY                 【拷贝】收到旧值

0x06-2 “发包成功”不等于”写进去了”

这可能是本次最有价值的一条工程教训。

原实现(以及我第一版)在写入后打印 “已写入 N 字节到 xxx”,
但那句话的真实含义只是 “UDP 包发出去了” —— 内核完全可能因为认证不过、
或者因为页压根没进 skb,把包丢掉,而用户看到的是一行”成功”。

所以我给它加了回读校验:每写一个 16 字节块,就 pread() 回来比对。

回读不符 @0x10: 期望 0200b700... 实际 0300b700...
回读校验: 通过 5 块 / 失败 82 块

(那”通过 5 块”其实还是巧合——splicehelper 里有几块本来就是全零,跟原内容正好一致。)
没有这个回读,这次排查会绕远得多。

0x06-3 关于”看看安全补丁级别”那条判据

参考实现的中文排障指引里写:

上游修复提交是 f4c50a4034e6(2026-05-08)。如果手机的安全补丁级别已经包含该修复,
本工具会失败——这不是 bug,是漏洞没了。

…… 走到一半失败,提示补丁 #1 / #2 失败? 大概率是内核里的 DirtyFrag 漏洞已经被修复了。

本机安全补丁级别是 2026-08-05(晚于 2026-05),而实测失败点正是补丁 #1 ——
从现象看完全对得上。但必须说清楚:这条判据在本机只是”碰巧给了对的结论”。

反汇编证据显示本机内核并未包含该修复(esp_input 里没有 shared-frag 判定、
ip_append_page 里没有标志写入)。真正的原因是 0x04 说的那件事:
页缓存页压根没进 skb,共享 frag 根本不存在——谈不上”被修复的检查拦下”。

所以更准确的表述是:

S24 上失败不是”漏洞被修了”,而是这条漏洞的输入端在该内核上不可达。
安全补丁级别是经验判据,不是因果解释。

0x06-4 一个有趣的推论:S24 出厂固件曾经能用

由 0x03-5 的分界线可以推:S24 系列出厂固件(2024 年初,约 6.1.25~6.1.50)的内核,
udp_sendpage() 还是老式实现,理论上当时是可达的。2024 年中把 sendpage-removal 系列
回移进 6.1.y 之后,这条共享路径就断了——属于回移的副作用,不是有意修洞。

这也解释了参考实现为什么同时携带 android12-5.10 / android13-5.15 与
android15-6.6 / android16-6.12 / android17-6.18 两头的模块:
它支持的是一头一尾两类内核,而 6.1 恰好夹在裂缝里。


0x07 机型对照 & 结语

内核udp_sendpageDirtyFrag ESP 原语机型举例
5.10 / 5.15ip_append_page✅ 可达S23 系列(机主实测)
6.1.25 ~ 6.1.50ip_append_page✅ 可达(代码层已核实;出厂固件是否落在该区间未逐一验证)S24 出厂固件(推断)
6.1.75 及以后bvec + MSG_SPLICE_PAGES❌ 不可达S24 全系现行固件
6.5 / 6.6+无 udp_sendpage,走 splice_to_socket✅ 可达S25 / S938B

一句话总结:

DirtyFrag 的密码学我们全对、内核也确实没打补丁,但 6.1 的 UDP 发送路径压根不会把
页缓存页共享进 skb —— 缺的是 6.5 才有的 MSG_SPLICE_PAGES 语义,而 6.1.y 的”半截回移”
让这条能力只到一半。备选的 RxRPC 与 AF_ALG 在本内核配置下都没有编译,
原 PoC 依赖的 user namespace 也没有开启。

S24 上这条路是结构性不通,不是调参问题。

对 S24 来说,现实结论是:想要免解锁 root,还是得回到竞态型的那套方案;
DirtyFrag 的”确定性 + 开机自动恢复”这套好处,得等到 6.6 及以上内核的机型才有。


0x08 复现附录

材料说明
独立探针 tools/psp.c自研;静态二进制;adb shell /data/local/tmp/psp <目录>
app 内探针 tools/page_share_probe.c便于编进任何 app 的 native 库
完整证据归档 FEASIBILITY_VERDICT.md含全部原始输出与反汇编结论
内核镜像 01_固件内核/vmlinux_dzh3.elf、vmlinux_CZB2.elf反汇编与符号普查的对象
设备自报配置zcat /proc/config.gz(7694 行)

验证环境:

机型    SM-S9280(e3q,国行 DZH3)
系统    Android 16(API 36)
固件    BP4A.251205.006.S9280ZCS6DZH3
内核    6.1.145-android14-11-3254743-abS9280ZCS6DZH3
KMI     android14-6.1
补丁级  2026-08-05
对照组  CZB2 = 6.1.128-android14-11-2755301-abS9280ZCS5CZB2(逐项相同)

本文只对自己拥有的设备做验证;所有写入目标都是内存里的 page cache,重启即还原。
引用到的第三方实现/文档均无 LICENSE,本文只引用其结论与事实,未复制其代码;
文中探针、转换工具等均为自行实现。

别检查我的网站了喵
本文采用 CC BY-NC-SA 4.0 国际许可协议进行许可。
转载请注明作者及原文链接,并遵循相同方式共享原则。
链接:https://blog.nanoturtle.cn/index.php/2026/09/27/galaxy-s24-dirtyfrag-kernel/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇