首页
社区
课程
招聘
[原创]初识白盒AES(含具体实操案例-某咖啡)
发表于: 2025-8-12 23:18 7969

[原创]初识白盒AES(含具体实操案例-某咖啡)

2025-8-12 23:18
7969

近期学习到了AES的白盒,所以开个帖子记录并且梳理一下,本篇文章的理论部分会出现大量其他AES方面的帖子里面的内容,然后再参杂着我个人的理解,这是因为我自身在梳理知识点,但是不会太深入研究,如果大佬们发现有错误的话还请指正

AES加密就是把你要加密的数据(比如一份文档或一张图片)切成一块块标准大小的"积木"——每块正好128位(16个字节),如果最后一块不够大小就用填充材料补齐,然后用你提供的密钥(可以是128位、192位或256位长)作为"模具",对每一块数据进行复杂的数学变换——包括替换、移位、混合等十几轮操作,最终把原本有意义的数据变成看起来完全随机的密文;而解密时,只要用完全相同的密钥,就能把这个过程完全逆转回来,重新得到原始数据。
图片描述
我们这里讲的是AES-128,如上图所示,其中AES-128接收16字节的明文输入,16字节的密钥,输出16字节的密文结果。
假设我们的明文是:00112233445566778899aabbccddeeff
密文是:2b7e151628aed2a6abf7158809cf4f3c
那么加密具体的流程就是:
图片描述
首先把密文进行算法编排成十一组密钥(具体如何生成下面说),将输入的明文转换成一个state(16*16)矩阵,将第一组(原始密钥)对矩阵进行运算,就得到了第一轮运算出来的state矩阵,然后再重复十次(轮密钥),最终出来的state矩阵结果将其转换成密文就是我们最终得到的加密结果。
【PS:为了方便起见,现在统一一下称呼,初始密钥称为主密钥,其他根据初始密钥生成的密钥统称为轮密钥】

在AES-128中,主密钥扩展后得到16×11共176字节。使用时按16字节为单位划分成K0, K1, ..., K10共11个轮密钥。但在密钥扩展生成过程中,算法是按4字节(一个字)为单位进行的,即生成44个字(44×4=176字节)。因此可以用一个包含44个元素的数组W来描述整个扩展后的密钥材料
图片描述
那它们是怎么计算出来了的呢?我们来看看以下的计算公式

红色部分:初始密钥矩阵 -> 循环左移 -> S盒替换 -> 与轮常数异或 -> 逐字节异或
橙色部分:进行异或运算即可

S盒全称:Substitution Box(替换盒 / 置换盒),如下图所示,S盒是密码学中的非线性变换组件,它将输入的比特串映射为输出的比特串,是对称密码算法中提供**混淆性(Confusion)**的关键元素。简单来说就是提供非线性替换,增强算法安全性
图片描述
单纯文字说明的话大家应该看得很懵,其实就红色部分难一点,不信的话咱们来具体操作一下看看
我们的初始密钥字(W0-W3,k0):
图片描述

首先是公式:
图片描述
公式知道了,那我们开始计算
w4:
根据公式得知:W[3] ==> 09cf4f3c = [09, cf, 4f, 3c]
RotWord(09cf4f3c) ==> 向左循环移位8位,结果 = [cf, 4f, 3c, 09] = cf4f3c09
SubWord(cf4f3c09)) ==> 通过S盒逐字节替换(看s盒的图片),最终得结果:cf4f3c09 → 8a84eb01
8a84eb01 ⊕ Rcon[1] ==> 将其结果进行与轮常数异或:Rcon[1]:01000000,计算结果得:8b84eb01
W[0] ⊕ 8b84eb01 ==> 2b7e1516 ⊕ 8b84eb01,最后的异或结果为:a0fafe17
w5:
公式:W[5] = W[1] ⊕ W[4],直接计算:28aed2a6 ⊕ a0fafe17 = 88542cb1
w6:
W[6] = W[2] ⊕ W[5],直接计算:abf71588 ⊕ 88542cb1 = 23a33939
w7:
W[7] = W[3] ⊕ W[6],直接计算:09cf4f3c ⊕ 23a33939 = 2a6c7605
k1:
将上方结果拼接起来,最终就是k1的密钥:a0fafe1788542cb123a339392a6c7605

按照上方的步骤再继续往下计算,很快全部的密钥值都能得出来,这就是密钥的计算过程
图片描述

正常情况下主密钥都是已知的,但是不正常的情况呢?比如说本文章介绍的白盒AES(具体是什么下面说),它就是会将主密钥给隐藏起来,那么这种情况下,如果我们有轮密钥的情况下,就可以拿轮密钥逆推算出主密钥来。以下是公式

