L3HCTF 2024 [复现]

1086a721-7532-40ea-8229-785a9efa1da6

ez_rust

从字符串发现了tauri框架

查到:

用 JavaScript 编写前端,用 Rust 编写应用程序逻辑,并使用 Swift 和 Kotlin 在系统中深入集成。

tauri javascript提取 搜索相关资料搜到了

[Tauri 框架的静态资源提取方法探究 | yllhwa’s blog](https://blog.yllhwa.com/2023/05/09/Tauri 框架的静态资源提取方法探究/)

按着找的时候在下面发现几个js

image-20250823231459083

image-20250823231516053

0140371D3A -1403772A3

1
2
3
4
5
start = 0x140371D3A
size = 21865
data = ida_bytes.get_bytes(start, size)
with open("D:/dump1.txt", "wb") as f: # Windows 路径
f.write(data)

JavaScript 代码格式化 - 锤子在线工具

解压出来后在线格式化,扒出来关键代码

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
const nl = ve("button", {
type: "submit"
}, "go!", -1),
sl = {
__name: "Greet",
setup(e) {
const t = ts(""),
n = ts("");

function s(o, i = "secret") {
for (var c = "", u = i.length, d = 0; d < o.length; d++) {
var h = o.charCodeAt(d),
x = i.charCodeAt(d % u),
w = h ^ x;
c += String.fromCharCode(w)
}
return c
}
async function r() {
if (n.value === "") {
t.value = "Please enter a name.";
return
}
btoa(s(n.value)) === "JFYvMVU5QDoNQjomJlBULSQaCihTAFY=" ? t.value = "Great, you got the flag!" : t.value = "No, that's not my name."
}
return (o, i) => (mr(), br(ge, null, [ve("form", {
class: "row",
onSubmit: Qi(r, ["prevent"])
}, [Mo(ve("input", {
id: "greet-input",
"onUpdate:modelValue": i[0] || (i[0] = c => n.value = c),
placeholder: "Enter a name..."
}, null, 512), [
[zi, n.value]
]), nl], 32), ve("p", null, Nr(t.value), 1)], 64))
}
},
rl = (e, t) => {
const n = e.__vccOpts || e;
for (const [s, r] of t) n[s] = r;
return n
},
Kn = e => (bo("data-v-bacdabd6"), e = e(), yo(), e),
ol = {
class: "container"
},
il = Kn(() => ve("h1", null, "Welcome to L3HCTF!", -1)),
ll = Kn(() => ve("p", null, "Hope you have a good time playing.", -1)),
cl = Kn(() => ve("p", null, "Now please tell me a name.", -1)),
fl = {
__name: "App",
setup(e) {
return (t, n) => (mr(), br("div", ol, [il, ll, cl, Ae(sl)]))
}
},
ul = rl(fl, [
["__scopeId", "data-v-bacdabd6"]
]);
ki(ul).mount("#app");
1
2
3
4
5
6
7
8
9
import base64
enc = "JFYvMVU5QDoNQjomJlBULSQaCihTAFY="
enc = base64.b64decode(enc).decode('utf-8')
key = 'secret'
flag = ''
for i in range(0, len(enc)):
flag += chr(ord(enc[i]) ^ ord(key[i % 6]))
print(flag)
# W3LC0M3_n0_RU57_AnyM0r3

babycom

运行发现要权限

ida管理员打开调试,发现有些dll其中

image-20250825103714423

没有找到具体加密方法,猜测应该在dll中

打开查看发现tea

image-20250825103751952

也可以在这下断点进入

image-20250825124345524

调试得到的key

image-20250825124610907

分析一下 sub_7FF9867B5600 这个函数。这是 babycom.dll 中的核心加密函数。

函数首先解密一个字符串(很可能是 “kernel32.dll”),然后使用 LoadLibraryA 加载这个库,密钥初始化

自定义分组密码加密 (类似 XTEA)

最后Windows CryptoAPI ( advapi32.dll )加密

可以给出如下的xtea解密代码

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
#include <stdint.h>
#include <stdio.h>

void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x114514;
uint32_t sum = (32) * delta;
for (uint32_t i = 0; i < 32; i++) {
v1 -= (k[(sum >> 11) & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (v0 << 4)));
sum -= delta;
v0 -= (k[sum & 3] + sum) ^ (v1 + ((v1 >> 5) ^ (v1 << 4)));
}
v[0] = v0; v[1] = v1;
}

int main() {
unsigned char enc[] = {
0x0B, 0xAF, 0x51, 0x21, 0x9C, 0x52, 0x10, 0x89, 0x3F, 0x2C,
0x34, 0x30, 0x87, 0x13, 0xC1, 0x4C, 0xC1, 0x7F, 0x81, 0x6E,
0xBA, 0xBD, 0xDF, 0x43, 0x1A, 0xF0, 0xD7, 0xDE, 0x8E, 0x66,
0xB9, 0x7C
};
uint32_t key[4] = { 0x1CD43EEA, 0x47D7CB70, 0x0DBCA5E98, 0x2B390C53 };
for (int i = 0; i < 32; i += 8) decrypt((uint32_t*)(enc + i), key);
for (int i = 0; i < 32; i++)printf("%c", enc[i]);
printf("%s", enc);
}

还差一个先 AES-128-ECB 解密

CryptHashData(phHash, pbData, 0x10u, 0)→ 把 pbData 的 16 个字节MD5

CryptDeriveKey(phProv, CALG_AES_128, phHash, CRYPT_EXPORTABLE, &phKey)在 WinCrypt 的实现里,这里会用 MD5 输出的 16 字节作为 AES-128 的密钥。(DeriveKey 对对称算法长度正好匹配的情况,就是直接用哈希输出,不再加工。)

CryptEncrypt(phKey, …, MultiByteStr, …, 0x20u) → 用这个 AES-128 Key 对 32 字节的明文缓冲做了一次 AES-ECB 加密

调试没找到密钥,自己跑一下

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
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>

int main(void) {
// 你的 pbData 四个 DWORD(32 位)
DWORD pbData[4] = {
0x1CD43EEA,
0x47D7CB70,
0xDBCA5E98, // 取低 32 位
0x2B390C53
};

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;

if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("CryptAcquireContextA failed\n");
return 1;
}

if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
printf("CryptCreateHash failed\n");
return 1;
}

// 把 pbData 的 16 字节送进 MD5
if (!CryptHashData(hHash, (BYTE*)pbData, 16, 0)) {
printf("CryptHashData failed\n");
return 1;
}

if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey)) {
printf("CryptDeriveKey failed\n");
return 1;
}

// 取出 key 的实际字节
DWORD keyLen = 0;
DWORD dwCount = sizeof(DWORD);
if (!CryptGetKeyParam(hKey, KP_KEYLEN, (BYTE*)&keyLen, &dwCount, 0)) {
printf("CryptGetKeyParam(KP_KEYLEN) failed\n");
return 1;
}
keyLen /= 8; // bits → bytes

BYTE key[32]; // 足够大
dwCount = sizeof(key);
if (!CryptExportKey(hKey, 0, PLAINTEXTKEYBLOB, 0, key, &dwCount)) {
printf("CryptExportKey failed\n");
return 1;
}

// PLAINTEXTKEYBLOB 格式:前 16 字节是头,真正的 key 在后面
BLOBHEADER* hdr = (BLOBHEADER*)key;
DWORD* dwKeySize = (DWORD*)(key + sizeof(BLOBHEADER));
BYTE* realKey = key + sizeof(BLOBHEADER) + sizeof(DWORD);

printf("AES-128 Key (%u bytes): ", *dwKeySize);
for (DWORD i = 0; i < *dwKeySize; i++) {
printf("%02X", realKey[i]);
}
printf("\n");

CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 0;
}

AES-128 Key (16 bytes): 67CB6DF854F392FF1FEF78AC1B59F84D

image-20250825171338249

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdint.h>
#include <stdio.h>

void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x114514;
uint32_t sum = (32) * delta;
for (uint32_t i = 0; i < 32; i++) {
v1 -= (k[(sum >> 11) & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (v0 << 4)));
sum -= delta;
v0 -= (k[sum & 3] + sum) ^ (v1 + ((v1 >> 5) ^ (v1 << 4)));
}
v[0] = v0; v[1] = v1;
}

int main() {
unsigned char enc[] = {
0x2a,0xb4,0xc1,0x74,0xd6,0x59,0xaa,0x05,0x73,0x10,0x7f,0x9c,0x40,0x49,0x99,0x62,0x3c,0x84,0x51,0x8f,0x3f,0x37,0xab,0xf1,0x0e,0xfe,0x61,0x96,0x45,0xad,0x41,0x6a
};
uint32_t key[4] = { 0x1CD43EEA, 0x47D7CB70, 0x0DBCA5E98, 0x2B390C53 };
for (int i = 0; i < 32; i += 8) decrypt((uint32_t*)(enc + i), key);
for (int i = 0; i < 32; i++)printf("%c", enc[i]);
printf("%s", enc);
}

L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}

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
74
75
76
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <stdint.h>

void decrypt_block(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x114514;
uint32_t sum = 32 * delta;
for (uint32_t i = 0; i < 32; i++) {
v1 -= (k[(sum >> 11) & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (v0 << 4)));
sum -= delta;
v0 -= (k[sum & 3] + sum) ^ (v1 + ((v1 >> 5) ^ (v1 << 4)));
}
v[0] = v0; v[1] = v1;
}

int main() {
// ===== AES种子 pbData =====
DWORD pbData[4] = {
0x1CD43EEA,
0x47D7CB70,
0xDBCA5E98, // 修正:8位hex
0x2B390C53
};

// ===== enc数据 =====
unsigned char enc[] = {
0x0B, 0xAF, 0x51, 0x21, 0x9C, 0x52, 0x10, 0x89, 0x3F, 0x2C,
0x34, 0x30, 0x87, 0x13, 0xC1, 0x4C, 0xC1, 0x7F, 0x81, 0x6E,
0xBA, 0xBD, 0xDF, 0x43, 0x1A, 0xF0, 0xD7, 0xDE, 0x8E, 0x66,
0xB9, 0x7C
};
DWORD encLen = sizeof(enc);

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;

// 1) 获取AES Key
CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
CryptHashData(hHash, (BYTE*)pbData, 16, 0);
CryptDeriveKey(hProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey);

// CBC + NoPadding
DWORD mode = CRYPT_MODE_CBC;
CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0);
BYTE iv[16] = { 0 };
CryptSetKeyParam(hKey, KP_IV, iv, 0);
DWORD padMode = ZERO_PADDING;
CryptSetKeyParam(hKey, KP_PADDING, (BYTE*)&padMode, 0);

// 2) 先AES解密
if (!CryptDecrypt(hKey, 0, FALSE, 0, enc, &encLen)) {
printf("CryptDecrypt failed, err=%lu\n", GetLastError());
return 1;
}
printf("[+] After AES (hex): ");
for (DWORD i = 0; i < encLen; i++) printf("%02X ", enc[i]);
printf("\n");

// 3) 再跑自定义 decrypt (4个block)
uint32_t key[4] = { 0x1CD43EEA, 0x47D7CB70, 0x0DBCA5E98, 0x2B390C53 };
for (int i = 0; i < (int)encLen; i += 8) {
decrypt_block((uint32_t*)(enc + i), key); // 用pbData作key
}

printf("[+] Final Plaintext: %.*s\n", (int)encLen, enc);

CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 0;
}

更简单的写法来自L3HCTF-2024-部分复现 | EPs1l0h’s Castle

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
#include<iostream>
#include"Windows.h"
#include<windef.h>
#include<stdint.h>
unsigned char enc[] =
{
0x0B, 0xAF, 0x51, 0x21, 0x9C, 0x52, 0x10, 0x89, 0x3F, 0x2C,
0x34, 0x30, 0x87, 0x13, 0xC1, 0x4C, 0xC1, 0x7F, 0x81, 0x6E,
0xBA, 0xBD, 0xDF, 0x43, 0x1A, 0xF0, 0xD7, 0xDE, 0x8E, 0x66,
0xB9, 0x7C
};

void xtea_decrypt(uint32_t v[2], uint32_t key[4])
{
unsigned int i;
unsigned int num_rounds = 32;
uint32_t v0=v[0], v1=v[1], delta=0x114514, sum=delta*num_rounds;
for (i=0; i < num_rounds; 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() {
BYTE pbData[] = "\xEA\x3E\xD4\x1Cp\xCB\xD7G\x98^\xCA\xDBS\f9+";
DWORD pdwDataLen = 32;
HCRYPTPROV phProv = 0;
HCRYPTHASH phHash = 0;
HCRYPTKEY phKey = 0;
CryptAcquireContextA(&phProv, 0, 0, 0x18u, 0xF0000000);
CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash);
CryptHashData(phHash, pbData, 0x10u, 0);
CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey);
std::cout << std::hex << phKey << std::endl;
CryptDecrypt(phKey, 0, 0, 0, enc, &pdwDataLen);
uint32_t k[4]={0x1CD43EEA, 0x47D7CB70, 0x0DBCA5E98, 0x2B390C53};
for(int i = 0; i < 32; i += 8)xtea_decrypt((uint32_t*)(enc + i), k);
for(int i = 0; i < 32; i++)printf("%c", enc[i]);
}

DAG

交给GPT

encode:核心就是把字符串按两个字符一组,映射成三个数字

1
2
3
4
5
6
7
8
9
10
11
12
def encode(s):
ret = []
ls = list(s)
for i in range(0, len(ls), 2):
num1 = ord(ls[i])
num2 = ord(ls[i+1])
numa = (num1 & 248) >> 3
numb = ((num1 & 7) << 3) | ((num2 & 240) >> 4)
numc = num2 & 15
ret += [numa, numb, numc]
return ret

1
2
3
4
5
6
7
8
encode(str1) == [12, 22, 1]
encode(str2) == [12, 14, 2]
encode(str3) == [12, 22, 3]
encode(str4) == [12, 30, 2]
encode(str5) == [12, 22, 4, 12, 30, 1]
encode(str6) == [12, 22, 1, 12, 30, 4]
encode(str7) == [12, 22, 2, 12, 22, 2]
encode(str8) == [12, 14, 3, 12, 38, 2]

func1 很复杂,但简化逻辑就是:判断 lss[i] 能不能连到 lss[j]

solution:本质上是在算某种“最长路径”或“最大深度”

1
2
3
4
5
6
7
8
def solution(lss):
abcarray = [-1] * len(lss)
arr = [[-1] * len(lss) for _ in range(len(lss))]

ans = 1
for i in range(len(lss)):
ans = max(ans, abc(lss, i))
return ans

solution(lss) 构造一张有向图:节点是字符串,边是“删一个字符能得到对方”

  • 然后用 DFS + 记忆化 (abcarray) 算 最长链的长度
  • 最终返回最长链的长度。

所以:

  • num1 = solution([...]) → 第一组数据的最长删字符链的长度。
  • num2 = solution([...]) → 第二组数据的最长删字符链长度。
  • num3 = solution([...]) → 第三组数据的最长删字符链长度。
1
2
3
4
5
6
7
8
9
def calc(nums):
num1, num2, num3 = nums

