2026 吾爱破解春节解题(day1-day6+mcp中级题)

2026 吾爱破解春节解题(day1-day6+mcp中级题)

Day1 - 送分题

关注论坛微信公众号:吾爱破解论坛,回复“52TDL”获得口令。

Day2 - Windows 初级题

一、题目概览

  • 平台: Windows 控制台程序

  • 难度: 初级

  • 交互: 提示输入 password,正确则给出 flag

本题的核心在于:

  • 先通过长度与内容完全匹配的方式校验输入
  • 再做一次自定义 checksum 校验
  • 所有校验全部通过后,原样输出 “Correct flag: <你的输入>”

二、入口与主逻辑定位

在 Strings 窗口中搜索关键词:

"Correct flag" → 字符串地址 0x4D3201

对该字符串做交叉引用(xrefs),可以定位到函数 sub_4CD130

反编译 sub_4CD130 可以看到核心逻辑:

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
int __cdecl sub_4CD130(char a1)
{
...
sub_4C7E50(..., "Hint: Fake flag; length is key");
...
sub_4C7E50(..., "\n[?] Enter the password: ");
v2 = sub_401560(); // 读取用户输入
sub_4C5840(&dword_4D25E0, &v22, v2);
Str = v22; // Str 指向输入字符串

v3 = sub_401740((int)v22); // 一次简单过滤 / 假 flag 检测
v4 = 53; // '5'
v5 = v3;
v6 = 0;
if ( !v5 )
{
while ( Str[v6] == v4 )
{
if ( ++v6 == 16 )
{
sub_4C7E50(..., "\n[!] You're getting closer...");
goto LABEL_9;
}
v4 = byte_4D3032[v6]; // 与某个 16 字节序列逐字比对
}
if ( strlen(Str) != 31 )
{
sub_4C7E50(..., "\n[!] Hint: The length is your first real challenge.");
goto LABEL_9;
}

if ( (unsigned __int8)sub_4016D0(Str, 31) ) // 关键内容校验
{
// 通过 sub_4016D0 后,继续做 checksum 校验
Str = 0;
v8 = *v22;
if ( !*v22 )
goto LABEL_16;
v9 = 0;
do
{
Str += ++v9 * v8;
v8 = v22[v9];
}
while ( v8 );
if ( Str != (char *)44709 )
{
sub_4C7E50(..., "\n[!] Checksum failed! Something is wrong...");
}
else
{
// 所有检查通过,输出成功信息与 flag
sub_4C7E50(..., "\n========================================");
sub_4C7E50(..., "[+] Correct flag: ");
sub_4C4330(..., v22, v23); // 打印我们的输入
}
}
}
}