就拿K10:d014f9a8c9ee2589e13f0cc8b6630ca6为例,假设我们只知道k10的话,我们按照上方的公式计算看看k9的值是多少?
已知条件
W[40] = d014f9a8,W[41] = c9ee2589
W[42] = e13f0cc8,W[43] = b6630ca6

第一步:计算W[39]

第二步:计算W[38]

第三步:计算W[37]

第四步:计算W[36]

4.1 计算T(W[39])

4.1.1 RotWord操作

4.1.2 SubWord操作

4.1.3 与轮常数Rcon[10]异或

4.2 计算W[36]

最终结果
W[36] = ac7766f3,W[37] = 19fadc21
W[38] = 28d12941,W[39] = 575c006e
完整密钥:K9 = ac7766f319fadc2128d12941575c006e
可以看到k9的结果已经被推算出来了,继续往下根据公式一个个推算的话,最终是能够把主密钥给推算出来的,我这里就不再继续了。

终于到了本篇幅最关键的地方了,白盒AES,白盒是什么?首先要理解密码学中的三种攻击模型:
图片描述
如果单单将密钥存放到本地,攻击者很容易就能够将其逆向出来,但是不放在本地又没有办法,因为某些数据需要解密。在这种两难问题的情况下,Stanley Chow及其团队在2002年论文《White-Box Cryptography and an AES Implementation》首次提出白盒AES实现方案,成为该领域奠基性工作。
白盒AES是一种特殊的对称加密实现技术,其核心目标是在算法内部细节完全暴露的环境下(称为"白盒环境")保护密钥不被提取。
它的特点是将AES算法的每一轮操作(如SubBytes、MixColumns、AddRoundKey)拆解为小模块,通过预计算的查找表(Lookup Table)替代计算过程,密钥被嵌入查找表中,与算法逻辑绑定,使得密钥在运行时永不显式出现。
那么问题来了,密钥都没了,那咋玩?这个时候就轮到DFA出场了

DFA(Differential Fault Analysis,差分故障分析)是一种密码学攻击技术,通过在密码算法执行过程中人为引入故障,然后分析正常输出与故障输出之间的差异来推导密钥信息。
DFA在AES中一般会选择在第9轮进行故障注入,为什么选择第9轮?
DFA在AES中选择第9轮进行故障注入的原因主要基于攻击复杂度最优化的考虑:由于AES-128的第10轮(最后一轮)省略了MixColumns操作,只包含SubBytes、ShiftRows和AddRoundKey三个步骤,这使得从第9轮注入的故障到最终输出之间的传播路径变得相对简单和可预测;攻击者可以通过逆向单轮变换(第10轮)来分析故障传播模式,避免了复杂的MixColumns逆变换计算,同时故障在第9轮SubBytes操作中注入能够产生可控的差分模式,使得攻击者只需要相对较少的故障注入次数(通常50-100次)就能够恢复完整的第10轮密钥,然后通过密钥调度的逆运算推导出主密钥;而如果选择更早的轮次进行故障注入,故障需要经过多轮复杂的非线性变换传播到输出,大大增加了分析的复杂度和所需的故障样本数量,因此第9轮成为了攻击效率与技术可行性之间的最佳平衡点。
图片描述

查找表(Lookup Table, LUT)是计算机科学中一种通过预存储计算结果替代实时计算的优化技术。在白盒AES中,它被用于将密钥和加密操作深度绑定,实现密钥隐藏。
查找表本质上是一个预定义的数组或映射结构,输入值作为索引(Index),直接输出预存的结果值(Value),其中这个数组不仅庞大,而且还进行混淆编码等一系列操作,使攻击者很难从查找表中分离出密钥(具体原理不这里就不深究,知道这个概念就行了,各位有兴趣的话可自行深入研究查阅资料),由此,直接将密钥融合进里面,很有效的保护了密钥的安全性

如何识别是不是白盒呢?
一:基于查表技术的白盒化,在程序中会包含大量静态数组(通常数千到数万个元素)
二:符号和字符串信息,XXXWhiteBox / Whitebox_init / WBAES / Whitebox_Sm4

大家通过以上的知识点应该都能了解一点AES加密、白盒、DFA攻击这些概念了,再深入的暂时也不打算研究下去了,毕竟只是为了逆向白盒AES做准备的,如果想深入研究的话可以看看下面的参考帖子,接下来就开始进行实战吧
参考资料:
白盒AES算法详解(一)
【密码学】一文读懂白盒AES(Chow方案)(一)

