TGCTF Reverse 方向复现

base 64

变种 base64

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
32
33
34
35
36
37
38
39
custom_table = "GLp/+Wn7uqX8FQ2JDR1c0M6U53sjBwyxglmrCVdSThAfEOvPHaYZNzo4ktK9iebI"
table_dict = {char: idx for idx, char in enumerate(custom_table)}

encoded_str = "AwLdOEVEhIWtajB2CbCWCbTRVsFFC8hirfiXC9gWH9HQayCJVbB8CIF="

# 移除末尾等号并计算填充数
pad_count = encoded_str.count('=')
encoded_clean = encoded_str.rstrip('=')
#rstrip()删除字符串结尾的指定字符 lstrip()删除字符串开开头的指定字符
decoded_bytes = []

# 每4字符一组解码
for i in range(0, len(encoded_clean), 4):
chunk = encoded_clean[i:i+4].ljust(4, 'A') #填充不影响最终结果

#计算每个字符对应的6位值
indexes = []
for c in chunk:
if c == '=':
indexes.append(0)
else:
x = (table_dict[c] - 24) % 64
indexes.append(x)

# 组合成3字节
byte1 = (indexes[0] << 2) | (indexes[1] >> 4)
byte2 = ((indexes[1] & 0x0F) << 4) | (indexes[2] >> 2)
byte3 = ((indexes[2] & 0x03) << 6) | indexes[3]

decoded_bytes.extend([byte1, byte2, byte3])

# 根据填充数去除多余字节
if pad_count:
decoded_bytes = decoded_bytes[:-pad_count]
#如果原始编码字符中有填充的等号,根据 pad_count 去除解码结果中多余的字节

# 转换为字符串并拼接Flag
flag_content = bytes(decoded_bytes).decode('latin-1')
print(f"HZNUCTF{{{flag_content}}}")

得到flagHZNUCTF{ad162c-2d94-434d-9222-b65dc76a32}

XTEA

  1. 种子确定,拿到key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <cstdlib>
#include <iomanip>

int main() {
srand(0x7e9u); // 初始化随机数种子

// 生成四个随机数
for (int i = 0; i < 4; i++) {
uint32_t value = rand() & 0xFFFF; // 取低 16 位
std::cout << "Generated: 0x" << std::hex << value << std::endl;
}

return 0;
}

// Generated: 0x19fb
// Generated: 0x3bba
// Generated: 0x4f59
// Generated: 0x1217

解密脚本

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void decrypt(uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * (-32);
for (i=0; i < 32; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);

}
v[0] = v0; v[1] = v1;
}

int main() {
uint32_t const k[4] = {0x19f8,0x11be,0x991,0x3418};
uint32_t enc[] = {0x8ccb2324,0x9a7741a,0xfb3c678d,0xf6083a79,0xf1cc241b,0x39fa59f2,0xf2abe1cc,0x17189f72};
for(int i=6; i>=0; i-=1){ //倒着解密
decrypt(&enc[i], k);
}
for (int i = 0; i < 8; i++) {
for (int m = 3; m>=0; m--) {
printf("%c", (enc[i] >> (8 * m)) & 0xff);
}
}
return 0;
}

得到flagHZNUCTF{ae6-9f57-4b74-b423-98eb}

水果忍者

  1. Unity游戏的核心逻辑通常由C#脚本编写,编译后会被打包到 Assembly-CSharp.dll;该文件位于游戏目录的 <游戏名>_Data\Managed\ 下,如本题在 \水果忍者\Fruit Ninja_Data\Managed\Assembly-CSharp.dll
  2. dnSpy打开 Assembly-CSharp.dll,在 GameManager 里面找到:

    在 Decrypt 里看到是 AES 加密,而密文、密钥、iv 在下面都能找到

    CyberChef 解密

    flag为HZNUCTF{de20-70dd-4e62-b8d0-06e}

蛇年的本名语言

  1. pyc: 脚本文件编译得到的字节码, 二进制文件
    pyd: 基本的Windows DLL文件, python的动态链接库
  2. pyinstxtractor 解包 exe 文件,把 pyinstxtractor.py 和 output.exe 放在同一目录下,执行
1
python pyinstxtractor.py output.exe

