2026 吾爱破解春节解题(day1-day6+mcp中级题) Day1 - 送分题 关注论坛微信公众号:吾爱破解论坛,回复“52TDL”获得口令。
Day2 - Windows 初级题 一、题目概览
本题的核心在于:
先通过长度与内容完全匹配的方式校验输入
再做一次自定义 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; v3 = sub_401740((int )v22); v4 = 53 ; 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]; } 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 ) ) { 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 { sub_4C7E50(..., "\n========================================" ); sub_4C7E50(..., "[+] Correct flag: " ); sub_4C4330(..., v22, v23); } } } }
从这段逻辑可以得到几个关键信息:
sub_401740 用来过滤某些”假 flag”,如果返回非 0,就直接输出 “Nice try”
接着有一个循环,将输入前 16 字节与 byte_4D3032 里的一串字节逐个比较
真正的 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(0x64 u); sub_401620(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; }
可以看出:
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++ ^= 0x42 u; while ( result != (_BYTE *)(a1 + 31 ) ); *(_BYTE *)(a1 + 31 ) = 0 ; return result; }
关键点:
先往 a1 这块缓冲区写入一系列整数(小端存储)
然后从 a1 开始到 a1 + 31,逐字节执行 ^= 0x42(与 0x42 异或)
最后在偏移 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 52 pojie!!!_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 文件,查看程序行为:
从输出可以看出:
这是一个 Python 打包的 exe 程序
需要输入正确的密码(flag)
提示”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)
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)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 密钥:0 x4 e 结果:52 p0 j!3 #2026 *H4 ppy-N3 w-Y34 r@@@
这个结果看起来像是一个 leet speak编码的信息:
52p0j!3# → 52pojie(吾爱破解的拼音)
2026 → 年份
H4ppy-N3w-Y34r → Happy 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 pefileimport struct dll_path = r"D:\Desktop\吾爱破解\day5\cEVm8pds\crackme.exe_extracted\crackme_hard.dll" pe = pefile.PE(dll_path)print ("Extracting resource..." ) found = False if hasattr (pe, 'DIRECTORY_ENTRY_RESOURCE' ): for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries: if entry.id == 10 : 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!" )try : with open (dll_path, "rb" ) as f: f.seek(0x5BF00 ) table1 = f.read(1024 ) with open ("table1.bin" , "wb" ) as t1: t1.write(table1) print ("Extracted table1.bin" ) 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 4 c 0 a <- 列表长度 10 63 64 63 21 ... <- 字符串 "cdc!a;`b" (前缀 0x63 'c' 为类型标记)11 <- 整数 0x11 (17 )63 63 61 63 67 ... <- 字符串 "ccacg" (前缀 0x63 'c' 为类型标记)2 f <- 整数 0x2f (47 ) ...
通过对已知明文(如 “Happy”, “New”, “Year”)的猜测和异或爆破,我们确认加密算法为 XOR ,密钥为 0x51 (即字符 'Q')。这与变量名 lQa_key 相吻合。
解密规则:
字符串 :首字节 0x63 (‘c’) 是 Nuitka 的字符串类型标记,需跳过。后续字节与 0x51 进行异或。
整数 :字节值直接与 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 52 p0j13@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 zipfileimport 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 函数:
分析代码可知:
需要读取 assets/flag.dat 文件
游戏难度必须是 hard
解密算法是简单的异或(XOR)运算
解密密钥(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 {52 pojie_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
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