首先是抓包,我们追踪的是q的来源
图片描述

咋追踪的就懒得写了,最终定位是来到localAESWork4Api这里,参数如下图,先写个主动调用把参数固定住
图片描述
图片描述
然后来源是libcryptoDD的0x1b1cd这个地址,进入之后很容易就能发现真正的核心功能只有这一行:android_native_wbaes_jni(env, jarray, jmode),然后单单看名字就能知道这个是什么加密,wbaes是 "White-Box AES(白盒AES) " 的缩写
图片描述
图片描述
在里面找找,发现PKCS5Padding、wbaes_decrypt_ecb、qmemcpy、removePKCS5Padding、wbaes_encrypt_ecb等关键函数
图片描述
我们要加密,所以继续往wbaes_encrypt_ecb里面进行分析,不过在这之前先hook一下看看参数什么的有没有变化,对照之后发现是没有什么改变,那继续往下分析
图片描述
图片描述
继续进入深入研究之后又发现关键函数aes128_enc_wb_coff、aes128_enc_wb_xlc,但是我们不清楚到底是走哪个实现,所以继续都hook看看,日志输出全部都是aes128_enc_wb_coff,这就证明走的是这里
图片描述
图片描述
进去之后发现一堆查表函数,点击Tyboxes函数进去之后还能发现一个庞大的查找表,实际的密钥就是隐藏在里面,接下来我们想要获取到主密钥的话,那就得使用到DFA攻击了,我们将在第九轮加密进行故障注入,再复习一下为什么选择第九轮呢?
因为修改前八轮的话影响到的结果会很大,而第九轮的话刚好只能影响到第十轮,波及范围小,很容易推导出第十轮的密钥,而如果选择第十轮的话,直接影响输出,无法分析,所以我们最终选择在第九轮进行故障攻击。
图片描述
图片描述
现在目标明确了,但是我们该在代码哪个位置注入呢?通过一番查找发现了wbShiftRows函数,我们就拿这个进行切入点进行注入吧
图片描述

首先写一个手动调用 wbaes_encrypt_ecb 函数的函数,然后定义的参数是:30313233343536373839616263646566,转换成10进制就是0123456789abcdef,为什么要拿这个呢?
是因为32个十六进制字符 = 16字节,而AES是块密码,每次处理16字节(128位),输入的正好是16字节,所以输出也是完整的16字节,没有填充,没有截断,而如果换成完整的数据的话,那么输出的就不是刚好十轮,而是几百轮+了
图片描述
记住现在的正确结果:b0f59c0d48c145915fc8f6a842c4d5eb,然后编写代码,修改wbShiftRows第九轮的字节,错误的结果:b0f59cb248c124915f66f6a88cc4d5eb
图片描述
直接对比,错误了四个字节,接下来写个循环,持续生成500次错误的结果,然后进行计算
图片描述
这里引入 phoenixAES 依赖进行计算,成功的把第十轮的密钥给计算出来了
图片描述
然后通过第十轮的密钥进行逆推,最终的密钥结果也得出来了
图片描述
将其加密,然后对比看看,结果正确,主密钥出来了,至此,白盒AES搞定!
图片描述

这个帖子原本是预计一两天内搞定的,但是没想到各种资料查找,加上中间拖了拖,写了三天,虽然付出的时间很长,但是对我自己的收获很大,之前很多概念都云里雾里的,但是现基本上都梳理清楚了,案例还有部分没有完善的地方暂时也不想再写下去了,就这样吧,反正核心部分都已经完成了,另外如果各位大佬看到哪里有错误的地方还请指正一下。(附代码)
PS:例子APP版本是21年旧版的,最新版本检测没过(没研究),索性拿旧版的研究了,想跟着操作的话网上找找

红色部分
W[4k]   = W[4(k-1)] ⊕ T(W[4k-1])     // 每轮第1字:复杂变换
T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
 
橙色部分
W[4k+1] = W[4(k-1)+1] ⊕ W[4k]       // 每轮第2字:简单异或 
W[4k+2] = W[4(k-1)+2] ⊕ W[4k+1]     // 每轮第3字:简单异或
W[4k+3] = W[4(k-1)+3] ⊕ W[4k+2]     // 每轮第4字:简单异或
 
PS:
⊕ 是异或运算符号(XOR,Exclusive OR)
K 是轮数
红色部分
W[4k]   = W[4(k-1)] ⊕ T(W[4k-1])     // 每轮第1字:复杂变换
T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
 