解包后发现是 pyc,用 https://tool.lu/pyc 解密 output.pyc,得到的代码变量命名被混淆
稍微修改一下

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from collections import Counter
print("Welcome to HZNUCTF!!!")
print("Plz input the flag:")
a = input()
b = Counter(a)
c = "".join((str(b[v]) for v in a))
print("ans1: ", _end_="")
print(c)
if c != "111111116257645365477364777645752361":
print("wrong_wrong!!!")
exit(1)
x = ""
for v in a:
if b[v] > 0:
x += v + str(b[v])
b[v] = 0
else:
enc = [ord(v) for v in x]
n = [
7 * enc[0] == 504,
9 * enc[0] - 5 * enc[1] == 403,
2 * enc[0] - 5 * enc[1] + 10 * enc[2] == 799,
3 * enc[0] + 8 * enc[1] + 15 * enc[2] + 20 * enc[3] == 2938,
5 * enc[0] + 15 * enc[1] + 20 * enc[2] - 19 * enc[3] + 1 * enc[4] == 2042,
7 * enc[0] + 1 * enc[1] + 9 * enc[2] - 11 * enc[3] + 2 * enc[4] + 5 * enc[5] == 1225,
11 * enc[0] + 22 * enc[1] + 33 * enc[2] + 44 * enc[3] + 55 * enc[4] + 66 * enc[5] - 77 * enc[6] == 7975,
21 * enc[0] + 23 * enc[1] + 3 * enc[2] + 24 * enc[3] - 55 * enc[4] + 6 * enc[5] - 7 * enc[6] + 15 * enc[7] == 229,
2 * enc[0] + 26 * enc[1] + 13 * enc[2] + 0 * enc[3] - 65 * enc[4] + 15 * enc[5] + 29 * enc[6] + 1 * enc[7] + 20 * enc[8] == 2107,
10 * enc[0] + 7 * enc[1] + -9 * enc[2] + 6 * enc[3] + 7 * enc[4] + 1 * enc[5] + 22 * enc[6] + 21 * enc[7] - 22 * enc[8] + 30 * enc[9] == 4037,
15 * enc[0] + 59 * enc[1] + 56 * enc[2] + 66 * enc[3] + 7 * enc[4] + 1 * enc[5] - 122 * enc[6] + 21 * enc[7] + 32 * enc[8] + 3 * enc[9] - 10 * enc[10] == 4950,
13 * enc[0] + 66 * enc[1] + 29 * enc[2] + 39 * enc[3] - 33 * enc[4] + 13 * enc[5] - 2 * enc[6] + 42 * enc[7] + 62 * enc[8] + 1 * enc[9] - 10 * enc[10] + 11 * enc[11] == 12544,
23 * enc[0] + 6 * enc[1] + 29 * enc[2] + 3 * enc[3] - 3 * enc[4] + 63 * enc[5] - 25 * enc[6] + 2 * enc[7] + 32 * enc[8] + 1 * enc[9] - 10 * enc[10] + 11 * enc[11] - 12 * enc[12] == 6585,
223 * enc[0] + 6 * enc[1] - 29 * enc[2] - 53 * enc[3] - 3 * enc[4] + 3 * enc[5] - 65 * enc[6] + 0 * enc[7] + 36 * enc[8] + 1 * enc[9] - 15 * enc[10] + 16 * enc[11] - 18 * enc[12] + 13 * enc[13] == 6893,
29 * enc[0] + 13 * enc[1] - 9 * enc[2] - 93 * enc[3] + 33 * enc[4] + 6 * enc[5] + 65 * enc[6] + 1 * enc[7] - 36 * enc[8] + 0 * enc[9] - 16 * enc[10] + 96 * enc[11] - 68 * enc[12] + 33 * enc[13] - 14 * enc[14] == 1883,
69 * enc[0] + 77 * enc[1] - 93 * enc[2] - 12 * enc[3] + 0 * enc[4] + 0 * enc[5] + 1 * enc[6] + 16 * enc[7] + 36 * enc[8] + 6 * enc[9] + 19 * enc[10] + 66 * enc[11] - 8 * enc[12] + 38 * enc[13] - 16 * enc[14] + 15 * enc[15] == 8257,
23 * enc[0] + 2 * enc[1] - 3 * enc[2] - 11 * enc[3] + 12 * enc[4] + 24 * enc[5] + 1 * enc[6] + 6 * enc[7] + 14 * enc[8] - 0 * enc[9] + 1 * enc[10] + 68 * enc[11] - 18 * enc[12] + 68 * enc[13] - 26 * enc[14] + 15 * enc[15] - 16 * enc[16] == 5847,
24 * enc[0] + 0 * enc[1] - 1 * enc[2] - 15 * enc[3] + 13 * enc[4] + 4 * enc[5] + 16 * enc[6] + 67 * enc[7] + 146 * enc[8] - 50 * enc[9] + 16 * enc[10] + 6 * enc[11] - 1 * enc[12] + 69 * enc[13] - 27 * enc[14] + 45 * enc[15] - 6 * enc[16] + 17 * enc[17] == 18257,
25 * enc[0] + 26 * enc[1] - 89 * enc[2] + 16 * enc[3] + 19 * enc[4] + 44 * enc[5] + 36 * enc[6] + 66 * enc[7] - 150 * enc[8] - 250 * enc[9] + 166 * enc[10] + 126 * enc[11] - 11 * enc[12] + 690 * enc[13] - 207 * enc[14] + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18] == 12591,
5 * enc[0] + 26 * enc[1] + 8 * enc[2] + 160 * enc[3] + 9 * enc[4] - 4 * enc[5] + 36 * enc[6] + 6 * enc[7] - 15 * enc[8] - 20 * enc[9] + 66 * enc[10] + 16 * enc[11] - 1 * enc[12] + 690 * enc[13] - 20 * enc[14] + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18] + 19 * enc[19] == 52041,
29 * enc[0] - 26 * enc[1] + 0 * enc[2] + 60 * enc[3] + 90 * enc[4] - 4 * enc[5] + 6 * enc[6] + 6 * enc[7] - 16 * enc[8] - 21 * enc[9] + 69 * enc[10] + 6 * enc[11] - 12 * enc[12] + 69 * enc[13] - 20 * enc[14] - 46 * enc[15] + 65 * enc[16] + 0 * enc[17] - 1 * enc[18] + 39 * enc[19] - 20 * enc[20] == 20253,
45 * enc[0] - 56 * enc[1] + 10 * enc[2] + 650 * enc[3] - 900 * enc[4] + 44 * enc[5] + 66 * enc[6] - 6 * enc[7] - 6 * enc[8] - 21 * enc[9] + 9 * enc[10] - 6 * enc[11] - 12 * enc[12] + 69 * enc[13] - 2 * enc[14] - 406 * enc[15] + 651 * enc[16] + 2 * enc[17] - 10 * enc[18] + 69 * enc[19] - 0 * enc[20] + 21 * enc[21] == 18768,
555 * enc[0] - 6666 * enc[1] + 70 * enc[2] + 510 * enc[3] - 90 * enc[4] + 499 * enc[5] + 66 * enc[6] - 66 * enc[7] - 610 * enc[8] - 221 * enc[9] + 9 * enc[10] - 23 * enc[11] - 102 * enc[12] + 6 * enc[13] + 2050 * enc[14] - 406 * enc[15] + 665 * enc[16] + 333 * enc[17] + 100 * enc[18] + 609 * enc[19] + 777 * enc[20] + 201 * enc[21] - 22 * enc[22] == 111844,
1 * enc[0] - 22 * enc[1] + 333 * enc[2] + 4444 * enc[3] - 5555 * enc[4] + 6666 * enc[5] - 666 * enc[6] + 676 * enc[7] - 660 * enc[8] - 22 * enc[9] + 9 * enc[10] - 73 * enc[11] - 107 * enc[12] + 6 * enc[13] + 250 * enc[14] - 6 * enc[15] + 65 * enc[16] + 39 * enc[17] + 10 * enc[18] + 69 * enc[19] + 777 * enc[20] + 201 * enc[21] - 2 * enc[22] + 23 * enc[23] == 159029,
520 * enc[0] - 222 * enc[1] + 333 * enc[2] + 4 * enc[3] - 56655 * enc[4] + 6666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 60 * enc[8] - 220 * enc[9] + 99 * enc[10] + 73 * enc[11] + 1007 * enc[12] + 7777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 99999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] == 2762025,
1323 * enc[0] - 22 * enc[1] + 333 * enc[2] + 4 * enc[3] - 55 * enc[4] + 666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 660 * enc[8] - 220 * enc[9] + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 9999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] == 1551621,
777 * enc[0] - 22 * enc[1] + 6969 * enc[2] + 4 * enc[3] - 55 * enc[4] + 666 * enc[5] - 6 * enc[6] + 96 * enc[7] - 60 * enc[8] - 220 * enc[9] + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 250 * enc[14] + 666 * enc[15] + 65 * enc[16] + 90 * enc[17] + 100 * enc[18] + 609 * enc[19] + 999 * enc[20] + 21 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] - 26 * enc[26] == 948348,
97 * enc[0] - 22 * enc[1] + 6969 * enc[2] + 4 * enc[3] - 56 * enc[4] + 96 * enc[5] - 6 * enc[6] + 96 * enc[7] - 60 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 90 * enc[17] + -2 * enc[18] + 609 * enc[19] + 0 * enc[20] + 21 * enc[21] + 2 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] - 26 * enc[26] + 27 * enc[27] == 777044,
177 * enc[0] - 22 * enc[1] + 699 * enc[2] + 64 * enc[3] - 56 * enc[4] - 96 * enc[5] - 66 * enc[6] + 96 * enc[7] - 60 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 69 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24] + 25 * enc[25] - 26 * enc[26] + 27 * enc[27] - 28 * enc[28] == 185016,
77 * enc[0] - 2 * enc[1] + 6 * enc[2] + 6 * enc[3] - 96 * enc[4] - 9 * enc[5] - 6 * enc[6] + 96 * enc[7] - 0 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 9 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24] + 26 * enc[25] - -58 * enc[26] + 27 * enc[27] - 2 * enc[28] + 29 * enc[29] == 130106]
if all(n):
print("Congratulation!!!")
else:
print("wrong_wrong!!!")

