MAZE

这个题比赛的时候没有做出来

这里重新分析一遍

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
for ( i = 0; ; ++i )
{
if ( i >= strlen(Str) )
print_wrong();
Sleep(0x28u);
switch ( Str[i] )
{
case 'a':
while ( 1 )
{
if ( v4 % 8 - 1 < 0 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 - 1) )
break;
--v4;
}
break;
case 'd':
while ( 1 )
{
if ( v4 % 8 + 1 >= 8 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 + 1) )
break;
++v4;
}
break;
case 'n':
while ( 1 )
{
if ( v4 - 64 < 0 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 - 64) )
break;
v4 -= 64;
}
break;
case 's':
while ( 1 )
{
if ( v4 % 64 + 8 >= 64 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 + 8) )
break;
v4 += 8;
}
break;
case 'u':
while ( 1 )
{
if ( v4 + 64 >= 512 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 + 64) )
break;
v4 += 64;
}
break;
case 'w':
while ( 1 )
{
if ( v4 % 64 - 8 < 0 )
print_wrong();
if ( *((_BYTE *)off_7FF692C56200 + v4 - 8) )
break;
v4 -= 8;
}
break;
default:
print_wrong();
}
if ( v4 == 436 )
break;
}

主函数的switch证明了这是一个迷宫题,有6个方向,可以看出offxxx是地图,根据方向可以对地图的加减可以看出是8*8*8的立体地图

每一个case里面,都有一个while,想要break必须off +xxx不为0,打开地图数组可以看到全是1和0,说明只有当这个方向的相邻格是1的时候才会停止。也就是说这个迷宫的移动不能在中间停止

最后,我们得到迷宫重点在436的位置(i,j,k)=(6,6,4)

画出地图

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
map = [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, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 9, 0, 1, 0,
0, 0, 0, 0, 1, 0, 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, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]

可得:

1
sduwandus

检验后发现结果错误

于是尝试调试看看哪里有问题

先检查了一下反调试,发现有tls

打开

发现tls还原了一个函数,不知道这个函数在哪里调用的

image-20240824223727101

查找资料显示,这个函数的

1
2
3
4
5
if ( Context.Dr0 || Context.Dr1 || Context.Dr2 || Context.Dr3 )
{
CurrentProcess = GetCurrentProcess();
((void (__fastcall *)(HANDLE, _QWORD))ProcAddress)(CurrentProcess, 0i64);
}

ProcAddress为ZwTerminateProcess

检查了是否有断点寄存器的值,如果有就会直接退出

DR0-DR3:存放断点寄存器
DR4-DR5:保留
DR6:状态寄存器

调试寄存器:Debug Register-CSDN博客

同时调试到这里的时候会发现这个不是主线程,而是其它的线程

这个线程就会在这里一直循环来反调试

同时这里的i!=j也很奇怪不知道判断了什么,i是输入的第多少位

同时从下面得到了另一张地图map2_num

尝试nop掉反调再调一次

发现进入这个函数的时候已经要求输入了

image-20240824231847577

于是查找交叉引用,发现__scrt_common_main_seh()中的

initterm_e((_PIFV *)&First, (_PIFV *)&Last)调用了这个函数

initterm_e遍历了地址从first到last执行了其中所有函数

似乎系统认为这个是初始化函数??

这里一共有两个用户自定义的函数,第一个为第二个执行初始化,解密字符串

image-20240824234314235

最后执行了ZwSetInformationThread函数

1
2
3
4
5
6
NTSYSAPI NTSTATUS ZwSetInformationThread(
[in] HANDLE ThreadHandle,
[in] THREADINFOCLASS ThreadInformationClass,
[in] PVOID ThreadInformation,
[in] ULONG ThreadInformationLength
);

这里第二个ThreadInformationClass传入的是17

对应的0x11标志是:ThreadHideFromDebugger