num1 = 2023 + (num1 & 15) - (num1 & 240)
num2 = fibonacci(num2 + 7)
random.seed(num3)
flag = f"{num1}{num2}{num3}{random.gauss(num2, 0.2)}"
flag = flag.replace('.', 'x')
return flag

func2:

1
2
3
4
5
6
def func2(n):
a, b = 1, 1
for i in range(n - 1):
a, b = b, a + b
return a

func1:

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
def func1(lss, i, j):
# 如果缓存里有结果,直接返回
if arr[i * len(lss) + j] != -1:
return arr[i * len(lss) + j]

s1 = list(lss[i])
s2 = list(lss[j])
l1, l2 = len(s1), len(s2)

flag = True
n = 0

# 只有当长度相差 1 时才可能有边
if l1 - l2 == 1:
for m in range(l1):
if s1[m] != s2[n]:
if flag:
flag = False
# 跳过 s1[m],继续比较
continue
else:
arr[i * len(lss) + j] = 0
return 0
else:
n += 1
if n == l2: # s2 全部匹配上了
break

arr[i * len(lss) + j] = 1
return 1
else:
arr[i * len(lss) + j] = 0
return 0

abc:

1
2
3
4
5
6
7
8
9
10
11
12
def abc(lss, i):
if abcarray[i] > 0:
return abcarray[i]

m = 1
for index, word in enumerate(lss):
if func1(lss, i, index) == 1:
m = max(m, abc(lss, index) + 1)

abcarray[i] = m
return m

  • abcarray 是记忆化数组(类似 dp 缓存),避免重复计算。
  • m = 1 表示从 lss[i] 自身开始的链长度。
  • 遍历 lss 中所有 word
    • 如果 func1(lss, i, index) == 1,说明 lss[i] 可以通过删除 1 个字符连到 lss[index]
    • 递归调用 abc(lss, index),加上当前这一步的 +1,更新 m
  • 记录到 abcarray[i],返回最大链长度。

bc(lss, i) 计算从 lss[i] 出发,能走出的最长删除链的长度

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import random
from typing import List, Tuple

def func2(n):
a, b = 1, 1
for i in range(n - 1):
a, b = b, a + b
return a

# --- func1: 判断字符串 lss[i] 是否可以通过删除一个字符得到 lss[j] ---
# arr 是全局缓存,存储连接结果:-1=未知, 0=不可连, 1=可连
def func1(lss: List[str], i: int, j: int) -> int:
N = len(lss)
index = i * N + j
# 如果缓存中已有结果,直接返回
if arr[index] != -1:
return arr[index]

s1 = list(lss[i])
s2 = list(lss[j])
l1, l2 = len(s1), len(s2)

# 只有长度差为 1 时才可能有边
if l1 - l2 != 1:
arr[index] = 0
return 0

flag = True # 允许跳过一个字符
n = 0 # 指针遍历 s2

for m in range(l1):
if n < l2 and s1[m] == s2[n]:
n += 1
if n == l2:
# s2 已完全匹配
break
else:
# 出现不匹配
if flag:
# 消耗掉一次允许跳过的机会
flag = False
continue
else:
arr[index] = 0
return 0

# 匹配成功
arr[index] = 1
return 1

# --- abc: DFS + 记忆化计算从 lss[i] 出发的最长链长度 ---
def abc(lss: List[str], i: int) -> int:
# 如果已计算过,直接返回缓存
if abcarray[i] > 0:
return abcarray[i]

m = 1 # 最短链长度至少为 1(自己)
for index, _word in enumerate(lss):
if func1(lss, i, index) == 1:
m = max(m, abc(lss, index) + 1)

abcarray[i] = m # 缓存结果
return m

# --- solution: 构建缓存数组,计算整个列表的最长删除链长度 ---
def solution(lss: List[str]) -> int:
global abcarray, arr
N = len(lss)
abcarray = [-1] * N
arr = [-1] * (N * N)

ans = 1
for i in range(N):
ans = max(ans, abc(lss, i))
return ans

# --- encode: 将字符串按两字符一组映射为三个整数 ---
def encode(s: str) -> List[int]:
ret: List[int] = []
ls = list(s)
if len(ls) % 2 != 0:
raise ValueError("encode函数要求字符串长度为偶数")
for i in range(0, len(ls), 2):
num1 = ord(ls[i])
num2 = ord(ls[i + 1])
# 将两字符编码为三个整数
numa = (num1 & 248) >> 3 # num1 高 5 位
numb = ((num1 & 7) << 3) | ((num2 & 240) >> 4) # num1低3位+num2高4位
numc = num2 & 15 # num2 低4位
ret += [numa, numb, numc]
return ret

# --- calc: 根据三个整数计算最终 flag 字符串 ---
def calc(nums: Tuple[int, int, int] or List[int]) -> str:
num1, num2, num3 = nums
num1 = 2023 + (num1 & 15) - (num1 & 240)
num2 = func2(num2 + 7)
random.seed(num3)
flag = f"{num1}{num2}{num3}{random.gauss(num2, 0.2)}"
flag = flag.replace(".", "x")
print("flag=", flag)
return flag

但是我们不知道str1-str8,可以爆破出来得到

str1~str8 = [‘ba’, ‘ab’, ‘bc’, ‘cb’, ‘bdca’, ‘bacd’, ‘bbbb’, ‘acdb’]

完整代码:

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# decompiled_reconstruction.py
import random
from typing import List, Tuple

# --- func2: 计算斐波那契数列 F(n),F(1)=1, F(2)=1 ---
def func2(n: int) -> int:
a, b = 1, 1
# 循环 n-1 次,最终 a 为 F(n)
for _ in range(n - 1):
a, b = b, a + b
return a

# --- func1: 判断字符串 lss[i] 是否可以通过删除一个字符得到 lss[j] ---
# arr 是全局缓存,存储连接结果:-1=未知, 0=不可连, 1=可连
def func1(lss: List[str], i: int, j: int) -> int:
N = len(lss)
index = i * N + j
# 如果缓存中已有结果,直接返回
if arr[index] != -1:
return arr[index]

s1 = list(lss[i])
s2 = list(lss[j])
l1, l2 = len(s1), len(s2)

# 只有长度差为 1 时才可能有边
if l1 - l2 != 1:
arr[index] = 0
return 0

flag = True # 允许跳过一个字符
n = 0 # 指针遍历 s2

for m in range(l1):
if n < l2 and s1[m] == s2[n]:
n += 1
if n == l2:
# s2 已完全匹配
break
else:
# 出现不匹配
if flag:
# 消耗掉一次允许跳过的机会
flag = False
continue
else:
arr[index] = 0
return 0

# 匹配成功
arr[index] = 1
return 1

# --- abc: DFS + 记忆化计算从 lss[i] 出发的最长链长度 ---
def abc(lss: List[str], i: int) -> int:
# 如果已计算过,直接返回缓存
if abcarray[i] > 0:
return abcarray[i]

m = 1 # 最短链长度至少为 1(自己)
for index, _word in enumerate(lss):
if func1(lss, i, index) == 1:
m = max(m, abc(lss, index) + 1)

abcarray[i] = m # 缓存结果
return m

# --- solution: 构建缓存数组,计算整个列表的最长删除链长度 ---
def solution(lss: List[str]) -> int:
global abcarray, arr
N = len(lss)
abcarray = [-1] * N # 记忆化数组
arr = [-1] * (N * N) # 扁平数组缓存 func1 结果

ans = 1
for i in range(N):
ans = max(ans, abc(lss, i))
return ans

# --- encode: 将字符串按两字符一组映射为三个整数 ---
def encode(s: str) -> List[int]:
ret: List[int] = []
ls = list(s)
if len(ls) % 2 != 0:
raise ValueError("encode函数要求字符串长度为偶数")
for i in range(0, len(ls), 2):
num1 = ord(ls[i])
num2 = ord(ls[i + 1])
# 将两字符编码为三个整数
numa = (num1 & 248) >> 3 # num1 高 5 位
numb = ((num1 & 7) << 3) | ((num2 & 240) >> 4) # num1低3位+num2高4位
numc = num2 & 15 # num2 低4位
ret += [numa, numb, numc]
return ret

# --- calc: 根据三个整数计算最终 flag 字符串 ---
def calc(nums: Tuple[int, int, int] or List[int]) -> str:
num1, num2, num3 = nums
# bytecode 中的运算逻辑
num1 = 2023 + (num1 & 15) - (num1 & 240)
num2 = func2(num2 + 7)
random.seed(num3)
flag = f"{num1}{num2}{num3}{random.gauss(num2, 0.2)}"
flag = flag.replace(".", "x")
print("flag=", flag)
return flag

def decode_from_encode(nums: List[int]) -> str:
"""穷举 ASCII 字符,恢复两字符字符串"""
for c1 in range(32, 127):
for c2 in range(32, 127):
numa = (c1 & 248) >> 3
numb = ((c1 & 7) << 3) | ((c2 & 240) >> 4)
numc = c2 & 15
if [numa, numb, numc] == nums:
return chr(c1) + chr(c2)
raise ValueError(f"无法解码 encode {nums}")

def decode_from_encode_multi(nums: List[int]) -> str:
"""处理长度 >3 的 encode(两字符一组)"""
if len(nums) % 3 != 0:
raise ValueError("encode 数组长度必须是3的倍数")
s = ""
for i in range(0, len(nums), 3):
s += decode_from_encode(nums[i:i+3])
return s

if __name__ == "__main__":
# 已知 encode 结果
encode_list = [
[12, 22, 1],
[12, 14, 2],
[12, 22, 3],
[12, 30, 2],
[12, 22, 4, 12, 30, 1],
[12, 22, 1, 12, 30, 4],
[12, 22, 2, 12, 22, 2],
[12, 14, 3, 12, 38, 2],
]

# --- 反推原始字符串 str1~str8 ---
strs = []
for e in encode_list:
strs.append(decode_from_encode_multi(e))
str1, str2, str3, str4, str5, str6, str7, str8 = strs
print("str1~str8 =", strs)
str1 = "ba"
str2 = "ab"
str3 = "bc"
str4 = "cb"
str5 = "bdca"
str6 = "bacd"
str7 = "bbbb"
str8 = "acdb"

# --- 对 encode 函数进行验证 ---
assert encode(str1) == [12, 22, 1], "str1 encode 验证失败"
assert encode(str2) == [12, 14, 2], "str2 encode 验证失败"
assert encode(str3) == [12, 22, 3], "str3 encode 验证失败"
assert encode(str4) == [12, 30, 2], "str4 encode 验证失败"
assert encode(str5) == [12, 22, 4, 12, 30, 1], "str5 encode 验证失败"
assert encode(str6) == [12, 22, 1, 12, 30, 4], "str6 encode 验证失败"
assert encode(str7) == [12, 22, 2, 12, 22, 2], "str7 encode 验证失败"
assert encode(str8) == [12, 14, 3, 12, 38, 2], "str8 encode 验证失败"

# --- 计算每组列表的最长删除链长度 ---
num1 = solution(
['a', str1, str2, str3, str4, 'bda', str5, str6, str7, str8, 'bcdef', 'aabcc', 'acbac', 'bdcaa', 'bbbbcc',
'babccc', 'abaccc'])
# --- 根据三个整数生成最终 flag ---
num2 = solution([...])
num3 = solution([...])
flag = calc([num1, num2, num3])
print("最终生成的 flag:", flag)

flag= 202817711117711x25763695063

最终生成的 flag: 202817711117711x25763695063

最终代码:

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
# decompiled_reconstruction.py
import random
from typing import List, Tuple

# --- func2: 计算斐波那契数列 F(n),F(1)=1, F(2)=1 ---
def func2(n: int) -> int:
a, b = 1, 1
# 循环 n-1 次,最终 a 为 F(n)
for _ in range(n - 1):
a, b = b, a + b
return a

# --- func1: 判断字符串 lss[i] 是否可以通过删除一个字符得到 lss[j] ---
# arr 是全局缓存,存储连接结果:-1=未知, 0=不可连, 1=可连
def func1(lss: List[str], i: int, j: int) -> int:
N = len(lss)
index = i * N + j
# 如果缓存中已有结果,直接返回
if arr[index] != -1:
return arr[index]

s1 = list(lss[i])
s2 = list(lss[j])
l1, l2 = len(s1), len(s2)

# 只有长度差为 1 时才可能有边
if l1 - l2 != 1:
arr[index] = 0
return 0

flag = True # 允许跳过一个字符
n = 0 # 指针遍历 s2

for m in range(l1):
if n < l2 and s1[m] == s2[n]:
n += 1
if n == l2:
# s2 已完全匹配
break
else:
# 出现不匹配
if flag:
# 消耗掉一次允许跳过的机会
flag = False
continue
else:
arr[index] = 0
return 0

# 匹配成功
arr[index] = 1
return 1

# --- abc: DFS + 记忆化计算从 lss[i] 出发的最长链长度 ---
def abc(lss: List[str], i: int) -> int:
# 如果已计算过,直接返回缓存
if abcarray[i] > 0:
return abcarray[i]

m = 1 # 最短链长度至少为 1(自己)
for index, _word in enumerate(lss):
if func1(lss, i, index) == 1:
m = max(m, abc(lss, index) + 1)

abcarray[i] = m # 缓存结果
return m

# --- solution: 构建缓存数组,计算整个列表的最长删除链长度 ---
def solution(lss: List[str]) -> int:
global abcarray, arr
N = len(lss)
abcarray = [-1] * N # 记忆化数组
arr = [-1] * (N * N) # 扁平数组缓存 func1 结果

ans = 1
for i in range(N):
ans = max(ans, abc(lss, i))
return ans

# --- encode: 将字符串按两字符一组映射为三个整数 ---
def encode(s: str) -> List[int]:
ret: List[int] = []
ls = list(s)
if len(ls) % 2 != 0:
raise ValueError("encode函数要求字符串长度为偶数")
for i in range(0, len(ls), 2):
num1 = ord(ls[i])
num2 = ord(ls[i + 1])
# 将两字符编码为三个整数
numa = (num1 & 248) >> 3 # num1 高 5 位
numb = ((num1 & 7) << 3) | ((num2 & 240) >> 4) # num1低3位+num2高4位
numc = num2 & 15 # num2 低4位
ret += [numa, numb, numc]
return ret

# --- calc: 根据三个整数计算最终 flag 字符串 ---
def calc(nums: Tuple[int, int, int] or List[int]) -> str:
num1, num2, num3 = nums
# bytecode 中的运算逻辑
num1 = 2023 + (num1 & 15) - (num1 & 240)
num2 = func2(num2 + 7)
random.seed(num3)
flag = f"{num1}{num2}{num3}{random.gauss(num2, 0.2)}"
flag = flag.replace(".", "x")
print("flag=", flag)
return flag

def decode_from_encode(nums: List[int]) -> str:
"""穷举 ASCII 字符,恢复两字符字符串"""
for c1 in range(32, 127):
for c2 in range(32, 127):
numa = (c1 & 248) >> 3
numb = ((c1 & 7) << 3) | ((c2 & 240) >> 4)
numc = c2 & 15
if [numa, numb, numc] == nums:
return chr(c1) + chr(c2)
raise ValueError(f"无法解码 encode {nums}")