一眼 z3, 111111116257645365477364777645752361即密文,每个数字代表一个字符出现的次数
z3 求解

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from z3 import *

# 定义 30 个变量,对应 flag 的每个字符的 ASCII 值
enc = [Int(f'enc{j}') for j in range(30)]

s = Solver()

# 限制所有变量在 ASCII 范围内(通常 flag 用可打印字符)
for var in enc:
s.add(var >= 32, var <= 126)


s.add(7 * enc[0] == 504)
s.add(9 * enc[0] - 5 * enc[1] == 403)
s.add(2 * enc[0] - 5 * enc[1] + 10 * enc[2] == 799)
s.add(3 * enc[0] + 8 * enc[1] + 15 * enc[2] + 20 * enc[3] == 2938)
s.add(5 * enc[0] + 15 * enc[1] + 20 * enc[2] - 19 * enc[3] + 1 * enc[4] == 2042)
s.add(7 * enc[0] + 1 * enc[1] + 9 * enc[2] - 11 * enc[3] + 2 * enc[4] + 5 * enc[5] == 1225)
s.add(11 * enc[0] + 22 * enc[1] + 33 * enc[2] + 44 * enc[3] + 55 * enc[4] + 66 * enc[5] - 77 * enc[6] == 7975)
s.add(21 * enc[0] + 23 * enc[1] + 3 * enc[2] + 24 * enc[3] - 55 * enc[4] + 6 * enc[5] - 7 * enc[6] + 15 * enc[7] == 229)
s.add(2 * enc[0] + 26 * enc[1] + 13 * enc[2] - 65 * enc[4] + 15 * enc[5] + 29 * enc[6] + 1 * enc[7] + 20 * enc[8] == 2107)
s.add(10 * enc[0] + 7 * enc[1] - 9 * enc[2] + 6 * enc[3] + 7 * enc[4] + enc[5] + 22 * enc[6] + 21 * enc[7] - 22 * enc[8] + 30 * enc[9] == 4037)
s.add(15 * enc[0] + 59 * enc[1] + 56 * enc[2] + 66 * enc[3] + 7 * enc[4] + enc[5] - 122 * enc[6] + 21 * enc[7] + 32 * enc[8] + 3 * enc[9] - 10 * enc[10] == 4950)
s.add(13 * enc[0] + 66 * enc[1] + 29 * enc[2] + 39 * enc[3] - 33 * enc[4] + 13 * enc[5] - 2 * enc[6] + 42 * enc[7] + 62 * enc[8] + enc[9] - 10 * enc[10] + 11 * enc[11] == 12544)
s.add(23 * enc[0] + 6 * enc[1] + 29 * enc[2] + 3 * enc[3] - 3 * enc[4] + 63 * enc[5] - 25 * enc[6] + 2 * enc[7] + 32 * enc[8] + enc[9] - 10 * enc[10] + 11 * enc[11] - 12 * enc[12] == 6585)
s.add(223 * enc[0] + 6 * enc[1] - 29 * enc[2] - 53 * enc[3] - 3 * enc[4] + 3 * enc[5] - 65 * enc[6] + 36 * enc[8] + enc[9] - 15 * enc[10] + 16 * enc[11] - 18 * enc[12] + 13 * enc[13] == 6893)
s.add(29 * enc[0] + 13 * enc[1] - 9 * enc[2] - 93 * enc[3] + 33 * enc[4] + 6 * enc[5] + 65 * enc[6] + enc[7] - 36 * enc[8] - 16 * enc[10] + 96 * enc[11] - 68 * enc[12] + 33 * enc[13] - 14 * enc[14] == 1883)
s.add(69 * enc[0] + 77 * enc[1] - 93 * enc[2] - 12 * enc[3] + enc[6] + 16 * enc[7] + 36 * enc[8] + 6 * enc[9] + 19 * enc[10] + 66 * enc[11] - 8 * enc[12] + 38 * enc[13] - 16 * enc[14] + 15 * enc[15] == 8257)
s.add(23 * enc[0] + 2 * enc[1] - 3 * enc[2] - 11 * enc[3] + 12 * enc[4] + 24 * enc[5] + enc[6] + 6 * enc[7] + 14 * enc[8] + enc[10] + 68 * enc[11] - 18 * enc[12] + 68 * enc[13] - 26 * enc[14] + 15 * enc[15] - 16 * enc[16] == 5847)
s.add(24 * enc[0] - enc[2] - 15 * enc[3] + 13 * enc[4] + 4 * enc[5] + 16 * enc[6] + 67 * enc[7] + 146 * enc[8] - 50 * enc[9] + 16 * enc[10] + 6 * enc[11] - enc[12] + 69 * enc[13] - 27 * enc[14] + 45 * enc[15] - 6 * enc[16] + 17 * enc[17] == 18257)
s.add(25 * enc[0] + 26 * enc[1] - 89 * enc[2] + 16 * enc[3] + 19 * enc[4] + 44 * enc[5] + 36 * enc[6] + 66 * enc[7] - 150 * enc[8] - 250 * enc[9] + 166 * enc[10] + 126 * enc[11] - 11 * enc[12] + 690 * enc[13] - 207 * enc[14] + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18] == 12591)
s.add(5 * enc[0] + 26 * enc[1] + 8 * enc[2] + 160 * enc[3] + 9 * enc[4] - 4 * enc[5] + 36 * enc[6] + 6 * enc[7] - 15 * enc[8] - 20 * enc[9] + 66 * enc[10] + 16 * enc[11] - enc[12] + 690 * enc[13] - 20 * enc[14] + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18] + 19 * enc[19] == 52041)
s.add(29 * enc[0] - 26 * enc[1] + 60 * enc[3] + 90 * enc[4] - 4 * enc[5] + 6 * enc[6] + 6 * enc[7] - 16 * enc[8] - 21 * enc[9] + 69 * enc[10] + 6 * enc[11] - 12 * enc[12] + 69 * enc[13] - 20 * enc[14] - 46 * enc[15] + 65 * enc[16] - enc[18] + 39 * enc[19] - 20 * enc[20] == 20253)
s.add(45 * enc[0] - 56 * enc[1] + 10 * enc[2] + 650 * enc[3] - 900 * enc[4] + 44 * enc[5] + 66 * enc[6] - 6 * enc[7] - 6 * enc[8] - 21 * enc[9] + 9 * enc[10] - 6 * enc[11] - 12 * enc[12] + 69 * enc[13] - 2 * enc[14] - 406 * enc[15] + 651 * enc[16] + 2 * enc[17] - 10 * enc[18] + 69 * enc[19] + 21 * enc[21] == 18768)
s.add(555 * enc[0] - 6666 * enc[1] + 70 * enc[2] + 510 * enc[3] - 90 * enc[4] + 499 * enc[5] + 66 * enc[6] - 66 * enc[7] - 610 * enc[8] - 221 * enc[9] + 9 * enc[10] - 23 * enc[11] - 102 * enc[12] + 6 * enc[13] + 2050 * enc[14] - 406 * enc[15] + 665 * enc[16] + 333 * enc[17] + 100 * enc[18] + 609 * enc[19] + 777 * enc[20] + 201 * enc[21] - 22 * enc[22] == 111844,)
s.add(1 * enc[0] - 22 * enc[1] + 333 * enc[2] + 4444 * enc[3] - 5555 * enc[4] + 6666 * enc[5] - 666 * enc[6] + 676 * enc[7] - 660 * enc[8] - 22 * enc[9] + 9 * enc[10] - 73 * enc[11] - 107 * enc[12] + 6 * enc[13] + 250 * enc[14] - 6 * enc[15] + 65 * enc[16] + 39 * enc[17] + 10 * enc[18] + 69 * enc[19] + 777 * enc[20] + 201 * enc[21] - 2 * enc[22] + 23 * enc[23] == 159029,)
s.add(520 * enc[0] - 222 * enc[1] + 333 * enc[2] + 4 * enc[3] - 56655 * enc[4] + 6666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 60 * enc[8] - 220 * enc[9] + 99 * enc[10] + 73 * enc[11] + 1007 * enc[12] + 7777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 99999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] == 2762025,)
s.add(1323 * enc[0] - 22 * enc[1] + 333 * enc[2] + 4 * enc[3] - 55 * enc[4] + 666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 660 * enc[8] - 220 * enc[9] + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 9999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] == 1551621,)
s.add(777 * enc[0] - 22 * enc[1] + 6969 * enc[2] + 4 * enc[3] - 55 * enc[4] + 666 * enc[5] - 6 * enc[6] + 96 * enc[7] - 60 * enc[8] - 220 * enc[9] + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 250 * enc[14] + 666 * enc[15] + 65 * enc[16] + 90 * enc[17] + 100 * enc[18] + 609 * enc[19] + 999 * enc[20] + 21 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] - 26 * enc[26] == 948348,)
s.add(97 * enc[0] - 22 * enc[1] + 6969 * enc[2] + 4 * enc[3] - 56 * enc[4] + 96 * enc[5] - 6 * enc[6] + 96 * enc[7] - 60 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 90 * enc[17] + -2 * enc[18] + 609 * enc[19] + 0 * enc[20] + 21 * enc[21] + 2 * enc[22] + 23 * enc[23] - 24 * enc[24] + 25 * enc[25] - 26 * enc[26] + 27 * enc[27] == 777044,)
s.add(177 * enc[0] - 22 * enc[1] + 699 * enc[2] + 64 * enc[3] - 56 * enc[4] - 96 * enc[5] - 66 * enc[6] + 96 * enc[7] - 60 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 69 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24] + 25 * enc[25] - 26 * enc[26] + 27 * enc[27] - 28 * enc[28] == 185016,)
s.add(77 * enc[0] - 2 * enc[1] + 6 * enc[2] + 6 * enc[3] - 96 * enc[4] - 9 * enc[5] - 6 * enc[6] + 96 * enc[7] - 0 * enc[8] - 20 * enc[9] + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 9 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24] + 26 * enc[25] - -58 * enc[26] + 27 * enc[27] - 2 * enc[28] + 29 * enc[29] == 130106)


