本帖最后由 whklhh 于 2017-9-28 00:10 编辑
这种题目用IDA会比较好啦~
走迷宫是比较常见的CTF套路了呢
首先按照字符串找到核心函数sub4015F3
不过在这之前,试输入会出现违xxx(不同的啊~,不太对劲啊~)的句子,这是在sub_4017B8处判断的
该函数检测开头五个字符和最后一个字符是否为xman{、},估计是比赛的名字吧
然后核心函数的代码是
[C++] 纯文本查看 复制代码 int __cdecl sub_4015F3(char *a1)
{
signed int v1; // eax@2
size_t v2; // ebx@17
int result; // eax@19
char v4; // [sp+4h] [bp-64h]@0
int v5; // [sp+1Ah] [bp-4Eh]@1
int v6; // [sp+1Eh] [bp-4Ah]@1
char v7; // [sp+22h] [bp-46h]@1
int v8; // [sp+23h] [bp-45h]@1
int v9; // [sp+27h] [bp-41h]@1
char v10; // [sp+2Bh] [bp-3Dh]@1
int v11; // [sp+2Ch] [bp-3Ch]@1
int v12; // [sp+30h] [bp-38h]@1
char v13; // [sp+34h] [bp-34h]@1
int input; // [sp+35h] [bp-33h]@1
int v15; // [sp+39h] [bp-2Fh]@1
char v16; // [sp+3Dh] [bp-2Bh]@1
int v17; // [sp+3Eh] [bp-2Ah]@1
int v18; // [sp+42h] [bp-26h]@1
char v19; // [sp+46h] [bp-22h]@1
int v20; // [sp+47h] [bp-21h]@1
int v21; // [sp+4Bh] [bp-1Dh]@1
char v22; // [sp+4Fh] [bp-19h]@1
int v23; // [sp+50h] [bp-18h]@1
int v24; // [sp+54h] [bp-14h]@1
size_t i; // [sp+58h] [bp-10h]@1
char flag; // [sp+5Fh] [bp-9h]@1
v5 = 0x5202020;
v6 = 0x20202020;
v7 = 0;
v8 = 0x5200520;
v9 = 0x20050520;
v10 = 0;
v11 = 0x20050520;
v12 = 0x20200520;
v13 = 0;
input = 0x20200520;
v15 = 0x20052020;
v16 = 0;
v17 = 0x5200520;
v18 = 0x5050520;
v19 = 0;
v20 = 0x5202020;
v21 = 0x20202020;
v22 = 0;
v24 = 0;
v23 = 0;
flag = 1;
for ( i = 0; ; ++i )
{
v2 = i;
if ( v2 >= strlen(a1) )
break;
v1 = a1;
if ( v1 == 50 ) // 2
{
flag = sub_40157C((int)&v24, &v23); // v23+1,v23<=7
goto LABEL_14;
}
if ( v1 > 50 )
{
if ( v1 == 51 ) // 3
{
flag = sub_4015A4(&v24); // v24-1, v24>=0
goto LABEL_14;
}
if ( v1 == 52 ) // 4
{
flag = sub_4015CB(&v24); // v24+1,v24<=7
goto LABEL_14;
}
}
else if ( v1 == 49 ) // 1
{
flag = sub_401555((int)&v24, &v23); // v23-1, v23>=0
goto LABEL_14;
}
flag = 0;
LABEL_14:
if ( (unsigned __int8)sub_401529((int)&v5, v24, v23) ^ 1 )// (a1+9*a2+a3)==32
// v24=y
// v25=x
{
flag = 0;
break;
}
}
if ( flag == 1 )
{
if ( v24 != 5 || v23 != 7 ) // 谁来救救我
{
result = sub_401500(&unk_489033, v4);
}
else if ( strlen(a1) <= 0x10 )
{
result = sub_401500("本当に 本当に よかった\n", v4);// 太好啦
}
else
{
result = sub_401500(&"ああ..疲れた....\n", v4);// 累死啦
}
}
else
{
result = sub_401500("痛いQAQ\n", v4); // 好痛!
}
return result;
}
开头处用十六进制可以看出来05和20两种字节,用python跑一下就能生成地图:
[Python] 纯文本查看 复制代码 a = '052020202020202005200520200505202005052020200520202005202005202005200520050505200520202020202020'
s = ''
w = ''
for i in range(len(a)):
# print(s)
if(i%2):
s += a
if(s=='20'):
w += '0'
else:
w += '1'
s = ''
else:
if(i%8==0):
print(w[::-1], end='')
w=''
s += a
if(i%16==0):
print()
print(w[::-1])
生成的地图样子是:
00010000
01010110
01100100
01000010
01010111
00010000
刚开始我直接搞上去还没反应过来╮(╯_╰)╭其实0x05202020有个大小端序的问题,所以需要倒过来来着
flag是标识,v24是y值,v23是x值
1234分别代表上下左右的移动
05代表刺儿君,20代表可走的路
如果撞到刺儿君就会把flag赋0,提示“好痛~”
如果指令走完了还没到达终点(右下角,即(5,7)),会提示“谁来救救我呀~”
如果走到终点但是消耗步数超过16步,提示“哎呀太累啦……”
如果在16步以内走到终点才会提示"真的真的太好啦"
(16步应该是最短不回头的步数,来保证flag唯一)
以前做过不少类似的题目啦,不过像这位作者一样辣么可爱的提示还没见过呢~很有趣~~
大体的情况就是这样,IDA导出的代码慢慢分析一下就行啦~
有不懂的欢迎继续交流=-=我也是CTF Re方向的菜鸡~ |