def decode_from_encode_multi(nums: List[int]) -> str:
"""处理长度 >3 的 encode(两字符一组)"""
if len(nums) % 3 != 0:
raise ValueError("encode 数组长度必须是3的倍数")
s = ""
for i in range(0, len(nums), 3):
s += decode_from_encode(nums[i:i+3])
return s

if __name__ == "__main__":

str1 = "ba"
str2 = "ab"
str3 = "bc"
str4 = "cb"
str5 = "bdca"
str6 = "bacd"
str7 = "bbbb"
str8 = "acdb"

# --- 计算每组列表的最长删除链长度 ---
num1 = solution(
['a', str1, str2, str3, str4, 'bda', str5, str6, str7, str8, 'bcdef', 'aabcc', 'acbac', 'bdcaa', 'bbbbcc',
'babccc', 'abaccc'])
num2 = solution(['klmnowx', 'abcdefgiklmno', 'fgij', 'bcfghijklmno', 'fgjpqrst', 'uy', 'abceklmnouvw', 'pqrstuwy', 'fghijlno',
'mnouvwxy', 'klmnopqt', 'klmnopqrstuy', 'aeuvw', 'muvw', 'abcdeklmnow', 'fhijpqrst', 'mpqrst', 'klmnoprt',
'fghijklno', 'abcdelmo', 'klnuvwxy', 'klmnopst', 'abcdeklmnov', 'fghj', 'luvwxy', 'ghklmnopqrst', 'pqrstwx',
'abcdklmno', 'cdefghij', 'pqrs', 'efghijklmno', 'fghjklmno', 'adeklmno', 'rs', 'kuvwxy', 'ghij',
'befghijklmno', 'ln', 'hijklmnopqrst', 'ghpqrst', 'fgiklmnopqrst', 'pqrtuvwxy', 'pqrsty', 'jklmnopqrst',
'lnouvwxy', 'klmnoqsuvwxy', 'abcdeghklmno', 'fi', 'fghijlnpqrst', 'abdklmnouvw', 'uwx', 'abcdekln', 'klmno',
'abcdekn', 'abcdemuvw', 'pqs', 'fghijpqt', 'klmnopqrstuw', 'n', 'nopqrstuvwxy', 'abcdefghj', 'fghiklmnopqrst',
'klmnorst', 'abcdemnouvw', 'fgh', 'pqt', 'abfghij', 'o', 'nouvw', 'abcdklmnouvw', 'abeklmno', 'abcden',
'klmnopqrstwxy', 'q', 'fghijklmnoprt', 'klmnovx', 'abceuvw', 'klmnopsuvwxy', 'hj', 'abcdefgh', 'fhjklmno',
'klmnoquvwxy', 'wxy', 'klmnopqrstuvwy', 'kln', 'abcdegklmno', 'mno', 'gklmno', 'klnouvw', 'fghijklmnoqr',
'fghijpqrst', 'mnuvwxy', 'ghipqrst', 'klmnoqrtuvwxy', 'acdfghij', 'uwy', 'fghjklmnopqrst', 'mnpqrstuvwxy',
'abcdeknouvw', 'abcdefghijklmno', 'klmnorsuvwxy', 'abcdeh', 'klmnost', 'iklmnopqrst', 'abcdegijklmno',
'fghijklmopqrst', 'fghijklmnors', 'pqrstux', 'abcdefghijlm', 'abcdem', 'klmn', 'opqrst', 'ghjklmnopqrst',
'cdfghij', 'kluvwxy', 'ceklmno', 'abcdeghijklmno', 'lmo', 'bklmno', 'fghijs', 'cdeklmnouvw', 'abcdeknuvw',
'cdklmnouvw', 'abcdeklmnovw', 'klmnopr', 'fghijklmnopqrst', 'klmnopqtuvwxy', 'abcdefhijklmno', 'abcdeuv',
'abcdefhklmno', 'x', 'abcdeouvw', 'fjklmno', 'a', 'klmnopqrstuv', 'abdklmno', 'fghijlm', 'bcefghijklmno',
'quvwxy', 'fghi', 'klmnopqrstuwx', 'r', 'klmnuvw', 'kn', 'abcdeklmn', 'abcdeklmno', 'ps', 'klmnoqrt',
'pstuvwxy', 'klmnopqrsty', 'lmn', 'd', 'abcdefghijmo', 'fghijmnopqrst', 'ghiklmno', 'mouvwxy', 'abcdeghj',
'fghijklmnopr', 'kmnouvwxy', 'fghijklmnopqst', 'klmnox', 'nouvwxy', 'adefghijklmno', 'kmo', 'klmnovy',
'klmnopqrstuvwxy', 'cde', 'y', 'klmnouy', 'fgklmnopqrst', 'nuvwxy', 'kluvw', 'abcdefghijkno', 'abcdekl',
'fghijno', 'ceuvw', 'abcdelo', 'bcdklmno', 'gij', 'abcdeijklmno', 'klmnopqrt', 'abcdeklm', 'pqruvwxy',
'klnuvw', 'fijklmno', 'knpqrstuvwxy', 'fghijklmnor', 'ace', 'abcdekluvw', 'deklmnouvw', 'lpqrstuvwxy',
'abcdefhiklmno', 'fijpqrst', 'klmnopqrstvwy', 'mn', 'kmpqrst', 'ipqrst', 'fghijkmnpqrst', 'uvxy', 'bklmnouvw',
'fghijkmnopqrst', 'fghijklnopqrst', 'kopqrstuvwxy', 'pqrstuwxy', 'abdeuvw', 'acefghij', 'jklmno', 'k',
'fghijqs', 'abcdefghijno', 'fghijklmnort', 'adeuvw', 'vwx', 'gjklmno', 'hi', 'abcdefghijm', 'nuvw',
'fklmnopqrst', 'abcdehklmno', 'fghijklmnoqrt', 'klmnoruvwxy', 'abcdemnuvw', 'klmnovw', 'klmnopqrstvw',
'klmnoqtuvwxy', 'klmnoy', 'wx', 'ouvwxy', 'lmopqrst', 'fghjpqrst', 'lnuvwxy', 'vy', 'abdfghijklmno', 'kmnouvw',
'uvy', 'klmnoqst', 'klmnort', 'pqrstuxy', 'qs', 'lopqrstuvwxy', 'mnouvw', 'abdeklmno', 'abcdelnouvw',
'pruvwxy', 'qrsuvwxy', 'cklmno', 'bc', 'acdfghijklmno', 'j', 'fghijpqs', 'fghijknopqrst', 'fgijklmno',
'fghijnopqrst', 'mpqrstuvwxy', 'knopqrst', 'acdeuvw', 'lnouvw', 'fghijklmn', 'klmnouvxy', 'abcdefghiklmno',
'abcdefghij', 'hij', 'abcdekuvw', 'klmnopqs', 'aklmnouvw', 'acdefghijklmno', 'cfghij', 'fghijpqst',
'cfghijklmno', 'abcdefhi', 'kmouvwxy', 'pquvwxy', 'pqrstuy', 'pqrstuwx', 'ce', 'klmnopqrstv', 'deklmno',
'klmnouvw', 'abcdeno', 'fghijkmo', 'knouvwxy', 'fpqrst', 'hklmno', 'fghijkmopqrst', 'abcdefghjklmno',
'kmpqrstuvwxy', 'dklmnouvw', 'abcdefghijkmo', 'abcdel', 'giklmnopqrst', 'buvw', 'klmo', 'klmnoqrsuvwxy',
'uvwy', 'abcdeluvw', 'klmnostuvwxy', 'bceklmno', 'fghijm', 'defghijklmno', 'ijklmno', 'pqr', 'abcduvw',
'fghijklmnopqt', 'hijklmno', 'klmnoprsuvwxy', 'aeklmno', 'lo', 'klmnouxy', 'cdklmno', 'fghijpr', 'muvwxy',
'lmnouvwxy', 'abce', 'kmnopqrst', 'pt', 'klmnoptuvwxy', 'abde', 'abcdeghiklmno', 'klmnopqsuvwxy', 'klmnouvx',
'efghij', 'klmnouwy', 'bceklmnouvw', 'klmnuvwxy', 'ad', 'klmnoux', 'gjpqrst', 'abcdegij', 'fghijkpqrst',
'fghijlmnopqrst', 'abcdefj', 'fghijklmnops', 'fghijklmnoqs', 'ghi', 'fghijqst', 'abcdemo', 'abcdefghijkl',
'fghklmnopqrst', 'no', 'klmnopqrstuwxy', 'klmnopqrstvwx', 'abcdeklmnou', 'abdefghijklmno', 'klmnopqrstxy',
'acfghij', 'pqrstuvwy', 'kuvw', 'abcdehi', 'de', 'fghijpq', 'lmuvwxy', 'abcdelmouvw', 'abdfghij', 'knuvwxy',
'acde', 'cuvw', 'uw', 'kmopqrstuvwxy', 'abcfghij', 'fghij', 'abcdeklmo', 'abcdehij', 'abcdek',
'fghijklmnoqrst', 'pqrstvx', 'klmnopqrstvx', 'abc', 'klmnoqrstuvwxy', 'acklmnouvw', 'afghijklmno',
'abcdeklmnuvw', 'abcdei', 'fgiklmno', 'klmnopqrstuvw', 'abcklmnouvw', 'abcdelmnuvw', 'abcdehj', 'abcdefghijlo',
'fghpqrst', 'acfghijklmno', 'abcdeg', 'klpqrst', 'klmouvw', 'bdfghijklmno', 'aefghijklmno', 'fijklmnopqrst',
'fghijps', 'fghijklnpqrst', 'fghijklmnop', 'fklmno', 'klmnopqrstw', 'abcdfghijklmno', 'fj', 'lnopqrst',
'fghijkmpqrst', 'fghijlnopqrst', 'ux', 'fgjklmno', 'fghijklmnopqr', 'abcdeghjklmno', 'abcdefghijkmn',
'abcdegiklmno', 'abcdefiklmno', 'acdeklmno', 'klmnops', 'fghijklmnopqrt', 'fghijklmnoqt', 'abcdegj',
'acdklmno', 'abcdeghi', 'abcdelmuvw', 'abcdefg', 'fghijkl', 'gjklmnopqrst', 'hipqrst', 'klmnopqstuvwxy',
'lnuvw', 'ghijpqrst', 'pqrstuvwxy', 'klmnovwx', 'klmnoqstuvwxy', 'bcklmnouvw', 'abdeklmnouvw', 'fghijklmnopq',
'abcdefghijk', 'abcdefghijklno', 'fiklmnopqrst', 'klmnopq', 'npqrstuvwxy', 'klmnopqrstwx', 'abcdefi', 'lpqrst',
'ghijklmnopqrst', 'bd', 'bcuvw', 'hjklmnopqrst', 'adfghijklmno', 'klmnosuvwxy', 'louvwxy', 'bce', 'gpqrst',
'fghijklmnot', 'wy', 'pqrstvwxy', 'fghijkln', 'lmouvw', 'gi', 'fghijn', 'fhklmnopqrst', 'ghj', 'klpqrstuvwxy',
'abcdefgklmno', 'fghijlmo', 'fghijo', 'fhpqrst', 'klmnoprs', 'abcefghij', 'abcdeklno', 'abcdefghijlmno',
'kmnpqrst', 'fghijklmnoq', 'abcdefhij', 'fghijklmnopt', 'klmnopt', 'abcdefklmno', 'abcdelno', 'pqrstw',
'fghijlopqrst', 'bfghij', 'abuvw', 'abcdefghijln', 'ac', 'aefghij', 'prs', 'lmnopqrstuvwxy', 'abcdefghijn',
'klmnopqrstux', 'luvw', 'giklmno', 'kpqrst', 'jpqrst', 'fghijrt', 'fghijlo', 'abcdefij', 'fghijklmnorst',
'fghijqrst', 'tuvwxy', 'fghijlmopqrst', 'klmnouwxy', 'bdeuvw', 'fghijprt', 'klmnoprst', 'pqrstuvy',
'fghijpqrt', 'fgj', 'pqrstvxy', 'abdefghij', 'abcdegh', 'abefghij', 'lno', 'klmnopuvwxy', 'klmnouvwxy',
'fghijrst', 'cd', 'euvw', 'hijpqrst', 'pqrst', 'klopqrst', 'gijpqrst', 'klmnopqrs', 'fghijk', 'klopqrstuvwxy',
'rtuvwxy', 'klmnorstuvwxy', 'stuvwxy', 'abcdevw', 'cdefghijklmno', 'bdeklmno', 'pqstuvwxy', 'fghipqrst',
'fghijpst', 'kmn', 'mo', 'abcdeuw', 'qst', 'fghijklmnost', 'klnopqrst', 'abcdekm', 'abcdefgj', 'klmnopqrstuvy',
'kouvw', 'abcdelmnouvw', 'abefghijklmno', 'fgipqrst', 'klm', 'klmnopstuvwxy', 'abcdekmno', 'fghijmno',
'pqrstvw', 'kmouvw', 'cdeklmno', 'st', 'fij', 'fhiklmno', 'abcdefghklmno', 'lmnuvwxy', 'klmnovwy', 'klmnow',
'mnuvw', 'fghijklmnpqrst', 'klmnoxy', 'fghklmno', 'b', 'lopqrst', 'pqrstuvw', 'abcdekmouvw', 'abcdeklmnouw',
'acduvw', 'klmnoq', 'bde', 'pqrstxy', 'qrs', 'bcdeklmnouvw', 'abcdekmo', 'abcdefghijkn', 'kno',
'abcdefghijklm', 'abcdefgij', 'kmopqrst', 'kmnuvwxy', 'pqrstuvwx', 'fghijkmn', 'acdefghij', 'fghijmn', 'qr',
'l', 'kmnopqrstuvwxy', 'abcdefghijl', 'afghij', 'auvw', 'abcdew', 'klmnopqrstwy', 'adfghij', 'abcdeghij',
'lmopqrstuvwxy', 'abcdefghijklmn', 'uvx', 'km', 'abcdefijklmno', 'abcdeij', 'pq', 'lnpqrst', 'bdfghij',
'abcdefhj', 'mopqrstuvwxy', 'fghijklmnopqs', 'fghijqt', 'ade', 'abcdejklmno', 'fghijklmpqrst', 'pqrstuvxy',
'mouvw', 'mopqrst', 'lmnopqrst', 'abcdefhjklmno', 'acdklmnouvw', 'bcklmno', 'nopqrst', 'qrt', 'fghijlmnpqrst',
'pqrstuv', 'klmnos', 'pqrstwxy', 'fgjklmnopqrst', 'pqrstuw', 'klmnopqrstuvxy', 'fhijklmno', 'abcdekmnuvw',
'ghjklmno', 'klmnoprtuvwxy', 'abcdefghijlmn', 'klmouvwxy', 'abcdegjklmno', 'p', 'hiklmnopqrst', 'rstuvwxy',
'gh', 'cdfghijklmno', 'klmnou', 'iklmno', 'klmnopqrstvxy', 'lmpqrstuvwxy', 'prtuvwxy', 'klmnovwxy', 'pqst',
'klmnortuvwxy', 'lmnpqrstuvwxy', 'fghijmpqrst', 'ghiklmnopqrst', 'klmpqrst', 'klmnoprstuvwxy', 'ghklmno',
'fghijopqrst', 'klmnoqruvwxy', 'abcdeklmouvw', 'ae', 'abcfghijklmno', 'vw', 'fghijr', 'kmnpqrstuvwxy',
'fghijklpqrst', 'vwxy', 'uxy', 'cklmnouvw', 'abcdefghijkm', 'uvw', 'bcd', 'bcefghij', 'abcdeiklmno', 'klmnot',
'cduvw', 'fghijmo', 'eklmnouvw', 'klmnopqrstuwy', 'kmnuvw', 'lmouvwxy', 'abcdefghijlmo', 'cefghij', 'klmnoqs',
'klmnouwx', 'kmuvwxy', 'ceklmnouvw', 'fghijklmnoqrs', 'abduvw', 'abceklmno', 'ghijklmno', 'abcdefghijmn',
'bcdfghij', 'pqrstvwx', 'fghijlpqrst', 'gijklmnopqrst', 'abcdelnuvw', 'pqrstvwy', 'pr', 'fghijklmnos', 'c',
'fghijklmno', 'abcdefghijkmno', 'abcuvw', 'abcdev', 'abeuvw', 'pqrstuvx', 'klo', 'fghijln', 'klmnpqrstuvwxy',
'abcdefghijlno', 'fghijklmnopst', 'acd', 'gipqrst', 'w', 'abcdenuvw', 'deuvw', 'abcdeklmnouvw', 'fg', 'cdeuvw',
'lmnuvw', 'abcdenouvw', 'klmnoqt', 'hklmnopqrst', 'klmnouvwy', 'gijklmno', 'klmnopqrst', 'fghijmopqrst',
'kmno', 'f', 'uv', 'fhij', 'knuvw', 'klmnor', 'klnouvwxy', 'bcdeuvw', 'bdklmno', 'abklmnouvw', 'abcdehjklmno',
'bcde', 'fghijklmo', 'abcdefghijklmo', 'ko', 'abcdeklmuvw', 'bcdefghijklmno', 'beuvw', 'qstuvwxy',
'aeklmnouvw', 'h', 't', 'kmuvw', 'fhi', 'fjklmnopqrst', 'hiklmno', 'fhipqrst', 'qrtuvwxy', 'abcdeklnuvw',
'fghijqrt', 'pqrstx', 'bdefghijklmno', 'gj', 'abcdelmno', 'abcdefjklmno', 'fhjpqrst', 'klnpqrst',
'fgijklmnopqrst', 'abcdelm', 'fghijrs', 'klmnouw', 'fhklmno', 'abcdeln', 'fgijpqrst', 'fghijklmnoqst',
'abeklmnouvw', 'klmuvw', 'i', 'lmno', 'fghijklo', 'fghijkm', 'g', 'adklmnouvw', 'be', 'abcdefgjklmno', 'prst',
'puvwxy', 'qrstuvwxy', 'klmnov', 'klmnopqrstuvwx', 'acefghijklmno', 'fghijpqrs', 'fhj', 'abklmno', 'abcd',
'fiklmno', 'ijpqrst', 'fghijnpqrst', 'lmnouvw', 'suvwxy', 'knouvw', 'duvw', 'fghijkmno', 'bdefghij',
'aceklmno', 'fgklmno', 'fghijst', 'adefghij', 'fghijklmnopqrs', 'bcdefghij', 'abcdefghijko', 'klmnotuvwxy',
'klmnopruvwxy', 'klmnovxy', 'qtuvwxy', 'fhjklmnopqrst', 'klmnoqrst', 'prt', 'fghijt', 'uvwx', 'abcdekmnouvw',
'dfghij', 'abcdehiklmno', 'klmnopqrstu', 'adeklmnouvw', 'abcdefghijmno', 'klmnopquvwxy', 'abcdefghijkln',
'mnpqrst', 'fghijlmn', 'lnopqrstuvwxy', 'pqrt', 'fghijpt', 'abcde', 'ij', 'bcdklmnouvw', 'fghijkn', 'pst',
'bdklmnouvw', 'abcdeko', 'fh', 'fjpqrst', 'fghijqr', 'beklmno', 'fghijklopqrst', 'lmuvw', 'klouvw', 'fghijpqr',
'abcdegi', 'psuvwxy', 'klnopqrstuvwxy', 'abcdelmn', 'fhiklmnopqrst', 'fghijprst', 'lnpqrstuvwxy', 'qruvwxy',
'aduvw', 'abcdekmuvw', 'adklmno', 'abcdeu', 'cefghijklmno', 'lm', 'hjklmno', 'abcdefghijklo', 'klmnoqrs',
'fghijko', 'ouvw', 'pqrstu', 'mnopqrst', 'louvw', 'prsuvwxy', 'abcdekno', 'klmnopqruvwxy', 'kpqrstuvwxy',
'abcdefgijklmno', 'klmnors', 'abcdefghijo', 'npqrst', 'knopqrstuvwxy', 'vx', 'fghijqrs', 'klmnopqrstuxy', 'u',
'aceuvw', 'klmnopqrtuvwxy', 'uvwxy', 'fipqrst', 'klmnowxy', 'befghij', 'gklmnopqrst', 'abe', 'mnopqrstuvwxy',
'fghijklmnoprs', 'abcdeo', 'eklmno', 'fgi', 'fghijlmpqrst', 'qt', 'abcdefghi', 'bcduvw', 'bduvw', 'klouvwxy',
'kouvwxy', 'fghiklmno', 'abcdemno', 'pqsuvwxy', 'ab', 'klmnopqrstvwxy', 'pqrstv', 'abfghijklmno', 'beklmnouvw',
'fghijklm', 'pqrsuvwxy', 'acdeklmnouvw', 'vwy', 'ghjpqrst', 'fghijl', 'klmnopqrstvy', 'abcdelouvw',
'fhijklmnopqrst', 'klmpqrstuvwxy', 'abcdef', 'bcfghij', 'fghijkno', 'kopqrst', 'rsuvwxy', 'abcdekmn', 'aklmno',
'dfghijklmno', 'abcdeklouvw', 'klmnpqrst', 'abcdeklmnouv', 'knpqrst', 'aceklmnouvw', 'kl', 'fghijprs', 'rt',
'klmnopqrsuvwxy', 'bfghijklmno', 'klmnouv', 'abcdefh', 's', 'klmnouvwx', 'fghijp', 'uwxy', 'fghijq', 'klmnoqr',
'vxy', 'fgpqrst', 'fghijlmno', 'defghij', 'pqtuvwxy', 'dklmno', 'klno', 'klmnowy', 'abcdemn', 'abcdeklnouvw',
'ptuvwxy', 'abcdehijklmno', 'acuvw', 'bcdfghijklmno', 'abcdemouvw', 'abcdefgi', 'opqrstuvwxy', 'v', 'lmpqrst',
'abcdeuvw', 'abcdekouvw', 'qrst', 'klmopqrstuvwxy', 'prstuvwxy', 'lmnpqrst', 'pqrstvy', 'abcdfghij', 'klmnop',
'ijklmnopqrst', 'klnpqrstuvwxy', 'klmnopqr', 'xy', 'abcdeklo', 'abd', 'klmnouvy', 'klmuvwxy', 'abcefghijklmno',
'fghijkopqrst', 'fghijklmnoprst', 'ruvwxy', 'm', 'e', 'abcdej', 'hpqrst', 'bceuvw', 'fghijmnpqrst', 'pqrstwy',
'klmnopqrstx', 'qsuvwxy', 'fghijknpqrst', 'bcdeklmno', 'klmopqrst', 'bdeklmnouvw', 'klmnopqst',
'klmnopqrstuvx', 'acklmno', 'hjpqrst', 'abcklmno', 'rst'])
num3 = solution(['ysvydhncudvxqgub', 'jxomzgqmpccovmyy', 'hxiwwqdowwbdzrql', 'zqfykhyqgxpuedhx', 'vhszanyizlocrcta',
'dthywqimclejyrxf', 'pxvnsacefcaeqwpn', 'eibroystpzgkhwkt', 'efioczniyhzlkgxx', 'jbafyifjrdsevjlt',
'noggsbrxuzxxxpnv', 'usxugdobkxyvebgp', 'omppygjbdzvfncoh', 'lszhxcyfyhbezqpl', 'sywbjmfmigsrdhbe',
'kmitesfpzturedvn', 'fhccayoplynamcmf', 'xwkxxvmngwdkktcq', 'bkdetlrdtrvxtwnm', 'otbqjkibazuiuzjc',
'bvdlpsuozpxykhso', 'sfkdemywenvutigi', 'zlsgexavkjlbniyz', 'omvmljrelegkrnly', 'ncfqxwbgspmmxequ',
'nsnusovrqfyjqcmi', 'xmfltlmbucykoygu', 'znevkwdmcjkxazvx', 'qmmlumphgweyuqll', 'vvwllhnjjilkkfbr',
'tfczebbrmcwkijpy', 'dyqudxtooxmzaivg', 'qabmbvkkacpipzwv', 'ousivmwzqkzowbsf', 'wiajbnzcyczvdkme',
'jtvkqglawuiitvne', 'hynkguvzlahiaweu', 'dcdhzutcxsrwhtiu', 'sjkbkfbzcltyhkzc', 'vmtoulenvyzgmzph',
'hhpjlqospgyrpjnr', 'trxsiqvzjdsumnbx', 'ifmzrmfjlfbxrspp', 'zuybbnxweoodzrcp', 'dqselcmauqpdbvji',
'ucdmjxlnodsqbtpf', 'yxqxoqyqsuxbvvwh', 'jifmvnffunc', 'jlgdux', 'fttypgxftlzhrjhu',
'rzmkqtaejgzrwvht', 'fylzmnvoslrjeuhu', 'xxhmsywcfchxybtz', 'nivviopjjkilmfnt', 'vlvtonhigprfttuk',
'cwgnurrfabcfotdmj', 'erjxfseyzaygaujp', 'nrcqdwczglmcvinq', 'dqbyglmywihtexid',
'vqggccuiimjqqpuz', 'wbvvklwhouxxcbzg', 'jxstdmcbouqvysje', 'envdnanmuewgheqr', 'oxjeneckyoxdypwq',
'ityoxogkfmlasgfq', 'tgpkcweywtqopjnc', 'hepoijpjgvckkqzc', 'ubppuzmagmjgmjnf', 'snvaiqinphtkbxtc',
'wvdwymqejrygisbn', 'kmbwjynfbwyablvs', 'rsscpinfcegvnulj', 'oplzudhvjaumtavx', 'oionhndcrjvfexir',
'cxxlrudrixtmjsgw', 'sfngfbrksewwbwuo', 'wngezcjkxlftmure', 'xgkmmsvjjvtlwyko', 'dfaihamfjrwobkai',
'ybzlbmtejcbhkbqn', 'yvgttkpmodjrdjaj', 'wsfkdifjxsisyazp', 'btdahuinzvvmyuti', 'sppdjjphoadtnxqz',
'idikaxmkupaaeyvd', 'bxmusrwhsuglelsa', 'wllftkyuyjwumzfz', 'lsrfakcruqfghhqr', 'oitbsfztaayzgttw',
'qvdaclqbkxzxtvji', 'hqtnylqopcuyitvv', 'dovrsivynjuycgob', 'zbeexmgffbvgyukt', 'jnyrkwuketocbnlp',
'kesivzsfimkupknz', 'fvctuhkhcsxgpnlc', 'geyiflxobsqqgysp', 'vdhnckkljiwiylkc', 'jxixmpjvkuisogjx',
'ggmgthlqqfjzvsiv', 'nkdbbqswrytidodb', 'cvnxasfxcyyprwky', 'msptawajcgigotxx', 'lggqfreicrrzgqug',
'pywexuvmpapzhhmk', 'yjfzlaazckdxqhpk', 'gxopiqnejwahizvy', 'rwptjuqhjshtosim', 'zhszbxltmwjfbcnn',
'hznbmqrhucjlhtev', 'repwvulbjzulzqlm', 'juemhyiaujdhjwda', 'iphegtklhgyiabcof',
'tpqxoalgjntzhxph', 'ahnrxtoyzqrqrxce', 'ljsunmfpleczezfi', 'flqbbwjpvmpiagkm', 'enxrdnasgsrczncm',
'setirvmdopdbgqqi', 'uuyoeqtcgvygmlbd', 'gznmxhdzpgclmmce', 'wrqmvtilsmjrfruj', 'nzbqahmftsbygrje',
'nodxqfwosevxikai', 'ynzmckxtfampkdcb', 'ishsysxcjavxukfq', 'mbwcnmktksqoptdx', 'ybpgwitxuarhyuud',
'odkhmislpnpjltvc', 'imlknoihasmgbjle', 'autoweexfbmsnamc', 'pzddxvvmnmujzovy', 'zbklmwsqltyiqjaq',
'wsfezmwlwnovzfnq', 'ipvtflaxlabczbjwg', 'xmeypiupgboeikma', 'qmhxpnusoafktsrp',
'akbzwaoevusmqhjy', 'ptnrluxfiaoedirs', 'fkkujjetvujaffev', 'iqlaebkqlabcuugvd',
'tvfazupnodyxyegj', 'cxxbmckkoocwwmkv', 'eiinwggrnufbuefm', 'jbajzgyvabcjrpirb',
'anotitqeflusqkmx', 'kkyyjfyqfwuyphvs', 'mkxxxgmewnnfmtgw', 'rfzfkowvhlbuptnn', 'yihacnrktjrrbupi',
'ljbfbmrxivbqhvgn', 'kelkifhcummieqec', 'qwglfqmlgtufeggt', 'ztdsjupiobdswepc', 'nxxrjnqebfrtztab',
'zwuijitgzkamuohu', 'skctyqbrtdlybrad', 'ftvbzzqisluhwvoj', 'tkyzlbdwikxwxtfm', 'yqzbwtibgyhezefc',
'ugmtditxujqhzdjk', 'pzqfxlcsbyiayoqn', 'mvuvmubzxoapqlwq', 'wxydvrxojyifgild', 'gaubuvvoncoahhqs',
'arrqgidasqpyozqo', 'hlktmcpfqmqunsiw', 'hpshspcjtkvjtyfc', 'xwdjpdyqbgkvbbto', 'dnipqamvliabetfk',
'zrptncovohuprjfj', 'zykerhdnpwqnklnp', 'wehvwpjsjmlhbxme', 'qhabvcixedhtacnm', 'nzbonhjtiragsjxu',
'piktfsxlejzjpmxa', 'kpgluxplomivhups', 'utbqkkbmdakmajvb', 'pbosjdvammowabof', 'hwwpavjyghyogxiz',
'qixjbuehpllqwbir', 'watokwdhqrlthmyt', 'fiuvnmucwsfhvirt', 'efjbktqktzylkzym', 'eyagoufvrlrbukvi',
'dbebcdxywrceoioj', 'dmejkiuqtpzkvtil', 'irxxxrbxjvvisefx', 'ezacasyffovrewri', 'zfoernjrzvxkzqjn',
'krrmkfftxdxqxrjf', 'xexiopshwbkipjdw', 'cnuiizhcocljycvu', 'idsxihqjacgtwiuu', 'nwjjtbiketrqdvxb',
'avmxhxabcxhflzcbs', 'uqxjgosfyjcbxshz', 'gwybdcsgvjjacjoq', 'zokabcujdqyhfvvve',
'dudqkxdyvnmzxbal', 'duurelhvlvlwtisc', 'vvduznkfxsydjjsu', 'jvohyxbezkxdybjk', 'tecmjpqvbqdfgbch',
'wmiwtqmxlipobteb', 'bzhfoutsommbeahv', 'pzxilyvfyokfmsmr', 'fvptnoujoahvjljv', 'nntjwlzvtlwjijtq',
'iiahigptxppvjwwh', 'fiwxrfkvznhngctp', 'hljuecxsqwhfhooj', 'kpgylifngxbybkwm', 'ckxgbjjygzkystat',
'anxjpmmadenhxunx', 'kztzbysfhebhkxhw', 'qeywqntlveiebhos', 'jlbvhtvumiyxwqlo', 'ubsttmdcjigfizes',
'tifeodqhusljfhxl', 'xhtrvehthwvsxkmj', 'slytykltdhwruorn', 'ettsedvbbxttpkwg', 'znlstbcrbxxyauvt',
'zvxkminzbadeyxpn', 'vkeqpqwrdrzvrdkg', 'lmgvnrmbwermpsxx', 'wpcihvumyumoljws', 'sqqleapevuisjovs',
'xrtefpneewlrlvwd', 'mmbabccilwfyvvjak', 'mqebclxzlkierkjf', 'cuytrwygyntgajgm',
'fhodjnmtmzrqzszj', 'kmgwmlnfykcuvqnl', 'aopjewaqievtqdct', 'tjouxksorchkworv',
'ncirabcozpldzewjz', 'sucivpgmovkfqxpn', 'akhusibommljkvfb', 'cdxrtkejlxftegjn',
'pcykwqocqfjcpygs', 'ddgipyltjxtthplq', 'uqtqauyppkzzztxr', 'byziilqifrkefnmx', 'pihmqvosbrmfwvgj',
'zcrokjgwuujlsqzk', 'midiigvhwxuuxdoj', 'quzizelifvrqgiqy', 'qoizxtjfeiykktbh', 'kopvmoiueozhbxfe',
'rabczignulcwpsobz', 'esmkumjwclulmmlg', 'cwknucjbjropshgm', 'xrkvscqbnuofxbbd',
'lfhexistfbnypjxb', 'qtvceoxufqerkgcd', 'nvqnrbzmizbmenoj', 'vaxeseydjahzmeqv', 'kkhvyzvdlupbekot',
'ghkdrqrrufndvlab', 'puuorkmgkyjrrfzm', 'qdojlkfsajazdbtr', 'trunvamzxxtruqqk', 'wyfqiycmuaxnwdmj',
'tehftxcnimfcgulv', 'xideohbursltsyaw', 'zukuxtscehugrlwz', 'tqyowyifdxmlekmi', 'gktvxxotbobtzjhz',
'sbrdswxuitwshrql', 'vjxkqyvipqlevbhk', 'xupvseicxsjlvprl', 'zzvgmaspjzobbbai', 'umqxughwbhxrbgnv',
'necgnedkdtsxllws', 'kfzhgtbffdkcmemk', 'jygmwohqgxytdabcc', 'xubntcuzhakycmhb',
'nykkvobihcvcbsom', 'jmpfjbgethlvegac', 'rcrkrqlqszizkuwn', 'mkvtjvezpqntwsor', 'vavxnwabzsvbxrta',
'wxjtawscbrqldboj', 'ukqyxnzmmregydtj', 'bzdoqdhyfxjhrtca', 'zwwifjejxilnlncq', 'zbhinfwhbsewmmnj',
'wpatetlrcetrwygn', 'qijjqtjtkjldjzpv', 'wizlmxgtbqokdive', 'gjowgwgtfyoyvakj', 'dutziyzhjwwdwbmh',
'hhxlvaslalqnjfez', 'nftbzbqrrdhpbvel', 'rawgbwriyffuvwea', 'qelvbxvcmyipiyux', 'gpvbmgzpjpvmfjou',
'edysbthmpzewjmhq', 'gimdgabewrjfmouq', 'kabamudmytcvskgz', 'jnbqnbtzepeettut', 'ubycgxbczobyuvty',
'ncqlwqzzlurrfurm', 'mqdliidaptajnque', 'aqkislhbhutlmskx', 'kqgowgleasjmgjro', 'anzasevxbinscrwy',
'mligzlmekbqjtlkz', 'acjwzeaariolohth', 'lewbaeswgtsegzgf', 'bkaleiidkzgtyukg', 'griqeggfgygajdxr',
'tiqtuoakcxhsppug', 'djwebkqgutgcqjkq', 'mtdquygxxpcnmxvg', 'lzbitojuuxxhrcms', 'wkqdzfkdeoxlrrrv',
'qdkvpynqxmqizxfh', 'rsypvochupieijuw', 'zhjqkrovsdewbwrg', 'cojrovhotitqglxf', 'vupizqllrxepdyej',
'rrcescgfpodyqgqj', 'enyhpwibqizxzxlf', 'ysgpfnkxewxpunmc', 'qqayjdiwesfhjqdj', 'vvxsqmsxkwlowkaz',
'vhbgvteemnjcjzjn', 'pjvysfsrgpzeefgi', 'hjpqwdkuxpvojlrb', 'qdviqqkpfpmusqku', 'zekclapatdchkkuu',
'ushhsykosapkwfvn', 'qlwhigtykfafzwkf', 'ueeemzyxxionuzvh', 'uxidcslniryrlkfr', 'wjrqpxvnjwnzvhaw',
'sfufkmlseobjehmb', 'viqcfxqgzfgjlwyn', 'vfffdaynlllgflud', 'xgbzqwuziammugee', 'juwviucofrqykbph',
'nfhofnyrvpgnrncr', 'xwnrmtztbduhaxzm', 'qwjuwencytcviddt', 'zgtzokhuophlklax', 'yhhhyqbivjulhxzz',
'qjlrmtnkpezzxbip', 'csjtxagscqzcyxgw', 'gibiwnkxfwmdypdb', 'zwuqefypxjswiqnr', 'rvwoomgislxnjiku',
'avtzjpgdqkrswwil', 'tybnjxlyeppveuln', 'hvjlkwgdbzjuthio', 'uwmvnynpvcrtjaoi', 'tazibajxbbektuny',
'eydtgcsqrjeudusa', 'cjvzwcgypecfudux', 'oovnezznsbbuzage', 'jjeciyognokzoavb', 'ewwzxbjfxgyrwdnz',
'mqtotsnaejvwsfxv', 'hewhemklxufjlxds', 'qfgrjckxuvxppffa', 'xrkanxmmdhjnrpms', 'ugszqiazpribuhin',
'hhtlbstnuebaovan', 'wmerwupitfwffwjq', 'cfhlftbplljrdnmt', 'iwgvszqjzoutyofq', 'rfddyjwanuajwfms',
'glcpwdgghxjjlbhl', 'opyabchjxtqeaqluw', 'zqrzsgsurxcablbp', 'tlzsuhpazrgyftra',
'hfbywjxrjvfyfjor', 'xfuisoaqkhitaneo', 'jbmpkilwrfevuabc', 'riftearjllxbsrpg', 'visatalbyphvpcqn',
'tezwyeuynxiqceny', 'gmllnngsknyuqfyg', 'jcptptnztjtczgin', 'sfslwzsttdrouqmi', 'oprcoelsndlnehzv',
'cfmhxjwgozohudcf', 'mhxzekxwbbccbumx', 'qeqyvhpujfgrmiop', 'gtqtcpovarcorjrf', 'aloszdzbbywgchfd',
'dknbhpmmjnuehczn', 'ebkeuntykvvfywib', 'nlgiglojmpbxhafl', 'uswobtqjlbukbjdo', 'deinrxindafjewms',
'bgkkntzoayoycmii', 'ibgusyotlezfhixr', 'jhduofjmetuvulfv', 'ncomoknshtsctgif', 'oeqgwqzgiuxzwnbo',
'kfqhheuvmfwtbokw', 'iqsoqygphhfktibu', 'bobacxbmnfzanumt', 'knnwtzpjwzujuuxw', 'vfnlobdgwymhcgun',
'gsvqncqugmzlvkcc', 'fqnfjzhlmmsjzvxx', 'isynioqvlkzdhldw', 'ysyenabcioynjgrzo',
'mgarisubmmtmxaqu', 'tlkplxdwjvivozqu', 'uumvkpkfqckauzpy', 'jqzzndmsdwuznmii', 'cqqaephdukcklkkh',
'arqsbqajtlzbxspv', 'fpwnogjkszhusmqn', 'arkauhwcnzyhgzgp', 'mmlbhlqmmpxdsjpr', 'hxsyiwgylwvfxvqf',
'fmgsmcxhczkblvrr', 'jfsbaiqqmrcqziyh', 'yonriirnykgcqqoa', 'loqnbxhvnqhefnzc', 'vnrwfrtawnjzmzpr',
'nwvmixbdevbawgcb', 'ssoscjougdkdgwzy', 'tdotnfxymskkechy', 'gdqyqjahcohateim', 'nmpingpzculglnzq',
'oshxfncaghkzfflo', 'brqucwymtbtbpkmg', 'dlbolallmawftyne', 'zaygaqdomkdndypz', 'frynwfgjeyczjiyj',
'fkrmnqytsxookgtf', 'ztsuspdffprgefji', 'urmvtcqxbzqlfenp', 'jtqnervrgeqgltma', 'mxazffkgorgqvasd',
'ohxmmsvrbcbakvtz', 'gvgbadnzvabrkajj', 'ytxszlngumxdrxgs', 'uyrufyweypbkrbcg', 'ylelxbcmvwdqlsst',
'fnqgyqxovwwitolz', 'nmrqcgovdmaregoh', 'jabcyxscsxpdwhduv', 'agyjbfjdrxsdxcbz',
'rsxthmvbbfsbapza', 'bnulsywwhvtckkmm', 'oetgshifgdhknjen', 'fdacdxgrjnfqhbgl', 'ltrpuqvqvaaijmix',
'aalhlxvddlhxsyev', 'qubggjexevkjzapf', 'qffkqkgvbxyrncum', 'ouebeyqrrbwluaiu', 'bsmvockhhfxdvwnn',
'wzyrusboriskzetg', 'qtkohvlnoxldzkhe', 'sknqielwtnmdozdk', 'hueabhcqpsziqofs', 'qvdcptldvpyzwbwt',
'gmcsgkgfgdzvdywo', 'whcybgsdsunkkpqd', 'zouenychsloywadi', 'ofnixothejurjqwx', 'baurihhbpsuzaxdz',
'odnxgsawwegaqqsk', 'avnvjxfrofflpnfl', 'fpeejbcasyuuirri', 'lnqcckixeovoabad', 'ogzfwbnpmoqzdxqb',
'lsfpkmktczfkgase', 'ckfkwbmenshnuzrk', 'puuxkxfbbtdttkec', 'oxplgbgxocgwayuc', 'tgxfplgbhcjubdtg',
'cpcwhsckcdfhbwmp', 'huaukdwwqenjsnbr', 'hvofxghsjlfhswhp', 'vnwbsvtnpfpwatiw', 'mcbkpsbgywhqxsix',
'zksceqawvnemisil', 'ojpmvjelrldcqflk', 'ppfxcvjrjywbkaci', 'vkkkabrzumejtwdr', 'jzzvegddqgtogyel',
'fvwxxwbukfrbazxg', 'rpvgsjrcsunopqja', 'ngjxvxsqxcboieeo', 'xgrdakguxugvngjr', 'zlixckrlsfjnvwiw',
'kqqahdzvaovwrarw', 'zeqmlrqvcymohkfc', 'fkdmammoniaqeaei', 'ktrvrgxstgvttftq', 'skujpfmasgqboljm',
'ydenwjcdlcdtodqp', 'hgsuqywmnwmyfotr', 'waufauuijgxaqceu', 'gbudfydfhbvoamth', 'afskwqlszmvafeqm',
'nbsjuuyfqbhqajok', 'iiawyxcdikosbwsx', 'kgqvvxhnmswfngde', 'icqcdxpedlxpvgms', 'wpxzbdlhhvarycks',
'wkwdjgkzzrmuhuol', 'swsgbdcrbhqhfcci', 'kgmkgeiryynvhwah', 'cmpvksdyjvmbdfhj', 'uglxrzjgijfcvhbx',
'bgevfvpmocxgausz', 'uqojyggipoyuwkby', 'avlnovzpuzubuuss', 'eyghurrorndubcsm', 'zdnntbwcugnykdti',
'lchrlndexvovoznd', 'cpnizzfmpzinymlk', 'hskvkurwexwqasxt', 'xprysdqnfmvifwjy', 'ngzdbejzpatoixnp',
'zxomsbqlfuhemazl', 'iqvuegauwclhvqma', 'tzdgvyptuayjvktt', 'zvhbvljserqbcbir', 'mukwzypdxlegwipe',
'uslhhogibvwqzhyz', 'rylrlapnfsdogovl', 'impmhoqumkogchoq', 'zarlqxhzfwhqjsms', 'ymxpexvboiwzkomy',
'nhgexfzvunjnosgb', 'wslojqmvusvumclp', 'uufkkyrchehmokjr', 'uadbebqfwaewmzdk', 'wwzazyhamqhdwjzc',
'yrwrqxhvmzfeiqpa', 'gycblakmiqqoioke', 'gpyfmbzhhhtuysyf', 'agtyhlalmwzmpnes', 'jhbfquwnkzzmmrqg',
'xahekbixkfaidgkb', 'njiajqrymsbxsfyj', 'xrhkzoerfwjjjvyv', 'mojaewgjwmmxmmcj', 'mcimexhcqqptnotx',
'lshefqasobmbuxdd', 'srgglcluxgheudmy', 'cgxocmkqzjagwgmm', 'iyreabcwxbnkpsjoa',
'zaljaqjvfvvqdays', 'gskeygtjgbijvkjn', 'smpslnyxjvbhjyvh', 'raeaxhedueaayvlp', 'vbzqcqhzdaptsdts',
'enurfjqxyapakpyu', 'xesnqtvzlkjudkgx', 'kjwfyrasqtafiyri', 'bsbavcxzjuaksbld', 'hstmbonbgsleppae',
'exyhezlohmqkhxlr', 'rqmhckbvtfyqwsxh', 'wfnvwsffbdliqsll', 'eaqnrvadjaojgfsm', 'rhocxroqdqrervjn',
'mzdczcvbrhjwcdve', 'yxlrftymqxqtbvso', 'baunrbrfzrapqzit', 'oipmrdynelruxvry', 'khppolojdkojxwqv',
'umwgrzharatzdqjb', 'jbabfxajhdducgsw', 'ohtxxfqthypvhbca', 'knwjiwadhywkwlsz', 'qteikhwuuasdyvpn',
'ytdeibtvnlysssfj', 'bdcflvlghfonjfik', 'eactaiaqtgrhwkbn', 'evfodntmumnmpltz', 'zklhlzjiueabafnz',
'zrsbbgkjcseqeang', 'cbvthkbgywxvjkhh', 'gykehthvmdzklzmm', 'bhrydwsdwtqaxyhu',
'abchczaihcevacgzx', 'yonhiezjoqwosrwx', 'lpwsvvjbtimkqkaz', 'tibcufriphwxwzhj',
'kqxnnvmxdyubsyma', 'jdjdalrfdvtzjzzf', 'qzijzvthlydyayby', 'xsmhbxalbihmkgmr', 'ickheeqdhkhfvagy',
'zgancfyzdspdikye', 'rglysjgxdhtlirpe', 'xwmvbwnbknuynzms', 'rtggytyubuthyvdu', 'hjfqzmmiqdopyduc',
'yyeixxunfkstmdly', 'stccdhodaeauqskv', 'bsemgaskpcgvmcgd', 'todqxrxzpksoowqy', 'wqpfgvkppuehavdx',
'oecawvidnbencfzv', 'ocpbksbgdutggshn', 'hvfvfvhuwftqdtys', 'raqymywkbzpjsomo', 'mnsgyltrdguifeom',
'zrtwkfvmrxgmebpc', 'esnlddvhmlycfnzm', 'ujmrrippyxxaitjd', 'cjqopvqjmwdwrhtc', 'axterdjcgvvkvjmt',
'wsfjhyhiwcskrnzl', 'excxprrgtvsdstkq', 'bqpvnpcbqbjeorfs', 'zgrbyxqcahdirxzz', 'ibruhcuhiwpsndjo',
'dmningijzetvgssq', 'vsbnskosiigyjwhd', 'gvbexrsmzefdfjra', 'rnjdwommvluzgmiw', 'qfnpnioafynmfnch',
'iutdykdyrnjbijim', 'yybpzynyyvqsibqw', 'ukcumxubdajklbow', 'qpfhjabesozcqxnt', 'ogpjowmcxjvltaei',
'nmmgxxpblhyvjcza', 'rsdicjpuitrhjhoo', 'rougghrsdcuhaxkb', 'ccoubobkldovhdha', 'heeysansiaiqecsy',
'txyzgixqzbqoyddo', 'zgonqkaonzusldmu', 'ksvocdxauzvzaqej', 'tthfhimluvparxna', 'jrfaqfteargbowaq',
'vwgdxfzukfkbwmoi', 'kxaxverroublhnkg', 'hxcyocruwhxerkwv', 'waaywxwtrwpnwcxe', 'kbrwbedcrxacnfzn',
'heqhjudnrfmpgffr', 'zoninmtmgfzwfivy', 'nhdjsbedakglczfb', 'eyklkfsriufgdeta', 'cdtcihvzlfrxcqkk',
'nszlmuisqibdhuij', 'frfwwwunnpwouryl', 'bahmwsfifpehpvlm', 'xinovuwjryvjderk', 'stdxirugdjwsxdrf',
'ukzsodimorlbassb', 'dcqdmnpirlwetexz', 'lnkkravbrdzuaixf', 'iqhikikqgoabcupoz',
'tqqnskydlxxyeloy', 'hoqhujloveotexob', 'tafrmbzoiiyxkrpv', 'gedftcwddbvqbcbp', 'tmlvgfxezfqhqlro',
'omkqddentowyusgs', 'uvmoywmfgcxprcob', 'wxaexnkxfscqpbvn', 'arouwkkwzmpxcraq', 'oshuiowfgoxvscum',
'wlcbjlvtpwbizxkk', 'pqdqfcardhablnlm', 'hncftotfykwkmcwc', 'ilbkfisyjvqmmjox', 'mjziuevwvgazkmrr',
'qxftpuleqzgeoxkn', 'qwfbcoulervauwzy', 'hzzahmyatnakmfkm', 'atlkeburbqttzgdv', 'chctjbylvaqivhnu',
'kljxzdlufmjsakrn', 'ldqznwrdmigxmplj', 'jnzsugujwghliiyj', 'davvfzptwjezrtut', 'ayvxlihyfxjghbnj',
'damnybtgbouyhgvm', 'xycclwykeleqgqbz', 'xcexkuimhauveeep', 'alawhglfqmrpujdu', 'ucqkzhnxzfmhrscm',
'giqfhrubpvulkbcz', 'ibjyvrczdfvorhxe', 'qbwwxgvtphqitwrc', 'nznctodxeivfdauc', 'gcelouuuaxwxmvsw',
'rqelrfgexnkdnazl', 'fbepvxtrhujvrdfc', 'iczbfakdstudncnv', 'qwyjcjokwchroxbr', 'ycjrzaetiivrrdkc',
'hjaflkntduxbssgu', 'rwfrleciyxwvxygj', 'pfkodbjvlrgvryzh', 'fyvawqjluonvjjxc', 'nzkedkvundnsfmnm',
'zkvlbpsldcyafkpj', 'hrnjhejkhdkcmnmh', 'sydwdkxfjjkvvbfk', 'ydznqbenlyrstgmu', 'katzotudzcpwwvkb',
'xucadxwemqvixtva', 'nnbzlmlmesntwwhh', 'sidmvrqryepebkda', 'zqlfnaleybermqpx', 'kduaxanohkcebsaj',
'jajuaudbrkkcnyyq', 'rhtefiqjirzhpjwt', 'tgbyhnyxxivxpebp', 'oqqwgmpqimqnjrxz', 'tptopmpejaaaxokz',
'rglhbkxoupbeqxhn', 'diannxikfirreuin', 'ilkjfpwdabcorejuk', 'tzygwhlicpqhsxsm',
'ednqyfigrhjjsixi', 'ichtvcqqxhzvwyrk', 'ckyoxfbufktqznpj', 'xoskspafepfgeeit', 'jcbtyhklimaasdfu',
'cfkabckzjghzapvxx', 'owdyarpowhkunwhy', 'etnyrgssgohswpva', 'ccdzytrxkxrfobiv',
'vxmwodlmkjmnanqf', 'lfoyuzoffzuzknom', 'avpouwwwczpcsixm', 'befuilgwreabcsjqn',
'wwlkjupnpinaskti', 'wuaufrnozwrcwrux', 'ddmlqscfylvvlqet', 'ngtehvarjqltinad', 'hxilufvmpbmybqse',
'sxckpnkpctadurmj', 'tkauepahazlgunce', 'wdnczbubbvaeugur', 'blbtvambkabhgfmt', 'hscywaqlqpzmajlw',
'kqbcyrflffoyrrde', 'swatgwoezppbhzrz', 'wncpezwknhwlkyfa', 'fxoalqugauheullc', 'yfejaqfwodcbvjxo',
'srdidycbfudekvry', 'wbmqrnpsbwvajyst', 'eojhwvsjkhruoihy', 'lebgsqpfytyfljzy', 'nlfrksicpahzoyzs',
'vwfuihhrcdfzahuq', 'zxossokxsiilrhwn', 'nnogzvnyavbajgxg', 'xudcsovkwdigfykp', 'oxnernpkebnwtzgk',
'lpkluymjfczcabbg', 'xwmoythsnnalagrd', 'bwxqduzhwponwuxh', 'tvqujorvigsrzqra', 'ruhirwfwnudvhndi',
'yigakwntqrddbxel', 'doyelkmwfiqrcvwf', 'nqepgxvwmpczbqmp', 'euwsrbwhhaosbuxv', 'qybvertwzftjmsbo',
'ovrxezhfnplztkrf', 'zhsklztsgdxqqlos', 'hjkalxuedegqevxf', 'acqcmxxnvxiyiarj', 'irfjxvnxvcwfggyf',
'ivjlvhotuhyjrbqi', 'ybowwazfbqnlxhix', 'rwldwkwiuokthyvd', 'emeoryhhzmchkcaf', 'wkjtfktltlxrpodu',
'zozxqufosbvhvzmk', 'kejjywawtflpnzxq', 'tgjqeqqyflstgyfn', 'edodalhdkbpbvbbi', 'svvbrdqtivcocuok',
'jqycfyojmcojaike', 'uysmgvolzqhvrjcg', 'jepqutdjnzdxpuis', 'htypdjotmvugsqrn', 'ruanlnsslyvcmloa',
'rmguapshfylrqcyw', 'idmrozfesprjyydi', 'igiijxxuaewkngez', 'mmfbpbxhjbbtaktl', 'wbryhbistnsnxcre',
'eyypsgultocxkddt', 'hmgsapmnlbhkldjy', 'srdiuczmorzzmqmx', 'jydlzvjtvssbiriv', 'xyxlubdngtpamnie',
'hzxhqmvdfeelavey', 'dnmkfxoqikbpnncm', 'uvykqjhcbjrkhwws', 'hcouhxnefskqtsmj', 'tlzdfixqvzmpnxey',
'bqthxadcjbuoihjb', 'amqcryxqrquugjds', 'kazopbofkzigbrjf', 'yoazjvgcjnuynogm', 'cekiuyvsxvnhllot',
'skaakenhygficler', 'vyyblxbztgjdxemi', 'cwijfnzpasohsysb', 'vxshtpkflepkegsv', 'dqlajjejvwkljffm',
'pdrurythrunegiyt', 'wyniiprlwdxayecx', 'onzimmmmwsczxrud', 'wahjycyykcusbzkh', 'pmxfomqplrchaeji',
'cuiofjxjmfwmwjpo', 'mqeyxhbjjhtyiqax', 'vxjtwryiiaiqmgxc', 'rpxhygecrrxsorep', 'pdhcrtkvutpxkjqk',
'xghqzhfjrcskksay', 'llatzvkvpehtkmlp', 'evcdafiqhelayolh', 'wnpjllgpnngclefg', 'cplkciggvoivrdrk',
'rwzojlohceoksqei', 'ibblbsqbtieahuip', 'rxymbuhpxlybbpwj', 'oufytsooclpjthdt', 'ladsdwyczkhlprsk',
'lqglakcncwvhbmdq', 'pvffqrafetpcnonv', 'ltxqocyoaqwqlclh', 'ujleyjgijrzxpohv', 'hdliszkijxjfdhuz',
'uerwlwcboltvibyv', 'frnvgotjrsmsvdrv', 'kprkmutaqpumileg', 'dyfntcyriixrbzpu', 'pljixloqwehtiyju',
'guvbkiuixwtllbyh', 'aywoiniduriovexc', 'xkhsubtnkyitnjuu', 'orgjwbnwirxnlvkv', 'tbnfpmbwrdvlcids',
'ljptwryckhaervnt', 'piklsbpqrpcwtkax', 'btjqiwzsjhtyrabp', 'xaqhoeyrofnixysd', 'ildloryxoleksykm',
'tpkrvszvlfvhpgua', 'uomslwptxjarrgtp', 'qfawaceubqhtfqia', 'xvsatjnexaphrcsq', 'chlowdcammoiqswp',
'vryqjuplbwlaomsw', 'zkndhkyqnmooseqy', 'oehmlodyfkbgwggc', 'ygicydiozmvrkjov', 'vffghaadldklcvpa',
'dudkmcpnwktzabcyc', 'cgpwhbxlqbydfial', 'xkeqyrbppiqzzdtc', 'aywomxmmicyapqry',
'qxrfswxmtgqwiaiu', 'ogesstqnbrqzcike', 'quvgbtgtjtgxrqez', 'ilrohxbbjzdyifwb', 'mwbgfsetpneteejs',
'awvqavqersnsgvym', 'lslutwvxqsgrasxf', 'hujsniqoktvleeph', 'tbibnfjtibcusfqc', 'jkeeyrhwuudkrzmx',
'rckpwpavcgvgmbqn', 'drzbjsuvjgfxgpzx', 'kmdsvposrrdokxzu', 'lapmakjdxbobqslx', 'awqhcznyrcbreinx',
'sgtrrbfxpgcdmlfi', 'hjvvuazaydvuqzfl', 'ukvueksttoovtqnx', 'fjcjtxrbzsrxelui', 'ynxnlswchgyljfah',
'ueznbslrhcswvlvg', 'ixvfnmhdbnowsido', 'tnvrbemiduyabcpgf', 'xicjxbvnripjquxk',
'pnguepiandvkkjgm', 'fmjuyijqtflklzrz', 'wowbwesqdjgbnfza', 'bzhqulhhfrmvlikt', 'xwwbxkpqwzuvbfcc',
'tzfeejglmxpjfiob', 'ttvlzzgyydwznuuj', 'zsaqdcbxiivqeibj', 'jqhivhimzrbhfjye', 'woxtmnynlehbynso',
'tweacunvvzvxvkhe', 'wvjiwrdllmbrzyzh', 'kpawpohuffukizip', 'culggzusblbzrbvp', 'rfiaujemuathqnrg',
'txcebmnimvozhnbq', 'lbpnqjkgkmqepuca', 'rqfueobyxicwpkao', 'rggegjcjqzhrkjqn', 'xbxlktpwwsergaut',
'lhowgnysedqhcquk', 'oqldregahyfprwsi', 'dizcwcthvgopgnwx', 'bzpodvsqzlmeakvy', 'vclpieckqkxhblhl',
'lnvngowxjpgdkwfv', 'yvkdxviywwowawba', 'zxymzgtfqsshclgz', 'boqkrbmnsxvbiema', 'hoeexawhwjrohbxe',
'luocnssrsnrlbmyi', 'tduuyggdvgbfgmhw', 'frvhgulszabsrunb', 'vcsontpzpacsgobo', 'kaiqymcnijuixgvp',
'vgfugfulxkppkurw', 'foudqjgejntrwhke', 'abldoxtbpltfnsni', 'kqxvgbgkkoakfeaj', 'rdkjzlwcpygzkshq',
'qfjxzlkyrpmuvlrf', 'depydkicbtuwrbuf', 'vmpfhqfgcyreyqdl', 'oneokdfkplafayzn', 'fjcerifwgajithlr',
'gtlxawvwmlmqsuuu', 'wgfxdchxqlzdxcpr', 'ajdrspwucswacivi', 'wjzhtgddolhaahmo', 'hbyrafvgohzefptw',
'roxblqysntdnkfqx', 'rmvrjdkeppblcmvy', 'xzgbkvnyxljluccp', 'dvvwfjxmydfdzqyt', 'kxxjltlgbaiguihx',
'rahukefeaibeekpq', 'spsdfgpofpoanurm', 'pjmewktbcytjsvrs', 'nhtbcrwqzoxbhkyi', 'eanjdepcqzqdeoea',
'ujhvaizclocaksng', 'tkucqzszyktwvyjq', 'dnummodkocgrdhbx', 'bzvvgfxvgzqjshji', 'ddctbuygjncstchf',
'mrpciqjmowzdjvsm', 'qhdgxhopljagfbfi', 'ksnimciprjexohfu', 'sdfgsfcwgaknzrqt', 'keiywmjuavometzf',
'pxdzshicopwmofxl', 'xdwlukdaxhwjojeq', 'krnlgjtxhnuntwsa', 'bpnrhdwfkagaubka', 'beoyleogpryyjcmv',
'rrhlmtgpyfszchsi', 'ozdknlljectjisdg', 'wdobdazbwjecqcep', 'jfxjpbzonkvxltib', 'fwcffctkbvpkgexm',
'gornbkdvwuqirrlk', 'yyiqngwrxevbwchf', 'ggyqhxvbjwyzuxwf', 'ixhwkhgotdmkamtj', 'dbqqdygrhtysgxgw',
'mzwmkjfknwfhulgv', 'xtngfkkjuaonbemi', 'vghhkblxwbijsqwi', 'fkfulljgmpkmvxwn', 'kqdckewxfcwyjkuo',
'msaxmgcjerovxgqo', 'bswhhcxiljhjeivr', 'lwllrzomgnjzjqxh', 'gugxbiwfpjbtscyw', 'mmqsxwrnsiprrmyv',
'pdjccwbewqxbhgzn', 'mshemwgzytwmqljx', 'moezekitiafkvsqr', 'edthrvvafeypjypw', 'qspowcqalsukqhhy',
'wasrmlhgjgalcbrb', 'dglyfamnfpqkmteh', 'xgpvsclrqskbjnao', 'iawgyqoqnmxmwtrk'])

