巅峰极客reverse baby_maze

这题通过ida64打开后发现是很多个函数写的地图,人看傻了`(>﹏<)′

后来一想 直接找到终点的函数,然后利用交叉引用溯回到起点就行了(”好像”还挺简单的😃)

通过字符串.

Good Job. \nAnd the flag is flag md5(your input)\nIf not, you may need to go faster!

找到终点sub_54DE35

通过Welcome to TastelessMaze! 找到主函数再找到起点sub_40187C()

我原本一个一个慢慢往上溯回,结果卡死了

出现了这种情况

image-20210802102522230

我需要看是谁走到了sub_53E6B7 一看D先走了sub_53CE65()这个函数,再来走sub_53E6B7

sub_53CE65()里面又是switch 人麻了🤡

我莫得办法

事后看师傅们的wp,QAQ,直接正面暴力莽,利用idapython中的gen_r_call_chain函数

学习网址:

https://blog.51cto.com/watertoeast/2287039

https://zhuanlan.zhihu.com/p/395205287

但是基于本题的话,一直递推到终点就可以回溯了,所以要再gen_r_call_chain中添加一个终点的参数

还要查询函数get_my_callee,来得到xref的引用函数列表

也就是

ida快捷键 Shift+F2

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
60
61
62
63
64
65
66
67
68
69
70
71
from __future__ import print_function
import idautils
visited_func = set()
steps = []
r_call_chain = []
idx2chr = {4: 'W',5: 'D',6: 'S',7: 'A'}

def gen_r_call_chain(func_name, osintneting,destination):
del r_call_chain[:]
del steps[:]
visited_func = set()
get_my_caller(func_name, osintneting,destination)

def get_my_caller(func_name, osintneting,destination):

cstr = '{0}\t'.format(func_name)
if cstr not in visited_func:
r_call_chain.append(cstr)
visited_func.add(cstr)
else:
return
addr = get_name_ea(0, func_name)
addr_ref_to = get_first_fcref_to(addr)

osinteneting_end = False
if addr_ref_to == BADADDR:
osinteneting_end = True
elif osintneting == -1:
osinteneting_end = False
elif osintneting == 1:
osinteneting_end = True

if (destination == func_name or osintneting == 1):
length = len(steps)
for idx in range(length):
sys.stdout.write(steps[length - idx - 1])
sys.stdout.write(' ' + func_name)
sys.stdout.write("\n")
r_call_chain.pop()
return

if osinteneting_end is True:
return

while (addr_ref_to != BADADDR) and (addr_ref_to != addr):
parent_func_name = get_func_name(addr_ref_to)
callee_list = get_my_callee(parent_func_name)
ids = callee_list.index(func_name)
#print (callee_list,func_name,cur_id,end = ",")
steps.append(idx2chr[ids])
get_my_caller(parent_func_name, osintneting - 1,destination)
steps.pop()
addr_ref_to = get_next_fcref_to(addr, addr_ref_to)
if addr_ref_to == BADADDR:
r_call_chain.pop()
break

def get_my_callee(func_name):
addr = get_name_ea(0, func_name)
dism_addr = list(idautils.FuncItems(addr))
xref_froms = []
for ea in dism_addr:
if ida_idp.is_call_insn(ea) is False:
continue
else:
callee = get_first_fcref_from(ea)
if callee != addr:
xref_froms.append(callee)
names = [get_func_name(callee) for callee in xref_froms]
return names
gen_r_call_chain('sub_54DE35', 600, 'sub_40187C')

idx2chr = {4: 'W',5: 'D',6: 'S',7: 'A'} 的原因是从汇编来看

callee_list , func_name , cur_id

[‘sub_55D500’, ‘sub_597460’, ‘sub_55F1F0’, ‘sub_597460’, ‘sub_4EB7E3’, ‘sub_4ED806’, ‘sub_4F11F5’, ‘sub_55D500’, ‘sub_55BD20’]

sub_4F11F5

6

image-20210803082306420

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
void sub_4ED753()
{
char v0; // [rsp+Fh] [rbp-1h]

sub_55D500((__int64)"Just do it");
while ( 1 )
{
sub_597460(0LL);
v0 = sub_55F1F0();
sub_597460(0LL);
switch ( v0 )
{
case 'A':
goto LABEL_6;
case 'D':
goto LABEL_4;
case 'Q':
sub_55BD20(0);
case 'S':
goto LABEL_5;
case 'W':
sub_4EB7E3(0LL, 0LL);
LABEL_4:
sub_4ED806(0LL, 0LL);
LABEL_5:
sub_4F11F5(0LL, 0LL);
LABEL_6:
sub_55D500((__int64)"OUCH!!!!");
break;
default:
continue;
}
}
}

对应的就是4: ‘W’,5: ‘D’,6: ‘S’,7: ‘A’

运行脚本后,第一个最短而且到达了终点

由于开始的时候需要“S”一下进入地图,所以在加上一个S,md5后得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void __noreturn sub_40180E()
{
char v0; // [rsp+Fh] [rbp-1h]

sub_55D500((__int64)"This is the beginning. You can only go south.");
do
{
sub_597460(0LL);
v0 = sub_55F1F0();
sub_597460(0LL);
if ( v0 == 'Q' )
goto LABEL_5;
}
while ( v0 != 'S' );
sub_40187C();
LABEL_5:
sub_55BD20(0);
}

image-20210802112122575