橙色部分
W[4k+1] = W[4(k-1)+1] ⊕ W[4k]       // 每轮第2字:简单异或 
W[4k+2] = W[4(k-1)+2] ⊕ W[4k+1]     // 每轮第3字:简单异或
W[4k+3] = W[4(k-1)+3] ⊕ W[4k+2]     // 每轮第4字:简单异或
 
PS:
⊕ 是异或运算符号(XOR,Exclusive OR)
K 是轮数
W[4k-1] = W[4k+3] ⊕ W[4k+2]
W[4k-2] = W[4k+2] ⊕ W[4k+1]
W[4k-3] = W[4k+1] ⊕ W[4k]
W[4k-4] = W[4k] ⊕ T(W[4k-1])
T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
PS:k=已知轮数
W[4k-1] = W[4k+3] ⊕ W[4k+2]
W[4k-2] = W[4k+2] ⊕ W[4k+1]
W[4k-3] = W[4k+1] ⊕ W[4k]
W[4k-4] = W[4k] ⊕ T(W[4k-1])
T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
PS:k=已知轮数
公式: W[4k-1] = W[4k+3] ⊕ W[4k+2]
应用: W[39] = W[43] ⊕ W[42]
计算:W[39] = b6630ca6 ⊕ e13f0cc8 = 575c006e
公式: W[4k-1] = W[4k+3] ⊕ W[4k+2]
应用: W[39] = W[43] ⊕ W[42]
计算:W[39] = b6630ca6 ⊕ e13f0cc8 = 575c006e
公式: W[4k-2] = W[4k+2] ⊕ W[4k+1]
应用: W[38] = W[42] ⊕ W[41]
计算:W[38] = e13f0cc8 ⊕ c9ee2589 = 28d12941
公式: W[4k-2] = W[4k+2] ⊕ W[4k+1]
应用: W[38] = W[42] ⊕ W[41]
计算:W[38] = e13f0cc8 ⊕ c9ee2589 = 28d12941
公式: W[4k-3] = W[4k+1] ⊕ W[4k]
应用: W[37] = W[41] ⊕ W[40]
计算:W[37] = c9ee2589 ⊕ d014f9a8 = 19fadc21
公式: W[4k-3] = W[4k+1] ⊕ W[4k]
应用: W[37] = W[41] ⊕ W[40]
计算:W[37] = c9ee2589 ⊕ d014f9a8 = 19fadc21
公式: W[4k-4] = W[4k] ⊕ T(W[4k-1])
应用: W[36] = W[40] ⊕ T(W[39])
公式: W[4k-4] = W[4k] ⊕ T(W[4k-1])
应用: W[36] = W[40] ⊕ T(W[39])
T函数公式: T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
应用: T(575c006e) = SubWord(RotWord(575c006e)) ⊕ Rcon[10]
T函数公式: T(W[4k-1]) = SubWord(RotWord(W[4k-1])) ⊕ Rcon[k]
应用: T(575c006e) = SubWord(RotWord(575c006e)) ⊕ Rcon[10]
RotWord(575c006e) → 向左循环移位8位:[57, 5c, 00, 6e] → [5c, 00, 6e, 57]
结果:5c006e57
RotWord(575c006e) → 向左循环移位8位:[57, 5c, 00, 6e] → [5c, 00, 6e, 57]
结果:5c006e57
SubWord(5c006e57) → 通过S盒逐字节替换,结果:4a639f5b
SubWord(5c006e57) → 通过S盒逐字节替换,结果:4a639f5b
4a639f5b ⊕ Rcon[10] = 4a639f5b 36000000 = 7c639f5b
T函数最终结果: T(W[39]) = 7c639f5b
4a639f5b ⊕ Rcon[10] = 4a639f5b 36000000 = 7c639f5b
T函数最终结果: T(W[39]) = 7c639f5b
W[36] = W[40] ⊕ T(W[39]) = d014f9a8 ⊕ 7c639f5b = ac7766f3
W[36] = W[40] ⊕ T(W[39]) = d014f9a8 ⊕ 7c639f5b = ac7766f3
function hexToBytes(hex) {
    let bytes = [];
    for (let i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
 
function bytesToHex(bytes) {
    return Array.from(bytes).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('');
}
 
function wbaes(hexInput) {
    if (!hexInput) {
        hexInput = '30313233343536373839616263646566';
    }
     
    try {
        let libBase = Module.findBaseAddress("libcryptoDD.so");
        let funcAddr = libBase.add(0x17BD4 + 1);
        let wbaes_encrypt_ecb = new NativeFunction(funcAddr, 'int32', ['pointer', 'uint32', 'pointer', 'uint32']);
         
        // 转换输入
        let inputBytes = hexToBytes(hexInput);
        console.log("[+] Input:", hexInput);
         
        // 分配16字节内存
        let inputPtr = Memory.alloc(16);
        let outputPtr = Memory.alloc(16);
         
        // 写入数据
        inputPtr.writeByteArray(inputBytes);
        outputPtr.writeByteArray(new Array(16).fill(0));
         
        // 调用函数
        let result = wbaes_encrypt_ecb(inputPtr, 16, outputPtr, 0);
         
        // 读取输出
        let outputBytes = [];
        for (let i = 0; i < 16; i++) {
            outputBytes.push(outputPtr.add(i).readU8());
        }
         
        let outputHex = bytesToHex(outputBytes);
        console.log("[+] Output:", outputHex);
        console.log("[+] Return:", result);
         
        return outputHex;
         
    } catch (e) {
        console.log("[-] Error:", e);
        return null;
    }
}
 
function simpleDFA() {
    let libBase = Module.findBaseAddress("libcryptoDD.so");
    let count = 0;
     
    Interceptor.attach(libBase.add(0x14F98 + 1), {
        onLeave: function() {
            if (++count % 9 === 0) {
                let pos = Math.floor(Math.random() * 16);
                let val = Math.floor(Math.random() * 256);
                this.context.r0.add(pos).writeU8(val);
                console.log(`[!] Fault injected at position ${pos}`);
            }
        }
    });
}
function forDFA() {
    let results = [];
     
    // 收集正确结果
    let correctResult = wbaes('30313233343536373839616263646566');
    console.log("[+] Correct:", correctResult);
     
    // 启动DFA攻击
    simpleDFA();
     
    // 收集500个错误结果
    for (let i = 0; i < 500; i++) {
        let faultyResult = wbaes('30313233343536373839616263646566');
        if (faultyResult && faultyResult !== correctResult) {
            results.push(faultyResult);
        } else {
            i--; // 重试
        }
    }
     
    // 输出结果
    console.log("\n[Correct Result]");
    console.log(correctResult);
    console.log("\n[Faulty Results]");
    results.forEach(r => console.log(r));
     
    console.log(`\n[+] Done! ${results.length} faulty results collected.`);
    return {correct: correctResult, faulty: results};
}
function hexToBytes(hex) {
    let bytes = [];
    for (let i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
 
function bytesToHex(bytes) {
    return Array.from(bytes).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('');
}
 
function wbaes(hexInput) {
    if (!hexInput) {
        hexInput = '30313233343536373839616263646566';
    }
     

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2025-8-12 23:51 被青衫不负雪编辑 ,原因: 错字修改
收藏
免费 101
支持
分享
最新回复 (55)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-8-13 06:44
0
雪    币: 465
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2025-8-13 13:09
0
雪    币: 104
活跃值: (7295)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
tql
2025-8-13 14:02
0
雪    币: 1501
活跃值: (3743)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
哟西 学习
2025-8-13 14:10
0
雪    币: 8297
活跃值: (4853)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习下
2025-8-13 15:55
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
666
2025-8-13 18:12
0
雪    币: 2118
活跃值: (2135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
666
2025-8-13 21:37
0
雪    币: 3048
活跃值: (3280)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
666
2025-8-14 10:07
0
雪    币: 1673
活跃值: (1892)
能力值: ( LV7,RANK:103 )
在线值:
发帖
回帖
粉丝
10
666
2025-8-15 11:04
0
雪    币: 9
活跃值: (393)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
555
2025-8-15 15:48
0
雪    币: 208
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
666
2025-8-18 16:00
0
雪    币: 5702
活跃值: (9622)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
用到的地方不多
2025-8-18 16:36
0
雪    币: 0
活跃值: (86)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
牛皮
2025-8-19 11:51
0
雪    币: 154
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
666
2025-8-22 17:13
0
雪    币: 209
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
666
2025-8-22 17:16
0
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
666
2025-8-23 20:29
0
雪    币: 2468
活跃值: (4776)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
666
2025-8-23 21:38
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
29o
19
111
2025-8-26 15:50
0
雪    币: 204
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
学习
2025-8-26 16:50
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
66666
2025-8-27 14:12
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
6
2025-8-29 11:47
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
11
2025-9-1 09:11
0
雪    币: 33
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
666
2025-9-3 00:21
0
雪    币: 81
活跃值: (1108)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
666
2025-9-3 17:24
0
游客
登录 | 注册 方可回帖
返回