# --- 根据三个整数生成最终 flag ---
flag = calc([num1, num2, num3])
print("最终生成的 flag:", flag)

ez_stack

只要少数几个函数,结合题目名分析可能跟虚拟机有关

sub_401139:似乎在执行代码的解混淆操作

image-20250827101410780

下面这些函数都是重命名的

sub_4017A1 是复杂函数,从其结构来看,似乎是一个虚拟机或解释器。它有一个主循环,在循环中读取字节码,解码并执行相应的操作。

sub_4015AE 和 sub_40170D ,并将它们分别重命名为 push_byte_to_dynamic_buffer 和 pop_byte_from_dynamic_buffer 。push_byte_to_dynamic_buffer 和 pop_byte_from_dynamic_buffer 函数用于管理虚拟机的堆栈。

以下是我识别出的操作码及其对应的功能:

  • 0xF0 (240): exit - 终止程序。

  • 0xE0 (224): write - 从堆栈中弹出一个值,并将其作为字节数,然后从一个缓冲区读取相应数量的字节并将其写入标准输出。

  • 0xD0 (208): read - 从堆栈中弹出一个值,并将其作为字节数,然后从标准输入读取相应数量的字节并将其推入一个缓冲区。

  • 0xC0 (192): rotate - 执行某种位旋转或移位操作。

    1
    2
    3
    4
    5
    参数 : 该指令有几个参数,编码在 op_byte1 和 op_word1 中,控制着旋转的 轮数 、 块大小 (旋转多少个字节)、 方向 (左旋或右旋)以及其他一些标志。
    数据移动 : 它使用两个堆栈, g_data_stack_ptr (主数据堆栈)和 g_helper_stack_ptr (辅助堆栈)。操作开始前,它会将需要加密/解密的数据块从一个堆栈移动到另一个。
    位旋转 : 核心操作是逐字节地进行位旋转。它使用一个变量作为“进位标志”,将一个字节移出的位带到下一个字节的移入位。这使得整个数据块的位操作相互关联。
    - 如果 op_word1 的第8位( 0x100 )被设置,它执行右旋 。
    - 否则,它执行 左旋 。
  • 0xB0 (176): or - 对堆栈顶部的两个值执行按位或运算。

  • 0xA0 (160): and - 对堆栈顶部的两个值执行按位与运算。

  • 0x90 (144): xor - 对堆栈顶部的两个值执行按位异或运算。

  • 0x80 (128): sub- 对堆栈顶部的两个值执行减法运算。

    1
    2
    3
    4
    v8 = sub_40170D((__int64)&addr_0);           // 再读 1 个字节
    v52 = v8 - (unsigned __int8)buf - v9; // 做差
    buf = v8 - buf - v9;
    v9 = -(v52 >> 8); // 更新进位/借位标志
  • 0x70 (112): add- 对堆栈顶部的两个值执行加法运算。

    1
    2
    3
    4
    v4 = v6 + v8;           // 两个字节相加
    v53 = v4 + v9; // 加上进位
    v6 += v8 + v9;
    v9 = (unsigned __int16)(v4 + v9) >> 8; // 更新进位 (高 8bit)
  • 0x60 (96): mul - 对堆栈顶部的两个值执行乘法运算。

  • 0x50 (80): div/mod - 对堆栈顶部的两个值执行除法或模运算。(?)

  • 0x40 (64): push - 将一个值推入堆栈。

  • 0x30 (48): dup - 复制堆栈顶部的值。

  • 0x20 (32): swap - 交换堆栈顶部的两个值。

  • 0x10 (16): pop - 从堆栈中弹出一个值。

  • 0x00 (0): jmpcc - 根据 zero_flag 的值进行条件跳转。

