【2026春节】解题领红包初级题+Web - 菜的很稳定
by dongye
又到了一年春节活动做题环节,感觉今年菜的依旧,只做了初级题和Web,基本依靠AI,对代码敏感度有所下降
解题领红包之二 {Windows 初级题}
程序好像加了IDA的检测,直接调试会进一个系统模块找不到实际逻辑代码,花了点时间做分析
方法1 静态分析
ida打开后搜索现实的字符串 "CrackMe Challenge v2.5 - 2026",可以找到真实的函数入口,跟踪找到 if ( passwordCheck(Str, 31) ) 可知flag长度是31
进入可以看到
bool __cdecl passwordCheck(int a1, int a2)
{
unsigned __int8 *Block; // ebp
int v3; // eax
int v4; // ebx
bool v5; // dl
// 申请内存
Block = (unsigned __int8 *)sub_4AB710(0x64u);
// 令牌生成
generateBlock((int)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;
}
代码生成Block,然后与输入值一一比对,也就是说 generateBlock中就是正确flag
进入
_BYTE *__cdecl sub_3E1620(int a1)
{
_BYTE *result; // eax
*(_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;
result = (_BYTE *)a1;
do
*result++ ^= 0x42u;
while ( result != (_BYTE *)(a1 + 31) );
*(_BYTE *)(a1 + 31) = 0;
return result;
}
看不懂,丢给AI,给出python代码
import struct
def generate_block():
# 1. 整理原始的 DWORD 数据 (32位无符号整数)
# 这些是从汇编代码中提取出的 4字节 整数
dwords = [
758280311, # a1[0-3]
1663511336, # a1[4-7]
1880974179, # a1[8-11]
494170226, # a1[12-15]
842146570, # a1[16-19]
657202491, # a1[20-23]
658185525 # a1[24-27]
]
# 2. 将 DWORD 转换为字节数组 (使用小端序 'I' 代表 unsigned int)
content = bytearray()
for val in dwords:
content.extend(struct.pack('<I', val))
# 3. 处理剩余的 3 个字节
# a1[30] = 99 ('c')
# *((_WORD *)a1 + 14) = 12323 (0x3023) -> 对应 a1[28] 和 a1[29]
content.append(0x23) # a1[28]
content.append(0x30) # a1[29]
content.append(99) # a1[30]
# 4. 执行异或 (XOR 0x42)
decrypted = ""
for b in content:
decrypted += chr(b ^ 0x42)
return decrypted
if __name__ == "__main__":
flag = generate_block()
print(f"解密后的内容为: {flag}")
52pojie!!!_2026_Happy_new_year!
方法2 动态调试
使用OD打开程序,再程序开始搜索字符 "CrackMe Challenge v2.5 - 2026" 可以找到主线程的方法,把 004AD130 8D4C24 04 lea ecx,dword ptr ss:[esp+0x4] 设置为新EIP
再按F8就可以跳过检测,直接进入主程序,然后跟踪比较方法
003E16D4 83EC 1C sub esp,0x1C
003E16D7 8B7424 34 mov esi,dword ptr ss:[esp+0x34]
003E16DB 8B7C24 30 mov edi,dword ptr ss:[esp+0x30]
003E16DF C70424 64000000 mov dword ptr ss:[esp],0x64
003E16E6 E8 25A00C00 call 【2026春.004AB710
003E16EB 890424 mov dword ptr ss:[esp],eax
003E16EE 89C5 mov ebp,eax
003E16F0 E8 2BFFFFFF call 【2026春.003E1620
003E16F5 85F6 test esi,esi
003E16F7 7E 37 jle short 【2026春.003E1730
再F8跟踪就也可以在寄存器中看到正确的flag
eax=011718A7
ebp=01171888, (ASCII "52pojie!!!_2026_Happy_new_year!")
解题领红包之三 {Android 初级题}
额 不知道怎么回事啊 玩了两次就过了。。。。早些年自己写过这种游戏所以玩的比较快
第一次快完成时候又打乱了,本来想看看程序逻辑,打开是混淆过得,用算法助手打点日志看看,然后玩了一次就过了
用jadx打开代码发现混淆过,后续就没有分析的动力了
拼图
解题领红包之四 {Windows 初级题}
使用IDA打卡还是有反调试,查看代码发现很多python相关的内容,使用Detect查壳 发现是pyinstaller打包的python程序
使用 pyinstxtractor 解包,得到 主程序 crackme_easy.pyc
反编译python时遇到问题,pyc是用过python3.14编译的,uncompyle6和pycdc都不支持
使用 dis 方法输出指令
import marshal
import dis
with open("crackme_easy.pyc","rb") as f:
f.read(16) # skip header
code = marshal.load(f)
dis.dis(code)
得到指令文件,这一步已经属于是源码了,相当于绕过工具对版本的校验,从python中直接拿执行的指令
丢给AI还原成py代码
代码很简单,直接调用generate_flag即可得到 flag
整理后的代码
import base64
enc_data = 'e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O'
data = base64.b64decode(enc_data)
flag = "".join([chr(b ^ 78) for b in data])
print(flag)
FLAG: 52p0j!3#2026*H4ppy-N3w-Y34r@@@
解题领红包之五 {Windows 中级题}
查壳发现是 Nuitka 打包的Python程序,运行时会释放文件,复制出来或者直接解压exe可以得到文件,里面有个crackme_hard.dll 应该就是实际运行的逻辑
这个dll很大猜测是把真实的程序打包进来的,后面不会解码了,没做出
解题领红包之六 {番外篇 初级题}
Detect 查信息发现是lua程序,附加数据方式为zip,通过AI分析,可以将exe文件解压,解压后发现lua脚本,打开脚本看内容,可直接看到胜利消息方法
local function getWinMessage()
local content = nil
if love.filesystem.getInfo("assets/flag.dat") then
content = love.filesystem.read("assets/flag.dat")
end
if not content or currentDifficulty ~= "hard" then
return "You WIN!"
end
local key = "52pojie"
local keyLen = #key
local result = {}
local bit = require("bit")
for i = 1, #content do
local b = string.byte(content, i)
local k = string.byte(key, ((i - 1) % keyLen) + 1)
table.insert(result, string.char(bit.bxor(b, k)))
end
return table.concat(result)
end
如果是easy模式返回 You WIN!,hard模式返回flag
flag是通过 assets/flag.dat 简单异或解密得到的
这份没有lua和love的环境,丢给ai翻译成python
def decrypt_flag():
key = "52pojie"
key_len = len(key)
try:
# 读取原始加密数据
with open("flag.dat", "rb") as f:
content = f.read()
result = []
for i in range(len(content)):
# 获取当前位置对应的密钥字符
k = ord(key[i % key_len])
# 执行异或操作
b = content[i]
result.append(chr(b ^ k))
return "".join(result)
except FileNotFoundError:
return "错误:未找到 flag.dat 文件"
print("解密结果为:", decrypt_flag())
得到FLAG: flag{52pojie_2026_Happy_NewYear!>w<}
后面又研究了方法2
用010 Editor打开exe文件,十六进制搜索 50 4B 03 04 找到main.lua的资源位置 5E800
导出为zip文件
打开zip文件修改其中的lua代码把hard模式中的3个初始墙改为30,或者简单模式输出FLAG,或者直接输出FLAG,方法就很多了
-- Shuffle and place walls
local targetWallCount = (currentDifficulty == "easy") and 12 or 3
修改为
-- Shuffle and place walls
local targetWallCount = (currentDifficulty == "easy") and 12 or 30
用010 Editor打开修改后的zip,复制全部内容,在exe文件中粘贴替换 5E800后续的全部内容即可实现资源的替换
程序没有做任何的校验,直接替换即可
再次打开游戏,选择hard模式满地都是墙随便点几下就可以拿到FLAG
另外补充一下,今年这只猫的逃跑思路会提前躲避点击的位置,这样反而导致很容易堵,即便直接手动堵猫也很容易完成,相较24年的猫就难多了,几乎不可能手动完成
CatchCat
【2026春节】解题领红包之九
验证码生成过程是随机数和uid拼接变换得到验证码,然后经过0x2026轮sha256生成hash校验码
随机数是在js层生成的,为了方便调试把随机数固化,不影响最终的校验,可以不做
imports.wbg.__wbg_getRandomValues_1c61fac11405ffdc = function() {
ret = handleError(function (arg0, arg1) {
let arr = getArrayU8FromWasm0(arg0, arg1)
arr.fill(1);
// globalThis.crypto.getRandomValues(arr);
console.log("__wbg_getRandomValues_1c61fac11405ffdc arg0: ", arg0, "arg1: ", arg1, "arr: ", arr)
}, arguments)
return ret
};
由于在js层和wasm层都做了对验证码的sha256因此在sha256函数的入口下断点应该就能拿到验证码
wasm代码去掉底部的data部分,丢给AI分析可知 func9 是sha256方法,在方法入口下断
(func $func9 (param $var0 i32) (param $var1 i32) (param $var2 i32)
(local $var3 i32)
...
(local $var35 i32)
local.get $var0
// 下断
i32.load offset=28
local.set $var33
local.get $var0
i32.load offset=24
使用内存查看器,查看参数对应内存地址内容
var1 变量地址,我这里是第二次看到的明文flag
对应的代码在 0x000911e call func9
这时候调试栈回到js,调用取值方法得到flag
1048216是var1参数值,50是验证码长度
getStringFromWasm0(1048216, 50)
得到flag: flag{fJj7rKZdAeB28zXWWDRLgZgDTBhvWDfcM8QBy5Q3uZfq2TuA9q}
完结