[原创]调试陷阱ThreadHideFromDebugger的另一种对抗方法-软件逆向-看雪-安全社区|安全招聘|kanxue.com

根据这个文章,可以看到效果是使调试器接收不到调试信息
然后调试就会寄掉

这里只需要跳过最后一行代码即可进入main函数中,为了后面调试方便,继续patch

然后再回到主函数,if里面有个sleep感觉是为了每轮开始时给那个检查函数足够的时间去检查的

如果是地图有问题那么off指向的东西肯定会变,所以下一个硬件写入断点

第一个循环完,没有问题,但是到sleep(0x28)的时候,断点被写入,忽然跳到了第5个线程

image-20240825000637454

这时因为sleep函数会将当前线程暂时挂起让cpu去执行其它线程

在这里它把qword数组的第-8位写入了v2

image-20240825000825078

那么我们就知道,它在另外一个线程检查了一个东西,然后写入这一轮(按1个字符算一轮)的地图。判断依据是什么呢

image-20240825001138474

很明显这里写入的是v2的值,v2的值根据v1来变化,v1根据test_num来变化,同时也和i,j有关

testnum每次和1比较同时每次都会被v1赋值,也就是说每一轮的test_num都是上一轮的v1得到的,由于v1为局部变量,一开始为0,所以test_num一定会是1,2,1,2交替

打上断点
发现test_num它只在这里被赋值。

然后给i和j打断点

调试的时候发现,由于i一直在main里面增加,所以一旦到新的一轮,这里就会触发,让j++,然后修改v1,赋值

至此,它的逻辑应该是:第一轮用map1,第二轮用map2,第三轮用map1…

然后就直接写脚本

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import hashlib

map1 = [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, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 9, 0, 1, 0,
0, 0, 0, 0, 1, 0, 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, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]

map2 = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 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, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
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, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 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, 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, 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, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]






def find_way(a,b,c,num,max_num):
def testc():
ans = []
flag = 0
for i in range(8):
if map[a*64+b*8+i] == 1:
if i< c-1:
flag = 1
ans.append([i+1,'a'])
elif i>c+1:
flag = 1
ans.append([i-1,'d'])
if flag == 0:
return False, c
return True, ans
def testb():
ans = []
flag = 0
for i in range(8):
if map[a*64+i*8+c] == 1:
if i< b-1:
flag = 1
ans.append([i+1,'w'])
elif i>b+1:
flag = 1
ans.append([i-1,'s'])
if flag == 0:
return False, b
return True, ans
def testa():
ans = []
flag = 0
for i in range(8):
if map[i*64+b*8+c] == 1:
if i< a-1:
flag = 1
ans.append([i+1,'n'])
elif i>a+1:
flag = 1
ans.append([i-1,'u'])
if flag == 0:
return False, b
return True, ans
if num>max_num:
return False,0
way = ''
pos = a*64+b*8+c
if pos==436:
return way,True
if not (num%2):
map=map2
else:
map=map1
test_c = testc()
test_a = testa()
test_b = testb()
if test_c[0]:
for j in range(len(test_c[1])):
next_way = find_way(a,b,test_c[1][j][0],num+1,max_num) #第一种情况
if next_way[1]:
way=test_c[1][j][1]+next_way[0]
return way,True

if test_a[0]:
for j in range(len(test_a[1])):
next_way = find_way(test_a[1][j][0],b,c,num+1,max_num)
if next_way[1]:
way = test_a[1][j][1]+next_way[0]
return way, True

if test_b[0]:
for j in range(len(test_b[1])):
next_way = find_way(a,test_b[1][j][0],c,num+1,max_num)
if next_way[1]:
way = test_b[1][j][1]+next_way[0]
return way, True
return way, False
for max_num in range(20,50):
mstr = (find_way(0,0,0,1,max_num))[0]
if mstr!='':
print(mstr)
hash = hashlib.md5()
hash.update(mstr.encode())
print('flag{'+hash.hexdigest()+'}')
break