# 求解
if s.check() == sat:
model = s.model()
flag = ''.join([chr(model[enc[j]].as_long()) for j in range(30)])
print("Flag is:", flag)
else:
print("No solution found.")

output:
Flag is: H1Z1N1U1C1T1F1{1a6d275f7-463}1
可以看到这里的一一对应关系 HZNUCTF{ 对应11111111,仍然回到这串数字111111116257645365477364777645752361,可以得到映射表 ‘6’->’a’,’2’->’d’,’5’->’7’,’7’->’f’,’4’->’-‘,’3’->’6’,’1’->’}’
继续求解

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
from z3 import *

def decrypt(_encrypted_):
res= "6257645365477364777645752361"

char_map = {}

remaining_map = {
'6': 'a',
'2': 'd',
'5': '7',
'7': 'f',
'4': '-',
'3': '6',
'1': '}'
}
char_map.update(remaining_map)

result = "HZNUCTF{"
for num in res:
result += char_map[num]

return result

s = Solver()

enc = [Int(f'x{i}') for i in range(30)]

s.add(7 * enc[0] == 504)
s.add(9 * enc[0] - 5 * enc[1] == 403)
s.add((2 * enc[0] - 5 * enc[1]) + 10 * enc[2] == 799)
s.add(3 * enc[0] + 8 * enc[1] + 15 * enc[2] + 20 * enc[3] == 2938)
s.add((5 * enc[0] + 15 * enc[1] + 20 * enc[2] - 19 * enc[3]) + 1 * enc[4] == 2042)
s.add((7 * enc[0] + 1 * enc[1] + 9 * enc[2] - 11 * enc[3]) + 2 * enc[4] + 5 * enc[5] == 1225)
s.add(11 * enc[0] + 22 * enc[1] + 33 * enc[2] + 44 * enc[3] + 55 * enc[4] + 66 * enc[5] - 77 * enc[6] == 7975)
s.add(((21 * enc[0] + 23 * enc[1] + 3 * enc[2] + 24 * enc[3] - 55 * enc[4]) + 6 * enc[5] - 7 * enc[6]) + 15 * enc[7] == 229)
s.add((2 * enc[0] + 26 * enc[1] + 13 * enc[2] + 0 * enc[3] - 65 * enc[4]) + 15 * enc[5] + 29 * enc[6] + 1 * enc[7] + 20 * enc[8] == 2107)
s.add((10 * enc[0] + 7 * enc[1] + -9 * enc[2] + 6 * enc[3] + 7 * enc[4] + 1 * enc[5] + 22 * enc[6] + 21 * enc[7] - 22 * enc[8]) + 30 * enc[9] == 4037)
s.add((15 * enc[0] + 59 * enc[1] + 56 * enc[2] + 66 * enc[3] + 7 * enc[4] + 1 * enc[5] - 122 * enc[6]) + 21 * enc[7] + 32 * enc[8] + 3 * enc[9] - 10 * enc[10] == 4950)
s.add((((13 * enc[0] + 66 * enc[1] + 29 * enc[2] + 39 * enc[3] - 33 * enc[4]) + 13 * enc[5] - 2 * enc[6]) + 42 * enc[7] + 62 * enc[8] + 1 * enc[9] - 10 * enc[10]) + 11 * enc[11] == 12544)
s.add((((23 * enc[0] + 6 * enc[1] + 29 * enc[2] + 3 * enc[3] - 3 * enc[4]) + 63 * enc[5] - 25 * enc[6]) + 2 * enc[7] + 32 * enc[8] + 1 * enc[9] - 10 * enc[10]) + 11 * enc[11] - 12 * enc[12] == 6585)
s.add(((((223 * enc[0] + 6 * enc[1] - 29 * enc[2] - 53 * enc[3] - 3 * enc[4]) + 3 * enc[5] - 65 * enc[6]) + 0 * enc[7] + 36 * enc[8] + 1 * enc[9] - 15 * enc[10]) + 16 * enc[11] - 18 * enc[12]) + 13 * enc[13] == 6893)
s.add(((((29 * enc[0] + 13 * enc[1] - 9 * enc[2] - 93 * enc[3]) + 33 * enc[4] + 6 * enc[5] + 65 * enc[6] + 1 * enc[7] - 36 * enc[8]) + 0 * enc[9] - 16 * enc[10]) + 96 * enc[11] - 68 * enc[12]) + 33 * enc[13] - 14 * enc[14] == 1883)
s.add((((69 * enc[0] + 77 * enc[1] - 93 * enc[2] - 12 * enc[3]) + 0 * enc[4] + 0 * enc[5] + 1 * enc[6] + 16 * enc[7] + 36 * enc[8] + 6 * enc[9] + 19 * enc[10] + 66 * enc[11] - 8 * enc[12]) + 38 * enc[13] - 16 * enc[14]) + 15 * enc[15] == 8257)
s.add(((((23 * enc[0] + 2 * enc[1] - 3 * enc[2] - 11 * enc[3]) + 12 * enc[4] + 24 * enc[5] + 1 * enc[6] + 6 * enc[7] + 14 * enc[8] - 0 * enc[9]) + 1 * enc[10] + 68 * enc[11] - 18 * enc[12]) + 68 * enc[13] - 26 * enc[14]) + 15 * enc[15] - 16 * enc[16] == 5847)
s.add((((((24 * enc[0] + 0 * enc[1] - 1 * enc[2] - 15 * enc[3]) + 13 * enc[4] + 4 * enc[5] + 16 * enc[6] + 67 * enc[7] + 146 * enc[8] - 50 * enc[9]) + 16 * enc[10] + 6 * enc[11] - 1 * enc[12]) + 69 * enc[13] - 27 * enc[14]) + 45 * enc[15] - 6 * enc[16]) + 17 * enc[17] == 18257)
s.add(((((25 * enc[0] + 26 * enc[1] - 89 * enc[2]) + 16 * enc[3] + 19 * enc[4] + 44 * enc[5] + 36 * enc[6] + 66 * enc[7] - 150 * enc[8] - 250 * enc[9]) + 166 * enc[10] + 126 * enc[11] - 11 * enc[12]) + 690 * enc[13] - 207 * enc[14]) + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18] == 12591)
s.add((((((5 * enc[0] + 26 * enc[1] + 8 * enc[2] + 160 * enc[3] + 9 * enc[4] - 4 * enc[5]) + 36 * enc[6] + 6 * enc[7] - 15 * enc[8] - 20 * enc[9]) + 66 * enc[10] + 16 * enc[11] - 1 * enc[12]) + 690 * enc[13] - 20 * enc[14]) + 46 * enc[15] + 6 * enc[16] + 7 * enc[17] - 18 * enc[18]) + 19 * enc[19] == 52041)
s.add(((((((29 * enc[0] - 26 * enc[1]) + 0 * enc[2] + 60 * enc[3] + 90 * enc[4] - 4 * enc[5]) + 6 * enc[6] + 6 * enc[7] - 16 * enc[8] - 21 * enc[9]) + 69 * enc[10] + 6 * enc[11] - 12 * enc[12]) + 69 * enc[13] - 20 * enc[14] - 46 * enc[15]) + 65 * enc[16] + 0 * enc[17] - 1 * enc[18]) + 39 * enc[19] - 20 * enc[20] == 20253)
s.add((((((((45 * enc[0] - 56 * enc[1]) + 10 * enc[2] + 650 * enc[3] - 900 * enc[4]) + 44 * enc[5] + 66 * enc[6] - 6 * enc[7] - 6 * enc[8] - 21 * enc[9]) + 9 * enc[10] - 6 * enc[11] - 12 * enc[12]) + 69 * enc[13] - 2 * enc[14] - 406 * enc[15]) + 651 * enc[16] + 2 * enc[17] - 10 * enc[18]) + 69 * enc[19] - 0 * enc[20]) + 21 * enc[21] == 18768)
s.add((((((555 * enc[0] - 6666 * enc[1]) + 70 * enc[2] + 510 * enc[3] - 90 * enc[4]) + 499 * enc[5] + 66 * enc[6] - 66 * enc[7] - 610 * enc[8] - 221 * enc[9]) + 9 * enc[10] - 23 * enc[11] - 102 * enc[12]) + 6 * enc[13] + 2050 * enc[14] - 406 * enc[15]) + 665 * enc[16] + 333 * enc[17] + 100 * enc[18] + 609 * enc[19] + 777 * enc[20] + 201 * enc[21] - 22 * enc[22] == 111844)
s.add((((((((1 * enc[0] - 22 * enc[1]) + 333 * enc[2] + 4444 * enc[3] - 5555 * enc[4]) + 6666 * enc[5] - 666 * enc[6]) + 676 * enc[7] - 660 * enc[8] - 22 * enc[9]) + 9 * enc[10] - 73 * enc[11] - 107 * enc[12]) + 6 * enc[13] + 250 * enc[14] - 6 * enc[15]) + 65 * enc[16] + 39 * enc[17] + 10 * enc[18] + 69 * enc[19] + 777 * enc[20] + 201 * enc[21] - 2 * enc[22]) + 23 * enc[23] == 159029)
s.add((((520 * enc[0] - 222 * enc[1]) + 333 * enc[2] + 4 * enc[3] - 56655 * enc[4]) + 6666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 60 * enc[8] - 220 * enc[9]) + 99 * enc[10] + 73 * enc[11] + 1007 * enc[12] + 7777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 99999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24] == 2762025)
s.add(((((1323 * enc[0] - 22 * enc[1]) + 333 * enc[2] + 4 * enc[3] - 55 * enc[4]) + 666 * enc[5] + 666 * enc[6] + 66 * enc[7] - 660 * enc[8] - 220 * enc[9]) + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 2500 * enc[14] + 6666 * enc[15] + 605 * enc[16] + 390 * enc[17] + 100 * enc[18] + 609 * enc[19] + 9999 * enc[20] + 210 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24]) + 25 * enc[25] == 1551621)
s.add((((((777 * enc[0] - 22 * enc[1]) + 6969 * enc[2] + 4 * enc[3] - 55 * enc[4]) + 666 * enc[5] - 6 * enc[6]) + 96 * enc[7] - 60 * enc[8] - 220 * enc[9]) + 99 * enc[10] + 3 * enc[11] + 100 * enc[12] + 777 * enc[13] + 250 * enc[14] + 666 * enc[15] + 65 * enc[16] + 90 * enc[17] + 100 * enc[18] + 609 * enc[19] + 999 * enc[20] + 21 * enc[21] + 232 * enc[22] + 23 * enc[23] - 24 * enc[24]) + 25 * enc[25] - 26 * enc[26] == 948348)
s.add(((((((97 * enc[0] - 22 * enc[1]) + 6969 * enc[2] + 4 * enc[3] - 56 * enc[4]) + 96 * enc[5] - 6 * enc[6]) + 96 * enc[7] - 60 * enc[8] - 20 * enc[9]) + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 90 * enc[17] + -2 * enc[18] + 609 * enc[19] + 0 * enc[20] + 21 * enc[21] + 2 * enc[22] + 23 * enc[23] - 24 * enc[24]) + 25 * enc[25] - 26 * enc[26]) + 27 * enc[27] == 777044)
s.add((((((177 * enc[0] - 22 * enc[1]) + 699 * enc[2] + 64 * enc[3] - 56 * enc[4] - 96 * enc[5] - 66 * enc[6]) + 96 * enc[7] - 60 * enc[8] - 20 * enc[9]) + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 69 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24]) + 25 * enc[25] - 26 * enc[26]) + 27 * enc[27] - 28 * enc[28] == 185016)
s.add(((((((77 * enc[0] - 2 * enc[1]) + 6 * enc[2] + 6 * enc[3] - 96 * enc[4] - 9 * enc[5] - 6 * enc[6]) + 96 * enc[7] - 0 * enc[8] - 20 * enc[9]) + 99 * enc[10] + 3 * enc[11] + 10 * enc[12] + 707 * enc[13] + 250 * enc[14] + 666 * enc[15] + -9 * enc[16] + 0 * enc[17] + -2 * enc[18] + 9 * enc[19] + 0 * enc[20] + 21 * enc[21] + 222 * enc[22] + 23 * enc[23] - 224 * enc[24]) + 26 * enc[25] - -58 * enc[26]) + 27 * enc[27] - 2 * enc[28]) + 29 * enc[29] == 130106)