1
2
3
4
5
6
7
8
0xC0 //rotate
0xB0 //or
0xA0 //and
0x90 //xor
0x80 //sub
0x70 //add
0x60 //dup
0x50 //pop

下断点打印出程序逻辑

406040:存储待执行的指令字节码,相当于 IR

406050:存储栈空间中的变量

406060:存储数据,相当于通用寄存器,并用于循环

格式为:

1
2
3
4
5
6
struct stack
{
unsigned char * base;
unsigned int top;
unsigned int max_size;
}

换句话说,qword_406050 就是一个“栈对象”,类似 Python 里的 list,只不过底层是 (addr, size) 两个字段。

例如 size = 4 → 每个数是 4 字节;size = 1 → 每个数是 1 字节。

因此可以在4023AE写出这样的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 4023AE sub
import struct

rbp = ida_dbg.get_reg_val('rbp')
rsp = ida_dbg.get_reg_val('rsp')

stk2_addr = ida_bytes.get_qword(0x406050)
stk2_size = ida_bytes.get_dword(0x406050+8)

size = ida_bytes.get_byte(rbp-0x15C)
stk2_data = ida_bytes.get_bytes(stk2_addr+stk2_size-size*2, size*2)

if size == 4:
v1, v2 = struct.unpack('<2I', stk2_data)
v = (v1-v2)&0xFFFFFFFF
print(f'0x{v1:08X}-0x{v2:08X}=0x{v:08X}')
elif size == 1:
v1, v2 = struct.unpack('<2B', stk2_data)
v = (v1-v2)&0xFF
print(f'0x{v1:02X}-0x{v2:02X}=0x{v:02X}')
else:
print(f'{size=:#X}')
return 0
1
2
3
4
5
6
.text:00000000004023AE loc_4023AE:                             ; CODE XREF: sub_4017A1+633↑j
.text:00000000004023AE mov [rbp+var_16D], 0
.text:00000000004023B5 mov [rbp+var_16C], 1
.text:00000000004023BC mov eax, [rbp+var_15C]
.text:00000000004023C2 mov [rbp+var_128], eax
.text:00000000004023C8 jmp loc_40255F

