迷宫逆向

前言:该篇文章会介绍一个在ctf当中reverse方向中常见的一种迷宫题,我从攻防世界中选取了一道比较有代表性的题目,逐一讲解,并且每个思路都相当清晰透彻,借此分享,相信看完之后对于迷宫类型的题目会有更深的理解。

例题1:攻防世界-reverse_re3

第一步

首先看有无壳,直接丢到exeinfope—发现是elf文件是linux的可执行程序

第二步

反手丢进ida看到main 直接F5反编译看一手

第三步

一个一个函数来,sub_11B4双击点开好像没啥东西,看看sub_940

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
__int64 sub_940()
{
int v0; // eax
int v2; // [rsp+8h] [rbp-218h]
int v3; // [rsp+Ch] [rbp-214h]
char v4[520]; // [rsp+10h] [rbp-210h] BYREF
unsigned __int64 v5; // [rsp+218h] [rbp-8h]

v5 = __readfsqword(0x28u);
v3 = 0;
memset(v4, 0, 0x200uLL);
_isoc99_scanf(&unk_1278, v4, v4);
while ( 1 )
{
do
{
v2 = 0;
sub_86C();
v0 = v4[v3];
if ( v0 == 'd' ) //原题是ascii码可以对着ascii按"r"快捷键转成字符
{
v2 = sub_E23();
}
else if ( v0 > 'd' ) //wasd很明显就是游戏里常见的移动键呗
{
if ( v0 == 's' )
{
v2 = sub_C5A();
}
else if ( v0 == 'w' )
{
v2 = sub_A92();
}
}
else
{
if ( v0 == 27 )
return 0xFFFFFFFFLL;
if ( v0 == 'a' )
v2 = sub_FEC();
}
++v3;
}
while ( v2 != 1 );
if ( dword_202AB0 == 2 )
break;
++dword_202AB0;
}
puts("success! the flag is flag{md5(your input)}");
return 1LL;
}

这里留个心眼,flag是要输入的md5值

接下来分析wasd到底是怎么走的(像这种题大概率就是迷宫图,所以要明白它是怎么运动的)

先打开sub_E23康康

第四步

千万不要给这几个变量绕晕了

dword_202020:其实就是题目给的地图,可以双击进去看看(shift+e 提取数据)

dword_202AB0:代表哪个迷宫,此题有3个迷宫(至于为什么后文会提及)

dword_202AB4:代表行(因为15*,说明可能是一行15个数字,大胆猜测!)

dword_202AB8:代表列

225:地图尺寸15*15

这里我转换了一下不容易混淆

第五步

第一个if!=14 是因为跟下标有关系,一行15个数字下标最大是14,我们这个函数是”d“的操作也就是向右移,所以是如果下标等于14的话就不能再”d“了
第二个if 判断当前位置右移的数字是不是1,如果是将该位置标志为3,之前的位置标志为1,其实就是暗示我们1是可以走的,而3其实是我们的起点,如果不理解后面看看迷宫就明白了,
第三个if如果右移后是4就返回1,说明4就是我们的终点

再看看上下移动的函数(下图是”s“的函数,也就是下移)——有一些题目上下移动不是单纯的往上或者往下 而是斜向下或者斜向上噢

第六步

每次加15说明每次加一行

注意:这里分析的是右移”d“和下移”s“的函数至于”w“ ”a“都是差不多的,这里就不过多赘述了

再回到sub_940函数

第七步

这里的dword_202AB0==2 我们在前面提到它可能是标识哪一个迷宫的,这里说==2的话就break,否则就++,说明这里会循环3次,说明会有3个迷宫,接下来我们来看看这个稍微的迷宫长什么样。

双击点开前文提到的dword_202020

第八步

这密密麻麻的数字就是它的数据啦,现在按shift+e提取数据,然后导出来


这里有个大大大坑,就是dword类型的数据是4位一组,只取第一位作为数值,也就是说100010000111 最终会变成110 ,后3位是填充的,接下来就是怎么转换成一个迷宫了,网上一堆wp却几乎没有人提到如何去把这份原始数据转换成迷宫,下面我提供了一个python脚本针对这道题目,只要运行即可得到迷宫的样子,


一开始数据是这样的,先利用记事本的功能替换掉 ,和空格 以及前面的括号等等


之后利用一下py脚本即可完成转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 输入需要处理的字符串  
input_string = input("请输入需要处理的字符串:")

# 将所有字符连起来,去掉换行符
output_string = input_string.replace("\n", "")
ZeK1D = output_string.replace(" ", "")

def extract_chars(input_string):
# 将输入字符串分割为每四位
chunks = [input_string[i:i+4] for i in range(0, len(input_string), 4)]

# 提取每四位中的第一位字符
first_chars = [chunk[0] for chunk in chunks if chunk]