for x in enc:
s.add(x >= 32)
s.add(x <= 126)

if s.check() == sat:
m = s.model()

solution = [m[x].as_long() if m[x] is not None else 0 for x in enc]

decrypted = decrypt(solution)
print(decrypted)

else:
print("No solution found")

得到flagHZNUCTF{ad7fa-76a7-ff6a-fffa-7f7d6a}

conforand

  1. 直接用 ida 打开发现有 ollvm 混淆,用 D-810 先去混淆,从给出的符号表看到是 rc4 加密
1
v4 = rc4(v127, 42LL, v125, 9LL);

看传入的每个参数分别代表什么,往上看


大致为

1
int rc4(void* data, int data_length, void* key, int key_length);

密文长度为42个字节,密钥长度为9字节,即JustDoIt!
2. 在init中的sub_5s5s5s里初始化随机数种子并传入密钥

1
2
*v84 = time(0LL);
srand(seed);

init_sbox中调用rand()函数,种子不确定,rand()也只调用了这一次
rc4 算法中包含一个 S 盒,是一个含有 256 个元素的数组,其中的每个元素都是一个 8 位无符号整数,即 0-255 范围内的值,rand()函数被用来影响 S 盒的初始化过程,hook rand()函数尝试爆破

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
32
33
34
35
36
37
38
39
40
41
42
43
44
var lib=Process.getModuleByName("conforand");
var sym=lib.enumerateSymbols();
//返回"conforand"模块中所有的导出符号(函数、变量)的数组