从这段逻辑可以得到几个关键信息:

  1. sub_401740 用来过滤某些”假 flag”,如果返回非 0,就直接输出 “Nice try”
  2. 接着有一个循环,将输入前 16 字节与 byte_4D3032 里的一串字节逐个比较
  3. 真正的 flag 需要:
    • 长度为 31 字节(strlen(Str) == 31
    • 通过 sub_4016D0(Str, 31) 的逐字节校验
    • 再通过 checksum 条件:$\sum_{i=0}^{n-1} (i+1) \times \text{ord}(s[i]) = 44709$

三、内容校验函数 sub_4016D0

反编译 sub_4016D0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool __cdecl sub_4016D0(int a1, int a2)
{
unsigned __int8 *Block;
Block = (unsigned __int8 *)sub_4CB710(0x64u);
sub_401620(Block); // 关键:在 Block 中生成目标序列
if ( a2 <= 0 )
{
v4 = 0;
}
else
{
v3 = 0;
v4 = 0;
do
{
v5 = *(char *)(a1 + v3) == Block[v3];
++v3;
v4 += v5;
}
while ( a2 != v3 );
}
j_j_free(Block);
return a2 == v4; // 只有全部字符都相等才返回 true
}

可以看出:

  • sub_4016D0 内部先调用 sub_401620 在一块缓冲区中生成真正的”答案串”
  • 然后将我们的输入与 Buffer 的前 a2 个字节逐一比较
  • 每相同一个字符就 v4++,最后要求 v4 == a2

因此,要找到正确口令,就必须还原 sub_401620 生成的那 31 个字节。

四、还原 sub_401620 生成的密文

反编译 sub_401620

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_OWORD *__cdecl sub_401620(int a1)
{
*(_DWORD *)a1 = 758280311;
*(_DWORD *)(a1 + 4) = 1663511336;
*(_DWORD *)(a1 + 8) = 1880974179;
*(_DWORD *)(a1 + 12) = 494170226;
*(_DWORD *)(a1 + 16) = 842146570;
*(_DWORD *)(a1 + 20) = 657202491;
*(_DWORD *)(a1 + 24) = 658185525;
*(_BYTE *)(a1 + 30) = 99;
*(_WORD *)(a1 + 28) = 12323;
do
*result++ ^= 0x42u;
while ( result != (_BYTE *)(a1 + 31) );
*(_BYTE *)(a1 + 31) = 0;
return result;
}

关键点:

  1. 先往 a1 这块缓冲区写入一系列整数(小端存储)
  2. 然后从 a1 开始到 a1 + 31,逐字节执行 ^= 0x42(与 0x42 异或)
  3. 最后在偏移 31 写入 0 作为字符串结束符

用 Python 脚本还原:

1
2
3
4
5
6
7
8
9
10
11
12
13
nums = [758280311, 1663511336, 1880974179,
494170226, 842146570, 657202491, 658185525]

buf = bytearray()
for n in nums:
buf += n.to_bytes(4, "little", signed=True)

buf += (12323).to_bytes(2, "little", signed=True)
buf.append(99)

buf = buf[:31]
flag = "".join(chr(b ^ 0x42) for b in buf)
print(flag)

五、最终答案

1
52pojie!!!_2026_Happy_new_year!

验证:长度为 31 字节,checksum 计算结果为 44709,符合所有校验条件。


Day3 - Android 初级题

题目描述

玩玩游戏就过关了,新年快乐,别感冒!


Day4 - Windows 初级题

一、题目信息

  • 题目名称: 【2026 春节】解题领红包之四 {Windows 初级题}
  • 出题老师: 云在天
  • 题目类型: Windows 逆向 / Python 反编译
  • 难度: 初级

二、工具准备

  • pyinstxtractor: PyInstaller 打包文件提取工具
  • Python 3.x: 运行环境
  • 基础工具: hexdump/xxd, base64, hashlib 等

三、解题过程

3.1 分析题目

首先运行 exe 文件,查看程序行为:

从输出可以看出:

  1. 这是一个 Python 打包的 exe 程序
  2. 需要输入正确的密码(flag)
  3. 提示”Decompile me if you can!”说明需要反编译

3.2 提取 PyInstaller 打包内容

使用 pyinstxtractor 工具提取 exe 文件:

1
python pyinstxtractor.py "【2026 春节】解题领红包之四 {Windows 初级题} 出题老师:云在天.exe"

输出结果:

提取后得到 crackme_easy.pyc 文件,这是主程序的 Python字节码文件。

3.3 分析 pyc 文件

由于 pyc 文件是用 Python 3.14 编译的,而当前系统只有 Python 3.13,直接反编译会失败。因此我们采用手动分析的方式。

通过分析 pyc 文件的二进制内容,找到以下关键字符串:

函数名:

  • xor_decrypt - XOR 解密函数
  • get_encrypted_flag - 获取加密 flag
  • generate_flag - 生成 flag
  • calculate_checksum - 计算校验和
  • hash_string - 哈希字符串
  • verify_flag - 验证 flag
  • fake_check_1 - 假检查函数 1
  • fake_check_2 - 假检查函数 2
  • main - 主函数

关键数据:

  • 加密数据(Base64):e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O

3.4 分析加密数据

将 Base64 编码的加密数据解码:

1
2
3
4
5
import base64

encrypted_b64 = "e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O"
encrypted = base64.b64decode(encrypted_b64)
# 解码后的十六进制:7b7c3e7e246f7d6d7c7e7c7864067a3e3e3763007d3963177d7a3c0e0e0e

3.5 破解 XOR 密钥

由于不知道 XOR 密钥,采用暴力破解的方式:

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

encrypted_b64 = "e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O"
encrypted = base64.b64decode(encrypted_b64)

def xor_decrypt(data, key):
result = bytearray()
for i, byte in enumerate(data):
result.append(byte ^ key[i % len(key)])
return bytes(result)

# 尝试单字节密钥 (0x00 - 0xff)
for i in range(256):
key = bytes([i])
result = xor_decrypt(encrypted, key)
try:
decoded = result.decode('utf-8', errors='ignore')
if decoded.isprintable() and len(decoded.strip()) > 5:
print(f"密钥:0x{i:02x}")
print(f"结果:{decoded}")
except:
pass

当尝试到密钥 0x4e (ASCII 字符’N’) 时,得到有意义的结果:

1
2
密钥:0x4e
结果:52p0j!3#2026*H4ppy-N3w-Y34r@@@

这个结果看起来像是一个 leet speak编码的信息:

  • 52p0j!3#52pojie(吾爱破解的拼音)
  • 2026 → 年份
  • H4ppy-N3w-Y34rHappy New Year

四、最终答案

1
52p0j!3#2026*H4ppy-N3w-Y34r@@@

Day5 - Windows 中级题

一、题目信息

  • 标题: CrackMe Challenge - Binary Edition

  • 关键词: 52pojie, 2026, Happy New Year

  • 提示: 1337 5p34k & 5ymb0l5! Try to decompile this in IDA!

二、初始分析

程序运行时输出提示信息,要求输入密码。通过观察文件结构或运行时的字符串,可以发现该程序是使用 Nuitka 打包的 Python 程序。核心逻辑通常位于主 DLL 文件中,在本例中为 crackme_hard.dll

导出后查看文件夹中的内容

三、逆向分析过程

3.1 静态分析与资源定位

使用 IDA Pro 打开 crackme_hard.dll。由于 Nuitka 会将 Python字节码或源码编译为 C 代码,并进行混淆,直接查看反汇编代码较为困难。

通过搜索字符串或导入表,发现程序使用了 Windows 资源 API(FindResourceA, LoadResource 等)。这通常意味着 Python 的 payload 数据被加密存储在 PE 资源节中。

通过资源查看工具,我们在 DLL 中定位到了资源类型为 10,ID 为 3 的资源。将其提取出来,命名为 payload.bin

3.2 Payload 结构分析

payload.bin 包含了 Nuitka 运行所需的模块数据。通过分析文件结构,我们识别出了 __main__ 模块的数据记录。将其单独提取为 main_record.bin

所用脚本如下:

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
import pefile
import struct

dll_path = r"D:\Desktop\吾爱破解\day5\cEVm8pds\crackme.exe_extracted\crackme_hard.dll"
pe = pefile.PE(dll_path)

# Extract Resource
print("Extracting resource...")
found = False
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if entry.id == 10: # RT_RCDATA
for sub_entry in entry.directory.entries:
if sub_entry.id == 3:
data_rva = sub_entry.directory.entries[0].data.struct.OffsetToData
size = sub_entry.directory.entries[0].data.struct.Size
data = pe.get_data(data_rva, size)
with open("payload.bin", "wb") as f:
f.write(data)
print(f"Extracted payload.bin (Size: {size})")
found = True
break
if not found:
print("Resource 10/3 not found!")

# Extract Tables
# ImageBase 0x3133e0000
# .rdata VA 0x58000, RawPtr 0x55e00
# Table1 (3E100): RVA 0x5E100 -> Offset 0x5BF00. Size: 256 * 4 = 1024 bytes.
# Table2 (3D100): RVA 0x5D100 -> Offset 0x5AF00. Size: 1024 * 4 = 4096 bytes.

try:
with open(dll_path, "rb") as f:
# Table 1
f.seek(0x5BF00)
table1 = f.read(1024)
with open("table1.bin", "wb") as t1:
t1.write(table1)
print("Extracted table1.bin")

# Table 2
f.seek(0x5AF00)
table2 = f.read(4096)
with open("table2.bin", "wb") as t2:
t2.write(table2)
print("Extracted table2.bin")
except Exception as e:
print(f"Error extracting tables: {e}")

main_record.bin 中,我们通过字符串搜索发现了与题目相关的关键变量名:

  • a_parts: 看起来像是一个包含口令分片的列表
  • lQa_key: 变量名中的 Qa 暗示了某种关联,且 Q 可能是密钥
  • a_total_len: 值为 30,提示了最终口令的长度

3.3 数据结构与解密

查看 a_parts 附近的数据,发现它是一个混合列表,包含字符串和整数。数据的大致结构如下(十六进制):

1
2
3
4
5
6
4c 0a                <- 列表长度 10
63 64 63 21 ... <- 字符串 "cdc!a;`b" (前缀 0x63 'c' 为类型标记)
11 <- 整数 0x11 (17)
63 63 61 63 67 ... <- 字符串 "ccacg" (前缀 0x63 'c' 为类型标记)
2f <- 整数 0x2f (47)
...

通过对已知明文(如 “Happy”, “New”, “Year”)的猜测和异或爆破,我们确认加密算法为 XOR,密钥为 0x51(即字符 'Q')。这与变量名 lQa_key 相吻合。

解密规则:

  1. 字符串:首字节 0x63 (‘c’) 是 Nuitka 的字符串类型标记,需跳过。后续字节与 0x51 进行异或。
  2. 整数:字节值直接与 0x51 进行异或。

3.4 口令还原

利用解密脚本,我们还原了口令的各个部分:

分片 类型 密文 (Hex) 去掉 Tag XOR 0x51 结果
1 String 63 64 63 21 61 3b 60 62 64 63 21 61 3b 60 62 52p0j13
2 Int 11 - @
3 String 63 63 61 63 67 63 61 63 67 2026
4 Int 2f - ~
5 String 63 19 65 21 21 28 19 65 21 21 28 H4ppy
6 Int 0e - _
7 String 63 1f 62 26 1f 62 26 N3w
8 Int 0e - _
9 String 63 08 62 65 23 08 62 65 23 Y34r
10 String 63 70 70 70 70 70 70 !!!

将所有部分拼接,得到完整口令。

四、最终答案

1
52p0j13@2026~H4ppy_N3w_Y34r!!!

验证:口令长度为 30 字符,符合 a_total_len 的限制。输入程序后显示 “SUCCESS!”。


Day6 - 番外篇 初级题

一、题目分析

拿到 CatchTheCat.exe 后,首先观察程序图标和运行界面,或者通过 IDA Pro 查看字符串,可以判断这是一个使用 Love2D 游戏引擎开发的游戏。

Love2D 的发布通常是将 love.exe 和游戏资源包(.love 文件,本质是 Zip 格式)合并成一个可执行文件。因此,我们可以尝试从 exe 文件中提取出 Lua 脚本和资源。

所用脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import zipfile
import os

filename = "CatchTheCat.exe"
extract_dir = "extracted"

if not os.path.exists(extract_dir):
os.makedirs(extract_dir)

try:
with zipfile.ZipFile(filename, 'r') as z:
print(f"Extracting {filename} to {extract_dir}...", flush=True)
z.extractall(extract_dir)
print("Extraction complete!", flush=True)

print("Files found:", flush=True)
for root, dirs, files in os.walk(extract_dir):
for file in files:
print(os.path.join(root, file), flush=True)
except Exception as e:
print(f"Error extracting zip: {e}", flush=True)

二、提取资源

编写脚本或使用工具检查文件末尾,发现了 Zip 文件的结束签名(End of Central Directory signature PK\x05\x06)。

直接将 CatchTheCat.exe 当作 Zip 文件解压,或者提取其尾部的 Zip 数据,得到了以下核心文件:

  • main.lua: 游戏主逻辑
  • conf.lua: 配置文件
  • assets/flag.dat: 加密的 Flag 文件

三、逻辑分析

打开 main.lua,搜索 “flag” 或 “win” 相关的逻辑,找到了 getWinMessage 函数:

分析代码可知:

  1. 需要读取 assets/flag.dat 文件
  2. 游戏难度必须是 hard
  3. 解密算法是简单的异或(XOR)运算
  4. 解密密钥(Key)是字符串 "52pojie"

四、解密 Flag

根据上述逻辑,编写 Python 脚本进行解密:

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

key = b"52pojie"
file_path = "extracted/assets/flag.dat"

with open(file_path, "rb") as f:
content = f.read()

result = bytearray()
key_len = len(key)
for i in range(len(content)):
b = content[i]
k = key[i % key_len]
result.append(b ^ k)

print("Decrypted Flag:", result.decode('utf-8'))

五、最终 Flag

运行解密脚本,得到 Flag:

1
flag{52pojie_2026_Happy_New_Year!_>w<}

Day11 - MCP 中级题

一、题目概述

这是一道基于 MCP(Model Context Protocol)的安全挑战题目,需要通过调用 remote52pojie MCP 服务完成多阶段认证流程,最终获取隐藏在密卷中的口令。

二、解题流程

2.1 启动会话

首先启动一个 MCP 会话,建立与系统的连接:

1
2
3
4
{
"user_id": "ctf_player",
"role": "auditor"
}

返回结果:

1
2
3
4
5
{
"session_id": "sess_c60d3d71-3afa-4895-b3e4-3314807227b7",
"user_level": 1,
"role": "employee"
}

2.2 收集公开线索

通过列出并读取公开文档,获取关键信息:

文档 关键信息
云台岁终告谕 偈语首字:玄霄
门规行仪录 偈语末字:密令
议会卷宗路引 终卷路径:secret:/board/resolutions
玄堂复核提示 复核流程说明

合成口令: 玄霄密令

2.3 触发拒绝获取审计编号

尝试访问受限文档 confidential:/audit/logs,触发访问拒绝:

1
2
3
4
{
"error": "access_denied",
"audit_log_id": "audit_1772434108392_421"
}

2.4 计算 seal 校验值

根据复核提示,seal 的计算公式为:

1
seal = sha256(audit_log_id + passphrase) 的前 8 位小写十六进制

计算过程:

1
2
echo -n "audit_1772434108392_421 玄霄密令" | sha256sum | cut -c1-8
# 输出:a8a4fb08

2.5 提交复核

使用 review_document 接口提交复核信息:

1
2
3
4
5
{
"ctf_request": "玄霄密令",
"audit_log_id": "audit_1772434108392_421",
"seal": "a8a4fb08"
}

复核结果:

1
2
3
4
5
{
"status": "challenge_issued",
"tool_access_token": "tool_access:get_audit_log:1772434129837:da1a373439848285",
"compliance_note": "chain_config 仅提交 get_audit_log"
}

2.6 配置并执行工具链

按照戒律要求,工具链只能包含 get_audit_log

1
2
3
{
"tool_chain": ["get_audit_log"]
}

使用获得的 access_token 获取审计日志:

1
2
3
{
"_audit_token": "audit_access:audit_1772434108392_421:1772434108392:d17843d57a864576"
}

2.7 访问终卷获取 flag

使用 audit_token 访问终卷 secret:/board/resolutions

1
2
3
4
5
{
"id": "secret:/board/resolutions",
"title": "至高议会密议",
"content": "flag{new_year_2026_keep_warm}"
}

三、最终答案

1
flag{new_year_2026_keep_warm}

四、关键知识点

4.1 复核字段说明

字段 说明
ctf_request 口令本身(非 access_token)
audit_log_id 触发拒绝后返回的完整审计编号
seal SHA256 校验值(audit_log_id + passphrase)前 8 位

4.2 重要注意事项

  • audit_log_id 必须使用完整的拒绝编号,不可截断
  • 只认可同一会话中最近一次拒绝的编号
  • 复核凭据有时效性和一次性特性
  • 工具链配置需保持单一职责原则

4.3 流程图

1
2
3
4
5
启动会话 → 收集线索 → 触发拒绝 → 计算 seal → 提交复核

获取审计日志 ← 配置工具链 ← 复核通过 ←─────────┘

访问终卷 → 获取 FLAG

2026 吾爱破解春节解题(day1-day6+mcp中级题)
https://erkangkang.github.io/2026/03/04/2026吾爱破解春节解题领红包/
作者
尔康康康康
发布于
2026年3月4日
许可协议