在栈帧里,rbp - 0x15C 这个偏移量上存了一个值。是 大整数的“字长(单位字节)

1 → byte (B)

4 → dword (I)

因此下面的代码也容易写出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 4021ED add
import struct

rbp = ida_dbg.get_reg_val('rbp')
rsp = ida_dbg.get_reg_val('rsp')

stk2_addr = ida_bytes.get_qword(0x406050)
stk2_size = ida_bytes.get_dword(0x406050+8)

size = ida_bytes.get_byte(rbp-0x15C)
stk2_data = ida_bytes.get_bytes(stk2_addr+stk2_size-size*2, size*2)

if size == 4:
v1, v2 = struct.unpack('<2I', stk2_data)
v = (v1+v2)&0xFFFFFFFF
print(f'0x{v1:08X}+0x{v2:08X}=0x{v:08X}')
elif size == 1:
v1, v2 = struct.unpack('<2B', stk2_data)
v = (v1+v2)&0xFF
print(f'0x{v1:02X}+0x{v2:02X}=0x{v:02X}')
else:
print(f'{size=:#X}')
return 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 402571 xor
import struct

rbp = ida_dbg.get_reg_val('rbp')
rsp = ida_dbg.get_reg_val('rsp')

stk2_addr = ida_bytes.get_qword(0x406050)
stk2_size = ida_bytes.get_dword(0x406050+8)

