运行程序后需要输入一串字符。若满足内部状态条件,则输出:
success! the flag is flag{md5(your input)}
所以目标不是找硬编码 flag,而是找到使程序进入胜利状态的输入指令序列。
1. 程序入口分析
int main(){
v3 = 0;
char input[0x200];
memset(input,0,0x200);
scanf("%s",input); // 输入字符串 = 操作指令序列(非密码)
while(true){
v2 = 0;
sub_86C(); // 刷新棋盘 / 显示 / 状态更新
char c = input[v3]; // 逐字符读取输入并执行动作
if(c=='d') v2=sub_E23(); // 100
else if(c=='s') v2=sub_C5A(); // 115
else if(c=='w') v2=sub_A92(); // 119
else if(c=='a') v2=sub_FEC(); // 97
else if(c==27) return -1; // ESC 直接退出
v3++;
// 核心胜利判断
if(v2==1){ // 某一步操作满足过关条件
if(dword_202AB0==2) // 已经达到目标层数
break;
dword_202AB0++; // 进入下一层
}
}
puts("success! the flag is flag{md5(your input)}");
}程序模拟关卡地图,玩家通过 w s a d 移动,当到达某个条件点后,sub_xxx() 返回 1,表示当前关卡通关,累计到第 3 个关卡时,即触发最终输出 flag。
2. 地图数据结构解析
.data:0000000000202020 dword_202020 起为多组连续 225 = 15×15 数据
即 每关一张 15×15 地图
Python 处理脚本:
# 映射含义:
# 0 = 墙 █ 1 = 路 ·
# 3 = 目标 * 4 = 起点 S
levels = [data[i*225:(i+1)*225] for i in range(len(data)//225)]
def show(level):
m = np.array(level).reshape(15,15)
for row in m:
print(''.join([
'█' if x==0 else
'·' if x==1 else
'S' if x==4 else
'*' if x==3 else '?'
for x in row]))运行展示地图后即可人工推路线或写 BFS/DFS 解路径。
我们真实跑出来的关卡视图如下:
??·····██·····█
*··██████?·····
███·██████·····
███?S·██████···
··███·····██?··
···███████·██··
···███████??·██
·····███████··█
·····?████████·
█·····████████S
█S·?██··█*·····
██████··?█··███
·██████··██████
?·██████··█··██
█·····??██··█··
3. sub_E23 / sub_A92 / sub_C5A / sub_FEC 行为
四个函数分别处理 d=右 / w=上 / s=下 / a=左,以 sub_E23() 例:
sub_E23(){
if(dword_202AB8 != 14){
if(dword_202020[...] == 1){
→ 移动成功 & 推方块
}
else if(dword_202020[...] == 4){
return 1; // ⭐ 触发过关信号
}
}
return 0;
}只要某行动到达标记 4(下一关入口/终点),即可返回 1。
而主循环中:
if(v2==1 && dword_202AB0==2) → 完全通关
即需成功抵达终点 三次(关卡 index = 0 → 1 → 2)。
最后输入的应该是
ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss
利用md5码加密得到结果