for(var i=0;i<sym.length;i++){
//打印函数符号表
console.log(sym[i].name);
}
var randptr=Module.findExportByName("libc.so.6","rand");
//查找 lib.so.6 中 rand() 函数的内存地址
console.log("randptr:"+randptr);

var rc4ptr=lib.findSymbolByName("rc4");

//将原生函数封装成 JavaScript 可调用函数
var rand=new NativeFunction(randptr,'int',[]);
var rc4=new NativeFunction(rc4ptr,'int',['pointer','int','pointer','int']);
var rc4key=Memory.alloc(9);
rc4key.writeUtf8String("JustDoIt!");
//爆破rand()函数返回值
let randRet=0;
Interceptor.attach(randptr,{
//在每次rand()函数执行完,将原本的返回值替换成爆破值(randRet)
onLeave:function(retval){
retval.replace(randRet);
}
})
for(let i=0;i<256;i++){
randRet=i;
var input=Memory.alloc(42);
//密文 output.txt
input.writeByteArray([0x83, 0x1e, 0x9c, 0x48, 0x7a, 0xfa, 0xe8, 0x88,
0x36, 0xd5, 0x0a, 0x08, 0xf6, 0xa7, 0x70, 0x0f,
0xfd, 0x67, 0xdd, 0xd4, 0x3c, 0xa7, 0xed, 0x8d,
0x51, 0x10, 0xce, 0x6a, 0x9e, 0x56, 0x57, 0x83,
0x56, 0xe7, 0x67, 0x9a, 0x67, 0x22, 0x24, 0x6e,
0xcd, 0x2f]);
rc4(input,42,rc4key,9);
try{
console.log(input.readUtf8String(41));
}catch(e){
console.log("error:"+e);
}
}
  1. 在linux环境运行 开虚拟环境装frida
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
import frida
import sys
import time