size = ida_bytes.get_byte(rbp-0x15C)
stk2_data = ida_bytes.get_bytes(stk2_addr+stk2_size-size*2, size*2)

if size == 4:
v1, v2 = struct.unpack('<2I', stk2_data)
v = (v1^v2)&0xFFFFFFFF
print(f'0x{v1:08X}^0x{v2:08X}=0x{v:08X}')
elif size == 1:
v1, v2 = struct.unpack('<2B', stk2_data)
v = (v1^v2)&0xFF
print(f'0x{v1:02X}^0x{v2:02X}=0x{v:02X}')
else:
print(f'{size=:#X} xor {stk2_data[:size].hex()}^{stk2_data[size:].hex()}')
return 0

最后输入11112222333344445555666677778888调试得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

0x00000000+0x9E3779B9=0x9E3779B9 sum
0x31313131^0x9E3779B9=0xAF064888 t0 = inp[(j+1)%8]^sum
0xAF064888+0x547FA369=0x0385EBF1 t1 = t0+keys[j]
0xB9B9B9B8^0x0385EBF1=0xBA3C5249 t2 = (inp[(j+7)%8]<<3)^t1
0x01898989^0xBA3C5249=0xBBB5DBC0 t3 = (inp[(j+1)%8]>>5)^t2
0x30303030+0xBBB5DBC0=0xEBE60BF0 inp[j] = inp[j]+t3

0x32323232^0x9E3779B9=0xAC054B8B t0 = inp[(j+1)%8]^sum
0xAC054B8B+0x43AF51A7=0xEFB49D32 t1 = t0+keys[j]
0x5F305F80^0xEFB49D32=0xB084C2B2 t2 = (inp[(j+7)%8]<<3)^t1
0x01919191^0xB084C2B2=0xB1155323 t3 = (inp[(j+1)%8]>>5)^t2
0x31313131+0xB1155323=0xE2468454 inp[j] = inp[j]+t3
...
...

那个移位的我不清楚到底做了什么,但是可以猜出来如下

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
0x00000000+0x9E3779B9=0x9E3779B9  sum+=delta

0x32323232^0x9E3779B9=0xAC054B8B enc[1] ^ sum
0xAC054B8B+0x547FA369=0x0084EEF4 t1 = (enc[1] ^ sum) + key[0]
?????? 0xC1C1C1C0 enc[7] << 3
0xC1C1C1C0^0x0084EEF4=0xC1452F34 t2 = (enc[7] << 3) ^ t1
???? 0x01919191 enc[1] >> 5
0x01919191^0xC1452F34=0xC0D4BEA5 t3 = (enc[1] >> 5) ^ t2
0x31313131+0xC0D4BEA5=0xF205EFD6 enc[0] += t3

0x33333333^0x9E3779B9=0xAD044A8A enc[2] ^ sum
0xAD044A8A+0x43AF51A7=0xF0B39C31 t1 = (enc[2] ^ sum) + key[1]
0x902F7EB0^0xF0B39C31=0x609CE281 t2 = (enc[0] << 3) ^ t1
0x01999999^0x609CE281=0x61057B18 t3 = (enc[2] >> 5) ^ t2
0x32323232+0x61057B18=0x9337AD4A enc[1] += t3

0x34343434^0x9E3779B9=0xAA034D8D
0xAA034D8D+0xEE8F66C7=0x9892B454
0x99BD6A50^0x9892B454=0x012FDE04
0x01A1A1A1^0x012FDE04=0x008E7FA5
0x33333333+0x008E7FA5=0x33C1B2D8

0x35353535^0x9E3779B9=0xAB024C8C
0xAB024C8C+0x265BFED5=0xD15E4B61
0x9E0D96C0^0xD15E4B61=0x4F53DDA1
0x01A9A9A9^0x4F53DDA1=0x4EFA7408
0x34343434+0x4EFA7408=0x832EA83C

0x36363636^0x9E3779B9=0xA8014F8F
0xA8014F8F+0xDA138396=0x8214D325
0x197541E0^0x8214D325=0x9B6192C5
0x01B1B1B1^0x9B6192C5=0x9AD02374
0x35353535+0x9AD02374=0xD00558A9

0x37373737^0x9E3779B9=0xA9004E8E
0xA9004E8E+0xE98434B5=0x92848343
0x802AC548^0x92848343=0x12AE460B
0x01B9B9B9^0x12AE460B=0x1317FFB2
0x36363636+0x1317FFB2=0x494E35E8

0x38383838^0x9E3779B9=0xA60F4181
0xA60F4181+0x84A65177=0x2AB592F8
0x4A71AF40^0x2AB592F8=0x60C43DB8
0x01C1C1C1^0x60C43DB8=0x6105FC79
0x37373737+0x6105FC79=0x983D33B0

0xF205EFD6^0x9E3779B9=0x6C32966F
0x6C32966F+0x4B6A084B=0xB79C9EBA
0xC1E99D80^0xB79C9EBA=0x7675033A
0x07902F7E^0x7675033A=0x71E52C44
0x38383838+0x71E52C44=0xAA1D647C

0x00+0x01=0x01
0x01-0x20=0xE1
0x9E3779B9+0x9E3779B9=0x3C6EF372
0x9337AD4A^0x3C6EF372=0xAF595E38
0xAF595E38+0x547FA369=0x03D901A1
0x50EB23E0^0x03D901A1=0x53322241
0x0499BD6A^0x53322241=0x57AB9F2B
0xF205EFD6+0x57AB9F2B=0x49B18F01
0x33C1B2D8^0x3C6EF372=0x0FAF41AA
0x0FAF41AA+0x43AF51A7=0x535E9351
0x4D8C7808^0x535E9351=0x1ED2EB59
0x019E0D96^0x1ED2EB59=0x1F4CE6CF
0x9337AD4A+0x1F4CE6CF=0xB2849419
0x832EA83C^0x3C6EF372=0xBF405B4E
0xBF405B4E+0xEE8F66C7=0xADCFC215
0x9424A0C8^0xADCFC215=0x39EB62DD
0x04197541^0x39EB62DD=0x3DF2179C
0x33C1B2D8+0x3DF2179C=0x71B3CA74
0xD00558A9^0x3C6EF372=0xEC6BABDB
0xEC6BABDB+0x265BFED5=0x12C7AAB0
0x8D9E53A0^0x12C7AAB0=0x9F59F910
0x06802AC5^0x9F59F910=0x99D9D3D5
0x832EA83C+0x99D9D3D5=0x1D087C11
0x494E35E8^0x3C6EF372=0x7520C69A
0x7520C69A+0xDA138396=0x4F344A30
0xE843E088^0x4F344A30=0xA777AAB8
0x024A71AF^0xA777AAB8=0xA53DDB17
0xD00558A9+0xA53DDB17=0x754333C0
0x983D33B0^0x3C6EF372=0xA453C0C2
0xA453C0C2+0xE98434B5=0x8DD7F577
0xAA199E00^0x8DD7F577=0x27CE6B77
0x04C1E99D^0x27CE6B77=0x230F82EA
0x494E35E8+0x230F82EA=0x6C5DB8D2
0xAA1D647C^0x3C6EF372=0x9673970E
0x9673970E+0x84A65177=0x1B19E885
0x62EDC690^0x1B19E885=0x79F42E15
0x0550EB23^0x79F42E15=0x7CA4C536
0x983D33B0+0x7CA4C536=0x14E1F8E6
0x49B18F01^0x3C6EF372=0x75DF7C73
0x75DF7C73+0x4B6A084B=0xC14984BE
0xA70FC730^0xC14984BE=0x6646438E
0x024D8C78^0x6646438E=0x640BCFF6
0xAA1D647C+0x640BCFF6=0x0E293472
0x01+0x01=0x02
0x02-0x20=0xE2
...
0x04227595^0x98C575B7=0x9CE70022
0xA584B9D0+0x9CE70022=0x426BB9F2
0x1F+0x01=0x20
0x20-0x20=0x00
size=0X20 xor acb24e84e84dd76c1216b97b920e8f3916fcb09c888db9bc0cdfd922f2b96b42^3e55bc810971ba74988147bde63d564561c6e862da790bd0ced32fb1030216f5