# 将字符连在一起并输出
output= ''.join(first_chars)
print(output)


# 调用函数并输出结果
extract_chars(ZeK1D)

之后可以将输出结果复制到word 改格式会好看一点

第九步

之后再按每15行为一个迷宫分成3个小迷宫,以3为起点4为终点进行运动,之后再md5加密即可得到flag

第一个迷宫

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

[1, 1, 1, 1, 1, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]

[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

第二个迷宫

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

[1, 1, 0, 3, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0]

[1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

[1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]

[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

第三个迷宫

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

[0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]

行动轨迹为:ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss

经过md5编码后flag是flag{aeea66fcac7fa80ed8f79f38ad5bb953}

总结:

逆向遇到迷宫题的思路大概分2点

1.弄清楚移动的方式

2.分析迷宫图的尺寸

3.手动走迷宫或写脚本走迷宫(建议BFS算法)

例题2

查壳,放ida

注意flag是md5(留个心眼),然后去动态调试找flag,这个createmap非常显眼

先下个断点,然后开始调试

任意输入一些,然后去search map

这里的快捷键有ctrl+T,查找下一个text

找到后shift+E提取数据,然后放入我们的脚本文件

修改脚本中行列参数,运行脚本得到16*16的二维列表

将二维列表复制到【二.(一)】中的**<脚本二:获得迷宫路径>**中

分析check()函数得到起点坐标为(15, 1),且本题未给出确切终点而是在main函数中给出了路径长为54

并且用aswd键位移动

这里附上最终代码

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from collections import deque
# str为ida中使用快捷键[shift+e]提取到的数据, 如果提取的是string literal则加上引号视作字符串,如果是C array(decimal)则加上中括号视作列表
str = [

1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
1, 1, 1, 1, 0, 1, 1, 1, 1, 0,
1, 1, 1, 0, 1, 1, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 1, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
0, 1, 0, 1, 1, 1, 1, 0, 1, 1,
1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 0, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 0, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 0, 1, 1, 0, 1,
0, 1, 1, 1, 1, 1, 0, 1, 1, 1,
1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1
]
s = 0 # s用作索引访问str, 供下面tmp列表取值

# 分析题目后设置迷宫的行列
row = 16 # 设置二维迷宫行数 input()
col = 16 # 设置二维迷宫列数 input()

maze = []
for i in range(row):
tmp = []
for j in range(col):
tmp.append(str[s])
s += 1
maze.append(tmp) # 凑一行添加一行到迷宫中
print(maze)
# 设置二维四向迷宫, 如果题目是多个小迷宫问题, 拆分多次调用脚本获取路径即可
path_len = 54+1 # 如果题目未给出终点坐标,则一定会指定路径的长度,在此处修改路径长度并+1,
#否则请保留path_len的极大值 0x7fffffff


# 进行BFS寻找路径
def bfs(start, end, barrier):
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 定义四个方向的移动
for i in range(len(maze)): # 获取起点和终点在列表中的索引
for j in range(len(maze[i])):
if (maze[i][j] == start):
start = (i, j)
if (maze[i][j] == end):
end = (i, j)
# 以下均是bfs算法套路
queue = deque()
queue.append((start, [start])) # (当前位置, 路径)
visited = set()
visited.add(start)
while queue:
position, path = queue.popleft()
if position == end:
return path
elif len(path) == path_len:
return path
for d in directions:
next_position = (position[0] + d[0], position[1] + d[1])
if 0 <= next_position[0] < len(maze) and 0 <= next_position[1] < len(maze[0]) and \
maze[next_position[0]][next_position[1]] != barrier and next_position not in visited:
queue.append((next_position, path + [next_position]))
visited.add(next_position)
return None


# 执行BFS搜索并打印结果
if __name__ == '__main__':
# maze[起点x坐标][起点y坐标] = 'S'
#如果题目给了起点终点的坐标,
#在这里直接给起点和终点添加特征
# maze[终点x坐标][终点y坐标] = 'E'
maze[15][1]='S'
path = bfs('S', 'E', 1) # bfs函数传入参数代表起点、终点、障碍的特征(若题目给出的数据无特征, 手动添加特征即可, 通常障碍是1也有可能是0或其它字符如'#')
print("移动路径坐标:", path)
print("移动路径方位:", end='')
for i in range(1, len(path)):
x1, y1, x2, y2 = path[i - 1][0], path[i - 1][1], path[i][0], path[i][1]
if (x1 > x2): # 上
print("w", end='')
elif (x1 < x2): # 下
print("s", end='')
elif (y1 > y2): # 左
print("a", end='')
elif (y1 < y2): # 右
print("d", end='')

exp

1)

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
# str为ida中使用快捷键[shift+e]提取到的数据, 如果提取的是string literal则加上引号视作字符串,如果是C array(decimal)则加上中括号视作列表
str = [

1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
1, 1, 1, 1, 0, 1, 1, 1, 1, 0,
1, 1, 1, 0, 1, 1, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 1, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
0, 1, 0, 1, 1, 1, 1, 0, 1, 1,
1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 0, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 0, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 0, 1, 1, 0, 1,
0, 1, 1, 1, 1, 1, 0, 1, 1, 1,
1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1
]#待输入的迷宫数组
s = 0 # s用作索引访问str, 供下面tmp列表取值

# 分析题目后设置迷宫的行列
row = 16 # 设置二维迷宫行数
col = 16 # 设置二维迷宫列数

maze = []
for i in range(row):
tmp = []
for j in range(col):
tmp.append(str[s])
s += 1
maze.append(tmp) # 凑一行添加一行到迷宫中
print(maze)

2)

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
from collections import deque

# 设置二维四向迷宫, 如果题目是多个小迷宫问题, 拆分多次调用脚本获取路径即可
maze = [] #二维列表迷宫,直接输入脚本1的二维数组
path_len = 0x7fffffff # 如果题目未给出终点坐标,则一定会指定路径的长度,在此处修改路径长度,否则请保留path_len的极大值


# 进行BFS寻找路径
def bfs(start, end, barrier):
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 定义四个方向的移动
for i in range(len(maze)): # 获取起点和终点在列表中的索引
for j in range(len(maze[i])):
if (maze[i][j] == start):
start = (i, j)
if (maze[i][j] == end):
end = (i, j)
# 以下均是bfs算法套路
queue = deque()
queue.append((start, [start])) # (当前位置, 路径)
visited = set()
visited.add(start)
while queue:
position, path = queue.popleft()
if position == end:
return path
elif len(path) == path_len:
return path
for d in directions:
next_position = (position[0] + d[0], position[1] + d[1])
if 0 <= next_position[0] < len(maze) and 0 <= next_position[1] < len(maze[0]) and \
maze[next_position[0]][next_position[1]] != barrier and next_position not in visited:
queue.append((next_position, path + [next_position]))
visited.add(next_position)
return None


# 执行BFS搜索并打印结果
if __name__ == '__main__':
# maze[起点x坐标][起点y坐标] = 'S'
#如果题目给了起点终点的坐标,在这里直接给起点和终点添加特征
# maze[终点x坐标][终点y坐标] = 'E'

path = bfs('S', 'E', 1) # bfs函数传入参数代表起点、终点、障碍的特征(若题目给出的数据无特征, 手动添加特征即可, 通常障碍是1也有可能是0或其它字符如'#')
print("移动路径坐标:", path)
print("移动路径方位:", end='')
for i in range(1, len(path)):
x1, y1, x2, y2 = path[i - 1][0], path[i - 1][1], path[i][0], path[i][1]
if (x1 > x2): # 上
print("w", end='')
elif (x1 < x2): # 下
print("s", end='')
elif (y1 > y2): # 左
print("a", end='')
elif (y1 < y2): # 右
print("d", end='')

wsad可以根据题目要求更改键位

3)

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
maze = [
[
1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1],
[
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
[
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[
1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
[
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1],
[
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],
[
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
[
1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1],
[
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
[
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1]]
usedmap=[[0 for i in range(len(maze))]for i in range(len(maze[0]))]
sti=0
stj=1
edi=24
edj=23
flag=''
def dfs(x,y):
global flag
if x==edi and y==edj:
print(flag)
return
if maze[x+1][y]==0 and usedmap[x+1][y]==0:
usedmap[x][y]=1
flag+='s'
dfs(x+1,y)
flag=flag[:-1]
usedmap[x][y]=0
if maze[x-1][y]==0 and usedmap[x-1][y]==0:
usedmap[x][y]=1
flag+='w'
dfs(x-1,y)
flag=flag[:-1]
usedmap[x][y]=0
if maze[x][y+1]==0 and usedmap[x][y+1]==0:
usedmap[x][y]=1
flag+='d'
dfs(x,y+1)
flag=flag[:-1]
usedmap[x][y]=0
if maze[x][y-1]==0 and usedmap[x][y-1]==0:
usedmap[x][y]=1
flag+='a'
dfs(x,y-1)
flag=flag[:-1]
usedmap[x][y]=0
dfs(sti,stj)
'''
for i in range(len(maze)):
for j in range(len(maze[0])):
print(maze[i][j],end='')
print()
'''

例题3 doublegame

运行

ctrl F搜索gameover出现的地方,然后x查找调用函数

(key非预期)发现有个可疑的数据,是key=13371337

key正常

发现key ^0x1DC4=13376013

静态分析发现,sub_14001136B函数是第二关,将去第二关路上的 if的字节码全部修改为相反的, 然后patch,重新调试 (记得备份)

或者找到迷宫,

先拿出迷宫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
maze=''' strcpy(Buffer, "000000000000000000000");
strcpy(v4, "0 0 0 0 0 0 0");
strcpy(&v4[22], "0 0 0 00000 00000 0 0");
strcpy(v5, "0 0 0 0");
strcpy(&v5[22], "0 000 000 0 000 0 0 0");
strcpy(v6, "0 0 0 0 0 0 0 0");
strcpy(&v6[22], "0 0 0 00000 000 000 0");
strcpy(v7, "0 0 0 0 0 0 ");
strcpy(&v7[22], "0 000 0 0 000 0 0 0 0");
strcpy(v8, "0 0 0 0 0 0 0 0 0");
strcpy(&v8[22], "0 00000 000 000 0 0 0");
strcpy(v9, "0 0 0 0 0");
strcpy(&v9[22], "000 0 0 0 000 0 0 0 0");
strcpy(v10, "0 0 0 0 0 0 * 0 0 0 0");
strcpy(&v10[22], "0 0000000 0 000 00000");
strcpy(v11, "@ 0 0 0 0");
strcpy(&v11[22], "0 0 0 0 0 00000000000");
strcpy(v12, "0 0 0 0 0");
strcpy(&v12[22], "000 0 00000 0 000 000");
strcpy(v13, "0 0 0 0 0");
strcpy(&v13[22], "000000000000000000000");'''
maze=[(i[-24:-3]) for i in maze.split('\n')]
for i in maze:
print(i)

然后运行脚本

exp

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
72
73
74
75
76
77
78
79
80
81
maze=''' strcpy(Buffer, "000000000000000000000");
strcpy(v4, "0 0 0 0 0 0 0");
strcpy(&v4[22], "0 0 0 00000 00000 0 0");
strcpy(v5, "0 0 0 0");
strcpy(&v5[22], "0 000 000 0 000 0 0 0");
strcpy(v6, "0 0 0 0 0 0 0 0");
strcpy(&v6[22], "0 0 0 00000 000 000 0");
strcpy(v7, "0 0 0 0 0 0 ");
strcpy(&v7[22], "0 000 0 0 000 0 0 0 0");
strcpy(v8, "0 0 0 0 0 0 0 0 0");
strcpy(&v8[22], "0 00000 000 000 0 0 0");
strcpy(v9, "0 0 0 0 0");
strcpy(&v9[22], "000 0 0 0 000 0 0 0 0");
strcpy(v10, "0 0 0 0 0 0 * 0 0 0 0");
strcpy(&v10[22], "0 0000000 0 000 00000");
strcpy(v11, "@ 0 0 0 0");
strcpy(&v11[22], "0 0 0 0 0 00000000000");
strcpy(v12, "0 0 0 0 0");
strcpy(&v12[22], "000 0 00000 0 000 000");
strcpy(v13, "0 0 0 0 0");
strcpy(&v13[22], "000000000000000000000");'''
maze=[(i[-24:-3]) for i in maze.split('\n')]


for i in maze:
print(i)
# print(len(maze),(len(maze[0])))
from hashlib import md5
def finda(d):
x,y=d[0],d[1]-1
return (x,y,'a')
def findw(d):
x,y=d[0]-1,d[1]
return (x,y,'w')
def finds(d):
x,y=d[0]+1,d[1]
return (x,y,'s')
def findd(d):
x,y=d[0],d[1]+1
return (x,y,'d')
def find0(d,row,column):
if d[0]==0:
t=[finda(d),findd(d),finds(d)]
elif d[0]==row-1:
t=[findw(d),finda(d),findd(d)]
elif d[1]==0:
t=[findw(d),findd(d),finds(d)]
elif d[1]==column-1:
t=[findw(d),finda(d),finds(d)]
else: t=[findw(d),finda(d),finds(d),findd(d)]
tmp=[]
for x,y,r in t:
if maze[x][y]==' 'or maze[x][y]=='*' :
tmp.append((x,y,r))
return tmp

def get(o,O,row,column):#起点,终点,行,列
SUM=[]
Road = [('', o)]
while True:
road=[]
for (r_pre,d) in Road:
if d==O:#终点
SUM.append((len(r_pre),r_pre,))
print(r_pre.encode())
print('NSSCTF{'+md5(r_pre.encode()).hexdigest()+'13371337'+'}')
exit()
# exit()
next=find0(d,row,column)
for x,y,r in next:
if len(r_pre)>=1:
if 'ws'in r_pre[-1]+r or 'sw' in r_pre[-1]+r:
continue
if 'ad' in r_pre[-1] + r or 'da' in r_pre[-1] + r:
continue
road.append((r_pre+r,(x,y)))
# print(road)
Road=road

row,column=21,21
get((15,0),(7,20),row,column)


迷宫逆向
http://example.com/2024/01/03/迷宫逆向/
Author
chaye
Posted on
January 3, 2024
Licensed under