with open('hook.js',"r",encoding="utf-8")as f:
jscode= f.read()

#目标程序路径为当前目录下的 "conforand" 可执行文件
targetProcessPackName="../conforand"
device=frida.get_local_device()

#启动并附加到目标进程
try:
pid=device.spawn([targetProcessPackName])
session=device.attach(pid)
print(pid)
except frida.ProcessNotFoundError:
print("No such process")
sys.exit(0)
device.resume(pid)#恢复目标进程
time.sleep(2)
#准备将 JavaScript 代码转换为可注入的脚本对象
script=session.create_script(jscode)
# script.on('message',onMassage)
script.load()#执行注入
sys.stdin.read()



得到flagHZNUCTF{489b88-1305-411e-b1f4-88a3070a73}

exchange

  1. 直接扔 ida 发现有壳,upx 工具去壳之后再打开,直接看没看出加密类型,用Findcrypt插件找到一个DES_sbox,基本确定是 DES 加密,x 交叉引用能一直跳到主函数那里

    Source 必须有至少 41 字节,否则 Source + 40 会越界访问,输入的flag形式必须是HZNUCTF{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx},中间部分长度为32个字节,否则程序会退出

  2. 第一个 for 循环对输入的{}中的字符进行处理,处理的结果存入 v12

    进入加密部分

  3. 由于 DES 的密钥是在加密前初始化好的,在 input 第一次传入前的函数动用处打断点,动调找密钥


    把 key 形式改 Q_word(64位) ,并且 Array size 改成32之后,能明显看到前后对称,而DES 的解密方式是16个子密钥倒着使用,于是直接修改寄存器(RCX)值,在原来的基础上加128(16*8),接着把密文 patch 到 input 里,直接运行解密

  4. 找到解密后的字符,导出为 hex string(unspaced),
    最后解密

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
def decrypt(v12):
result = ""
for i in range(0, len(v12), 4):
block = v12[i:i+4]
if len(block) < 4:
break # 防止异常
# 交换回去:2、3位交换
block = block[0] + block[2] + block[1] + block[3]

# 拆成两部分
hex1 = block[0:2]
hex2 = block[2:4]

# 转成字符
char1 = chr(int(hex1, 16))
char2 = chr(int(hex2, 16))

result += char1 + char2
return result


v12 = "333936147332632923d96353321d3345636826d26314621d3349330463126348"
flag_middle = decrypt(v12)

# 组装完整flag
flag = "HZNUCTF{" + flag_middle + "}"
print(flag)

# HZNUCTF{391ds2b9-9e31-45f8-ba4a-4904a2d8}

flag即为HZNUCTF{391ds2b9-9e31-45f8-ba4a-4904a2d8}


TGCTF Reverse 方向复现
http://example.com/2025/04/27/tgctf/
作者
Eleven
发布于
2025年4月27日
许可协议