中间的0xC1C1C1C0不知道怎么来的

1
2
3
4
5
6
7
8
9
print(hex(0x31313131 << 3))
print(hex(0x32323232 << 3))
print(hex(0x33333333 << 3))
print(hex(0x34343434 << 3))
print(hex(0x35353535 << 3))
print(hex(0x36363636 << 3))
print(hex(0x37373737 << 3))
print(hex(0x38383838 << 3))
print(hex(0x39393939 << 3))

跑了下,发现是0x38383838

得到代码

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
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define DELTA 0x9E3779B9
uint32_t keys[] = { 0x547FA369,
0x43AF51A7,
0xEE8F66C7,
0x265BFED5,
0xDA138396,
0xE98434B5,
0x84A65177,
0x4B6A084B };

unsigned char sec[32] = {
0x3E, 0x55, 0xBC, 0x81, 0x09, 0x71, 0xBA, 0x74, 0x98, 0x81, 0x47, 0xBD, 0xE6, 0x3D, 0x56, 0x45,
0x61, 0xC6, 0xE8, 0x62, 0xDA, 0x79, 0x0B, 0xD0, 0xCE, 0xD3, 0x2F, 0xB1, 0x03, 0x02, 0x16, 0xF5 };

int main()
{
uint32_t inp[8] = {};
uint32_t sum = 0;

memcpy(inp, sec, 32);
for (int i = 0; i < 8; i += 1)
{
printf("0x%08X\n", inp[i]);
}
uint32_t enc[8] = { 0x81BC553E,
0x74BA7109,
0xBD478198,
0x45563DE6,
0x62E8C661,
0xD00B79DA,
0xB12FD3CE,
0xF5160203 };
sum = DELTA * 32;
for (int i = 0; i < 32; i++)
{
for (int j = 7; j >= 0; j--)
{
uint32_t t1 = (inp[(j + 1) % 8] ^ sum) + keys[j];
uint32_t t2 = (inp[(j + 7) % 8] << 3) ^ t1;
uint32_t t3 = (inp[(j + 1) % 8] >> 5) ^ t2;
inp[j] -= t3;
}
sum -= DELTA;
}
printf("%s\n", (char*)inp);
// L3HSEC{f1751f5a3d69ab5ac2fe24e2}
return 0;
}

dictionary compression

运行闪退

分析得sub_1400058B0应该是主要程序逻辑所在

调试发现

image-20250828201336004

读取输入 :程序会寻找一个名为 flag.txt 的文件,并读取其中的内容。这是算法的输入数据。

程序首先会初始化三个包含特定数字序列的数组。这些数组构成了压缩算法的“字典”或查找表。

接着,程序进入一个主循环,逐个字符地读取来自 flag.txt 的内容。

循环的核心是一个巨大的 switch 语句。它会根据当前读入的字符,执行不同的处理分支。例如,如果读到字符 ‘a’,就执行一套逻辑;如果读到 ‘b’,就执行另一套逻辑,以此类推。

switch 语句中的每个分支都定义了如何将输入的字符转换为另一组数据。这个转换过程相当复杂,它会利用之前初始化的那三个“字典”数组进行查找和计算。

从代码中出现的 “output bits:” (输出比特) 这个字符串来看,程序很可能是将输入的字符转换成一串二进制的比特流(0和1)。

经过算法处理后,生成的最终数据(很可能是比特流)会被写入一个名为 output 的文件。我在分析中找到的 write_to_file_func 函数就是用来执行这个写入操作的。

创建了一个flag.txt随便输了abcabc

有数据了

image-20250828205404694

实在没看懂做了什么,大概是bit什么转换吧

31==11111 —– > 31>> 3 = 3 == 11

31 >> 2 == 7

11100011

0101011110011010100

[27, 227, 87, 154, 4]

这是output文件的内容

image-20250828213635906

..分析失败 没看懂

最终的答案要求是output是

image-20250828213415141

那我们的输入就是flag

我们的输入只会是abc中的一个

那其实我们这题是有爆破的空间,他会打印出最终的结果

无论输入多少最后肯定是5位

image-20250828221918574

那么我们可以直接爆破

输入一个a ,那么他就是a的四位+5位laststate

我们不关心laststate ,我们只关心当前位,因为比如答案是abc+5,那么我们输入了aba所产生的state肯定不一样,但是我们能确定前缀一样。

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
import subprocess

def a(flag):
open('./flag.txt', 'wb').write(flag.encode())
res = subprocess.check_output('./main.exe')
return res.decode().split('\n')[-3]

# ['before:31', 'output bits:11', 'after output:7', 'last state 16', 'last state 10000', '111010000', '[9, 232, 0]', '']

output = open('./output.txt', 'rb').read()

s = ''
for i in range(1, len(output)):
s += bin(output[i])[2:].zfill(8)

correct = s
print(correct)
def dfs(fullpath=''):
for ch in 'abc':
comp_bits = a(fullpath + ch)
if correct[:-5].startswith(comp_bits[:-5]):
print(comp_bits[:-5])
dfs(fullpath + ch)
if correct == comp_bits:
print(fullpath + ch)

dfs()
# bbccaacbcacbacbaaabcacbaaabcccaaaabbaaab
print('end')

hhhc

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
[L3HSEC-ROUTER-1]show current-configuration
#
version 7.1.064, Release 0821P16
#
sysname L3HSEC-ROUTER-1
#
wlan global-configuration
#
security-zone intra-zone default permit
#
dhcp enable
dhcp server always-broadcast
#
dns proxy enable
#
system-working-mode standard
password-recovery enable
#
vlan 1
#
dhcp server ip-pool lan1
gateway-list 192.168.0.1
network 192.168.0.0 mask 255.255.254.0
address range 192.168.1.2 192.168.1.254
dns-list 192.168.0.1
#
controller Cellular0/0
#
interface Dialer0
ppp chap password cipher $c$3$TKYJXT4RmMIvPHQX+5Ehf9oD3kjskIur3PGJfR/7fEyqfbx0K0DAokR0pd3rsRbWR5t9Cr3xSbYoPdogCg==
ppp chap user hustpppoe114514
ppp pap local-user hustpppoe114514 password cipher $c$3$3PbDU2m2/6Neiiz9iO+i641UKjafFMvrfphBc3fmrZ+9Q2TZu3g5l2Hlg1gJWO6ZQLJ4S+r85qU8EQpqQQ==
dialer bundle enable
dialer-group 2
dialer timer idle 0
dialer timer autodial 5
ip address ppp-negotiate
nat outbound
#
interface NULL0
#
interface GigabitEthernet0/0
port link-mode route
description LAN-interface
ip address 192.168.0.1 255.255.254.0
tcp mss 1280
#
interface GigabitEthernet0/1
port link-mode route
#
interface GigabitEthernet0/1.3647
vlan-type dot1q vid 3647
pppoe-client dial-bundle-number 0
#
interface GigabitEthernet0/2
port link-mode route
combo enable copper
#
interface GigabitEthernet0/3
port link-mode route
combo enable copper
#
interface GigabitEthernet0/4
port link-mode route
#
interface GigabitEthernet0/5
port link-mode route
#
scheduler logfile size 16
#
line class console
user-role network-admin
#
line class tty
user-role network-operator
#
line class vty
user-role network-operator
#
line con 0
user-role network-admin
#
line vty 0 63
authentication-mode scheme
user-role network-operator
#
performance-management
#
password-control enable
undo password-control aging enable
undo password-control history enable
password-control length 6
password-control login-attempt 3 exceed lock-time 10
password-control update-interval 0
password-control login idle-time 0
#
domain system
#
domain default enable system
#
role name level-0
description Predefined level-0 role
#
role name level-1
description Predefined level-1 role
#
role name level-2
description Predefined level-2 role
#
role name level-3
description Predefined level-3 role
#
role name level-4
description Predefined level-4 role
#
role name level-5
description Predefined level-5 role
#
role name level-6
description Predefined level-6 role
#
role name level-7
description Predefined level-7 role
#
role name level-8
description Predefined level-8 role
#
role name level-9
description Predefined level-9 role
#
role name level-10
description Predefined level-10 role
#
role name level-11
description Predefined level-11 role
#
role name level-12
description Predefined level-12 role
#
role name level-13
description Predefined level-13 role
#
role name level-14
description Predefined level-14 role
#
user-group system
#
local-user admin class manage
service-type telnet http
authorization-attribute user-role network-admin
#
ip http enable
web new-style
#
wlan ap-group default-group
vlan 1
#
return
[L3HSEC-ROUTER-1]

2024 L3HCTF writeup by Arr3stY0u

https://blog.wm-team.cn/index.php/archives/71/#re%E6%80%9D%E8%B7%AF%EF%BC%9A%E9%80%86%E5%90%91%E5%9B%BA%E4%BB%B6%E5%BE%97%E5%88%B0%E5%AF%86%E7%A0%81%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95

没看懂 留着

box

java层啥也没发现,直接看so

image-20250829163155369

发现有个getzip,直接看blob

PK标记的压缩包,提出来解压

0x538-0x1597C3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import idaapi
import idc

def dump_bytes_before_address(address, output_file='output.zip'):
# 获取程序的起始地址
start_addr = 0x538

# 打开输出文件
with open(output_file, 'wb') as f:
# 读取指定地址之前的字节并写入文件
for addr in range(start_addr, address):
byte = idaapi.get_byte(addr) # 使用get_byte方法读取字节
f.write(byte.to_bytes(1, byteorder='little')) # 将字节写入文件

print(f"Dumped bytes before address {hex(address)} to {output_file}")

# 示例:把地址0x1597C3之前的字节写入output.zip
address_to_dump = 0x1597C3
dump_bytes_before_address(address_to_dump)

解压后打开sokoban

这似乎是混淆视听的

image-20250829170356254

sokoban是推箱子的意思,应该是个小游戏

  • start (原 sub_216680 ): 程序的入口点。
  • loader_wrapper (原 sub_216BE8 ): 加载器包装函数。
  • main_loader (原 sub_216C1C ): 主要的加载器函数,负责解析和加载程序。
  • main (原 sub_2190D0 ): 程序的主逻辑入口。
  • load_level_and_run_vm (原 sub_219BB8 ): 加载关卡并运行虚拟机。
  • vm_interpreter (原 sub_216F80 ): 虚拟机解释器。
  • print_game_status (原 sub_21951C ): 打印游戏状态。
  • handle_input (原 sub_2193F0 ): 处理用户输入。

sub_270F50 函数的逻辑如下:

  1. 反调试检查 : 函数首先会读取 /proc/self/status 文件并检查 TracerPid 的值。如果 TracerPid 不为0,意味着程序正在被调试,程序会直接退出。这是一个常见的反调试手段。
  2. 输入处理和比较 : 函数调用了 sub_270A28 和 sub_270864 。 sub_270864 的返回值会与一个硬编码的字符串 “f877ef65780ac593e8f1bd8d8565ae07” 进行比较。这个字符串看起来像是一个哈希值(很可能是MD5)。
  3. 胜利条件 : 如果 sub_270864 的返回值与硬编码的哈希值相等,程序会打印 “You win! Here is your flag:\n”。
  4. Flag解密 : 接着,程序会执行一个循环,对一个名为 byte_48AF3C 的全局缓冲区进行异或(XOR)操作。 *(_DWORD *)&byte_48AF3C[i] ^= 0x48334Cu; 这段代码每3个字节进行一次异或解密。
  5. 打印Flag : 解密完成后,程序再次调用 sub_270864 (此时 byte_48AF3C 的内容已经被修改),并将其返回值作为flag,用 “L3HCTF%s\n” 的格式打印出来。
  6. 失败条件 : 如果第二步中的哈希值不匹配,程序会打印 “Try again.\n”。

270A28有个函数来处理输入,我重命名为了process_input_and_update_game_state

image-20250829203638850

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
map_data_str = "0xFF,0xFF,0xFF,0x0,0x19,0x24,0x82,0x0,0x28,0x40,0x8D,0x0,0x79,0xAA,0xB0,0x0,0x1,0x29,0xAA,0x0,0x7,0xA2,0xA2,0x0,0xF9,0x6,0xA6,0x0,0x11,0xBB,0xBA,0x0,0x51,0x42,0x88,0x0,0x9,0x2,0x8C,0x0,0x29,0xB9,0x89,0x0,0x29,0x42,0x84,0x0,0x35,0xA0,0x83,0x0,0x25,0x17,0x8D,0x0,0x29,0x80,0x94,0x0,0xC9,0x96,0x92,0x0,0x5,0x18,0xA0,0x0,0xA5,0x63,0xA4,0x0,0xA5,0xA0,0x97,0x0,0xBD,0x23,0xE2,0x0,0xA5,0x20,0x2,0x0,0xA5,0x3B,0xD2,0x0,0x41,0x4,0xA4,0x0,0xFF,0xFF,0xFF,0x0"

hex_values = [int(x, 16) for x in map_data_str.replace("0x", "").split(",")]

map_rows = []
for i in range(0, len(hex_values), 4):
# Assuming little-endian byte order
val = (hex_values[i+3] << 24) | (hex_values[i+2] << 16) | (hex_values[i+1] << 8) | hex_values[i]
map_rows.append(val)

for row_val in map_rows:
row_str = ""
# The map seems to be 24 bits wide, based on the first and last rows.
for i in range(24):
if (row_val >> i) & 1:
row_str += "#"
else:
row_str += "."
print(row_str)

image-20250829211614443

不知道箱子在哪,人在哪,完全没找到下面不太会了,后面再看看吧,wp在下面

2024 L3HCTF writeup by Arr3stY0u

image-20250829211705754