记录BUU上刷的Reverse题

[羊城杯 2020]Bytecode (py字节码)

题目中给出了挺长的字节码,在解这道题的时候,需要多参考查看官方dis反汇编器的文档

可以使用以下命令,时不时反汇编一下逆向出的代码,进行对比。

1
python3 -m dis fileName.py

题目给出的字节码:

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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
 4           0 LOAD_CONST               0 (3) # LOAD_CONST 压栈操作
3 LOAD_CONST 1 (37)
6 LOAD_CONST 2 (72)
9 LOAD_CONST 3 (9)
12 LOAD_CONST 4 (6)
15 LOAD_CONST 5 (132)
18 BUILD_LIST 6 # 创建列表
21 STORE_NAME 0 (en) # en = [3,37,72,9,6,132]

5 24 LOAD_CONST 6 (101)
27 LOAD_CONST 7 (96)
30 LOAD_CONST 8 (23)
33 LOAD_CONST 9 (68)
36 LOAD_CONST 10 (112)
39 LOAD_CONST 11 (42)
42 LOAD_CONST 12 (107)
45 LOAD_CONST 13 (62)
48 LOAD_CONST 7 (96)
51 LOAD_CONST 14 (53)
54 LOAD_CONST 15 (176)
57 LOAD_CONST 16 (179)
60 LOAD_CONST 17 (98)
63 LOAD_CONST 14 (53)
66 LOAD_CONST 18 (67)
69 LOAD_CONST 19 (29)
72 LOAD_CONST 20 (41)
75 LOAD_CONST 21 (120)
78 LOAD_CONST 22 (60)
81 LOAD_CONST 23 (106)
84 LOAD_CONST 24 (51)
87 LOAD_CONST 6 (101)
90 LOAD_CONST 25 (178)
93 LOAD_CONST 26 (189)
96 LOAD_CONST 6 (101)
99 LOAD_CONST 27 (48)
102 BUILD_LIST 26 # 创建列表
105 STORE_NAME 1 (output) # output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]

7 108 LOAD_CONST 28 ('welcome to GWHT2020')
111 PRINT_ITEM
112 PRINT_NEWLINE

9 113 LOAD_NAME 2 (raw_input)
116 LOAD_CONST 29 ('please input your flag:')
119 CALL_FUNCTION 1
122 STORE_NAME 3 (flag)

10 125 LOAD_NAME 3 (flag)
128 STORE_NAME 4 (str)

12 131 LOAD_NAME 5 (len)
134 LOAD_NAME 4 (str)
137 CALL_FUNCTION 1
140 STORE_NAME 6 (a)

13 143 LOAD_NAME 6 (a)
146 LOAD_CONST 30 (38)
149 COMPARE_OP 0 (<)
152 POP_JUMP_IF_FALSE 173

14 155 LOAD_CONST 31 ('lenth wrong!')
158 PRINT_ITEM
159 PRINT_NEWLINE

15 160 LOAD_NAME 7 (exit) # if len(str) < 38:
163 LOAD_CONST 32 (0) # sys.exit(0)
166 CALL_FUNCTION 1 # else:
169 POP_TOP
170 JUMP_FORWARD 0 (to 173)

17 >> 173 LOAD_NAME 8 (ord)
176 LOAD_NAME 4 (str)
179 LOAD_CONST 32 (0)
182 BINARY_SUBSCR
183 CALL_FUNCTION 1

186 LOAD_CONST 33 (2020)

189 BINARY_MULTIPLY # ord(str[0])*2020


190 LOAD_NAME 8 (ord)
193 LOAD_NAME 4 (str) # ord(str[1])
196 LOAD_CONST 34 (1)
199 BINARY_SUBSCR
200 CALL_FUNCTION 1

203 BINARY_ADD # ord(str[0])*2020 + ord(str[1])


204 LOAD_CONST 33 (2020) # (ord(str[0])*2020 + ord(str[1]))*2020
207 BINARY_MULTIPLY


208 LOAD_NAME 8 (ord)
211 LOAD_NAME 4 (str)
214 LOAD_CONST 35 (2)
217 BINARY_SUBSCR
218 CALL_FUNCTION 1

221 BINARY_ADD # (ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2])


222 LOAD_CONST 33 (2020)
225 BINARY_MULTIPLY # ((ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2]))*2020


226 LOAD_NAME 8 (ord) ord(str[3])
229 LOAD_NAME 4 (str)
232 LOAD_CONST 0 (3)
235 BINARY_SUBSCR
236 CALL_FUNCTION 1
239 BINARY_ADD # ((ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2]))*2020 + ord(str[3])

240 LOAD_CONST 33 (2020)
243 BINARY_MULTIPLY
244 LOAD_NAME 8 (ord)
247 LOAD_NAME 4 (str)
250 LOAD_CONST 36 (4)
253 BINARY_SUBSCR
254 CALL_FUNCTION 1 # ord(str[4])

257 BINARY_ADD # (((ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2])*2020) + ord(str[3]))*2020 + ord(str[4])

258 LOAD_CONST 37 (1182843538814603)
261 COMPARE_OP 2 (==) # (((ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2])*2020) + ord(str[3]))*2020 + ord(str[4]) == 1182843538814603
264 POP_JUMP_IF_FALSE 275

18 267 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
270 PRINT_ITEM
271 PRINT_NEWLINE
272 JUMP_FORWARD 15 (to 290)

20 >> 275 LOAD_CONST 39 ('bye~')
278 PRINT_ITEM
279 PRINT_NEWLINE

21 280 LOAD_NAME 7 (exit)
283 LOAD_CONST 32 (0)
286 CALL_FUNCTION 1
289 POP_TOP

23 >> 290 BUILD_LIST 0
293 STORE_NAME 9 (x) # x = []

24 296 LOAD_CONST 40 (5)
299 STORE_NAME 10 (k) # k = 5

25 302 SETUP_LOOP 128 (to 433) # for i in range(13):
305 LOAD_NAME 11 (range)
308 LOAD_CONST 41 (13)
311 CALL_FUNCTION 1
314 GET_ITER
>> 315 FOR_ITER 114 (to 432)
318 STORE_NAME 12 (i)

26 321 LOAD_NAME 8 (ord)
324 LOAD_NAME 4 (str)
327 LOAD_NAME 10 (k) # b = ord(str[k])
330 BINARY_SUBSCR
331 CALL_FUNCTION 1
334 STORE_NAME 13 (b)

27 337 LOAD_NAME 8 (ord)
340 LOAD_NAME 4 (str)
343 LOAD_NAME 10 (k)
346 LOAD_CONST 34 (1)
349 BINARY_ADD
350 BINARY_SUBSCR
351 CALL_FUNCTION 1
354 STORE_NAME 14 (c) # c = ord(str[k+1])

28 357 LOAD_NAME 14 (c)
360 LOAD_NAME 0 (en)
363 LOAD_NAME 12 (i)
366 LOAD_CONST 4 (6)
369 BINARY_MODULO # %
370 BINARY_SUBSCR
371 BINARY_XOR
372 STORE_NAME 15 (a11) # a11 = c ^ en[(i % 6)]

29 375 LOAD_NAME 13 (b)
378 LOAD_NAME 0 (en)
381 LOAD_NAME 12 (i)
384 LOAD_CONST 4 (6)
387 BINARY_MODULO
388 BINARY_SUBSCR
389 BINARY_XOR
390 STORE_NAME 16 (a22) # a22 = b ^ en[(i % 6)]

30 393 LOAD_NAME 9 (x)
396 LOAD_ATTR 17 (append)
399 LOAD_NAME 15 (a11)
402 CALL_FUNCTION 1 # x.append(a11)
405 POP_TOP

31 406 LOAD_NAME 9 (x)
409 LOAD_ATTR 17 (append)
412 LOAD_NAME 16 (a22) # x.append(a22)
415 CALL_FUNCTION 1
418 POP_TOP

32 419 LOAD_NAME 10 (k) # k = k + 2
422 LOAD_CONST 35 (2)
425 INPLACE_ADD
426 STORE_NAME 10 (k)
429 JUMP_ABSOLUTE 315
>> 432 POP_BLOCK

33 >> 433 LOAD_NAME 9 (x)
436 LOAD_NAME 1 (output) # if x != output:
439 COMPARE_OP 2 (==)
442 POP_JUMP_IF_FALSE 453

34 445 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
448 PRINT_ITEM
449 PRINT_NEWLINE
450 JUMP_FORWARD 15 (to 468)

36 >> 453 LOAD_CONST 42 ('oh,you are wrong!')
456 PRINT_ITEM
457 PRINT_NEWLINE

37 458 LOAD_NAME 7 (exit)
461 LOAD_CONST 32 (0)
464 CALL_FUNCTION 1
467 POP_TOP

39 >> 468 LOAD_NAME 5 (len)
471 LOAD_NAME 4 (str)
474 CALL_FUNCTION 1
477 STORE_NAME 18 (l) # l = len(str)

40 480 LOAD_NAME 8 (ord)
483 LOAD_NAME 4 (str)
486 LOAD_NAME 18 (l)
489 LOAD_CONST 43 (7)
492 BINARY_SUBTRACT
493 BINARY_SUBSCR
494 CALL_FUNCTION 1
497 STORE_NAME 19 (a1) # a1 = ord(str[l-7])

41 500 LOAD_NAME 8 (ord)
503 LOAD_NAME 4 (str)
506 LOAD_NAME 18 (l)
509 LOAD_CONST 4 (6)
512 BINARY_SUBTRACT
513 BINARY_SUBSCR
514 CALL_FUNCTION 1
517 STORE_NAME 20 (a2) # a2 = ord(str[l-6])

42 520 LOAD_NAME 8 (ord)
523 LOAD_NAME 4 (str)
526 LOAD_NAME 18 (l)
529 LOAD_CONST 40 (5)
532 BINARY_SUBTRACT
533 BINARY_SUBSCR
534 CALL_FUNCTION 1
537 STORE_NAME 21 (a3) # a3 = ord(str[l-5])

43 540 LOAD_NAME 8 (ord)
543 LOAD_NAME 4 (str)
546 LOAD_NAME 18 (l)
549 LOAD_CONST 36 (4)
552 BINARY_SUBTRACT
553 BINARY_SUBSCR
554 CALL_FUNCTION 1
557 STORE_NAME 22 (a4) # a4 = ord(str[l-4])

44 560 LOAD_NAME 8 (ord)
563 LOAD_NAME 4 (str)
566 LOAD_NAME 18 (l)
569 LOAD_CONST 0 (3)
572 BINARY_SUBTRACT
573 BINARY_SUBSCR
574 CALL_FUNCTION 1
577 STORE_NAME 23 (a5) # a5 = ord(str[l-3])

45 580 LOAD_NAME 8 (ord)
583 LOAD_NAME 4 (str)
586 LOAD_NAME 18 (l)
589 LOAD_CONST 35 (2)
592 BINARY_SUBTRACT
593 BINARY_SUBSCR
594 CALL_FUNCTION 1
597 STORE_NAME 24 (a6) # a6 = ord(str[l-2])

46 600 LOAD_NAME 19 (a1)
603 LOAD_CONST 0 (3)
606 BINARY_MULTIPLY
607 LOAD_NAME 20 (a2)
610 LOAD_CONST 35 (2)
613 BINARY_MULTIPLY
614 BINARY_ADD
615 LOAD_NAME 21 (a3)
618 LOAD_CONST 40 (5)
621 BINARY_MULTIPLY
622 BINARY_ADD
623 LOAD_CONST 44 (1003)
626 COMPARE_OP 2 (==)
629 POP_JUMP_IF_FALSE 807 # if a1*3+a2*2+a3*5 == 1003:

47 632 LOAD_NAME 19 (a1)
635 LOAD_CONST 36 (4)
638 BINARY_MULTIPLY
639 LOAD_NAME 20 (a2)
642 LOAD_CONST 43 (7)
645 BINARY_MULTIPLY
646 BINARY_ADD
647 LOAD_NAME 21 (a3)
650 LOAD_CONST 3 (9)
653 BINARY_MULTIPLY
654 BINARY_ADD
655 LOAD_CONST 45 (2013)
658 COMPARE_OP 2 (==)
661 POP_JUMP_IF_FALSE 807 # if a1*4 + a2*7 + a3*9 == 2013:

48 664 LOAD_NAME 19 (a1)
667 LOAD_NAME 20 (a2)
670 LOAD_CONST 46 (8)
673 BINARY_MULTIPLY
674 BINARY_ADD
675 LOAD_NAME 21 (a3)
678 LOAD_CONST 35 (2)
681 BINARY_MULTIPLY
682 BINARY_ADD
683 LOAD_CONST 47 (1109)
686 COMPARE_OP 2 (==)
689 POP_JUMP_IF_FALSE 804 # if a1 + a2*8 +a3*2 == 1109

49 692 LOAD_NAME 22 (a4)
695 LOAD_CONST 0 (3)
698 BINARY_MULTIPLY
699 LOAD_NAME 23 (a5)
702 LOAD_CONST 35 (2)
705 BINARY_MULTIPLY
706 BINARY_ADD
707 LOAD_NAME 24 (a6)
710 LOAD_CONST 40 (5)
713 BINARY_MULTIPLY
714 BINARY_ADD
715 LOAD_CONST 48 (671)
718 COMPARE_OP 2 (==)
721 POP_JUMP_IF_FALSE 801 # if a4*3+a5*2+a6*5 == 671:

50 724 LOAD_NAME 22 (a4)
727 LOAD_CONST 36 (4)
730 BINARY_MULTIPLY
731 LOAD_NAME 23 (a5)
734 LOAD_CONST 43 (7)
737 BINARY_MULTIPLY
738 BINARY_ADD
739 LOAD_NAME 24 (a6)
742 LOAD_CONST 3 (9)
745 BINARY_MULTIPLY
746 BINARY_ADD
747 LOAD_CONST 49 (1252)
750 COMPARE_OP 2 (==)
753 POP_JUMP_IF_FALSE 798 # if a4*4+a5*7+a6*9 == 1252

51 756 LOAD_NAME 22 (a4)
759 LOAD_NAME 23 (a5)
762 LOAD_CONST 46 (8)
765 BINARY_MULTIPLY
766 BINARY_ADD
767 LOAD_NAME 24 (a6)
770 LOAD_CONST 35 (2)
773 BINARY_MULTIPLY
774 BINARY_ADD
775 LOAD_CONST 50 (644)
778 COMPARE_OP 2 (==)
781 POP_JUMP_IF_FALSE 795 # if a4 + a5*8 + a6*2 == 644

52 784 LOAD_CONST 51 ('congraduation!you get the right flag!')
787 PRINT_ITEM
788 PRINT_NEWLINE
789 JUMP_ABSOLUTE 795
792 JUMP_ABSOLUTE 798
>> 795 JUMP_ABSOLUTE 801
>> 798 JUMP_ABSOLUTE 804
>> 801 JUMP_ABSOLUTE 807
>> 804 JUMP_FORWARD 0 (to 807)
>> 807 LOAD_CONST 52 (None)
810 RETURN_VALUE

本人逆向出来的,或许有些许出入,但逻辑基本正确……

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
import sys
en = [3,37,72,9,6,132]

print('welcome to GWHT2020')

flag = input('please input your flag:')

str = flag

a = len(str(a))

if a < 38:
print('lenth wrong!')
sys.exit()

if (((ord(str[0])*2020 + ord(str[1]))*2020 + ord(str[2])*2020) + ord(str[3]))*2020 + ord(str[4]) == 1182843538814603:
print("good!continue\xe2\x80\xa6\xe2\x80\xa6")
else:
sys.exit()
output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]
x = []
k = 5
for i in range(13):

a11 = ord(str[k]) ^ en[(i % 6)]
a22 = ord(str[k+1])^ en[(i % 6)]
x.append(a11)
x.append(a22)
k = k + 2

if x == output:
print('good!continue\xe2\x80\xa6\xe2\x80\xa6')
else:
sys.exit()

l = len(str)
a1 = ord(str[l-7])
a2 = ord(str[l-6])
a3 = ord(str[l-5])
a4 = ord(str[l-4])
a5 = ord(str[l-3])
a6 = ord(str[l-2])
if a1*3+a2*2+a3*5 == 1003:
if a1*4 + a2*7 + a3*9 == 2013:
if a1 + a2*8 +a3*2 == 1109:
if a4*3+a5*2+a6*5 == 671:
if a4*4+a5*7+a6*9 == 1252:
if a4 + a5*8 + a6*2 == 644:
print('congraduation!you get the right flag!')

首先是开头的五个字符的爆破代码:

1
2
3
4
5
6
7
8
9
10
11
import string
arr = []
for i in string.printable:
arr.append(ord(i))
for str_0 in arr:
for str_1 in arr:
for str_2 in arr:
for str_3 in arr:
if ((((str_0*2020 + str_1)*2020 + str_2)*2020) + str_3)*2020 + ord("{") == 1182843538814603:
print(chr(str_0),chr(str_1),chr(str_2),chr(str_3),"{")
# G W H T {

然后是中间的异或运算,我还是使用的爆破:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import string

output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]
en = [3,37,72,9,6,132]
flag1 = []
k = 0
for i in range(13):
for j in string.printable:
if ord(j) ^ en[(i%6)] == output[k]:
flag1.append(j)
for j in string.printable:
if ord(j) ^ en[(i%6)] == output[k+1]:
flag1.append(j)
k += 2
flag1 = "".join(flag1)
print(flag1)
# fc2a8bb7f347a6f8a05c5c69f3

最后只需要解z3就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from z3 import *
s = Solver()
a1,a2,a3,a4,a5,a6 = Ints("a1 a2 a3 a4 a5 a6")
s.add(a1*3+a2*2+a3*5 == 1003)
s.add(a1*4 + a2*7 + a3*9 == 2013)
s.add(a1 + a2*8 +a3*2 == 1109)
s.add(a4*3+a5*2+a6*5 == 671)
s.add(a4*4+a5*7+a6*9 == 1252)
s.add(a4 + a5*8 + a6*2 == 644)
s.check()
print(s.model())

flag2 = ""
result = [97,101,102,102,55,51]
for i in result:
flag2 += chr(i)
# aeff73

最后把flag拼一下:

GWHT{fc2a8bb7f347a6f8a05c5c69f3aeff73}

[ACTF新生赛2020]fungame (溢出)

ida32打开看看

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v4; // [esp+1Ch] [ebp-4h]

__main();
v4 = malloc(0x14u);
memset(v4, 0, 0x14u);
memset(x, 0, 0x18u);
sub_401340(v4);
sub_4013BA(v4);
return 0;
}

sub_401340函数,动调y1的值即可(后来发现y1的数组直接告诉我们了,shift+e提取即可)

shift+e提取数据

1
2
3
4
5
6
7
8
9
y1 = [0x23, 0x61, 0x3e, 0x69, 0x54, 0x41, 0x18, 0x4d, 0x6e, 0x3b, 0x65, 0x53, 0x30, 0x79, 0x45, 0x5b]
y2 = [0x71, 0x04, 0x61, 0x58, 0x27, 0x1E, 0x4B, 0x22, 0x5E, 0x64, 0x03, 0x26, 0x5E, 0x17, 0x3C, 0x7A]
flag = ""
print(len(y1))
print(len(y2))
for i in range(len(y1)):
flag += chr(y1[i]^y2[i])
print(flag)
#Re_1s_So0_funny!

–更新–

参考

以为到这边就结束了,发现输入的flag不对,于是查看下面一个函数

1
2
3
4
5
6
7
8
int __cdecl sub_4013BA(char *Source)
{
char Destination[12]; // [esp+1Ch] [ebp-Ch] BYREF

strcpy(Destination, Source);
strcpy(x, Source);
return 0;
}

Destination的大小只有12,但是我们传过来的参数大小为16位,所以肯定会溢出,超出的4个字符,作为地址,调用隐藏函数sub_40233D,交叉引用参数x,可以找到函数sub_40233D

base64解码,注意,函数sub_40233D还输出了x,即函数的地址,所以我们需要在flag中添加上

且,ida中使用的是小端序,添加地址需要注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *
import base64
y1 = [0x23, 0x61, 0x3e, 0x69, 0x54, 0x41, 0x18, 0x4d, 0x6e, 0x3b, 0x65, 0x53, 0x30, 0x79, 0x45, 0x5b]
y2 = [0x71, 0x04, 0x61, 0x58, 0x27, 0x1E, 0x4B, 0x22, 0x5E, 0x64, 0x03, 0x26, 0x5E, 0x17, 0x3C, 0x7A]

flag = ""
for i in range(len(y2)):
flag += (chr(y1[i]^y2[i]))

string = b"YTFzMF9wV24="
decode = base64.b64decode(string)
flag = "flag{" + flag +chr(0x3d)+chr(0x23)+chr(0x40)+ decode.decode('utf-8')+"}"
print(flag)
# flag{Re_1s_So0_funny!=#@a1s0_pWn}

给我整蒙了……

[未完FlareOn2]very_success

放在linux中,file一下

die查一下:

用ida32打开

查看sub_401000函数,调整一下堆栈平衡,alt+k,调整最前面的堆栈平衡。

反汇编成功的伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL __usercall sub_401000@<eax>(int a1@<ebp>)
{
HANDLE StdHandle; // [esp-14h] [ebp-14h]
HANDLE v3; // [esp-10h] [ebp-10h]
int v4[3]; // [esp-Ch] [ebp-Ch] BYREF
int retaddr; // [esp+0h] [ebp+0h]

v4[1] = a1;
StdHandle = GetStdHandle(0xFFFFFFF6);
v3 = GetStdHandle(0xFFFFFFF5);
WriteFile(v3, aYouCrushedThat, 0x43u, v4, 0);
ReadFile(StdHandle, Buffer, 0x32u, v4, 0);
if ( sub_401084(v4, retaddr, Buffer, v4[0]) )
return WriteFile(v3, aYouAreSuccess, 17u, v4, 0);
else
return WriteFile(v3, aYouAreFailure, 17u, v4, 0);
}

这题的逻辑看的我头晕

境界还不够,先放一放

[SCTF2019]Strange apk (apk动态释放文件)

用jeb进行返汇编。

上次做apk逆向,告诉我assets目录下面存放着很重要的东西,在这边只看到了一个data文件,很奇怪。

发现了几个奇怪的函数

按x查看“_”函数的调用

函数的意思就是把这个asset目录下的data文件和字符串”syclover” 进行异或,我们用脚本来还原。

这个脚本网上很多都是还原成2000KB+的文件,和源文件对应不上,反汇编不起来。我重新找了个脚本,但是需要很长时间跑出来。

1
2
3
4
5
6
7
8
9
10
11
12
s = "syclover"
count = 0
with open('data', 'rb') as f:
while (1):
data = f.read(1)
if not data: break
data2 = ord(data) ^ ord(s[count % len(s)])
with open('dates', 'ab') as g:
c = data2.to_bytes(1, byteorder='little', signed=False)
g.write(c)
count += 1
f.close

查看datas头文件可以发现,跑出来datas文件是apk格式的文件,后缀改成apk,然后再用jeb打开。

首先查看s文件

1
string = "c2N0ZntXM2xjMG1l"

base64解码一下

再去分析t文件

syclover在进行md5加密之后,作为key与data进行了encode

将这串字符中的“8”去掉

1
2
3
string = "~8t808_8A8n848r808i8d8-8w808r8l8d8}8".replace("8","")
print(string)
# ~t0_An4r0id-w0rld}

sctf{W3lc0me~t0_An4r0id-w0rld}

还是先用正常一点的方法来看这道题:

首先是寻找app的入口点,打开Manifest文件,入口点是myappllicatin.t,但是我们只能看到sctf.hello这个包。所以可能是app动态释放文件

当我们运行上面的脚本之后,再次查看Mainfest文件,可以看到入口点和包对应上了。

较好解决方案应该是用映射大师,“frida dex dump(python)将app运行时候的dex给dump下来再进行分析。”–引用大佬的话

尝试了许久,发现不太支持,先放一放……

[RoarCTF2019]polyre (OLLVM控制流程平坦化+CRC)

ida64拖进去看看

定位一下:

对于这个程序,我没有一点话要说……

–更新–

参考:

https://security.tencent.com/index.php/blog/msg/112

https://blog.csdn.net/liuxiaohuai_/article/details/114369681

查阅博客后,得知该程序添加了控制流平坦化,目的是为了模糊基本块之间的前后关系,以及增大分析的难度,我们需要使用deflat.py执行控制流平坦化脚本命令,且使用其脚本需要安装angr库

输入命令:

1
python3 deflat.py attachment 0x400620

关于这行命令,最重要的就是后面的地址的选取,其实是函数的起始地址

还是感谢大佬的好心提示,脚本运行需要修改一些东西,关于这边存放的是am_graph模块的存放地址

复原成功之后,下面是ida反汇编伪代码:

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
signed __int64 v4; // [rsp+1E0h] [rbp-110h]
int i; // [rsp+1E8h] [rbp-108h]
int v6; // [rsp+1ECh] [rbp-104h]
int v7; // [rsp+1ECh] [rbp-104h]
char s1[48]; // [rsp+1F0h] [rbp-100h] BYREF
char s[60]; // [rsp+220h] [rbp-D0h] BYREF
unsigned int v10; // [rsp+25Ch] [rbp-94h]
char *v11; // [rsp+260h] [rbp-90h]
int v12; // [rsp+26Ch] [rbp-84h]
bool v13; // [rsp+272h] [rbp-7Eh]
unsigned __int8 v14; // [rsp+273h] [rbp-7Dh]
int v15; // [rsp+274h] [rbp-7Ch]
char *v16; // [rsp+278h] [rbp-78h]
int v17; // [rsp+284h] [rbp-6Ch]
int v18; // [rsp+288h] [rbp-68h]
bool v19; // [rsp+28Fh] [rbp-61h]
char *v20; // [rsp+290h] [rbp-60h]
int v21; // [rsp+298h] [rbp-58h]
bool v22; // [rsp+29Fh] [rbp-51h]
__int64 v23; // [rsp+2A0h] [rbp-50h]
bool v24; // [rsp+2AFh] [rbp-41h]
__int64 v25; // [rsp+2B0h] [rbp-40h]
__int64 v26; // [rsp+2B8h] [rbp-38h]
__int64 v27; // [rsp+2C0h] [rbp-30h]
__int64 v28; // [rsp+2C8h] [rbp-28h]
int v29; // [rsp+2D0h] [rbp-20h]
int v30; // [rsp+2D4h] [rbp-1Ch]
char *v31; // [rsp+2D8h] [rbp-18h]
int v32; // [rsp+2E0h] [rbp-10h]
int v33; // [rsp+2E4h] [rbp-Ch]
bool v34; // [rsp+2EBh] [rbp-5h]

v10 = 0;
memset(s, 0, 0x30uLL);
memset(s1, 0, sizeof(s1));
printf("Input:");
v11 = s;
if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 )
goto LABEL_43;
while ( 1 )
{
__isoc99_scanf("%s", v11);
v6 = 0;
if ( dword_603058 < 10 || (((dword_603054 - 1) * dword_603054) & 1) == 0 )
break;
LABEL_43:
__isoc99_scanf("%s", v11);
}
while ( 1 )
{
do
v12 = v6;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
v13 = v12 < 64;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 )
;
if ( !v13 )
break;
v14 = s[v6];
do
v15 = v14;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
if ( v15 == 10 )
{
v16 = &s[v6];
*v16 = 0;
break;
}
v17 = v6 + 1;
do
v6 = v17;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
}
for ( i = 0; ; ++i )
{
do
v18 = i;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
do
v19 = v18 < 6;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
if ( !v19 )
break;
do
v20 = s;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
v4 = *&v20[8 * i];
v7 = 0;
while ( 1 )
{
v21 = v7;
do
v22 = v21 < 64;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
if ( !v22 )
break;
v23 = v4;
v24 = v4 < 0;
if ( v4 >= 0 )
{
v27 = v4;
do
v28 = 2 * v27;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
v4 = v28;
}
else
{
v25 = 2 * v4;
do
v26 = v25;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
v4 = v26 ^ 0xB0004B7679FA26B3LL;
}
v29 = v7;
do
v7 = v29 + 1;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
}
v30 = 8 * i;
v31 = &s1[8 * i];
if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 )
LABEL_55:
*v31 = v4;
*v31 = v4;
if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 )
goto LABEL_55;
v32 = i + 1;
}
do
v33 = memcmp(s1, &unk_402170, 0x30uLL);
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 );
v34 = v33 != 0;
while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 )
;
if ( v34 )
puts("Wrong!");
else
puts("Correct!");
return v10;
}

从大佬那边荡过来的简化代码

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
_int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed __int64 v4;
signed int j,i,k;
char s1[48],s[60];
unsigned __int8 v14;
char *v16;
int v33;

memset(s, 0, 0x30uLL);
memset(s1, 0, 0x30uLL);
printf("Input:", 0LL);
scanf_s("%s", s);
for (i = 0; ; ++i)
{
if (i >= 64)
break;
v14 = s[i];
if (v14 == '\n')
{
v16 = &s[i];
*v16 = 0;
break; //换行符换成 '/0 '
}
}

for (j = 0; j < 6; ++j)
{
v4 = *&s[8 * j]; // 输入的每8个字节一组,组成1个64位的v4,小端序
for (k = 0; k < 64 ; ++k) // 循环64次
{
if (v4 >= 0) // 如果v4非负,v4*=2,相当于左移一位,结果必为偶数,如果左移一位后最高位为1,则v4变成了负数
v4 *= 2LL;
else // 如果v4为负,v4乘2后再异或0xB0004B7679FA26B3,相当于先左移一位再异或,结果必为奇数,注意这时最高位的1被移出了
v4 = 2 * v4 ^ 0xB0004B7679FA26B3LL;
}
}

v33 = memcmp(s, &unk_402170, 0x30uLL); /*(冗余码)unk_402170=[
0x96, 0x62, 0x53, 0x43, 0x6D, 0xF2, 0x8F, 0xBC,
0x16, 0xEE, 0x30, 0x05, 0x78, 0x00, 0x01, 0x52,
0xEC, 0x08, 0x5F, 0x93, 0xEA, 0xB5, 0xC0, 0x4D,
0x50, 0xF4, 0x53, 0xD8, 0xAF, 0x90, 0x2B, 0x34,
0x81, 0x36, 0x2C, 0xAA, 0xBC, 0x0E, 0x25, 0x8B,
0xE4, 0x8A, 0xC6, 0xA2, 0x81, 0x9F, 0x75, 0x55] */
if (v33 != 0)
puts("Wrong!");
else
puts("Correct!");
return 0;
}

具体的逻辑:

1
2
3
4
5
6
7
8
9
v12 = 0
if(v12<0x40):
v4 = v28
if(v4 >= 0):
v28 = v28 * 2
else:
v28 = v28 * 2
v28 = v28 ^ 0xB0004B7679FA26B3
v12 += 1

从别处得知是CRC32加密

大致流程:输入 48位,分成 6 组,将每组 8 字节转化为 long 类型的值,对每组进行加密,先判断正负,然后将值乘 2,随后根据正负异或 0xB0004B7679FA26B3,循环 64 次,最后与unk_402170进行比较。

需要注意的是ida的小端序,代码来源

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
origin = [0xbc8ff26d43536296,
0x520100780530ee16,
0x4dc0b5ea935f08ec,
0x342b90afd853f450,
0x8b250ebcaa2c3681,
0x55759f81a2c68ae4]
key = 0xB0004B7679FA26B3
data = ""

for value in origin:
for i in range(0, 64):
# 判断奇偶
parity = value & 1
if parity == 1:
value = (value ^ key) >> 1
value = value | 0x8000000000000000
else:
value = value >> 1
print(hex(value))
j = 0
while (j < 8):
# 因为是小端序,需要从最后一个字节开始取
data += chr(value & 0xFF)
# 右移 8 位,倒着取字节
value = value >> 8
j += 1
print(data)

可以对照看一下CRC64加密算法的C实现

https://blog.csdn.net/l1028386804/article/details/50748724

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
/*
* Improved calculation of CRC-64 values for protein sequences
* By Adam Lu 刘亚壮 - 2016-02-26
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

/* If you want to try the old CRC-64 function, currently employed in
SWISSPROT/TrEMBL then uncomment the next line */
/* #define OLDCRC */

#ifdef OLDCRC
#define POLY64REV 0xd800000000000000ULL
#define INITIALCRC 0x0000000000000000ULL
#else
#define POLY64REV 0x95AC9329AC4BC9B5ULL
#define INITIALCRC 0xFFFFFFFFFFFFFFFFULL
#endif



void crc64(char *seq, char *res)
{
int i, j, low, high;
unsigned long long crc = INITIALCRC, part;
static int init = 0;
static unsigned long long CRCTable[256];

if (!init)
{
init = 1;
for (i = 0; i < 256; i++)
{
part = i;
for (j = 0; j < 8; j++)
{
if (part & 1)
part = (part >> 1) ^ POLY64REV;
else
part >>= 1;
}
CRCTable[i] = part;
}
}

while (*seq)
crc = CRCTable[(crc ^ *seq++) & 0xff] ^ (crc >> 8);

/*
The output is done in two parts to avoid problems with
architecture-dependent word order
*/
low = crc & 0xffffffff;
high = (crc >> 32) & 0xffffffff;
sprintf (res, "%08X%08X", high, low);

return;
}

void main (int argc, char *argv[])
{
char *testseq1 = "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE";
char *testseq2 = "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE"; /* Differs from 1st seq in two places */
char result[20];


crc64(testseq1, result);
printf("The CRC-64 for sequence %s is %s\n", testseq1, result);

crc64(testseq2, result);
printf("The CRC-64 for sequence %s is %s\n", testseq2, result);
}

[GKCTF 2021]QQQQT (base58)

用die扫一下:

用网上下载了一个EnigmaVBUnpacker

解包之后再次扫描已经没有壳了

但是程序也打不开了……

放到xdbg32中,发现可以字符串

1
string = "56fkoP8KhwCf3v7CEz"

flag{12t4tww3r5e77}

[NPUCTF2020]你好sao啊(base64换表解密)

可以看出,中间的RxEncode是一个base64换表解密

将只需要将v15,v16,v17,v18从后往前拼成字节

可以看到这个表中,数字5和6换成了{和},只需要把最后base64加密中的5和6替换即可。

1
2
3
4
5
import base64
string = b"\x9E\x9b\x9C\xB5\xFE\x70\xD3\x0F\xb2\xd1\x4f\x9c\x02\x7f\xab\xde\x59\x65\x63\xe7\x40\x9d\xcd\xfa\x04"
flag = base64.b64encode(string)
print(flag)
#'npuctf{w0w+y0U+cAn+r3lllY+dAnc3}BA=='

[UTCTF2020]babymips (mips+异或运算)

用ida打开,函数很清晰:

shift+e提取数据unk_4015F4,并将前84个赋值给v7

跟进sub_401164函数:

a2,是上面数据提取的v7,这样的话,这题静态分析也可以做,动调也可以做。

1
2
3
4
5
6
7
arr =[98, 108, 127, 118, 122, 123, 102, 115, 118, 80, 82, 125, 64, 84, 85, 121, 64, 73, 71, 77, 116, 25, 123, 106, 66, 10, 79, 82, 125, 105, 79, 83, 12, 100, 16, 15, 30, 74, 103, 3, 124, 103, 2, 106, 49, 103, 97, 55, 122, 98, 44, 44, 15, 110, 23, 0, 22, 15, 22, 10, 109, 98, 115, 37, 57, 118, 46, 28, 99, 120, 43, 116, 50, 22, 32, 34, 68, 25, 0, 0, 0, 0, 0, 78]
print(len(arr))
flag = ""
for i in range(len(arr)):
flag += chr(arr[i]^(i+23))
print(flag)
#utflag{mips_cpp_gang_5VDm:~`N]ze;\)5%vZ=C'C(r#$q=*efD"ZNY_GX>6&sn.wF8$v*mvA@'}efghi$

[WUSTCTF2020]funnyre (花指令+异或运算)

ida64打开,一整块的汇编都在报红,需要手动恢复main函数

mian函数调好之后发现有错误,跟进查看返汇编

经典花指令,会出现好几次,需要一个一个手修。

nop掉jz和jnz,然后对比其他汇编的硬编码就能知道错误在哪里了

修复成功之后,分析一下main函数,输入字符串为38位,除去头5位与最后一位,其他字符串,经过很多次运算之后,与unk_4025C0数组的32位进行对比

对unk_4025C0数组进行数据提取:

注意,中间还存在了一个取反运算

三百多个数据,一个一个输入,累死了=^=,幸好解出来了:

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
arr = [ 0xD9, 0x2C, 0x27, 0xD6, 0xD8, 0x2A, 0xDA, 0x2D, 0xD7, 0x2C, 0xDC, 0xE1, 0xDB, 0x2C, 0xD9, 0xDD, 0x27, 0x2D, 0x2A, 0xDC, 0xDB, 0x2C, 0xE1, 0x29, 0xDA, 0xDA, 0x2C, 0xDA, 0x2A, 0xD9, 0x29, 0x2A]
add = [8,21,60,24,7,16,20,31,28,54,26,78,34,45,13,81,98,22,76,93,36,48,72,3,95,92,18,51,25,35,39,63,88,19,46,82,66,27,47,49,29,62,23,2,77,15,37,40,4,75,14,69,61,42,52,73,6,56,96,71,67,50,68,97,32,55,86,94,11,33,43,38,17,74,10,84,12,70,44,89,85,41,53,65,57,90,1,58,59,83,87,99,5,9,91,30,79,64,80]
huo1 = [0x67,0x68,0xc3,0x23,0xe9,0x8,0x3b,0x50,0xfa,0x64,0xc8,0x5,0xf5,0x76,0x86,0x41,0x99,0xf0,0x37,0x49,0x4c,0x18,0x39,0x5d,0x2c,0x75,0x4d,0x95,0xed,0x84,0x10,0x32,0x2,0x12,0x9c,0x65,0x73,0x2f,0x13,0xc,0xbd,0x96,0xa8,0x33,0xd2,0xe2,0xc7,0xd3,0x4e,0xa9,0xf9]
# not
huo2 = [0xef,0x62,0x66,0xce,0x14,0xb,0xb6,0x7,0xa3,0x97,0xdc,0xb8,0xe7,0xd5,0x7f,0x82,0x34,0xe1,0x98,0xe3,0xf6,0xeb,0xd8,0xda,0x1d,0x9d,0x7d,0x80,0xc9,0x27,0xa0,0x8e,0xf7,0x6f,0xfb,0x9a,0x9b,0xcb,0xd4,0x30,0xac,0x60,0x92,0xaf,0x2d,0xab,0x51,0xb7,0x35,0xd0,0xa4,0xad,0xc0,0xec,0xbe,0xfc,0xbb,0x54,0xc5,0xc1,0xc6,0x3,0xde,0x5e,0x3a,0xfd,0x29,0x31,0x85,0x2b,0xb9,0x55,0xdf,0xcf,0x4b,0xcc,0x1f,0xd6,0x93,0xf,0xe0,0xd1,0xb0,0xf1,0x56,0xf4,0x45,0x63,0x7c,0x2e,0x11,0x81,0x1c,0x77,0xfe,0x3f,0x36,0x87,0xbf,0xba,0x8b,0xa7,0x26,0x5f,0x72,0xdb,0x47,0x4a,0x15,0x19,0xb4,0x7b,0x8a,0x9,0xe8,0x71,0x20,0x88,0xe6,0x46,0x25,0xee,0xa5,0x8f,0x43,0x1a,0x5b,0xd9,0x61,0x79,0xa6,0xb3,0x8c,0x90,0x44,0x3d,0xc2,0x22,0x6b,0xa2,0x1e,0x6d,0x57,0x74,0x1,0xbc,0x94,0x2a,0x7e,0xe5,0x21,0x5c,0x69,0xb1,0x5a,0x17,0xd,0xb5,0xd7,0x16,0x89,0x40,0x6e,0xe4,0x48,0xea,0x28,0x70,0x78,0x6,0xa1,0x3c,0x9f,0xf2,0x58,0xf8,0xae,0xaa,0x1b,0x52,0xdd,0x7a,0x38,0x8d,0xe,0x42,0x9e,0x4,0x53,0xc4,0x83,0x24,0x4f,0x6c,0x3e,0xca,0xf3,0xa,0x59,0x6a,0xcd,0x91]
for i in range(len(add)):
for j in range(32):
arr[j] -= add[i]

for i in range(len(huo1)):
for j in range(32):
arr[j] ^= huo1[i]

for i in range(32):
arr[i] = ~arr[i]

for i in range(len(huo2)):
for j in range(32):
arr[j] ^= huo2[i]

flag = ""
for i in arr:
flag += chr(i%128)
print("flag{"+flag+"}")
#flag{1dc20f6e3d497d15cef47d9a66d6f1af}

[QCTF2018]Xman-babymips (mips+位移运算)

用ida32打开,虽然是mips架构的程序,但是生成的伪代码还是很清晰的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int __fastcall main(int a1, char **a2, char **a3)
{
int i; // [sp+18h] [+18h] BYREF
char v5[36]; // [sp+1Ch] [+1Ch] BYREF

setbuf((FILE *)stdout, 0);
setbuf((FILE *)stdin, 0);
printf("Give me your flag:");
scanf("%32s", v5);
for ( i = 0; i < 32; ++i )
v5[i] ^= 32 - (_BYTE)i;
if ( !strncmp(v5, fdata, 5u) )
return sub_4007F0(v5);
else
return puts("Wrong");
}

跟进sub_4007F0函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __fastcall sub_4007F0(const char *a1)
{
char v1; // $v1
size_t i; // [sp+18h] [+18h]

for ( i = 5; i < strlen(a1); ++i )
{
if ( (i & 1) != 0 )
v1 = (a1[i] >> 2) | (a1[i] << 6);
else
v1 = (4 * a1[i]) | (a1[i] >> 6);
a1[i] = v1;
}
if ( !strncmp(a1 + 5, (const char *)off_410D04, 0x1Bu) )
return puts("Right!");
else
return puts("Wrong!");
}

先进行一个异或,然后五位后面的进行一个移位或运算

最后对比,shift+e提取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
string1 = [81,124,106,123,103]
string2 =[ 0x52, 0xFD, 0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80, 0x13, 0x41, 0x54, 0xA0, 0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0, 0x16, 0x79, 0x1A, 0x15, 0x5B, 0x75, 0x1F]
for i in range(len(string2)):
if i%2 == 0:
string2[i] = ((string2[i] << 2) % 0x100 | string2[i] >> 6)
else:
string2[i] = ( string2[i] >> 2 | (string2[i] << 6) % 0x100)
string1.append(string2[i])

flag = ""
for i in range(len(string1)):
flag += chr((32-i) ^ string1[i])
print(flag)

其中,因为要考虑到溢出情况,所以%0x100,当然ascii码的范围在128以内,所以求余0x80也可以。

[羊城杯 2020]login (pyinstaller解包+pyc返汇编+z3)

Pyinstaller如何解包

现在就是需要根据struct.pyc文件头来修复login.pyc的文件头

大佬使用010editor,那我也使用010editor

struct.pyc:

login.pyc:

对比一下,我们复制struct.pyc的E3之前的数据复制到login就可以成功修复文件了

uncompyle6不支持反汇编python 3.9版本的pyc文件

我使用的是pycdc,使用方法在这里

1
./pycdc /home/ks/桌面/pyinstaller/login.pyc

就能看到py代码了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from z3 import *

a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14=Ints("a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14")

s=Solver()

s.add(a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748)
s.add(a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 + a14 * 17 == 7258)
s.add(a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 + a14 * 23 == 26190)
s.add(a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59 + a5 * 49 + a6 * 81 + a7 * 25 + a8 * 128 - a9 * 32 + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60 + a14 * 29 == 37136)
s.add(a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52 + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36 + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915)
s.add(a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45 + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26 + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61 + a14 * 28 == 17298)
s.add(a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42 + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47 + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44 + a14 * 65 == 19875)
s.add(a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85 + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30 + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784)
s.add(a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85 + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36 + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64 + a14 * 27 == 9710)
s.add(a1 * 67 - a2 * 68 + a3 * 68 - a4 * 51 - a5 * 43 + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38 + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52 + a14 * 31 == 13376)
s.add(a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51 + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6 + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67 + a14 * 78 == 24065)
s.add(a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5 + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35 + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61 + a14 * 20 == 27687)
s.add(a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25 + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92 + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250)
s.add(a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43 + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36 + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317)

print(s.check())
print(s.model())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sat
[a13 = 88,
a3 = 10,
a4 = 7,
a10 = 108,
a12 = 74,
a1 = 119,
a7 = 28,
a6 = 43,
a9 = 52,
a14 = 33,
a5 = 104,
a8 = 91,
a2 = 24,
a11 = 88]
1
2
3
4
5
6
7
8
9
10
11
arr = [ 10,24,119,7,104,43,28,91,108,52,88,74,88,33]

for i in range(12,-1,-1):
arr[i] = arr[i]^arr[i+1]

flag = ""
for i in arr:
flag += chr(i)
print(flag)
#U_G07_th3_k3y!
#flag{58964088b637e50d3a22b9510c1d1ef8}

[MRCTF2020]PixelShooter(apk逆向/C#逆向)

这次又换了一个安卓逆向工具:jeb

听大佬说安卓Unity游戏核心逻辑一般位于assets\bin\Data\Managed\Assembly-CSharp.dll中

进入之后,搜索字符串就出来了

如果说是unity逆向,那么dnspy可以逆向出来啊,大佬能逆出来,为啥我逆不出来??

参考链接:

[FlareOn5]Ultimate Minesweeper (.NET逆向)

dotnet题,用dnSpy64打开

动调了许久,找不出门路,于是借鉴了大佬Hk_Mayfly的文章

首先是找到判断的主要函数处

跟进SquareRevealedCallback函数,可以发现前面的if语句中输出了结束信息以及程序结束的函数,那么后面的getkey函数就是输出我们flag的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Token: 0x0600000D RID: 13 RVA: 0x000023E4 File Offset: 0x000005E4
private string GetKey(List<uint> revealedCells)
{
revealedCells.Sort();
Random random = new Random(Convert.ToInt32((revealedCells[0] << 20) | (revealedCells[1] << 10) | revealedCells[2]));
byte[] array = new byte[32];
byte[] array2 = new byte[]
{
245, 75, 65, 142, 68, 71, 100, 185, 74, 127,
62, 130, 231, 129, 254, 243, 28, 58, 103, 179,
60, 91, 195, 215, 102, 145, 154, 27, 57, 231,
241, 86
};
random.NextBytes(array);
uint num = 0U;
while ((ulong)num < (ulong)((long)array2.Length))
{
byte[] array3 = array2;
uint num2 = num;
array3[(int)num2] = array3[(int)num2] ^ array[(int)num];
num += 1U;
}
return Encoding.ASCII.GetString(array2);
}

我们将SquareRevealedCallback函数中的if语句注释掉,就不会弹出失败信息了,右键,编辑方法。

接着是将文件保存,ctrl+shift+s,选择一个目录保存

然后打开文件,找到关键点

后面一次点击这3个点,就可以成功输出flag

flag{Ch3aters_Alw4ys_W1n@flare-on.com}

参考

[网鼎杯 2020 青龙组]jocker [混淆+动调]

又遇到了混淆题……

一眼就看出来前面的是假把戏,只有最后的encrypt才是真正的加密函数,还进行了混淆。

上idc代码:

1
2
3
4
5
6
7
8
#include <idc.idc>
static main(){
auto addr = 0x401500;
auto i;
for(i = 0;i <= 186;i++){
PatchByte((addr+i),(addr+i)^0x41);
}
}

在运行idc代码之后,修改一下函数,再跳过for循环,应用补丁,删除ida数据库,重新加载后,呈现出来的mian函数就是这样:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str[50]; // [esp+12h] [ebp-96h] BYREF
char Destination[80]; // [esp+44h] [ebp-64h] BYREF
DWORD flOldProtect; // [esp+94h] [ebp-14h] BYREF
size_t v7; // [esp+98h] [ebp-10h]
int v8; // [esp+9Ch] [ebp-Ch]

__main();
puts("please input you flag:");
if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
exit(1);
scanf("%40s", Str);
v7 = strlen(Str);
if ( v7 != 24 )
{
puts("Wrong!");
exit(0);
}
strcpy(Destination, Str);
wrong(Str);
omg(Str);
v8 = 0;
if ( encrypt(Destination) )
finally(Destination);
return 0;
}

再稍微修改一下encrypt函数,以及函数的范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl encrypt(char *a1)
{
int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREF
int v3; // [esp+68h] [ebp-20h]
int i; // [esp+6Ch] [ebp-1Ch]

v3 = 1;
qmemcpy(v2, &unk_403040, sizeof(v2));
for ( i = 0; i <= 18; ++i )
{
if ( (char)(a1[i] ^ aHahahahaDoYouF[i]) != v2[i] )
{
puts("wrong ~");
v3 = 0;
exit(0);
}
}
puts("come here");
return v3;
}

还有finally函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl finally(char *a1)
{
unsigned int v1; // eax
char v3[9]; // [esp+13h] [ebp-15h] BYREF
int v4; // [esp+1Ch] [ebp-Ch]

strcpy(v3, "%tp&:");
v1 = time(0);
srand(v1);
v4 = rand() % 100;
v3[6] = 0;
*(_WORD *)&v3[7] = 0;
if ( (v3[(unsigned __int8)v3[5]] != a1[(unsigned __int8)v3[5]]) == v4 )
return puts("Really??? Did you find it?OMG!!!");
else
return puts("I hide the last part, you will not succeed!!!");
}

分析一下encrypt函数

input与ahh异或之后需要等于v2,动调一下v2

1
2
3
4
5
6
v2 = [0xe,0xd,0x9,0x6,0x13,0x5,0x58, 0x56, 0x3e, 0x06,0xc, 0x3c, 0x1f, 0x57, 0x14, 0x6b, 0x57, 0x59, 0xd]
ahh = "hahahaha_do_you_find_me?"
arr = []
for i in range(len(v2)):
arr.append(ord(ahh[i])^v2[i])
# flag{d07abccf8a410c

encrypt函数只能求出前19位,还有最后5位是在finally函数中

v3字符串是”%tp&:”,我们唯一可以确定的是最后一位是”}”,可以算出同一加密的key是多少

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
v2 = [0xe,0xd,0x9,0x6,0x13,0x5,0x58, 0x56, 0x3e, 0x06,0xc, 0x3c, 0x1f, 0x57, 0x14, 0x6b, 0x57, 0x59, 0xd]
ahh = "hahahaha_do_you_find_me?"
arr = []
for i in range(len(v2)):
arr.append(ord(ahh[i])^v2[i])
# flag{d07abccf8a410c

s = "%tp&:"
key = ord(":")^ord("}")
#71

for i in s:
arr.append(ord(i)^71)
flag = "".join([chr(i) for i in arr])
#flag{d07abccf8a410cb37a}

[GWCTF 2019]re3 (混淆+动调+AES)

findcrypt查看加密

再查看字符串,跟进成功的字符串

发现已被混淆

跟进此处,发现这是个函数,下面还调用了

查看反汇编窗口:

这些数据其实是代码,经过异或之后,变成代码执行

shift+F2 调用idc

1
2
3
4
5
6
7
8
#include <idc.idc>
static main(){
auto addr = 0x402219;
auto i;
for(i = 0;i<223;i++){
PatchByte(addr+i,Byte(addr+i)^0x99);
}
}

选中修改后的数据,按c,force,转换成代码,

xuanzsub_402219函数,修改函数的范围

tab键查看反汇编

我们再修改一下main函数的值

注意,修改完成之后,需要patch一下源程序,然后把ida数据库文件删除后,再用ida重新打开。而且在调试的时候,需要跳过中间的混淆函数

反汇编函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
int i; // [rsp+8h] [rbp-48h]
char s[40]; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+48h] [rbp-8h]

v5 = __readfsqword(0x28u);
__isoc99_scanf("%39s", s);
if ( (unsigned int)strlen(s) != 32 )
{
puts("Wrong!");
exit(0);
}
mprotect(&dword_400000, 0xF000uLL, 7);
for ( i = 0; i <= 223; ++i )
*((_BYTE *)sub_402219 + i) ^= 0x99u;
sub_40207B(&unk_603170);
if ( (unsigned int)sub_402219(s) )
puts("Correct!");
else
puts("Wrong!");
exit(0);
}

参考链接:

从后往前分析:

跟进最后的sub_402219函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__int64 __fastcall sub_402219(__int64 a1)
{
unsigned int v2; // [rsp+18h] [rbp-D8h]
int i; // [rsp+1Ch] [rbp-D4h]
char v4[200]; // [rsp+20h] [rbp-D0h] BYREF
unsigned __int64 v5; // [rsp+E8h] [rbp-8h]

v5 = __readfsqword(0x28u);
sub_400A71(v4, &unk_603170);
sub_40196E(v4, a1);
sub_40196E(v4, a1 + 16);
v2 = 1;
for ( i = 0; i <= 31; ++i )
{
if ( *(_BYTE *)(i + a1) != byte_6030A0[i] )
v2 = 0;
}
return v2;
}

sub_40196E是AES加密,sub_400A71是生成轮密钥,最后对比的byte_6030A0的值可以动调出来:

1
byte_6030A0 = 0xBC0AADC0147C5ECCE0B140BC9C51D52B46B2B9434DE5324BAD7FB4B39CDB4B5B

现在我们需要知道作为轮密钥的unk_603170的值

分析sub_402219上面的sub_40207B函数

sub_401CF9函数,将base64的表传入,赋值给v2

最下面的一个函数sub_401CF9,传入参数unk_603170和v2

动调unk_603170的值。sub_402219中,unk_603170作为二参传入sub_400A71函数中

分析其反汇编,因为参数传递是从右往左传递,通过ida动调,就能得知unk_603170

shift+e数据提取

1
unk_603170 = 0xcb8d493521b47a4cc1ae7e62229266ce
  1. Base64表经过sub_40207B函数两次加密,传入unk_603170
  2. 使用unk_603170作为轮回密钥,进行AES加密
  3. 结果与byte_6030A0比较

代码参考:

1
2
3
4
5
6
7
from Crypto.Cipher import AES
from Crypto.Util.number import *
key = long_to_bytes(0xcb8d493521b47a4cc1ae7e62229266ce)
crypto = long_to_bytes(0xbc0aadc0147c5ecce0b140bc9c51d52b46b2b9434de5324bad7fb4b39cdb4b5b)
lun = AES.new(key, mode=AES.MODE_ECB)
flag = lun.decrypt(crypto)
print(flag)

[RCTF2019]DontEatMe

迷宫题:

[红帽杯2019] xx

上来先用findcrypt插件识别一下加密算法

先是判断输入字符串长度是否等于19

动调后可以看出,xxtea加密上面的代码,就是把输入字符串第四个后面的所有元素赋值为0,并把这四个字符作为二参,作为密钥,进入到xxtea加密算法中

1
2
3
4
四参:"qwertyuiopasdfghjklzxcvbnm1234567890"字符串地址
三参:0x13
二参:0x00000001000FF998 地址
一参:0x00000001000FF9B0

然后是对xxtea加密后的算法进行混淆

然后是进行异或操作:

最后是进行对比

正向:

—->输入字符串(19位)

—->取前面输入的前4位作为xxtea算法密钥

—->xxtea算法加密

—->加密字符串后进行打乱置换

—->对打乱之后的数组进行异或

—->对比16进制数组

逆向:

—->得到最后对比的16进制数组

—->异或

—->恢复置换

—->xxtea解密

—->得到输入字符串

因为是小端序,最后对比的16进制数组应该是:

1
data =[0xCE,0xBC,0x40,0x6B,0x7C,0x3A,0x95,0xC0,0xEF,0x9B,0x20,0x20,0x91,0xF7,0x02,0x35,0x23,0x18,0x02,0xC8,0xE7,0x56,0x56,0xFA] 

动调了一下异或,发现第一次和第二次都没有异或,第三次才异或,而且越往后,内层异或次数越多。i在外层递增遍历数组v20,i/3的值越大,内层v20[j]与v20[i]的异或次数i/3越多。下面是c的正向伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
for ( i = 1; i < 24; ++i )
{
j = 0;
if ( i / 3 > 0 )
{
do
{
v20[i] ^= v20[j++];
}
while ( j < i / 3 );
}
}

下面是逆向的python代码:

1
2
3
for i in range(len(data)-1,-1,-1):
for j in range(i//3):
data[i] ^= data[j]

数组置换代码:

1
2
3
4
5
table = {0:2,1:0,2:3,3:1,4:6,5:4,6:7,7:5,8:10,9:8,10:11,11:9,12:14,13:12,14:15,15:13,16:18,17:16,18:19,19:17,20:22,21:20,22:23,23:21}

data1 = [0]*len(table)
for i in range(len(table)):
data1[table[i]] = data[i]
1
data1 = [0xbc, 0xa5, 0xce, 0x40, 0xf4, 0xb2, 0xb2, 0xe7, 0xa9, 0x12, 0x9d, 0x12, 0xae, 0x10, 0xc8, 0x5b, 0x3d, 0xd7, 0x6, 0x1d, 0xdc, 0x70, 0xf8, 0xdc]

xxtea 加密 python2代码

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
import struct  

_DELTA = 0x9E3779B9

def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n): return ''
n = m
s = struct.pack('<%iL' % len(v), *v)
return s[0:n] if w else s

def _str2long(s, w):
n = len(s)
m = (4 - (n & 3) & 3) + n
s = s.ljust(m, "\0")
v = list(struct.unpack('<%iL' % (m >> 2), s))
if w: v.append(n)
return v

def encrypt(str, key):
if str == '': return str
v = _str2long(str, True)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
sum = 0
q = 6 + 52 // (n + 1)
while q > 0:
sum = (sum + _DELTA) & 0xffffffff
e = sum >> 2 & 3
for p in xrange(n):
y = v[p + 1]
v[p] = (v[p] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
z = v[p]
y = v[0]
v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff
z = v[n]
q -= 1
return _long2str(v, False)

def decrypt(str, key):
if str == '': return str
v = _str2long(str, False)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
q = 6 + 52 // (n + 1)
sum = (q * _DELTA) & 0xffffffff
while (sum != 0):
e = sum >> 2 & 3
for p in xrange(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
y = v[p]
z = v[n]
v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
y = v[0]
sum = (sum - _DELTA) & 0xffffffff
return _long2str(v, True)

if __name__ == "__main__":
key = "flag"
data1 = [0xbc,0xa5,0xce,0x40,0xf4,0xb2,0xb2,0xe7,0xa9,0x12,0x9d,0x12,0xae,0x10,0xc8,0x5b,0x3d,0xd7,0x6,0x1d,0xdc,0x70,0xf8,0xdc]
s = "".join(map(chr, data1))
s = decrypt(s, key)
print(repr(s))
# flag = b'flag{CXX_and_++tea}'
# flag = encrypt(flag,key)
# print(flag)

[虎符2022 未完] fpbe

查看官方wp,发现使用的是另一款基于java的反汇编器:Ghidra

插件也下载好了,就是不会安装……没有在file下面找到extension

[GUET CTF2019] encrypt RC4/elf动调/base64分块

写在前面:关于elf的动调

把ida目录下dbgsrv的两个linux_server拖到linux需要调试的文件的文件夹中

运行相关格式的linux_server

返回ida中,选择remote linux debugger,F9,选择相应配置

在程序开始的地方打上断点,按F9,就可以动调了(操作与其他动调工具一致)

这道题是关于RC4的加密算法

算法共有三个步骤

  1. S列表和T向量的初始值,同时建立一个临时变量T,将密钥的值循环赋值到T数组中
  2. S的初始置换
  1. 生成密码流

查看main函数

题目中给出了密钥v10数组,并作为二参进入了函数sub_4006B6

跟进sub_4006B6函数,其融合了RC4加密算法的第一二步骤

将v9(以下统称S)数组中元素的值按升序置为0-255,题目中没有明显的赋值T向量,但效果一致

接下来就是swap(),打乱S数组了

展示一下打乱前和打乱后的S数组(大可不必)

打乱前:

打乱后:

跟进sub_4007DB函数,与RC4有所出入的是生成的 k(v9[(v7 + v8)])直接与明文(s)异或了

正向:s –> k

​ k ^ 明文 ==> 密文

逆向:密文 ^ k ==> 明文

所以我们只需要求等式右边的k值,与密文异或,就能求出明文了(很多wp上来就是求数组S,说实话没啥用,因为k就是通过S生成的,S则是通过递增数组和密钥T数组生成的,当然也是可以求出来的)

动调elf文件,跟进sub_4007D8函数,光标放在22行,查看反汇编界面,rdx是异或之前的数,在其处下断点,一直F9,将k数组统计出来

1
k = [0x10,0x59,0x9C,0x92,0x06,0x22,0xCF,0xA5,0x72,0x1E,0x45,0x6A,0x06,0xCB,0x08,0xC3,0xE4,0x49,0x5A,0x63,0x0C,0xDF,0xF6,0x5F,0x08,0x28,0xBD,0xE2,0x10,0x15,0x1F,0x6E,0xAA,0x5A,0xCA,0xEC,0x80,0xAF,0x9B,0x16,0xBB,0x3D,0x13,0x2F,0x6A,0xA4,0xC7,0x2E,0xBC,0x4B,0x60,0x9A,0xAF,0xE9,0xCE,0xDA,0x67,0x39,0xBA,0x3B,0x85,0xEB,0xD2,0x6B,0xAB,0x06,0x6B,0x10,0x57,0x2C,0x88,0x70,0xF7,0x4F,0xAA,0x7F,0x12,0x47,0xD6,0xDE,0x74,0xB2,0x1D,0xA4,0xD7,0x76,0x9A,0xE0]

现在我们需要求的是密文,我们跟进下面的函数

这边很眼熟,在base64加密中看见过,将3位字符,转换成4位字符

正向:rc4加密后的字符每4位转换成3位

逆向:最后对比的byte_602080字符,每3位转换成4位

shift+e数据提取(漏了一位,记得手动添上)

脚本参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data = [0x5a, 0x60, 0x54, 0x7A, 0x7A, 0x54, 0x72, 0x44,0x7C, 0x66, 0x51, 0x50, 0x5B, 0x5F, 0x56, 0x56,0x4C, 0x7C, 0x79, 0x6E, 0x65, 0x55, 0x52, 0x79,0x55, 0x6D, 0x46, 0x6B, 0x6C, 0x56, 0x4A, 0x67,0x4C, 0x61, 0x73, 0x4A, 0x72, 0x6F, 0x5A, 0x70,0x48, 0x52, 0x78, 0x49, 0x55, 0x6C, 0x48, 0x5C,0x76, 0x5A, 0x45, 0x3D]
string = ''
for i in range(0,len(data),4):
string += chr((((data[i]-0x3D)&0x3F)<<2)|(((data[i+1]-0x3D)&0x30)>>4))
string += chr((((data[i+1]-0x3D)&0x0F)<<4)|(((data[i+2]-0x3D)&0x3C)>>2))
string += chr(((data[i+3]-0x3D)&0x3F)|((data[i+2]-0x3D)&0x03)<<6)

k = [0x10,0x59,0x9C,0x92,0x06,0x22,0xCF,0xA5,0x72,0x1E,0x45,0x6A,0x06,0xCB,0x08,0xC3,0xE4,0x49,0x5A,0x63,0x0C,0xDF,0xF6,0x5F,0x08,0x28,0xBD,0xE2,0x10,0x15,0x1F,0x6E,0xAA,0x5A,0xCA,0xEC,0x80,0xAF,0x9B,0x16,0xBB,0x3D,0x13,0x2F,0x6A,0xA4,0xC7,0x2E,0xBC,0x4B,0x60,0x9A,0xAF,0xE9,0xCE,0xDA,0x67,0x39,0xBA,0x3B,0x85,0xEB,0xD2,0x6B,0xAB,0x06,0x6B,0x10,0x57,0x2C,0x88,0x70,0xF7,0x4F,0xAA,0x7F,0x12,0x47,0xD6,0xDE,0x74,0xB2,0x1D,0xA4,0xD7,0x76,0x9A,0xE0]
arr = list(string)

flag=''
for i in range(len(arr)):
flag += chr(ord(arr[i])^k[i])

print(flag)

太强了……改天得研究一下这个脚本是怎么写的

[HDCTF] MFC (Win消息发送+DES加密)

刚开始用的火绒剑,感觉没啥用

去下了个spy类工具,用来查看windows的窗口,消息和进程等等

这边用的是大佬推荐的CometAssistant,彗星小助手

还去下载了一个spy++ (但是看着有点膈应人)

关于xspy的使用很简单,只需要把这个放大镜拖动放到需要嗅探的窗口中就可以了

突破口在这边,当然也涉及我的知识盲区了:向窗口发送信息

这边直接把大佬博客里的代码贴过来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main()
{
HWND h = ::FindWindowA(NULL, "Flag就在控件里");
if (h)
{
SendMessage(h, 0x464, NULL, NULL);
}
else{
printf("false");
}

system("pause");
return 0;
}

分析一下:

首先Win32 API的使用需要导入Windows.h的库

FindWindowA:检索其类名和窗口名与指定字符串匹配的顶级窗口的句柄。此函数不搜索子窗口。此函数不执行区分大小写的搜索。返回值是一个窗口句柄。一参是窗口的类名,可为空。二参是窗口的标题名称。

SendMessage:将指定的消息发送到一个或多个窗口。SendMessage函数调用指定窗口的窗口过程,直到窗口过程处理完消息后才返回。

贴上详细解释,长话短说就是一参是接受窗口的句柄,二参是指定被发送的消息,三四参数是附加消息指定信息。

这个窗口的窗口名称为“Flag就在控件中”,我们就去寻找这个窗口的句柄,并赋值为h。

找到句柄之后我们向其发送一个数字:0x464(至于为什么要发送0x464,还得让我琢磨琢磨……)

当发送完数字之后,窗口变了

DES是一个常见的分组加密形式,需要一个密钥+明文==>明文

貌似这个名字就是明文了

1
2
crypto: 944c8d100f82f0c18b682f63e4dbaa207a2f1e72581c2f1b
key: {I am a Des key}

flag{thIs_Is_real_kEy_hahaaa}

[CISCN2018]2ex (base64换表)

啊这……

放到ida中,这个字符很起疑心:

长度竟然为64?base64换表走起:

1
2
3
4
5
6
7
8
9
10
11
12
13
import base64

string = "|_r-+_Cl5;vgq_pdme7#7eC0="

new_base = "@,.1fgvw#`/2ehux$~\"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD"

base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

flag = base64.b64decode(string.translate(str.maketrans(new_base,base)))

print(flag)

#b'flag{change53233})'

CTFtools也成,得把表中的转义字符\给去掉才行

(太棒了,水了一题)

[安洵杯 2019]crackMe (SM4+base64魔改+hook)

搞不懂为什么我运行不起来,修复了半天,去装了个win7

运行之后,应该是这样的界面:

猜测这道题的考点是hook

正向:

——–>base64表大小写转换

——–>SM4加密(key = “where_are_you_now?”)

——–>SM4加密后,密码相邻位互换

——–>base64表,先进行大小写转换,再进行(a1+24)%64转换[相当于把字母表向左移动了24位]

——–>base64解密

逆向

——–>base64表转换(大小写与移位)

——–>加密字符转换(相邻位置互换)

——–>base64换表解密

——–>SM4解密(需要pysm4的包)

这道base64是用”!”,来替换’=’ ,先来转换base64的表:

1
2
3
4
5
6
7
8
9
base = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
for i in range(64):
#
base[i] = base[i].swapcase()
print(''.join(base))

new_base = [base[(i+24)%64] for i in range(len(base))]
print(''.join(new_base))
# new_base = yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx

再把需要转换的字符两两转换,换表base64解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import base64
base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
new_base = "yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx"

raw_string = list("1UTAOIkpyOSWGv/mOYFY4R!!".replace("!","="))
# 1UTAOIkpyOSWGv/mOYFY4R==

for i in range(0,len(raw_string),2):
raw_string[i],raw_string[i+1] = raw_string[i+1],raw_string[i]
# U1ATIOpkOyWSvGm/YOYFR4==

string = "".join(raw_string)
s = base64.b64decode(string.translate(str.maketrans(new_base,base)))
print(list(s))
# [89, 208, 149, 41, 13, 242, 64, 6, 20, 244, 141, 39, 105, 6, 135, 78]

# 字符串转换成16进制
hex_s = binascii.b2a_hex(s)
print(hex_s)
# b'59d095290df2400614f48d276906874e'

然后把生成的两个16进制数:需要解密的数hex_key以及轮回秘钥hex_s,放到SM4解密函数decode()中解密,将生成的Int类型数字,转换成16进制,再转换成bytes类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import binascii
from pysm4 import encrypt,decrypt
key = "where_are_u_now?"
hex_key = hex(binascii.b2a_hex(key.encode('utf-8')))
# b'77686572655f6172655f755f6e6f773f'

hex_s = 0x59d095290df2400614f48d276906874e
hex_key = 0x77686572655f6172655f755f6e6f773f

clear_num = decrypt(cipher_num, mk)
# clear_num = 110726793309279461591673877471154814753
# 将生成的int型结果转换成16进制字符串
# 再将16进制字符串去除头两位,转换成bytes类型
# 最后再将bytes类型编码
print('flag{'+bytes.fromhex(hex(clear_num)[2:]).decode()+'}')

# flag{SM4foRExcepioN?!}

参考链接:http://81.69.232.121/%E5%AE%89%E6%B4%B5%E6%9D%AF-2019crackme-%E6%88%91%E4%BA%BA%E5%82%BB%E4%BA%86/

[WUSTCTF2020]level4 (idc or 算法)

没想到这题竟然有三种解法,之前写这篇的时候,没有深入的研究:

ida打开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl main(int argc, const char **argv, const char **envp)
{
puts("Practice my Data Structure code.....");
puts("Typing....Struct.....char....*left....*right............emmmmm...OK!");
init("Typing....Struct.....char....*left....*right............emmmmm...OK!", argv);
puts("Traversal!");
printf("Traversal type 1:");
type1(&unk_601290);
printf("\nTraversal type 2:");
type2(&unk_601290);
printf("\nTraversal type 3:");
puts(" //type3(&x[22]); No way!");
puts(&byte_400A37);
return 0;
}

跟进type1:

1
2
3
4
5
6
7
8
9
10
11
__int64 __fastcall type1(char *a1)
{
__int64 result; // rax

if ( a1 )
{
type1(*((_QWORD *)a1 + 1));
putchar(*a1);
return type1(*((_QWORD *)a1 + 2));
}
return result;

跟进type2:

1
2
3
4
5
6
7
8
9
10
11
int __fastcall type2(char *a1)
{
int result; // eax

if ( a1 )
{
type2(*((_QWORD *)a1 + 1));
type2(*((_QWORD *)a1 + 2));
return putchar(*a1);
}
return result;

两个递归调用,可以确定type1是中序遍历二叉树,type2是后序遍历二叉树,我们需要做的就是通过type1,type2,我们可以尝试还原出二叉树的构造。

方法一:

手算,如果二叉树太大,耗时耗力。

方法二:

可以猜测出flag应为前序遍历,使用idc脚本编写

跟进type2,查看反汇编代码,发现只需要调整代码块的位置,就使type2函数变成前序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static main()
{
auto address1=0x4007CA;
auto address2=0x4007EA;
auto address3=0x4007FB;
auto code1="";
auto i=0,j=0;

for(i=address1;i<address2;i++)
{
code1=code1+Byte(i);
}

j=address1;
for(i=address2;i<address3;i++)
{
PatchByte(j++,Byte(i));
}

for(i=0;i<strlen(code1);i++)
{
PatchByte(j++,ord(code1[i]));
}
}

在计算机中,汇编指令和数据其实都是一码事,都是二进制代码,为了方便使用的是16进制数,一个字节8位,使用的是两个十六进制数。Byte是根据给出的虚拟地址,取一个字节,PatchByte则是用二参的字节去patch一参的地址。

idc代码就是把address1-address2处的字节与address2-address3的字节交换

可以在这边输入6,可以看到指令的字节

选中代码,右键分析,强制执行之后:

改变前:

改变后:

别的大佬的博客用的都是keypatch插件,我是直接把对应地址的call指令重新patch了

最后,把patch完的程序,apply patches to应用

出来了:

方法三:

上手C++代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
char post[] = "20f0Th{2tsIS_icArE}e7__w"; // 后序遍历结果
char mid[] = "2f0t02T{hcsiI_SwA__r7Ee}"; // 中序遍历结果
void pre(int root, int start, int end)
{
if (start > end)
return;
int i = start;
while (i < end && mid[i] != post[root]) i++; //定位根在中序的位置
cout << mid[i]; //访问当前处理的树的根
pre(root - 1 - (end - i), start, i - 1); //递归处理左子树
pre(root - 1, i + 1, end); //递归处理右子树
}
int main()
{
pre(24, 0, 24);
return 0;
}


#flag{This_IS_A_7reE}

感谢师傅送我的代码!!

[CFI-CTF 2018]IntroToPE (.NET逆向)

打开看一下:

查个壳,这让我有点害怕,第一次遇到带红的

1
2
Big sec. 1 .text ,  Explore and analyze .NET assemblies with .NET Reflector v10 - www.red-gate.com
- IF file is packed try .NET Generic unpacker : www.quequero.org/Pack_Unpack

还去下载了.net Reflector 和 .NET Generic unpacker

我们直接用dnSpy打开,

找到对应的函数

热泪盈眶

[GXYCTF2019]simple CPP (z3+反调试+动调)

这题折磨的我没有脾气……

先查个壳,C++逆向,据我所知,c++的题目,一般都得调试……

瞧瞧这是人看的题目么

main函数中,还出现了反调试函数,调试会崩,需要打补丁。我用ida调试了很久,太菜,无果……

题目的意思是将输入的字符转换成16进制字符串,假设输入abc,则字符串为616263

我们需要求出v20数组

用x,y,z,w分别代表v20[0]~v20[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
v20[3] = w

v20[2] = z

v20[1] = y

v20[0] = x

v41 = v20[2] = z

v21 = v20[1] = y

v22 = v20[0] = x

v24 = v21 & v22 = x & y

v25 = z & ~x = 0x11204161012

v26 = ~v21 = ~y

v27 = v41 & v26 = z & ~y

v28 = x & ~y

v23[0] = v21 & v22 = x & y

v23[1] = v25 = z & ~x =

v23[2] = v41 & v26 = z & ~y

v23[3] = v28 = x & ~y


v29 = v25 | v24 | v27 | v28
= (z & ~x)|(x & y)|(z & ~y)|(x & ~y)


v30 = y

v31 = z

v32 = v27 & *v20 | v31 & (v24 | v30 & ~*v20 | ~(v30 | *v20))
==> (z & ~y) & x | z & (x & y | y & ~(x)) | ~(y | x)
==> 0x8020717153E3013


v33 = v29 ==> (z & ~x)|(x & y)|(z & ~y)|(x & ~y)
==> 0x3E3A4717373E7F1F


(v29 ^ v20[3]) == 0x3E3A4717050F791F
==> ((z & ~x)|(x & y)|(z & ~y)|(x & ~y))^ w



v3 = v33

(v25 | v24 | v30 & v31) == (~v20[0] & v31 | 0xC00020130082C0Ci64) && v33

==> 0x11204161012 | (x & y) | (y & z) == ((~x & z) | 0xC00020130082C0C) && 0x3E3A4717373E7F1F

在Z3中,只有BitVecs可以进行位运算

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
# -*- coding:utf-8 -*-

from z3 import *

x,y,z,w=BitVecs('x y z w',64)

s=Solver()

s.add(z & ~x == 0x11204161012)

s.add(((z & ~y) & x | z & (x & y | y & ~(x)) | ~(y | x)) == 0x8020717153E3013)

s.add(((z & ~x)|(x & y)|(z & ~y)|(x & ~y)) == 0x3E3A4717373E7F1F)

s.add(0x11204161012 | (x & y) | (y & z) == ((~x & z) | 0xC00020130082C0C))

s.add((((z & ~x)|(x & y)|(z & ~y)|(x & ~y))^ w ) == 0x3E3A4717050F791F)

s.check()

m = s.model()

for i in m:
print("%s = 0x%x"%(i,m[i].as_long()))
y = 0xcdc5bae9f8c9acec
x = 0x3e3a460533286f0d
w = 0x32310600
z = 0x8020717153e3013

然而我的代码和大佬的代码运行结果只有一个变量不一致……

1
2
3
4
y = 0xc00020130082c0c
x = 0x3e3a460533286f0d
w = 0x32310600
z = 0x8020717153e3013

在动调中发现了这些字符

下面的代码是大佬的代码,我实在没有搞懂lis中0x8c之后的十六进制数是哪里来的……

1
2
3
4
5
6
7
flag = ''
lis = [0x3E,0x3A,0x46,0x05,0x33,0x28,0x6F,0x0D,0x8C,0x00,0x8A,0x09,0x78,0x49,0x2C,0xAC,0x08,0x02,0x07,0x17,0x15,0x3E,0x30,0x13,0x32,0x31,0x06]
string = 'i_will_check_is_debug_or_noi_wil'

for i in range(len(lis)):
flag += chr(lis[i] ^ ord(string[i]))
print(flag)

We1l_D0näeéb’ _ólgebra_am_i

第二部分的解,比赛的时候已经给出e!P0or_a

所以flag{We1l_D0ne!P0or_algebra_am_i}

参考链接:https://blog.csdn.net/mcmuyanga/article/details/113628506

[FlareOn1]Bob Doge (.net逆向+dnspy逆向)

先查个壳,发现没有壳,c++编写

运行一下,发现是个安装的程序

安装成功之后,会在安装目录下,生成一个.exe文件,我们再扫个壳,这边就能看出来是C#编写的.net程序了

(麻了,我还以为要逆向安装程序,给我ida给我看呆了)

点击decode之后变成了doge,哈哈哈

我们放到dnSpy中进行反编译

找到加密函数之后,text3就是flag

断点打在加密函数最后的text3处,F5运行到这边,flag就出来了

(我跟个憨憨一样用逆向算法算了半天还没算出来……)

[SWPU2019]ReverseMe (od动调plus)

首先是查壳:

因为是c++编写的,ida静态分析难度较大,所以选择od动调分析:

快过来熟悉一下od的操作!!!

首先通过中文搜索引擎跳转到提示性语句:

可以确定的是call语句的下一条cmp指令,与0x20,也就是32,决定是否跳转,也就是0x20是长度

我们输入一个符合条件的数值,继续向下调试。我这边输入了32个1

可以看到,在执行lea语句后,esi被赋值成”SWPU_2019_CTF”

这边是与输入字符进行异或,ord(1) ^ ord(S) = ord(‘b’)

可以在循环之外下断点,然后F9快速跳到断点出,再往下看,下面则是把数据依次压入栈:

再往下看,遇到一个函数,我们进入一个函数

F7跟进,我们遇到了xor,从0xae58b8地址读取数据赋给ecx,进行异或

选中下面的框框,我们选择在数据窗口中跟随地址

就能看到是什么数据进行对比了

1
string2 = [0x86,0x0C,0x3E,0xCA,0x98,0xD7,0xAE,0x19,0xE2,0x77,0x6B,0xA6,0x6A,0xA1,0x77,0xB0,0x69,0x91,0x37,0x05,0x7A,0xF9,0x7B,0x30,0x43,0x5A,0x4B,0x10,0x86,0x7D,0xD4,0x28]

跳出这个函数之后,接着往下看:

开始了第三次异或,和第二次一样,我们只需要找这个地址的数据就行了

继续跟随数据窗口,跳转如下,我们找到了需要最终对比的数据了:

1
final = [0xB3,0x37,0x0F,0xF8,0xBC,0xBC,0xAE,0x5D,0xBA,0x5A,0x4D,0x86,0x44,0x97,0x62,0xD3,0x4F,0xBA,0x24,0x16,0x0B,0x9F,0x72,0x1A,0x65,0x68,0x6D,0x26,0xBA,0x6B,0xC8,0x67]

最终脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
# 正  final[i] = input[i]^string1[i%13]^string2[i]
# 逆 input[i] = final[i]^string1[i%13]^string2[i]

string1 = "SWPU_2019_CTF"
string2 = [0x86,0x0C,0x3E,0xCA,0x98,0xD7,0xAE,0x19,0xE2,0x77,0x6B,0xA6,0x6A,0xA1,0x77,0xB0,0x69,0x91,0x37,0x05,0x7A,0xF9,0x7B,0x30,0x43,0x5A,0x4B,0x10,0x86,0x7D,0xD4,0x28]
final = [0xB3,0x37,0x0F,0xF8,0xBC,0xBC,0xAE,0x5D,0xBA,0x5A,0x4D,0x86,0x44,0x97,0x62,0xD3,0x4F,0xBA,0x24,0x16,0x0B,0x9F,0x72,0x1A,0x65,0x68,0x6D,0x26,0xBA,0x6B,0xC8,0x67]

flag = ""

for i in range(32):
flag += chr(final[i] ^ ord(string1[i%13]) ^ string2[i])
print(flag)

flag{Y0uaretheB3st!#@_VirtualCC}

参考:

https://blog.nowcoder.net/n/aa8086cbf8c54e3b8dd49c52e2fcefe0?from=nowcoder_improve

[SCTF2019]babyre (花指令+三维迷宫+暗藏base64+???)

ida打开后一瞅,我就知道事情不简单

发现了海量的花指令

第一处:

修改之后

第二处,下面的jrcxz也需要nop掉(细节上出问题后面就得重修……)

第三处:

第四处:

E13处,in指令第二个字节C7是mov指令,就需要去把第一个字节给nop掉了

第五处:

所以说,一共 是五处花指令?

下面是转换main函数,快捷键P

这边的话,先d键,转换为数据,再c键,force转换为代码

(注意,需要把所有的花指令修完之后,再去转换main函数和C22函数,重复了n次,每次都再C22处JUMPOUT)

选中798到C21,按P键转换成函数,还原main函数

这边也类似,选中到c22,按住P键,就可以把刚刚的loc_C22声明成函数,之后就可以F5反汇编了

以下就是成功反汇编出的主函数:

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char v4; // [rsp+Fh] [rbp-151h]
int v5; // [rsp+10h] [rbp-150h]
int v6; // [rsp+14h] [rbp-14Ch]
char *v7; // [rsp+18h] [rbp-148h]
char v8[10]; // [rsp+26h] [rbp-13Ah] BYREF
_QWORD input3[2]; // [rsp+30h] [rbp-130h] BYREF
int v10; // [rsp+40h] [rbp-120h]
__int64 input2[3]; // [rsp+50h] [rbp-110h] BYREF
char v12; // [rsp+68h] [rbp-F8h]
__int64 v13[3]; // [rsp+70h] [rbp-F0h] BYREF
char v14; // [rsp+88h] [rbp-D8h]
__int64 input1[6]; // [rsp+90h] [rbp-D0h] BYREF
__int16 v16; // [rsp+C0h] [rbp-A0h]
char v17[136]; // [rsp+D0h] [rbp-90h] BYREF
unsigned __int64 v18; // [rsp+158h] [rbp-8h]

v18 = __readfsqword(0x28u);
v5 = 0;
memset(input2, 0, sizeof(input2));
v12 = 0;
memset(v13, 0, sizeof(v13));
v14 = 0;
memset(input1, 0, sizeof(input1));
v16 = 0;
strcpy(
v17,
"**************.****.**s..*..******.****.***********..***..**..#*..***..***.********************.**..*******..**...*..*.*.**.*");
input3[0] = 0LL;
input3[1] = 0LL;
v10 = 0;
v7 = &v17[22];
strcpy(v8, "sctf_9102");
puts((const char *)(unsigned int)"plz tell me the shortest password1:");
scanf("%s", input1);
v6 = 1;
while ( v6 )
{
v4 = *((_BYTE *)input1 + v5);
switch ( v4 )
{
case 'w':
v7 -= 5;
break;
case 's':
v7 += 5;
break;
case 'd':
++v7;
break;
case 'a':
--v7;
break;
case 'x':
v7 += 25;
break;
case 'y':
v7 -= 25;
break;
default:
v6 = 0;
break;
}
++v5;
if ( *v7 != 46 && *v7 != 35 )
v6 = 0;
if ( *v7 == 35 )
{
puts("good!you find the right way!\nBut there is another challenge!");
break;
}
}
if ( v6 )
{
puts((const char *)(unsigned int)"plz tell me the password2:");
scanf("%s", input2);
sub_C22(input2, v13);
if ( (unsigned int)sub_F67(v13, v8) == 1 )
{
puts("Congratulation!");
puts((const char *)(unsigned int)"Now,this is the last!");
puts("plz tell me the password3:");
scanf("%s", input3);
if ( (unsigned int)sub_FFA(input3) == 1 )
{
puts("Congratulation!Here is your flag!:");
printf("sctf{%s-%s(%s)}", (const char *)input1, (const char *)input2, (const char *)input3);
}
else
{
printf("something srong...");
}
return 0LL;
}
else
{
printf("sorry,somthing wrong...");
return 0LL;
}
}
else
{
printf("sorry,is't not a right way...");
return 0LL;
}
}

可以看出这是个迷宫题,而且看起来方向键很多,是三维迷宫,长度为125 = 5 * 5 * 5

1
2
3
4
5
6
7
8
9
10
11
12
maze = '**************.****.**s..*..******.****.***********..***..**..#*..***..***.********************.**..*******..**...*..*.*.**.*'

maze_3d = []
for i in range(25):
maze_3d.append(maze[5*i:5*(i+1)])

for i in range(1,len(maze_3d)+1):
for j in maze_3d[i]:
print(j,end = ' ')
print()
if i%5 == 0:
print()

得出:

1
input1 = 'ddwwxssxaxwwaasasyywwdd'

第二个挑战,就是每输入四个字符,就将其转换成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
#include <stdio.h>


unsigned int data[128] = {
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x3E, 0x7F, 0x7F, 0x7F, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, 0x7F, 0x7F, 0x7F, 0x40, 0x7F, 0x7F,
0x7F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
0x7F, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F
};

int main()
{
int shuju[3] = { 0x736374,0x665f39,0x313032 };
int i0, i1, i2, i3, i4, i5;
for (i0 = 0; i0 < 3; i0++)
{
for(i1=32;i1<128;i1++)
for (i2 = 32; i2 < 128; i2++)
for (i3 = 32; i3 < 128; i3++)
for (i4 = 32; i4 < 128; i4++)
{
i5 = (((((data[i1] << 6) | data[i2]) << 6) | data[i3]) << 6) | data[i4];
if (i5 == shuju[i0])
printf("第%d组:%c%c%c%c\n", i0+1,i1, i2, i3, i4);
}
}
return 0;
}

每个都带进入算了一遍,得知:

1
input2 = "c2N0Zl85MTAy"

麻了,每四位转换成3位,就是唯一不同的地方是,缺4补上@,就是base64加密啊……

最后进入第三个challenge,参考的是这位大佬

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
__int64 __fastcall sub_FFA(char *a1)
{
int v2; // [rsp+18h] [rbp-158h]
int i; // [rsp+18h] [rbp-158h]
int v4; // [rsp+1Ch] [rbp-154h]
unsigned int v5; // [rsp+24h] [rbp-14Ch]
unsigned int v6; // [rsp+28h] [rbp-148h]
unsigned int v7; // [rsp+2Ch] [rbp-144h]
int v8[16]; // [rsp+30h] [rbp-140h]
int v9[16]; // [rsp+70h] [rbp-100h]
int v10[26]; // [rsp+B0h] [rbp-C0h]
unsigned int v11; // [rsp+118h] [rbp-58h]
unsigned int v12; // [rsp+11Ch] [rbp-54h]
unsigned int v13; // [rsp+120h] [rbp-50h]
unsigned int v14; // [rsp+124h] [rbp-4Ch]
unsigned __int64 v15; // [rsp+168h] [rbp-8h]

v15 = __readfsqword(0x28u);
v8[0] = 190;
v8[1] = 4;
v8[2] = 6;
v8[3] = 128;
v8[4] = 197;
v8[5] = 175;
v8[6] = 118;
v8[7] = 71;
v8[8] = 159;
v8[9] = 204;
v8[10] = 64;
v8[11] = 31;
v8[12] = 216;
v8[13] = 191;
v8[14] = 146;
v8[15] = 239;
v5 = (a1[6] << 8) | (a1[5] << 16) | (a1[4] << 24) | a1[7];
v6 = (a1[10] << 8) | (a1[9] << 16) | (a1[8] << 24) | a1[11];
v7 = (a1[14] << 8) | (a1[13] << 16) | (a1[12] << 24) | a1[15];
v4 = 0;
v2 = 4;
v10[0] = sub_78A((a1[2] << 8) | (a1[1] << 16) | (*a1 << 24) | a1[3]);
v10[1] = sub_78A(v5);
v10[2] = sub_78A(v6);
v10[3] = sub_78A(v7);
do
{
v10[v2] = sub_143B(v10[v4], v10[v4 + 1], v10[v4 + 2], v10[v4 + 3]);
++v4;
++v2;
}
while ( v2 <= 29 );
v9[0] = HIBYTE(v11);
v9[1] = BYTE2(v11);
v9[2] = BYTE1(v11);
v9[3] = v11;
v9[4] = HIBYTE(v12);
v9[5] = BYTE2(v12);
v9[6] = BYTE1(v12);
v9[7] = v12;
v9[8] = HIBYTE(v13);
v9[9] = BYTE2(v13);
v9[10] = BYTE1(v13);
v9[11] = v13;
v9[12] = HIBYTE(v14);
v9[13] = BYTE2(v14);
v9[14] = BYTE1(v14);
v9[15] = v14;
for ( i = 0; i <= 15; ++i )
{
if ( v9[i] != v8[i] )
return 0xFFFFFFFFLL;
}
return 1LL;
}

跟进这个函数

因为v2 初始等于 4 , v4 初始等于 0 ,上面的代码就可以转换成:

v10[n+4] = v10[n] ^ function(v10[a+1] ^ v10[a+2] ^ v10[a+3])

根据交换律

==>v10[n] = v10[n+4] ^ function(v10[a+1] ^ v10[a+2] ^ v10[a+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
import libnum

v3 = [214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72, 198, 186, 177, 163, 80, 51, 170, 86, 151, 145, 125, 103, 220, 34, 112, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

def HIBYTE(a):
return a>>(8*3)
def BYTE2(a):
return (a>>(8*2))%256
def BYTE1(a):
return (a>>8)%256
def LOBYTE(a):
return a%256


def rol(value, time):
if (time == 0):
return value
a = (value & (1 << 31)) >> 31
value <<= 1
value &= (1 << 32) - 1
value += a
return rol(value, time - 1)

def ror(value, time):
if (time == 0):
return value
a = (value & (1)) << 31
value >>= 1
value += a
return ror(value, time - 1)

def sub_55B683001464(a):
v2 = (v3[BYTE2(a)]<<16)|v3[LOBYTE(a)]|(v3[BYTE1(a)]<<8)|(v3[HIBYTE(a)]<<24)

return rol(v2,12)^rol(v2,8)^ror(v2,2)^ror(v2,6)

def sub_55B68300143B(a, b, c, d):
return a ^ sub_55B683001464(b ^ c ^ d)

vx = [190,4,6,128,197,175,118,71,159,204,64,31,216,191,146,239]
v8 = []
for i in range(4):
x = vx[i*4]
x <<= 8
x += vx[i*4+1]
x <<= 8
x += vx[i*4+2]
x <<= 8
x += vx[i*4+3]
print(hex(x))
v8.append(x)

input = [0]*30
input[26] = v8[0]
input[27] = v8[1]
input[28] = v8[2]
input[29] = v8[3]
for i in range(26):
input[25-i] = input[25-i+4]^sub_55B683001464(input[25-i+3]^input[25-i+2]^input[25-i+1])

flag = ''

for i in range(4):
x = libnum.n2s(input[i]).decode()
x = list(x)
x.reverse()
x = ''.join(x)
flag += x

print(flag)

运行结果:

所以最后的flag为:

sctf{ddwwxxssxaxwwaasasyywwdd-c2N0Zl85MTAy(fl4g_is_s0_ug1y!)}

Ecquation (js fuck加密+z3)

http://codertab.com/JsUnFuck

题目中提示这个是Js的fuck加密,可以在网站上一个一个的解密,当然也可以用脚本跑

在网上找了一份关于此的解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
<script>
function deEquation(str) {
for (let i = 0; i <= 1; i++) {
str = str.replace(/l\[(\D*?)](\+l|-l|==)/g, (m, a, b) => 'l[' + eval(a) + ']' + b);
}
str = str.replace(/==(\D*?)&&/g, (m, a) => '==' + eval(a) + '&&');
return str;
}
s="l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[+!+[]]])&&l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]+l[+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+[]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]+l[+[]]==+(+!+[]+[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]])&&l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]])&&l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(+!+[]+[+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+[+!+[]+[!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]-l[+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]==+(+!+[]+[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]==-+(!+[]+!+[]+!+[]+[+!+[]+[!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+[]]+l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]])&&l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]==+(!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]+l[+!+[]+[!+[]+!+[]]]+l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(+!+[]+[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]+l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]]])&&l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]+l[!+[]+!+[]+!+[]+[+!+[]]]==+(+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==+(+!+[]+[+[]+[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]])&&l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]==+(!+[]+!+[]+!+[]+[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]]+l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[+[]]]==-+(+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+[]]-l[!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]]==-+(!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+[+!+[]+[!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]+l[!+[]+!+[]+!+[]]==-+(!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]-l[+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]+l[+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]])&&l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]+l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+[+!+[]+[!+[]+!+[]]])&&l[+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]])&&l[!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[+!+[]]]-l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]]-l[+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[+!+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]+l[+[]]+l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==+(+!+[]+[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]])&&l[+!+[]+[!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]==-+(+!+[]+[!+[]+!+[]+[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]])&&l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[+!+[]]]+l[+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]==-+(+!+[]+[+!+[]+[!+[]+!+[]+!+[]+!+[]]])&&l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]+l[+!+[]+[+!+[]]]+l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+[+[]]])&&l[+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]-l[+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]]+l[+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+!+[]+[+!+[]+[!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]+l[!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+[]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+!+[]+[+[]+[!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]])&&l[+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+[]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[+!+[]]-l[!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]])&&l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+!+[]]]-l[!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[+[]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]+l[!+[]+!+[]+[+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]==-+(+!+[]+[!+[]+!+[]])&&l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+[+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]]]-l[+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]]]-l[!+[]+!+[]+!+[]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]-l[!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]]]+l[+!+[]]-l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+[+!+[]]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[+!+[]+[+[]]]-l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+[!+[]+!+[]]]+l[!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]+l[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+l[+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]-l[!+[]+!+[]+!+[]+[+!+[]]]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[+!+[]])";
ss=deEquation(s);
document.write(ss);
</script>

解出来之后:

1
l[40]+l[35]+l[34]-l[0]-l[15]-l[37]+l[7]+l[6]-l[26]+l[20]+l[19]+l[8]-l[17]-l[14]-l[38]+l[1]-l[9]+l[22]+l[41]+l[3]-l[29]-l[36]-l[25]+l[5]+l[32]-l[16]+l[12]-l[24]+l[30]+l[39]+l[10]+l[2]+l[27]+l[28]+l[21]+l[33]-l[18]+l[4]==861&&l[31]+l[26]+l[11]-l[33]+l[27]-l[3]+l[12]+l[30]+l[1]+l[32]-l[16]+l[7]+l[10]-l[25]+l[38]-l[41]-l[14]-l[19]+l[29]+l[36]-l[9]-l[28]-l[6]-l[0]-l[22]-l[18]+l[20]-l[37]+l[4]-l[24]+l[34]-l[21]-l[39]-l[23]-l[8]-l[40]+l[15]-l[35]==-448&&l[26]+l[14]+l[15]+l[9]+l[13]+l[30]-l[11]+l[18]+l[23]+l[7]+l[3]+l[12]+l[25]-l[24]-l[39]-l[35]-l[20]+l[40]-l[8]+l[10]-l[5]-l[33]-l[31]+l[32]+l[19]+l[21]-l[6]+l[1]+l[16]+l[17]+l[29]+l[22]-l[4]-l[36]+l[41]+l[38]+l[2]+l[0]==1244&&l[5]+l[22]+l[15]+l[2]-l[28]-l[10]-l[3]-l[13]-l[18]+l[30]-l[9]+l[32]+l[19]+l[34]+l[23]-l[17]+l[16]-l[7]+l[24]-l[39]+l[8]-l[12]-l[40]-l[25]+l[37]-l[35]+l[11]-l[14]+l[20]-l[27]+l[4]-l[33]-l[21]+l[31]-l[6]+l[1]+l[38]-l[29]==-39&&l[41]-l[29]+l[23]-l[4]+l[20]-l[33]+l[35]+l[3]-l[19]-l[21]+l[11]+l[26]-l[24]-l[17]+l[37]+l[1]+l[16]-l[0]-l[13]+l[7]+l[10]+l[14]+l[22]+l[39]-l[40]+l[34]-l[38]+l[32]+l[25]-l[2]+l[15]+l[6]+l[28]-l[8]-l[5]-l[31]-l[30]-l[27]==485&&l[13]+l[19]+l[21]-l[2]-l[33]-l[0]+l[39]+l[31]-l[23]-l[41]+l[38]-l[29]+l[36]+l[24]-l[20]-l[9]-l[32]+l[37]-l[35]+l[40]+l[7]-l[26]+l[15]-l[10]-l[6]-l[16]-l[4]-l[5]-l[30]-l[14]-l[22]-l[25]-l[34]-l[17]-l[11]-l[27]+l[1]-l[28]==-1068&&l[32]+l[0]+l[9]+l[14]+l[11]+l[18]-l[13]+l[24]-l[2]-l[15]+l[19]-l[21]+l[1]+l[39]-l[8]-l[3]+l[33]+l[6]-l[5]-l[35]-l[28]+l[25]-l[41]+l[22]-l[17]+l[10]+l[40]+l[34]+l[27]-l[20]+l[23]+l[31]-l[16]+l[7]+l[12]-l[30]+l[29]-l[4]==939&&l[19]+l[11]+l[20]-l[16]+l[40]+l[25]+l[1]-l[31]+l[28]-l[23]+l[14]-l[9]-l[27]+l[35]+l[39]-l[37]-l[8]-l[22]+l[5]-l[6]+l[0]-l[32]+l[24]+l[33]+l[29]+l[38]+l[15]-l[2]+l[30]+l[7]+l[12]-l[3]-l[17]+l[34]+l[41]-l[4]-l[13]-l[26]==413&&l[22]+l[4]-l[9]+l[34]+l[35]+l[17]+l[3]-l[24]+l[38]-l[5]-l[41]-l[31]-l[0]-l[25]+l[33]+l[15]-l[1]-l[10]+l[16]-l[29]-l[12]+l[26]-l[39]-l[21]-l[18]-l[6]-l[40]-l[13]+l[8]+l[37]+l[19]+l[14]+l[32]+l[28]-l[11]+l[23]+l[36]+l[7]==117&&l[32]+l[16]+l[3]+l[11]+l[34]-l[31]+l[14]+l[25]+l[1]-l[30]-l[33]-l[40]-l[4]-l[29]+l[18]-l[27]+l[13]-l[19]-l[12]+l[23]-l[39]-l[41]-l[8]+l[22]-l[5]-l[38]-l[9]-l[37]+l[17]-l[36]+l[24]-l[21]+l[2]-l[26]+l[20]-l[7]+l[35]-l[0]==-313&&l[40]-l[1]+l[5]+l[7]+l[33]+l[29]+l[12]+l[38]-l[31]+l[2]+l[14]-l[35]-l[8]-l[24]-l[39]-l[9]-l[28]+l[23]-l[17]-l[22]-l[26]+l[32]-l[11]+l[4]-l[36]+l[10]+l[20]-l[18]-l[16]+l[6]-l[0]+l[3]-l[30]+l[37]-l[19]+l[21]+l[25]-l[15]==-42&&l[21]+l[26]-l[17]-l[25]+l[27]-l[22]-l[39]-l[23]-l[15]-l[20]-l[32]+l[12]+l[3]-l[6]+l[28]+l[31]+l[13]-l[16]-l[37]-l[30]-l[5]+l[41]+l[29]+l[36]+l[1]+l[11]+l[24]+l[18]-l[40]+l[19]-l[35]+l[2]-l[38]+l[14]-l[9]+l[4]+l[0]-l[33]==289&&l[29]+l[31]+l[32]-l[17]-l[7]+l[34]+l[2]+l[14]+l[23]-l[4]+l[3]+l[35]-l[33]-l[9]-l[20]-l[37]+l[24]-l[27]+l[36]+l[15]-l[18]-l[0]+l[12]+l[11]-l[38]+l[6]+l[22]+l[39]-l[25]-l[10]-l[19]-l[1]+l[13]-l[41]+l[30]-l[16]+l[28]-l[26]==-117&&l[5]+l[37]-l[39]+l[0]-l[27]+l[12]+l[41]-l[22]+l[8]-l[16]-l[38]+l[9]+l[15]-l[35]-l[29]+l[18]+l[6]-l[25]-l[28]+l[36]+l[34]+l[32]-l[14]-l[1]+l[20]+l[40]-l[19]-l[4]-l[7]+l[26]+l[30]-l[10]+l[13]-l[21]+l[2]-l[23]-l[3]-l[33]==-252&&l[29]+l[10]-l[41]-l[9]+l[12]-l[28]+l[11]+l[40]-l[27]-l[8]+l[32]-l[25]-l[23]+l[39]-l[1]-l[36]-l[15]+l[33]-l[20]+l[18]+l[22]-l[3]+l[6]-l[34]-l[21]+l[19]+l[26]+l[13]-l[4]+l[7]-l[37]+l[38]-l[2]-l[30]-l[0]-l[35]+l[5]+l[17]==-183&&l[6]-l[8]-l[20]+l[34]-l[33]-l[25]-l[4]+l[3]+l[17]-l[13]-l[15]-l[40]+l[1]-l[30]-l[14]-l[28]-l[35]+l[38]-l[22]+l[2]+l[24]-l[29]+l[5]+l[9]+l[37]+l[23]-l[18]+l[19]-l[21]+l[11]+l[36]+l[41]-l[7]-l[32]+l[10]+l[26]-l[0]+l[31]==188&&l[3]+l[6]-l[41]+l[10]+l[39]+l[37]+l[1]+l[8]+l[21]+l[24]+l[29]+l[12]+l[27]-l[38]+l[11]+l[23]+l[28]+l[33]-l[31]+l[14]-l[5]+l[32]-l[17]+l[40]-l[34]+l[20]-l[22]-l[16]+l[19]+l[2]-l[36]-l[7]+l[18]+l[15]+l[26]-l[0]-l[4]+l[35]==1036&&l[28]-l[33]+l[2]+l[37]-l[12]-l[9]-l[39]+l[16]-l[32]+l[8]-l[36]+l[31]+l[10]-l[4]+l[21]-l[25]+l[18]+l[24]-l[0]+l[29]-l[26]+l[35]-l[22]-l[41]-l[6]+l[15]+l[19]+l[40]+l[7]+l[34]+l[17]-l[3]-l[13]+l[5]+l[23]+l[11]-l[27]+l[1]==328&&l[22]-l[32]+l[17]-l[9]+l[20]-l[18]-l[34]+l[23]+l[36]-l[35]-l[38]+l[27]+l[4]-l[5]-l[41]+l[29]+l[33]+l[0]-l[37]+l[28]-l[40]-l[11]-l[12]+l[7]+l[1]+l[2]-l[26]-l[16]-l[8]+l[24]-l[25]+l[3]-l[6]-l[19]-l[39]-l[14]-l[31]+l[10]==-196&&l[11]+l[13]+l[14]-l[15]-l[29]-l[2]+l[7]+l[20]+l[30]-l[36]-l[33]-l[19]+l[31]+l[0]-l[39]-l[4]-l[6]+l[38]+l[35]-l[28]+l[34]-l[9]-l[23]-l[26]+l[37]-l[8]-l[27]+l[5]-l[41]+l[3]+l[17]+l[40]-l[10]+l[25]+l[12]-l[24]+l[18]+l[32]==7&&l[34]-l[37]-l[40]+l[4]-l[22]-l[31]-l[6]+l[38]+l[13]-l[28]+l[8]+l[30]-l[20]-l[7]-l[32]+l[26]+l[1]-l[18]+l[5]+l[35]-l[24]-l[41]+l[9]-l[0]-l[2]-l[15]-l[10]+l[12]-l[36]+l[33]-l[16]-l[14]-l[25]-l[29]-l[21]+l[27]+l[3]-l[17]==-945&&l[12]-l[30]-l[8]+l[20]-l[2]-l[36]-l[25]-l[0]-l[19]-l[28]-l[7]-l[11]-l[33]+l[4]-l[23]+l[10]-l[41]+l[39]-l[32]+l[27]+l[18]+l[15]+l[34]+l[13]-l[40]+l[29]-l[6]+l[37]-l[14]-l[16]+l[38]-l[26]+l[17]+l[31]-l[22]-l[35]+l[5]-l[1]==-480&&l[36]-l[11]-l[34]+l[8]+l[0]+l[15]+l[28]-l[39]-l[32]-l[2]-l[27]+l[22]+l[16]-l[30]-l[3]+l[31]-l[26]+l[20]+l[17]-l[29]-l[18]+l[19]-l[10]+l[6]-l[5]-l[38]-l[25]-l[24]+l[4]+l[23]+l[9]+l[14]+l[21]-l[37]+l[13]-l[41]-l[12]+l[35]==-213&&l[19]-l[36]-l[12]+l[33]-l[27]-l[37]-l[25]+l[38]+l[16]-l[18]+l[22]-l[39]+l[13]-l[7]-l[31]-l[26]+l[15]-l[10]-l[9]-l[2]-l[30]-l[11]+l[41]-l[4]+l[24]+l[34]+l[5]+l[17]+l[14]+l[6]+l[8]-l[21]-l[23]+l[32]-l[1]-l[29]-l[0]+l[3]==-386&&l[0]+l[7]-l[28]-l[38]+l[19]+l[31]-l[5]+l[24]-l[3]+l[33]-l[12]-l[29]+l[32]+l[1]-l[34]-l[9]-l[25]+l[26]-l[8]+l[4]-l[10]+l[40]-l[15]-l[11]-l[27]+l[36]+l[14]+l[41]-l[35]-l[13]-l[17]-l[21]-l[18]+l[39]-l[2]+l[20]-l[23]-l[22]==-349&&l[10]+l[22]+l[21]-l[0]+l[15]-l[6]+l[20]-l[29]-l[30]-l[33]+l[19]+l[23]-l[28]+l[41]-l[27]-l[12]-l[37]-l[32]+l[34]-l[36]+l[3]+l[1]-l[13]+l[18]+l[14]+l[9]+l[7]-l[39]+l[8]+l[2]-l[31]-l[5]-l[40]+l[38]-l[26]-l[4]+l[16]-l[25]==98&&l[28]+l[38]+l[20]+l[0]-l[5]-l[34]-l[41]+l[22]-l[26]+l[11]+l[29]+l[31]-l[3]-l[16]+l[23]+l[17]-l[18]+l[9]-l[4]-l[12]-l[19]-l[40]-l[27]+l[33]+l[8]-l[37]+l[2]+l[15]-l[24]-l[39]+l[10]+l[35]-l[1]+l[30]-l[36]-l[25]-l[14]-l[32]==-412&&l[1]-l[24]-l[29]+l[39]+l[41]+l[0]+l[9]-l[19]+l[6]-l[37]-l[22]+l[32]+l[21]+l[28]+l[36]+l[4]-l[17]+l[20]-l[13]-l[35]-l[5]+l[33]-l[27]-l[30]+l[40]+l[25]-l[18]+l[34]-l[3]-l[10]-l[16]-l[23]-l[38]+l[8]-l[14]-l[11]-l[7]+l[12]==-95&&l[2]-l[24]+l[31]+l[0]+l[9]-l[6]+l[7]-l[1]-l[22]+l[8]-l[23]+l[40]+l[20]-l[38]-l[11]-l[14]+l[18]-l[36]+l[15]-l[4]-l[41]-l[12]-l[34]+l[32]-l[35]+l[17]-l[21]-l[10]-l[29]+l[39]-l[16]+l[27]+l[26]-l[3]-l[5]+l[13]+l[25]-l[28]==-379&&l[19]-l[17]+l[31]+l[14]+l[6]-l[12]+l[16]-l[8]+l[27]-l[13]+l[41]+l[2]-l[7]+l[32]+l[1]+l[25]-l[9]+l[37]+l[34]-l[18]-l[40]-l[11]-l[10]+l[38]+l[21]+l[3]-l[0]+l[24]+l[15]+l[23]-l[20]+l[26]+l[22]-l[4]-l[28]-l[5]+l[39]+l[35]==861&&l[35]+l[36]-l[16]-l[26]-l[31]+l[0]+l[21]-l[13]+l[14]+l[39]+l[7]+l[4]+l[34]+l[38]+l[17]+l[22]+l[32]+l[5]+l[15]+l[8]-l[29]+l[40]+l[24]+l[6]+l[30]-l[2]+l[25]+l[23]+l[1]+l[12]+l[9]-l[10]-l[3]-l[19]+l[20]-l[37]-l[33]-l[18]==1169&&l[13]+l[0]-l[25]-l[32]-l[21]-l[34]-l[14]-l[9]-l[8]-l[15]-l[16]+l[38]-l[35]-l[30]-l[40]-l[12]+l[3]-l[19]+l[4]-l[41]+l[2]-l[36]+l[37]+l[17]-l[1]+l[26]-l[39]-l[10]-l[33]+l[5]-l[27]-l[23]-l[24]-l[7]+l[31]-l[28]-l[18]+l[6]==-1236&&l[20]+l[27]-l[29]-l[25]-l[3]+l[28]-l[32]-l[11]+l[10]+l[31]+l[16]+l[21]-l[7]+l[4]-l[24]-l[35]+l[26]+l[12]-l[37]+l[6]+l[23]+l[41]-l[39]-l[38]+l[40]-l[36]+l[8]-l[9]-l[5]-l[1]-l[13]-l[14]+l[19]+l[0]-l[34]-l[15]+l[17]+l[22]==-114&&l[12]-l[28]-l[13]-l[23]-l[33]+l[18]+l[10]+l[11]+l[2]-l[36]+l[41]-l[16]+l[39]+l[34]+l[32]+l[37]-l[38]+l[20]+l[6]+l[7]+l[31]+l[5]+l[22]-l[4]-l[15]-l[24]+l[17]-l[3]+l[1]-l[35]-l[9]+l[30]+l[25]-l[0]-l[8]-l[14]+l[26]+l[21]==659&&l[21]-l[3]+l[7]-l[27]+l[0]-l[32]-l[24]-l[37]+l[4]-l[22]+l[20]-l[5]-l[30]-l[31]-l[1]+l[15]+l[41]+l[12]+l[40]+l[38]-l[17]-l[39]+l[19]-l[13]+l[23]+l[18]-l[2]+l[6]-l[33]-l[9]+l[28]+l[8]-l[16]-l[10]-l[14]+l[34]+l[35]-l[11]==-430&&l[11]-l[23]-l[9]-l[19]+l[17]+l[38]-l[36]-l[22]-l[10]+l[27]-l[14]-l[4]+l[5]+l[31]+l[2]+l[0]-l[16]-l[8]-l[28]+l[3]+l[40]+l[25]-l[33]+l[13]-l[32]-l[35]+l[26]-l[20]-l[41]-l[30]-l[12]-l[7]+l[37]-l[39]+l[15]+l[18]-l[29]-l[21]==-513&&l[32]+l[19]+l[4]-l[13]-l[17]-l[30]+l[5]-l[33]-l[37]-l[15]-l[18]+l[7]+l[25]-l[14]+l[35]+l[40]+l[16]+l[1]+l[2]+l[26]-l[3]-l[39]-l[22]+l[23]-l[36]-l[27]-l[9]+l[6]-l[41]-l[0]-l[31]-l[20]+l[12]-l[8]+l[29]-l[11]-l[34]+l[21]==-502&&l[30]-l[31]-l[36]+l[3]+l[9]-l[40]-l[33]+l[25]+l[39]-l[26]+l[23]-l[0]-l[29]-l[32]-l[4]+l[37]+l[28]+l[21]+l[17]+l[2]+l[24]+l[6]+l[5]+l[8]+l[16]+l[27]+l[19]+l[12]+l[20]+l[41]-l[22]+l[15]-l[11]+l[34]-l[18]-l[38]+l[1]-l[14]==853&&l[38]-l[10]+l[16]+l[8]+l[21]-l[25]+l[36]-l[30]+l[31]-l[3]+l[5]-l[15]+l[23]-l[28]+l[7]+l[12]-l[29]+l[22]-l[0]-l[37]-l[14]-l[11]+l[32]+l[33]-l[9]+l[39]+l[41]-l[19]-l[1]+l[18]-l[4]-l[6]+l[13]+l[20]-l[2]-l[35]-l[26]+l[27]==-28&&l[11]+l[18]-l[26]+l[15]-l[14]-l[33]+l[7]-l[23]-l[25]+l[0]-l[6]-l[21]-l[16]+l[17]-l[19]-l[28]-l[38]-l[37]+l[9]+l[20]-l[8]-l[3]+l[22]-l[35]-l[10]-l[31]-l[2]+l[41]-l[1]-l[4]+l[24]-l[34]+l[39]+l[40]+l[32]-l[5]+l[36]-l[27]==-529&&l[38]+l[8]+l[36]+l[35]-l[23]-l[34]+l[13]-l[4]-l[27]-l[24]+l[26]+l[31]-l[30]-l[5]-l[40]+l[28]-l[11]-l[2]-l[39]+l[15]+l[10]-l[17]+l[3]+l[19]+l[22]+l[33]+l[0]+l[37]+l[16]-l[9]-l[32]+l[25]-l[21]-l[12]+l[6]-l[41]+l[20]-l[18]==-12&&l[6]-l[30]-l[20]-l[27]-l[14]-l[39]+l[41]-l[33]-l[0]+l[25]-l[32]-l[3]+l[26]-l[12]+l[8]-l[35]-l[24]+l[15]+l[9]-l[4]+l[13]+l[36]+l[34]+l[1]-l[28]-l[21]+l[18]+l[23]+l[29]-l[10]-l[38]+l[22]+l[37]+l[5]+l[19]+l[7]+l[16]-l[31]==+(!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+[+!+[]])

可以看到等式最后有个数字没有解出来

我们放到网站中解就行了

http://codertab.com/JsUnFuck

是个81,关于等式,我们使用z3

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
from z3 import *
l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33,l34,l35,l36,l37,l38,l39,l40,l41 \
= Ints('l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12 l13 l14 l15 l16 l17 l18 l19 l20 l21 l22 l23 l24 l25 l26 l27 l28 l29 l30 l31 l32 l33 l34 l35 l36 l37 l38 l39 l40 l41')
x = Solver()
x.add(l40+l35+l34-l0-l15-l37+l7+l6-l26+l20+l19+l8-l17-l14-l38+l1-l9+l22+l41+l3-l29-l36-l25+l5+l32-l16+l12-l24+l30+l39+l10+l2+l27+l28+l21+l33-l18+l4==861)
x.add(l31+l26+l11-l33+l27-l3+l12+l30+l1+l32-l16+l7+l10-l25+l38-l41-l14-l19+l29+l36-l9-l28-l6-l0-l22-l18+l20-l37+l4-l24+l34-l21-l39-l23-l8-l40+l15-l35==-448)
x.add(l26+l14+l15+l9+l13+l30-l11+l18+l23+l7+l3+l12+l25-l24-l39-l35-l20+l40-l8+l10-l5-l33-l31+l32+l19+l21-l6+l1+l16+l17+l29+l22-l4-l36+l41+l38+l2+l0==1244)
x.add(l5+l22+l15+l2-l28-l10-l3-l13-l18+l30-l9+l32+l19+l34+l23-l17+l16-l7+l24-l39+l8-l12-l40-l25+l37-l35+l11-l14+l20-l27+l4-l33-l21+l31-l6+l1+l38-l29==-39)
x.add(l41-l29+l23-l4+l20-l33+l35+l3-l19-l21+l11+l26-l24-l17+l37+l1+l16-l0-l13+l7+l10+l14+l22+l39-l40+l34-l38+l32+l25-l2+l15+l6+l28-l8-l5-l31-l30-l27==485)
x.add(l13+l19+l21-l2-l33-l0+l39+l31-l23-l41+l38-l29+l36+l24-l20-l9-l32+l37-l35+l40+l7-l26+l15-l10-l6-l16-l4-l5-l30-l14-l22-l25-l34-l17-l11-l27+l1-l28==-1068)
x.add(l32+l0+l9+l14+l11+l18-l13+l24-l2-l15+l19-l21+l1+l39-l8-l3+l33+l6-l5-l35-l28+l25-l41+l22-l17+l10+l40+l34+l27-l20+l23+l31-l16+l7+l12-l30+l29-l4==939)
x.add(l19+l11+l20-l16+l40+l25+l1-l31+l28-l23+l14-l9-l27+l35+l39-l37-l8-l22+l5-l6+l0-l32+l24+l33+l29+l38+l15-l2+l30+l7+l12-l3-l17+l34+l41-l4-l13-l26==413)
x.add(l22+l4-l9+l34+l35+l17+l3-l24+l38-l5-l41-l31-l0-l25+l33+l15-l1-l10+l16-l29-l12+l26-l39-l21-l18-l6-l40-l13+l8+l37+l19+l14+l32+l28-l11+l23+l36+l7==117)
x.add(l32+l16+l3+l11+l34-l31+l14+l25+l1-l30-l33-l40-l4-l29+l18-l27+l13-l19-l12+l23-l39-l41-l8+l22-l5-l38-l9-l37+l17-l36+l24-l21+l2-l26+l20-l7+l35-l0==-313)
x.add(l40-l1+l5+l7+l33+l29+l12+l38-l31+l2+l14-l35-l8-l24-l39-l9-l28+l23-l17-l22-l26+l32-l11+l4-l36+l10+l20-l18-l16+l6-l0+l3-l30+l37-l19+l21+l25-l15==-42)
x.add(l21+l26-l17-l25+l27-l22-l39-l23-l15-l20-l32+l12+l3-l6+l28+l31+l13-l16-l37-l30-l5+l41+l29+l36+l1+l11+l24+l18-l40+l19-l35+l2-l38+l14-l9+l4+l0-l33==289)
x.add(l29+l31+l32-l17-l7+l34+l2+l14+l23-l4+l3+l35-l33-l9-l20-l37+l24-l27+l36+l15-l18-l0+l12+l11-l38+l6+l22+l39-l25-l10-l19-l1+l13-l41+l30-l16+l28-l26==-117)
x.add(l5+l37-l39+l0-l27+l12+l41-l22+l8-l16-l38+l9+l15-l35-l29+l18+l6-l25-l28+l36+l34+l32-l14-l1+l20+l40-l19-l4-l7+l26+l30-l10+l13-l21+l2-l23-l3-l33==-252)
x.add(l29+l10-l41-l9+l12-l28+l11+l40-l27-l8+l32-l25-l23+l39-l1-l36-l15+l33-l20+l18+l22-l3+l6-l34-l21+l19+l26+l13-l4+l7-l37+l38-l2-l30-l0-l35+l5+l17==-183)
x.add(l6-l8-l20+l34-l33-l25-l4+l3+l17-l13-l15-l40+l1-l30-l14-l28-l35+l38-l22+l2+l24-l29+l5+l9+l37+l23-l18+l19-l21+l11+l36+l41-l7-l32+l10+l26-l0+l31==188)
x.add(l3+l6-l41+l10+l39+l37+l1+l8+l21+l24+l29+l12+l27-l38+l11+l23+l28+l33-l31+l14-l5+l32-l17+l40-l34+l20-l22-l16+l19+l2-l36-l7+l18+l15+l26-l0-l4+l35==1036)
x.add(l28-l33+l2+l37-l12-l9-l39+l16-l32+l8-l36+l31+l10-l4+l21-l25+l18+l24-l0+l29-l26+l35-l22-l41-l6+l15+l19+l40+l7+l34+l17-l3-l13+l5+l23+l11-l27+l1==328)
x.add(l22-l32+l17-l9+l20-l18-l34+l23+l36-l35-l38+l27+l4-l5-l41+l29+l33+l0-l37+l28-l40-l11-l12+l7+l1+l2-l26-l16-l8+l24-l25+l3-l6-l19-l39-l14-l31+l10==-196)
x.add(l11+l13+l14-l15-l29-l2+l7+l20+l30-l36-l33-l19+l31+l0-l39-l4-l6+l38+l35-l28+l34-l9-l23-l26+l37-l8-l27+l5-l41+l3+l17+l40-l10+l25+l12-l24+l18+l32==7)
x.add(l34-l37-l40+l4-l22-l31-l6+l38+l13-l28+l8+l30-l20-l7-l32+l26+l1-l18+l5+l35-l24-l41+l9-l0-l2-l15-l10+l12-l36+l33-l16-l14-l25-l29-l21+l27+l3-l17==-945)
x.add(l12-l30-l8+l20-l2-l36-l25-l0-l19-l28-l7-l11-l33+l4-l23+l10-l41+l39-l32+l27+l18+l15+l34+l13-l40+l29-l6+l37-l14-l16+l38-l26+l17+l31-l22-l35+l5-l1==-480)
x.add(l36-l11-l34+l8+l0+l15+l28-l39-l32-l2-l27+l22+l16-l30-l3+l31-l26+l20+l17-l29-l18+l19-l10+l6-l5-l38-l25-l24+l4+l23+l9+l14+l21-l37+l13-l41-l12+l35==-213)
x.add(l19-l36-l12+l33-l27-l37-l25+l38+l16-l18+l22-l39+l13-l7-l31-l26+l15-l10-l9-l2-l30-l11+l41-l4+l24+l34+l5+l17+l14+l6+l8-l21-l23+l32-l1-l29-l0+l3==-386)
x.add(l0+l7-l28-l38+l19+l31-l5+l24-l3+l33-l12-l29+l32+l1-l34-l9-l25+l26-l8+l4-l10+l40-l15-l11-l27+l36+l14+l41-l35-l13-l17-l21-l18+l39-l2+l20-l23-l22==-349)
x.add(l10+l22+l21-l0+l15-l6+l20-l29-l30-l33+l19+l23-l28+l41-l27-l12-l37-l32+l34-l36+l3+l1-l13+l18+l14+l9+l7-l39+l8+l2-l31-l5-l40+l38-l26-l4+l16-l25==98)
x.add(l28+l38+l20+l0-l5-l34-l41+l22-l26+l11+l29+l31-l3-l16+l23+l17-l18+l9-l4-l12-l19-l40-l27+l33+l8-l37+l2+l15-l24-l39+l10+l35-l1+l30-l36-l25-l14-l32==-412)
x.add(l1-l24-l29+l39+l41+l0+l9-l19+l6-l37-l22+l32+l21+l28+l36+l4-l17+l20-l13-l35-l5+l33-l27-l30+l40+l25-l18+l34-l3-l10-l16-l23-l38+l8-l14-l11-l7+l12==-95)
x.add(l2-l24+l31+l0+l9-l6+l7-l1-l22+l8-l23+l40+l20-l38-l11-l14+l18-l36+l15-l4-l41-l12-l34+l32-l35+l17-l21-l10-l29+l39-l16+l27+l26-l3-l5+l13+l25-l28==-379)
x.add(l19-l17+l31+l14+l6-l12+l16-l8+l27-l13+l41+l2-l7+l32+l1+l25-l9+l37+l34-l18-l40-l11-l10+l38+l21+l3-l0+l24+l15+l23-l20+l26+l22-l4-l28-l5+l39+l35==861)
x.add(l35+l36-l16-l26-l31+l0+l21-l13+l14+l39+l7+l4+l34+l38+l17+l22+l32+l5+l15+l8-l29+l40+l24+l6+l30-l2+l25+l23+l1+l12+l9-l10-l3-l19+l20-l37-l33-l18==1169)
x.add(l13+l0-l25-l32-l21-l34-l14-l9-l8-l15-l16+l38-l35-l30-l40-l12+l3-l19+l4-l41+l2-l36+l37+l17-l1+l26-l39-l10-l33+l5-l27-l23-l24-l7+l31-l28-l18+l6==-1236)
x.add(l20+l27-l29-l25-l3+l28-l32-l11+l10+l31+l16+l21-l7+l4-l24-l35+l26+l12-l37+l6+l23+l41-l39-l38+l40-l36+l8-l9-l5-l1-l13-l14+l19+l0-l34-l15+l17+l22==-114)
x.add(l12-l28-l13-l23-l33+l18+l10+l11+l2-l36+l41-l16+l39+l34+l32+l37-l38+l20+l6+l7+l31+l5+l22-l4-l15-l24+l17-l3+l1-l35-l9+l30+l25-l0-l8-l14+l26+l21==659)
x.add(l21-l3+l7-l27+l0-l32-l24-l37+l4-l22+l20-l5-l30-l31-l1+l15+l41+l12+l40+l38-l17-l39+l19-l13+l23+l18-l2+l6-l33-l9+l28+l8-l16-l10-l14+l34+l35-l11==-430)
x.add(l11-l23-l9-l19+l17+l38-l36-l22-l10+l27-l14-l4+l5+l31+l2+l0-l16-l8-l28+l3+l40+l25-l33+l13-l32-l35+l26-l20-l41-l30-l12-l7+l37-l39+l15+l18-l29-l21==-513)
x.add(l32+l19+l4-l13-l17-l30+l5-l33-l37-l15-l18+l7+l25-l14+l35+l40+l16+l1+l2+l26-l3-l39-l22+l23-l36-l27-l9+l6-l41-l0-l31-l20+l12-l8+l29-l11-l34+l21==-502)
x.add(l30-l31-l36+l3+l9-l40-l33+l25+l39-l26+l23-l0-l29-l32-l4+l37+l28+l21+l17+l2+l24+l6+l5+l8+l16+l27+l19+l12+l20+l41-l22+l15-l11+l34-l18-l38+l1-l14==853)
x.add(l38-l10+l16+l8+l21-l25+l36-l30+l31-l3+l5-l15+l23-l28+l7+l12-l29+l22-l0-l37-l14-l11+l32+l33-l9+l39+l41-l19-l1+l18-l4-l6+l13+l20-l2-l35-l26+l27==-28)
x.add(l11+l18-l26+l15-l14-l33+l7-l23-l25+l0-l6-l21-l16+l17-l19-l28-l38-l37+l9+l20-l8-l3+l22-l35-l10-l31-l2+l41-l1-l4+l24-l34+l39+l40+l32-l5+l36-l27==-529)
x.add(l38+l8+l36+l35-l23-l34+l13-l4-l27-l24+l26+l31-l30-l5-l40+l28-l11-l2-l39+l15+l10-l17+l3+l19+l22+l33+l0+l37+l16-l9-l32+l25-l21-l12+l6-l41+l20-l18==-12)
x.add(l6-l30-l20-l27-l14-l39+l41-l33-l0+l25-l32-l3+l26-l12+l8-l35-l24+l15+l9-l4+l13+l36+l34+l1-l28-l21+l18+l23+l29-l10-l38+l22+l37+l5+l19+l7+l16-l31==81)
print(x.check())
print(x.model())

l = [0]*42
l[14] = 78
l[28] = 95
l[16] = 95
l[17] = 101
l[6] = 95
l[30] = 52
l[36] = 84
l[38] = 95
l[40] = 51
l[3] = 103
l[32] = 121
l[11] = 95
l[9] = 110
l[31] = 83
l[0] = 102
l[4] = 123
l[1] = 108
l[41] = 125
l[35] = 49
l[8] = 48
l[19] = 85
l[15] = 71
l[21] = 84
l[18] = 113
l[23] = 48
l[34] = 87
l[7] = 108
l[25] = 95
l[13] = 48
l[33] = 95
l[27] = 115
l[10] = 103
l[2] = 97
l[37] = 104
l[5] = 65
l[20] = 52
l[29] = 69
l[12] = 49
l[24] = 110
l[26]= 49
l[22] = 105
l[39] = 122

for i in range(42):
print(chr(l[i]),end = '')

把求出来的手动转换成数组,然后输出

用的是之前的方法做的,感觉不太简洁,看网上还有更好的方法

https://www.codetd.com/article/10613214

BUUCTF–[V&N2020 公开赛]CSRe

这题首先是去混淆,然后是逆向.NET文件

exeinfo PE可以得知这是个有混淆的文件.NET文件

使用de4dot文件去混淆

然后用dnSpy逆向.net

str解出来后是1415

text解出来之后是turn

flag{1415turn}

[ACTF新生赛2020]SoulLike (elf暴力/pwntools)

用ida打开

sub_83A太大了,且篇都是xor,mov,add三个指令,

除了最后的几个字符

参考链接:

https://blog.css8.cn/post/1439298.html

原来是配置的问题,需要修改ida /ctg目录下的hexrays.cfg文件中的MAX_FUNCSIZE=64,改成1024

就是将输入的flag,经过3000行的异或后,与最后的几个进行对比

因为最后有提示错误的位数,所以可以试着用爆破的方法……

这边放上大佬整理的关于pwntools的使用方法:

https://seamiloak.github.io/2020/10/16/pwntools%E4%BD%BF%E7%94%A8/

https://blog.csdn.net/hanqdi_/article/details/107164199

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
from pwn import *
context.log_level = 'debug'

table = []
for i in range(128):
table.append(chr(i))

now = "actf{"
num = 0

while 1:
# 长度为12,跳出
if num == 12:
break
for i in table:

io = process('./SoulLike')

# 构造flag
flag = now + i
flag = flag.ljust(17,'@')
flag += '}'


# success(flag)
io.sendline(flag)

#一直读到#出现为止
io.recvuntil('#')

#10位之后就读两位
if num < 9 :

#recv里的1是接受的字节长度,n是数值
n = int(io.recv(1))
else:
n = int(io.recv(2))

io.close()

# 如果n==num+1,则跳出内层循环
if n == num + 1:
now = now + i
num = num + 1
break

print (num)
print (now + '}')

太强了!!

参考链接:

http://bubuko.com/infodetail-3671012.html

[羊城杯 2020]easyre (base64/凯撒)

还是很庆幸自己能独立做出来这一题的

第一个加密是base64加密,

第二个加密是base64加密后的变换,

第三次加密是所有字符向后+3

主要是第二次的加密,不知道到底是怎样转换的,

放到x64dbg中动调了一下

输入时带入了字符串

1
string = "abcdefghijklmnopqrstuvwxyz0123456789012"

一次加密后:

1
string = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MTI="

二次加密后:

1
string = "R1dnd4eXowMTIYWJjZGVmZ2hpazNDU2Nzg5MTI=mtsbW5vcHFyc3"

当时看到加密函数之后人傻了,仔细观察发现只是固定字符段调换了位置,就写出了下面的解法:

1
2
3
4
5
6
7
8
9
10
11
#a3-->a1
def decode2(decode_string):
a3 = decode_string
a = a3[0:13]
b = a3[13:26]
c = a3[26:39]
d = a3[39:52]

a1 = b+d+a+c
print(a1)
return a1

三次加密后:

1
string = "U4gqg7hArzPWLBZMmCJYpC5ksdcQGX5Qcj8PWL=pwveZ8yfKIbf6"

整体还是不难的

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
import base64
flag_encode_3_times = "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG"

#a3-->a1
def decode2(decode_string):
a3 = decode_string
a = a3[0:13]
b = a3[13:26]
c = a3[26:39]
d = a3[39:52]
## print(a)
## print(b)
## print(c)
## print(d)
a1 = b+d+a+c
print(a1)
return a1

def decode1(string):
s = ''
print(string)
for i in string:
m = ord(i)
if m >= 65 and m <= 90:
s += chr((m-65+23)%26+65)
elif m >= 97 and m <= 122:
s += chr((m-97+23)%26+97)
elif m >= 48 and m <= 57:
s += chr((m-48+7)%10+48)
else:
s += i
print(s)
return s

decode_string = decode1(flag_encode_3_times)

decode2_string = decode2(decode_string)

decode3_string = base64.b64decode(decode2_string)

print(decode3_string)

findKey (花指令+正逆向+MD5)

先查个壳

打开运行之后:

发现有花指令:

push了两个一样的指令,需要把下面一个去掉才行,nop一次就好

(大佬z1r0说,下面调用了一个系统的strlen函数,在call函数前,应该会push参数到栈中,而突然跳转本来就很奇怪……)

最后选中所有红色的代码,按一下p键,就反汇编成功了

注意,选中的代码一定要包含所有的红色代码,否则会有函数不显示

开始分析代码:(题目是findkey,而且也没有的输入……)

进一下sub_40101E函数,发现关键词8003u,是熟悉的味道:md5

string1经过md5加密之后,与v15异或,需要等于Str的值

经过if判断之后,string1再与v14异或,得到flag

整个程序可以写成以下的伪代码:

1
2
3
4
5
6
Str = "0kk`d1a`55k222k2a776jbfgd`06cjjb"
string1 = string1(md5加密)
if string1^v15 == Str:
flag = string1^v14
else:
print("Are you kidding me?")

逆向思路:

–>Str^v15–>string1(md5加密后)

–>md5解密还原string1

–>string1与v14异或

–>解出flag

1
2
3
4
5
Str = "0kk`d1a`55k222k2a776jbfgd`06cjjb"
v15 = ord('S')

for i in _str:
print(chr(ord(i)^v15),end='')

得出string1的值为“123321”

v14的值:

1
v14 = [0x57,0x5E,0x52,0x54,0x49,0x5F,0x1,0x6D,0x69,0x46,0x2,0x6E,0x5F,0x2,0x6C,0x57,0x5B,0x54,0x4C]

string1与v15异或:

1
2
3
4
5
6
7
8
v14 = [0x57,0x5E,0x52,0x54,0x49,0x5F,0x1,0x6D,0x69,0x46,0x2,0x6E,0x5F,0x2,0x6C,0x57,0x5B,0x54,0x4C]
string1 = ['1','2','3','3','2','1']
flag = ''

for i in range(len(v14)):
flag+=chr(v14[i]^ord(string1[i%6]))

print(flag)

flag{n0_Zu0_n0_die}

[GUET-CTF2019]number_game (动调/二叉树)

ida打开函数,是这个样子:

4006D6判断输入字符类型,不满足直接输出wrong

400758这块把我看迷糊了,很像二叉树的前序遍历

后面的400807也是一个打乱顺序的函数

用户输入字符–>两个函数打乱–>满足数独情况

满足数独的情况是

[0,4,2,1,4,2,1,4,3,0]

下午直接找了大佬z1r0来研究这一题。

首先我们想到的是pwndbg来动态调试这一题,当然调试出来了,但是我们带入的是值,不是下标,没有很好的解决这一题,然后我们选择了爆破,只是我们的方法不太好,也就爆破个几个小时就出来了……

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
from pwn import *
from time import sleep

file_name = './z1r0'

context.log_level = 'debug'

r = process(file_name)
d = ''

ppp =['0', '1', '2', '3', '4']

for i in ppp:
for j in ppp:
for k in ppp:
for l in ppp:
for m in ppp:
for n in ppp:
for o in ppp:
for p in ppp:
for q in ppp:
for s in ppp:
try:
r = process(file_name)
d = i + j + k + l + m + n + o + p + q + s
#d = '11342400' + i + j
r.sendline(d)
if r.recvline() == b'TQL!\n':
r.interactive()
except:
print('error')

https://www.cnblogs.com/th1r7een/articles/14532420.html

这题最好还是正向来做……

首先是sub_400758函数构建了一颗二叉树

1
2
3
4
5
6
7
8
def test(index,lenth):
print(index)
if index > lenth:
return
test(2*index+1,lenth)
test(2*(index+1),lenth)

test(0,10)

中序遍历后的顺序为:[7,3,8,1,9,4,0,5,2,6]

flag{1134240024}

发现IDA还可以动调!!

需要查看IDA权威指南,IDA动调的话,先放一防,先刷题先……

firmware (路由器逆向/binwalk)

关于固件分析的文章:

https://www.freebuf.com/articles/ics-articles/262454.html

关于路由器逆向的文章:

https://blog.csdn.net/QQ1084283172/article/details/66971242

通常固件文件以bin/zip/LZMA/arj等文件压缩类型封装。

题目给了一个bin文件,

用linux的file命令查看一下,查看是否是二进制镜像文件

通常用binwalk对其进行提取,当然也可以再用binwalk查看一下bin文件的细节信息

用binwalk对bin文件进行提取(e–extract)

1
binwalk -e firmware.bin

可以看到提取出了这些文件

我们再通过hexdump或者file确认一下,是否是squashsf文件系统,其地址00包含squashsf的头部特征(hsqs)

squashsf后缀文件需要进一步解压,从而获得固件的根文件

可能是binwalk没有安装完全,导致squashfs文件系统损坏

binwalk安装传送门:

https://blog.csdn.net/QQ1084283172/article/details/65441110

摸索了很久,发现firmware-mod-kit可以成功解压squashfs文件系统,

https://blog.csdn.net/sjt670994562/article/details/98071249

这边放上github的firmware-mod-kit的链接

1
git clone https://github.com/mirror/firmware-mod-kit

炸了……搞了很久还是报错kali和ubuntu都试过了……

再放一放……

–更新–

1
sudo apt install firmware-mod-kit

直接用apt安装即可(感谢大佬z1r0的指导!!)默认路径在opt下,在binwalk提取bin文件后的目录下输入下面的指令就行了

1
/opt/firmware-mod-kit/trunk/unsquashfs_all.sh ./120200.squashfs  

进入squashfs-root目录下的tmp文件夹

file一下,elf文件,ARM类型,但是无法执行

发现有upx壳

1
upx -d backdoor  

脱壳之后放在ida里面反汇编

1
echo.byethost51.com:36667

​ flag{33a422c45d551ac6e4756f59812a954b}

[WMCTF2020]easy_re (perl特性)

查壳后发现没壳,用x64dbg打开

搜索script,并添加断点

向下F8,flag就出来了

WMCTF{I_WAnt_dynam1c_F1ag}

据说是因为perl语言解压call有字符串script,

参考链接:https://blog.csdn.net/Palmer9/article/details/107727922

crackMe (od动调)

用ida32打开后

最外层是一个死循环,要想跳出死循环,需要满足后面的if嵌套,

可以发现if嵌套上面的sub_401090是用来给byte_416050赋值的,还把welcomebeijing这个用户名作为了参数传递到了其中

接着跟进sub_401830,说了一大串之后,v17作为二参进入了sub_401470

要使得v14,也就是sub_40147中的a3等于43924,需要满足a2满足所有的if条件,也就是a2=”dbappsec”,即v17=”dbappsec”,猜测v17是输入的flag经过变换后对比的值

返回sub_401830函数,关于v17的值的代码块也就只有这边了

接下来,我们需要动调,把与byte_416050异或的v16数组求出来

通过明显的地方,可以推算出ida和x32dbg的地址差

光标确定到某一参数,按住tab键可以查看其汇编代码,在伪代码窗口的定义部分可以看到这些参数关于ebp的偏移

加上偏移量就能快速定位到需要执行的函数了

在ida中定位while大循环,然后再dbg中定位,在循环开始和xor处打断点,多按几次F9,记录一下edx低位的值

正向:

user输入–>byte_406050–>byte_406050^v16[v5-1]–>v17

逆向:

v17–>byte_406050^v17–>v16[v5-1]

byte_406050数组,是user传入之后经过一系列变换生成的,我们需要动调的就是byte_406050的值,然后在与已知的v17异或,就是v16的值了,也就是题目要求的flag

我动调之后的结果是[0x7e,0x98,0xc9,0x95,0x10,0x6d,0xf3,0x67]

先放一放……

—-更新—-

在xor的上下有两个反调试指令,所以应该把je改成jmp,动调就行了

调试结果:

1
v16 = [0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,0xcd]

代码:

1
2
3
4
5
6
7
8
v16 = [0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,0xcd]
v17 = "dbappsec"

flag = []
for i in range(8):
flag.append(hex(v16[i]^ord(v17[i])).replace("0x",""))
for i in flag:
print(i,end = '')

关于反调试的可以看看雪大神的这篇文章:

https://bbs.pediy.com/thread-225740.htm

参考文章:

https://www.songbingjia.com/nginx/show-209658.html

https://www.cnblogs.com/pppyyyzzz/p/12546844.html

特殊的base64 (base64换表)

经典的base64换表,“mTy……”是换表之后的加密的字符串,字符串搜索之后可以看到换的base64表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64

string = "mTyqm7wjODkrNLcWl0eqO8K8gc1BPk1GNLgUpI=="

new_base = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0987654321/+"

base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print(len(new_base))

print(len(base))

flag = base64.b64decode(string.translate(str.maketrans(new_base,base)))

print(flag)

[网鼎杯 2020 青龙组]singal (vm题/ponce插件)

传送门:https://www.52pojie.cn/thread-1176826-1-1.html

查壳,发现没有壳

这个qmemcpy的意思是把unk_403040的456个字符复制到v4中

这个题就是首先是需要去摸清楚指令的调用顺序

进行观察,可以发现,v4 与 a1[v10 + 1]比较 是判断条件,a1是输入的opcode, 而v4来自v5,v5由flag进行运算得到: flag—>v5—->v4 所以我们要得到v4,然后推v5,再得到flag

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
#include <stdio.h>
#include <string.h>

unsigned char vmcode[] =
{
0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x84, 0xFF,
0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x7A, 0x00, 0x00, 0x00
};

int * a = (int *)vmcode;

int __cdecl vm_operad(int *opcode, int len_114)
{
char order[114] = {}; //顺序 即i
char flag[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int j; // [esp+DCh] [ebp-1Ch]
int m; // [esp+E0h] [ebp-18h]
int k; // [esp+E4h] [ebp-14h]
int n; // [esp+E8h] [ebp-10h]
int i; // [esp+ECh] [ebp-Ch]
int s = 0;

i = 0;
n = 0;
k = 0;
m = 0;
j = 0;
while (1)
{
if (i >= len_114) // 成功的地方
break;
switch (opcode[i])
{
case 1:
v4[m] = v5;
++i;
++m;
++n;
break;
case 2:
v5 = opcode[i + 1] + flag[n];
i += 2;
break;
case 3:
v5 = flag[n] - opcode[i + 1];
i += 2;
break;
case 4:
v5 = opcode[i + 1] ^ flag[n];
i += 2;
break;
case 5:
v5 = opcode[i + 1] * flag[n];
i += 2;
break;
case 6:
++i;
break;
case 7:
v4[k] = opcode[i + 1]; // 打印关键数据V4
printf("%#X, ", v4[k]);
++k;
i += 2;
break;
case 8:
flag[j] = v5;
++i;
++j;
break;
case 10:
scanf("%s", flag); // 输入flag //长度是15
++i;
break;
case 11:
v5 = flag[n] - 1;
++i;
break;
case 12:
v5 = flag[n] + 1;
++i;
break;
}
order[s++] = i;
}
printf("\n执行顺序是: ");
for (int ss = 0; ss < strlen(order); ss++) {
printf("%d, ", order[ss]);
}

return 0;
}
int decode(int * opcode, int len_114)
{
int i;
//获取flag 的关键数据
unsigned char v4[] = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
//执行opcode 的索引,即执行顺序
char order[100] = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114 };
unsigned char flag[100] = {};
int m = 15;
int n = 15;
int j = 15;
int v5;
for (int k = strlen(order) - 1; k >= 0 ; k--)
{
i = order[k];
switch (opcode[i]) // 倒序执行
{
case 1:
--m;
--n;
v5 = v4[m];
break;
case 2:
flag[n] = v5 - char(opcode[i + 1]) ;
break;
case 3:
flag[n] = v5 + char(opcode[i + 1]);
break;
case 4:
flag[n] = (v5 ^ opcode[i + 1]) & 0XFF;
break;
case 5:
flag[n] = v5 / opcode[i + 1];
break;
case 6:
break;
case 8:
v5 = flag[--j];
break;
case 11:
flag[n] = v5 + 1;
break;
case 12:
flag[n] = v5 - 1;
break;
}
}

printf("%s", flag);
return 0;
}
int main()
{
vm_operad(a, 114);
decode(a, 114);
return 0;
}

通过case7对比的数组v4来求出v5,即执行的顺序,然后通过v5来求出flag反向推出flag,执行顺序由后往前。

学到一招,可以把多行的数据转换成数组

https://www.52pojie.cn/thread-1187493-1-1.html

很好奇还有关于ida插件ponce的使用来解决这一道题

–待更新–

[GWCTF 2019]xxor (xor plus)

当初发现这个题目不是一般的难,就跳过了,这次正好来总结一下。

下载后发现是个linux文件,先放linux运行一下:

放到ida里面看一下

首先是循环输入六次,然后进入一个循环,然后sub_400686这个函数一看就是加密函数了,一参是我们输入的值,二参是一个固定数组。

2 dup(2) ,就是2出现两次的意思,上次个maze题也出现过

那这样二参我们就知道了:{2,2,3,4}

注意一下第二个循环,j循环了三次

后面的的sub_400770则是比较函数了

我们跟进:

我这边正好熟悉一下z3的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from z3 import *

a0,a1,a2,a3,a4,a5 = Ints('a0 a1 a2 a3 a4 a5')

x = Solver()

x.add(a2 - a3 == 2225223423)
x.add(a3 + a4 == 4201428739)
x.add(a2 - a4 == 1121399208)
x.add(a0 == 3746099070)
x.add(a5 == 2230518816)
x.add(a1 == 550153460)

print(x.check())
print(x.model())
unsigned lis[] = {3746099070, 550153460,3774025685,1548802262,2652626477,2230518816};

也就是六个数字,循环三次,两两计算

v5初始等于0,那逆向就是0x40*1166789954 = 74674557056,原来每次递增,那么最后就递减

别的如果是加,那么就都减去,次序再调换一下

(貌似python对位移运算不够友善,以后做这种计算的题目还是用c吧)

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
#include <stdio.h>

int a[] = {2,2,3,4};

unsigned lis[] = {3746099070, 550153460,3774025685,1548802262,2652626477,2230518816};

void function(unsigned* x){
unsigned v3 = *x;
unsigned v4 = *(x + 1);
int v5 = 74674557056;
for (int i = 0; i <= 63 ;i++){
v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a[2]) ^ ((v3 >> 9) + a[3]) ^ 0x10;
v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + a[0]) ^ ((v4 >> 9) + a[1]) ^ 0x20;
v5 -= 1166789954;
}
*x = v3;
*(x+1) = v4;
}
int main(){
for (int i = 0; i < 6 ;i += 2){
function(lis+i);
}
for (int i = 0;i < 6 ;i ++)
printf("%c%c%c",(lis[i] >> 16) & 0xff,(lis[i] >> 8) & 0xff,lis[i] & 0xff);
return 0;
}

令我疑惑的是,为什么会有下面的操作?

1
2
for (int i = 0;i < 6 ;i ++)
printf("%c%c%c",(lis[i] >> 16) & 0xff,(lis[i] >> 8) & 0xff,lis[i] & 0xff);

思考了一下,发现不加后面的&0xff结果也一样

[WUSTCTF2020]level4(二叉树遍历)

先放linux里面运行了一下

1
2
3
2f0t02T{hcsiI_SwA__r7Ee}
20f0Th{2tsIS_icArE}e7__w
//type3(&x[22]); No way!

ida打开

只能理解为顺序错了,两串字符串的内容是一致的。

两个函数都是递归函数,Type1函数putchar()在中间,Type2函数putchar()在后面,而且上面的提示语句(Data Structure)已经告诉我们是关于数据结构的东西。我们便可以想到是树的前中后遍历,那么Type1就是中序遍历,Type2函数就是后序遍历,我们需要的就是Type3就是前序遍历,开始手动绘制……

wctf2020{This_IS_A_7reE}

[ACTF新生赛2020]Universe_final_answer (z3计算)

查个壳,然后用ida64打开

跟进这个sub_860函数,就能看到一堆的方程

在网上学习了一下python中z3的基本用法

1
2
3
4
5
6
7
8
9
10
from z3 import *
a,s,d = Ints('a s d')
x = Solver()
x.add(a-d == 18)
x.add(a+s == 12)
x.add(s-d == 20)

x.check()
x.model()
print(x.model())

下面开始着手编写对应脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from z3 import *
v1,v2,v3,v4,v5,v6,v7,v8,v9,v11 = Ints('v1 v2 v3 v4 v5 v6 v7 v8 v9 v11')
x = Solver()
x.add(-85 * v9 + 58 * v8 + 97 * v6 + v7 + -45 * v5 + 84 * v4 + 95 * v2 - 20 * v1 + 12 * v3 == 12613)
x.add(30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400)
x.add(-103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - v6 * 64 - 120 * v9 == -10283)
x.add(71 * v6 + v7 * 128 + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855)
x.add( 5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944)
x.add(-54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222)
x.add(-83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258)
x.add(81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559)
x.add(101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308)
x.add(99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697)


print(x.check())

print(x.model())

解出来之后,还需要转化一下,且注意顺序,v2是a1[0],v6与v5的次序是对调的。

1
2
3
4
5
6
7
8
9
10
[v1 = 48,
v6 = 95,
v2 = 70,
v4 = 82,
v11 = 64,
v3 = 117,
v5 = 84,
v7 = 121,
v9 = 119,
v8 = 55]
1
2
3
4
5
lis = [ 70,48,117,82,84,121,95,55,119]
flag = ''
for i in lis:
flag+=chr(i)
print(flag)

F0uRTy_7w@

所以说sub_860的值出来了,进入一个sub_C50()函数判断,我们只需要用Linux虚拟机运行一下,将我们求得的字符串带入输入到其中,使得条件成立,flag就出来了。

flag{F0uRTy_7w@_42}

[UTCTF2020]basic-re (水题)

用ida64打开看看

flag{str1ngs_1s_y0ur_fr13nd}

[Zer0pts2020]easy strcmp (binascii+函数变址)

查壳后用ida64打开

这题貌似没有我想的那么简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 __fastcall main(int a1, char **a2, char **a3)
{
if ( a1 > 1 )
{
if ( !strcmp(a2[1], "zer0pts{********CENSORED********}") )
puts("Correct!");
else
puts("Wrong!");
}
else
{
printf("Usage: %s <FLAG>\n", *a2);
}
return 0LL;
}

这边的mian函数只是一个比较的函数

参考资料:https://www.cnblogs.com/Mayfly-nymph/p/13154909.html

但是人没写怎么查找到加密输入符号的函数

这边放上z1r0的解析:

https://www.zhihu.com/people/xu-xu-xuxu-94

在机智聪明,成熟老练的z1r0大佬的指导下,我逐渐摸清楚为两个函数是如何变幻的,并且还学到了很多东西,我总结一下:

在sub_795这个函数中,可以看到:

qword_201090这个全局变量(在.bss表中,所以是全局变量)保存的是strcmp的地址

off_201028=sub_6EA是什么意思?我们跟进一下

首先理解一下offset是什么意思:

https://blog.csdn.net/deniece1/article/details/102934346

offset为属性操作符,表示应该把其后面的符号地址的值,不是内容作为操作数,所以off_201028应该存放的是strcmp的地址

所以,off_201028 = sub_6EA,相当于把sub_6EA的地址赋值给了strcmp!!!再推理一下,全局变量qword_201090保存的是strcmp的地址,所以如果要执行strcmp函数,我们需要用qword_201090来实现。

z1r0大佬说, .plt段存放的一般是puts/printf函数,.bss存放的是全局变量,init放置的是程序初始化的代码块,.text存放代码段。

因此,在main函数中的strcmp函数,其实调用的是sub_6EA这个函数

我们跟进sub_6EA这个函数:

第一个for循环是用来测定输入字符串的长度,v4除以8再+1,相当于组数。然后第二个for循环,每组减去qword_201060这个数组,我们跟进

程序后面的qword_201090,我们推理过了,就相当于于是strcmp,用来于外面的”zer0pts{*CENSORED*}”相比较

所以我们应该是加上qword_201060的值才对,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import binascii

string = "********CENSORED********"
qword_201060 = [0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B]

flag = b'flag{'
for i in range(3):
#这边就是把string均分成长度为8的三段
z = string[i * 8 : (i + 1) * 8]

#这个函数就是把每一段字符串都转换为十六进制ascii码
x = binascii.b2a_hex(z.encode('ascii')[::-1])

#逆向操作,加上qword_201060中对应的值
y = binascii.a2b_hex(hex(int(x, 16) + qword_201060[i])[2:])[::-1]
flag += y
print(flag + b'}')

binascii.b2a_hex()函数运行之后的结果为b’4445524f534e4543’,为byte类型的字符串,所以需要转换一下,hex(x,16)

奇怪啊,为什么要把每一段字符串逆一下?([::-1])

如果说这个是因为ida的小段存储机制,所以要逆一下,那后面求完之后的y为什么要逆一下?奇怪??

b’flag{l3ts_m4k3_4_DETOUR_t0d4y}’

[FlareOn3]Challenge1 (base64换表)

先查个壳,再用ida32打开

输入的字符串经过sub_401260函数的转换,变成了str2,然后与str1进行比较

可以看到这边是很熟悉的base64算法,我们点进去byte_413000看看

一个很经典的base64换标操作,下面是代码:

1
2
3
4
5
6
7
8
9
10
11
12
import base64

string = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q"

new_base = 'ZYXABCDEFGHIJKLMNOPQRSTUVWzy\
xabcdefghijklmnopqrstuvw0123456789+/'

base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

flag = base64.b64decode(string.translate(str.maketrans(new_base,base)))

print(flag)

flag{sh00ting_phish_in_a_barrel@flare-on.com}

[ACTF新生赛2020]Oruga(迷宫plus)

oruga是什么文件?不管了,先插个壳看看

用ida64打开看看

前面五个字符告诉我们了,继续跟进sub_78A看看

再到byte_201020看看

到这就傻了,琢磨了半天……

https://www.cxybb.com/article/weixin_43876357/107525490

原来是迷宫啊,但是这个迷宫怎么用上面的查看的……

原来下面的这个意思是代表这4个0x00的意思,那这样就能把ida中的这一组数据转换成列表了,这边我搬运的大佬z1r0的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mz = [0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x23, 0x23,0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x4C, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,0x00, 0x00, 0x00, 0x30, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,54, 0x54, 0x54, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x21, 0x00, 0x00, 0x00, 0x45, 0x45]

for i in range(16):
for j in range(16):
if i == 0 and j == 0:
print('V', end = ' ')
elif mz[16 * i + j] == 0:
print('*', end = ' ')
elif mz[16 * i + j] == 0x21:
print('X', end= ' ')
else:
print('O', end=' ')
print()

还有三个问题我没有解决:

  1. 地图大小如何确定
  2. 游戏规则如何建立(碰到障碍物才能停下再继续操作)
  3. 障碍物如何显示?

16*16 = 256,所以可以确定地图的大小

第二层while循环中就限制了移动的范围,一是在地图的边缘,而是碰到障碍物

而障碍物貌似就是第二层循环中的后面的限制条件,可以把实体化,打印出来……

flag{MEWEMEWJMEWJM} 吧

[BJDCTF2020]BJD hamburger competition(unity逆向+sha1+mod5)

我惊了……

查个壳子看看,没有壳,用ida64打开,貌似查壳+ida不是正确的打开方式

看看z1r0的博客(下面的这句话才是最装逼的,哈哈哈),用到的是dnSPY这个软件:

https://www.zhihu.com/people/xu-xu-xuxu-94

成功下载,并打开

https://blog.csdn.net/weixin_47158947/article/details/107818896

主要看第二点,反编译这个Assembly-CSharp.dll这个文件,直接修改unity的C#源代码

然后放到dnspy中……

顺利找到一个BJDCTF的字眼

踩坑了,我都不知道哈希函数基本是不可逆的

看z1r0的博客才知道文中的Sha1只是判断第一个字符,我们通过这个获得了密文,接着将1001这个密文进行MOD5加密

可以看到,哈希值是下面这个,(我看z1r0的博客,会有两个值……)

不管了,继续看

作者的意图是获取mod5加密的前20个字符

1
2
3
4
5
string = 'b8c37e33defde51cf91e1e03e51657da'

flag = 'flag{'+string[0:20].upper()+'}'

print(flag)

flag{B8C37E33DEFDE51CF91E}

[WUSTCTF2020]Cr0ssfun(水题)

先查个壳,用ida64打开

可以看到v4是我们输入的flag,check函数是比较函数,我们跟进

继续跟进……

1
2
3
4
_BOOL8 __fastcall iven_1s_educated(_BYTE *a1)
{
return *a1 == 119 && a1[6] == 50 && a1[22] == 115 && a1[31] == 110 && a1[12] == 95 && (unsigned int)iven_1s_brave(a1);
}

继续跟进……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
_BOOL8 __fastcall iven_1s_brave(_BYTE *a1)
{
return a1[15] == 100
&& a1[8] == 123
&& a1[18] == 51
&& a1[28] == 95
&& a1[21] == 114
&& (unsigned int)iven_1s_great(a1);
}
_BOOL8 __fastcall iven_1s_great(_BYTE *a1)
{
return a1[2] == 116
&& a1[9] == 99
&& a1[32] == 125
&& a1[19] == 118
&& a1[5] == 48
&& a1[14] == 110
&& (unsigned int)iven_and_grace(a1);
}
_BOOL8 __fastcall iven_and_grace(_BYTE *a1)
{
return a1[4] == 50 && a1[17] == 114 && a1[29] == 102 && a1[17] == 114 && a1[24] == 95 && (unsigned int)finally_fun(a1);
}

这iven也太自恋了吧……下面是代码

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
a1 = [0]*40

a1[10] = 112
a1[13] = 64
a1[3] = 102
a1[26] = 114
a1[20] = 101
a1[7] = 48
a1[16] = 95
a1[11] = 112
a1[23] = 101
a1[30] = 117
a1[0] = 119
a1[6] = 50
a1[22] = 115
a1[31] = 110
a1[12] = 95
a1[15] = 100
a1[8] = 123
a1[18] = 51
a1[28] = 95
a1[21] = 114
a1[2] = 116
a1[9] = 99
a1[32] = 125
a1[19] = 118
a1[5] = 48
a1[14] = 110
a1[4] = 50
a1[17] = 114
a1[29] = 102
a1[17] = 114
a1[24] = 95
a1[1] = 99
a1[25] = 64
a1[27] = 101
for i in a1:
print(chr(i),end = '')

wctf2020{cpp*@nd_r3verse*@re_fun}

[FlareOn6]Overlong(od动调)

差壳,啥意思?要用ide试试?

我也没看出来个啥,运行了一下,到时候上ida直接查找这句话。

打开ida32查看,

1
2
3
4
5
6
7
8
9
int __stdcall start(int a1, int a2, int a3, int a4)
{
CHAR Text[128]; // [esp+0h] [ebp-84h] BYREF
int v6; // [esp+80h] [ebp-4h]

v6 = sub_401160(Text, &unk_402008, 28);
Text[v6] = 0;
MessageBoxA(0, Text, Caption, 0);
return 0;

unk_402008,中有很多数字,但最后弹出的框中,只有28个数字……

写了很多代码之后,解不出来……

https://blog.csdn.net/P_Black_K/article/details/122342264

原来是要去用od去动调这个28啊……

我用的是吾爱破解的od,打开后可以看到push 0x1c,而这个数字正好是28,我们做的就是去修改这个0x1c。

出来了!第一次用od动调程序!!

flag{I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com}

[GWCTF 2019]xxor (xor plus++)

先查个壳,用IDA64打开

1
2
3
4
5
6
7
8
9
10
11
12
13
// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void))
{
__int64 v3; // rax
int v4; // esi
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
char *retaddr; // [rsp+0h] [rbp+0h] BYREF

v4 = v5;
v5 = v3;
__libc_start_main((int (__fastcall *)(int, char **, char **))main, v4, &retaddr, init, fini, a3, &v5);
__halt();
}

我们跟进main

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+8h] [rbp-68h]
int j; // [rsp+Ch] [rbp-64h]
__int64 v6[6]; // [rsp+10h] [rbp-60h] BYREF
__int64 v7[6]; // [rsp+40h] [rbp-30h] BYREF

v7[5] = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
memset(v6, 0, 40);
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ");
a2 = (char **)((char *)v6 + 4 * i);
__isoc99_scanf("%d");
}
memset(v7, 0, 40);
for ( j = 0; j <= 2; ++j )
{
dword_601078 = v6[j];
dword_60107C = HIDWORD(v6[j]);
a2 = (char **)dword_601060;
sub_400686((unsigned int *)&dword_601078, dword_601060);// 加密函数
LODWORD(v7[j]) = dword_601078;
HIDWORD(v7[j]) = dword_60107C;
}
if ( (unsigned int)sub_400770(v7, a2) != 1 )
{
puts("NO NO NO~ ");
exit(0);
}
puts("Congratulation!\n");
puts("You seccess half\n");
puts("Do not forget to change input to hex and combine~\n");
puts("ByeBye");
return 0LL;
}

输入六次,

先是循环三次,可以看出sub_400686是一个加密的函数

而sub_400770是一个对比的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__int64 __fastcall sub_400770(_DWORD *a1)
{
if ( a1[2] - a1[3] == 2225223423LL
&& a1[3] + a1[4] == 4201428739LL
&& a1[2] - a1[4] == 1121399208LL
&& *a1 == 3746099070
&& a1[5] == 2230518816
&& a1[1] == 550153460 )
{
puts("good!");
return 1LL;
}
else
{
puts("Wrong!");
return 0LL;
}
}

加密之后的v7数组

1
v7 = [3746099070,550153460,3774025685,1548802262,2652626477,2230518816]

这边可以看到,dword_601060数组为[2,2,3,4]

然后看看加密算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
__int64 result; // rax
unsigned int v3; // [rsp+1Ch] [rbp-24h]
unsigned int v4; // [rsp+20h] [rbp-20h]
int v5; // [rsp+24h] [rbp-1Ch]
unsigned int i; // [rsp+28h] [rbp-18h]

v3 = *a1;
v4 = a1[1];
v5 = 0;
for ( i = 0; i <= 63; ++i )
{
v5 += 1166789954;
v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
}
*a1 = v3;
result = v4;
a1[1] = v4;
return result;
}

好!到这边就没了,炸了!

参考链接:

https://blog.csdn.net/HardDebugger/article/details/108625220

https://www.programminghunter.com/article/3800202454/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import long_to_bytes
from ctypes import *
v6=[3746099070,550153460,3774025685,1548802262,2652626477,2230518816]
unk=[2,2,3,4]
for i in range(0,5,2):
v5=(c_int(1166789954*0x40))
v3 = c_uint(v6[i])
v4 = c_uint(v6[i+1])
for j in range(0x40):
v4.value -= ((v3.value+v5.value+20)^((v3.value<<6)+unk[2])^((v3.value>>9)+unk[3])^0x10)
v3.value -= ((v4.value+v5.value+11)^((v4.value<<6)+unk[0])^((v4.value>>9)+unk[1])^0x20)
v5.value = (v5.value - 1166789954)
v6[i] =v3.value
v6[i+1] = v4.value

for k in range(6):
print(long_to_bytes(v6[k]).decode(),end='')

分析一下这个代码:

ctypes是python的外部函数库,提供与C兼容的数据类型,并允许调用DLL或共享库中的函数(我暂时不需要了解这个)

我们这边就探讨这个c_uint 这是个无符号数,对数组中的类型进行限制,限制为无符号数,最后还需要进行long_to_bytes的转换??太强了,先放这边搁着,先下一题看看

[MRCTF2020]Xor

没有壳子,直接用ida32打开。

啥情况?

我就先用跳转,跳转到401095这个地址

进入sub_401020之后,我按了一下tab,貌似就可以反汇编了,我返回主函数看一下,成功反汇编!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int i; // eax

sub_401020((int)"Give Me Your Flag String:\n");
sub_401050("%s", byte_4212C0);
if ( strlen(byte_4212C0) != 27 )
{
LABEL_6:
sub_401020((int)"Wrong!\n");
sub_404B7E("pause");
_loaddll(0);
__debugbreak();
}
for ( i = 0; i < 0x1B; ++i )
{
if ( ((unsigned __int8)i ^ (unsigned __int8)byte_4212C0[i]) != byte_41EA08[i] )
goto LABEL_6;
}
sub_401020((int)"Right!\n");
sub_404B7E("pause");
return 0;
}

byte_4212C0来存放字符串,然后在后面的for语句中,与i异或之后,与byte_41EA08比较,如下所示,我们开始编写代码

奇怪了,暴力和正常的异或都没用啊,这肯定是错的……

1
2
3
4
5
6
7
8
9
10
11
12
string = 'SAWB~FXZ:J:`tQJ"N@ bpdd}8g'

print(len(string))
flag = ''

for i in range(26):
for j in range(128):
k = j
if j^i == ord(string[i]):
flag+=chr(k)

print(flag)

发现了暗门

那是什么暗门,这个这个函数包含了我们刚刚看过的主函数

算了,看看吧……

麻了,原来串个字符的前面有个M,没注意到,脚本编写没有问题的

1
2
3
4
5
6
7
8
9
10
11
12
string = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g'

print(len(string))
flag = ''

for i in range(27):
for j in range(128):
k = j
if j^i == ord(string[i]):
flag+=chr(k)

print(flag)

27 MRCTF{@_R3@1ly_E2_R3verse!}

[MRCTF2020]hello_world_go

没看到壳子,用ida64打开

???

下一题

[WUSTCTF2020]level3(base64换表)

用64位的IDA打开

一个base64有问题的题目

这个是

本程序里面的,我特地找了之前做过的reverse_3,纯正的base64题目,中的码表,用来做了个对比

这边是少了个=号,base62倒是可以解出来,结果却都是数字

像我之前做过的一个换码表的题目了,我正好反过来看一看

[ACTF新生赛2020]usualCrypt这道题

刚刚试了一下,换表的话,长度相等才行……新表的明显短了,这怎样才好??

我懂了,题目中的表的次序换了

在table上按x,果真有引用这个的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 O_OLookAtYou()
{
__int64 result; // rax
char v1; // [rsp+1h] [rbp-5h]
int i; // [rsp+2h] [rbp-4h]

for ( i = 0; i <= 9; ++i )
{
v1 = base64_table[i];
base64_table[i] = base64_table[19 - i];
result = 19 - i;
base64_table[result] = v1;
}
return result;
}

这就简单了,换表之后,就能解码了,下面就是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import base64
string = 'd2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=='

base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

newbase = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=')

for i in range(0,9):
newbase[i] , newbase[19-i] = newbase[19-i] , newbase[i]

newbase = ''.join(newbase)

flag = base64.b64decode(string.translate(str.maketrans(newbase,base)))
print(flag)

b’wctf2020{Base64_is_the_start_of_reverse}’

[FlareOn4]IgniteMe()

先查个壳,发现没有壳,用32位IDA打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void __noreturn start()
{
DWORD NumberOfBytesWritten; // [esp+0h] [ebp-4h] BYREF

NumberOfBytesWritten = 0;
hFile = GetStdHandle(0xFFFFFFF6);
dword_403074 = GetStdHandle(0xFFFFFFF5);
WriteFile(dword_403074, aG1v3M3T3hFl4g, 19u, &NumberOfBytesWritten, 0);
sub_4010F0();
if ( sub_401050() )
WriteFile(dword_403074, aG00dJ0b, 10u, &NumberOfBytesWritten, 0);
else
WriteFile(dword_403074, aN0tT00H0tRWe7r, 36u, &NumberOfBytesWritten, 0);
ExitProcess(0);
}

一眼看出if语句是用来判断的,我们跟进这个sub_401050()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int sub_401050()
{
int v1; // [esp+0h] [ebp-Ch]
int i; // [esp+4h] [ebp-8h]
unsigned int j; // [esp+4h] [ebp-8h]
char v4; // [esp+Bh] [ebp-1h]

v1 = my_return_i(my_arr);
v4 = my_rol();
for ( i = v1 - 1; i >= 0; --i )
{
my_flag[i] = v4 ^ my_arr[i];
v4 = my_arr[i];
}
for ( j = 0; j < 39; ++j )
{
if ( my_flag[j] != model[j] )
return 0;
}
return 1;
}

判断数组我命名成为model,转换后的数组我命名成my_flag,而中间的转换数组,我命名成为my_arr

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
int sub_4010F0()
{
unsigned int v0; // eax
char Buffer[260]; // [esp+0h] [ebp-110h] BYREF
DWORD NumberOfBytesRead; // [esp+104h] [ebp-Ch] BYREF
unsigned int i; // [esp+108h] [ebp-8h]
char v5; // [esp+10Fh] [ebp-1h]

v5 = 0;
for ( i = 0; i < 260; ++i )
Buffer[i] = 0;
ReadFile(hFile, Buffer, 260u, &NumberOfBytesRead, 0);
for ( i = 0; ; ++i )
{
v0 = my_return_i(Buffer);
if ( i >= v0 )
break;
v5 = Buffer[i];
if ( v5 != '\n' && v5 != '\r' )
{
if ( v5 )
my_arr[i] = v5;
}
}
return 1;
}

发现在判断函数的上面的sub_4010F0()函数,已经开辟了my_arr数组了,

可以推理出my_arr里面的元素都是0,总数没细看,再回到判断函数。

v4 =的这个函数,我给它命名为my_rol,我属实没看懂这个是什么意思

1
2
3
4
__int16 sub_401000()
{
return __ROL4__(2147942400, 4) >> 1;
}

我假设就是向左移动一位的意思,为1,073,971,200

那也就是v4 = 1,073,971,200,i = v1 - 1,那么这个v1我猜是40

看了人家的脚本之后,v4=4??

这是我没想到的,差别大了……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
model = [0x0D,0x26,0x49,0x45,0x2A,0x17,0x78,0x44,0x2B,0x6C,0x5D,0x5E,0x45,0x12,0x2F,0x17,
0x2B,0x44,0x6F,0x6E,0x56,0x09,0x5F,0x45,0x47,0x73,0x26,0x0A,0x0D,0x13,0x17,0x48,
0x42,0x01,0x40,0x4D,0x0C,0x02,0x69]

print(model)

v4 = 4

my_flag = []

for i in range(38,-1,-1):
my_flag.append(model[i]^v4)
v4 = my_flag[-1]

flag = ''
for i in my_flag:
flag += chr(i)
print(flag[::-1])

R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com

网上还有一个爆破版本,不想动脑子了,球球了,我用python实现一下。

https://blog.csdn.net/Palmer9/article/details/105253318

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
model = [0x0D,0x26,0x49,0x45,0x2A,0x17,0x78,0x44,0x2B,0x6C,0x5D,0x5E,0x45,0x12,0x2F,0x17,
0x2B,0x44,0x6F,0x6E,0x56,0x09,0x5F,0x45,0x47,0x73,0x26,0x0A,0x0D,0x13,0x17,0x48,
0x42,0x01,0x40,0x4D,0x0C,0x02,0x69]

v4 = 4

flag = [0]*40

for i in range(38,-1,-1):
for j in range(128):
k = j
j ^= v4
if j == model[i]:
flag[i] = k
v4 = k
break
for i in flag:
print(chr(i),end = '')

2.9日补充:

最近比赛挺多,压力都很大,特地过来复习一下od动调:

关于od调试常用的快捷键:

https://mambainveins.gitee.io/2020/09/02/2020-09-02-GDB_common_instructions/

F7步进,也就是遇到一个函数会进去,就是步入call的意思。

F8步过,也就是遇到一个函数,执行完之后,不会进入call.

F9,直接执行

我们需要做的就是动态调试v4的值,v4在sub_401050这个函数中

然后值等于sub_401000()函数的返回值

首先我们是搜索字符串,定位提示性语句

F8一直步过,到输入字符串的位置停下

我们随便输入一串字符串,回车就能一直运行

现在到达401050这个位置,我们F7步进

然后F7一直步过

到401000下面,我们就能看到v4的值了

al = 4

Youngter-drive(windows多线程+index逆向)

Exeinfo:

有壳,咱们脱壳先,对比一下,没有了貌似

继续,咱们用IDA32打开

下一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
HANDLE Thread; // [esp+D0h] [ebp-14h]
HANDLE hObject; // [esp+DCh] [ebp-8h]

((void (*)(void))sub_4110FF)();
::hObject = CreateMutexW(0, 0, 0);
j_strcpy(Destination, &Source);
hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
Thread = CreateThread(0, 0, sub_41119F, 0, 0, 0);
CloseHandle(hObject);
CloseHandle(Thread);
while ( dword_418008 != -1 )
;
sub_411190();
CloseHandle(::hObject);
return 0;
}

首先是sub_4110FF()函数,我们跟进

1
((void (*)(void))sub_4110FF)();

输入语句,将输出的flag给Source,

1
2
::hObject = CreateMutexW(0, 0, 0);
::hObject = CreateMutexW(0, 0, 0);

CreateMutexW函数,创建或者打开一个命名或未命名的互斥对象

1
j_strcpy(Destination, Source);

将source赋值给destination

1
2
3
4
hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
Thread = CreateThread(0, 0, sub_41119F, 0, 0, 0);
CloseHandle(hObject);
CloseHandle(Thread);

创建线程 CreateThread(0, 0, StartAddress, 0, 0, 0),通常起始地址是程序代码中定义的函数名称

后面的CloseHandle真实关闭前面线程对象的句柄

我们跟进StartAddress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __stdcall __noreturn StartAddress_0(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
sub_41112C(Source, dword_418008);
--dword_418008;
Sleep(0x64u);
}
ReleaseMutex(hObject);
}
}

这边的sleep(0x64u)要当心,这个函数对字符串的加密是隔一个字符加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 已检测到正的sp值, 输出可能错误!     
char *__cdecl sub_411940(int a1, int a2)
{
char *result; // eax
char v3; // [esp+D3h] [ebp-5h]

v3 = *(a2 + a1);
if ( (v3 < 'a' || v3 > 'z') && (v3 < 'A' || v3 > 'Z') )
exit(0);
if ( v3 < 'a' || v3 > 'z' )
{
result = off_418000[0];
*(a2 + a1) = off_418000[0][*(a2 + a1) - 38];
}
else
{
result = off_418000[0];
*(a2 + a1) = off_418000[0][*(a2 + a1) - 96];
}
return result;
}

https://www.cnblogs.com/Mayfly-nymph/p/12573658.html

第二个线程执行的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
void __stdcall __noreturn sub_411B10(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
Sleep(0x64u);
--dword_418008;
}
ReleaseMutex(hObject);
}
}

有两个线程,别人博客上面,还得确认哪一个线程先执行,说是第二个先执行

也就是偶数不变,奇数会变。

下面是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding:utf-8 -*-

secret = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
flag = ''
model = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
for i in range(len(secret)):
if i % 2 == 0:
flag += secret[i]
continue
if(secret[i].isupper()):
flag += chr(model.find(secret[i]) + 96)
else:
flag += chr(model.find(secret[i]) + 38)
print ('flag{'+flag+'}')

不用看了,我甚至连线程的工作原理都不知道,先去看看python的多线程机制

https://www.runoob.com/python/python-multithreading.html

创建线程类,生成线程对象,将需要运行的函数放入run()这个方法中,而且每运行一次都需要获得锁,来保证线程的同步性,在运行完成之后需要释放锁,还可以把线程放入线程列表中,使其具有优先级,使其可以交替执行

现在可以理解了。。

flag{ThisisthreadofwindowshahaIsES}

z1r0的博客上说,最后差了一位,确实

传入的参数a2,是29,而我们要求的flag为30位

该爆破是就爆破:

1
2
3
flag = 'ThisisthreadofwindowshahaIsES'
for i in range(26):
print(flag+chr(ord('A')+i))

flag{ThisisthreadofwindowshahaIsESE}

[WUSTCTF2020]level2(upx脱壳)

查壳后发现有壳,upx工具走起

打开之后,没看到正确的主函数

在string窗口中,找到了,试试呗

好家伙,还真是

flag{Just_upx_-d}

去看看z1r0的博客吧,z1r0老师傅专程详解了汇编代码,我得好好看看

相册(apk病毒+base64)

有意思……

看了一段时间就麻了

看看z1r0的博客中,用的是导航中的搜索文本功能,搜索的是email

然后直接跟进sendMailjavamail

这个软件的操作和ida一样啊,x键就能看到引用的地方,跟进之后

跟进后面的的MAILSERVER

嗯,base64加密……

然后是解压apk,找到.so文件,我都不知道so文件是干嘛的

百度了一下,so文件对于linux系统来说,就像dll文件相对于windows系统一样,一般来讲,so文件称为共享库

https://blog.csdn.net/wangquan1992/article/details/113770115

我搞了半天也不知道so文件怎么打开

什么叫strings看一下,哈哈哈

1
2
3
4
5
6
7
import base64

string = 'MTgyMTg0NjUxMjVAMTYzLmNvbQ=='

flag = base64.b64decode(string)

print(flag)

18218465125@163.com

我的心态是这样的:

[HDCTF2019]Maze (easy 迷宫)

有壳,万能脱壳FFI,没有壳了应该

maze是迷宫的意思,之前做过一个迷宫的题目,被虐了

上来啥也别干,直接查看strings窗口

找到了!

用python 算了一下是70个字符,我猜是7*10

1
2
3
4
5
6
7
8
maze = "*******+********* ******    ****   ******* **F******    **************"

print(len(maze))

for i in range(7):
for j in range(10):
print(maze[i*10+j],end = '')
print()

这边是输入14个字符,看我上面的图案,还真是

接下来就是寻找规则了

22333233224441?

ssaaasaassdddw?

好家伙,第二个就对了,笑死了

flag{ssaaasaassdddw}

[WUSTCTF2020]level1

先查壳

没有壳,然后放到ida64中打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+4h] [rbp-2Ch]
FILE *stream; // [rsp+8h] [rbp-28h]
char ptr[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v7; // [rsp+28h] [rbp-8h]

v7 = __readfsqword(0x28u);
stream = fopen("flag", "r");
fread(ptr, 1uLL, 0x14uLL, stream);
fclose(stream);
for ( i = 1; i <= 19; ++i )
{
if ( (i & 1) != 0 )
printf("%ld\n", (unsigned int)(ptr[i] << i));
else
printf("%ld\n", (unsigned int)(i * ptr[i]));
}
return 0;
}

很清晰,output文本文件是输出之后的文件

直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
lists = [198,232,816,200,1536,300,6144,984,51200,570,92160,\
1200,565248,756,1474560,800,6291456,1782,65536000]

print(lists)
lists2 = []
for i in range(19):
if ((i+1) & 1) :
n = int(lists[i] >> (i+1))
lists2.append(n)
else:
n = int(lists[i] // (i+1))
lists2.append(n)
print(lists2)
for i in range(len(lists2)):
print(chr(lists2[i]),end = '')

需要注意的是

  1. i&1 == 1代表是奇数,i&1==0代表是偶数,
1
2
3
4
str[0]		没有输出
str[1] << 1
str[2] * 2
str[3] << 3

而对于我们output文件,我们看到的第一个数字198其实是在第二个,所以,可以理解为什么是 int(lists[i] >> (i+1))

  1. i & 1 == 0 代表i是偶数 i & 1 == 1代表i是奇数

最终结果:ctf2020{d9-dE6-20c}

[MRCTF2020]Transform(index 逆向)

首先是查壳,没有壳,我们用ida64打开

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str[104]; // [rsp+20h] [rbp-70h] BYREF
int j; // [rsp+88h] [rbp-8h]
int i; // [rsp+8Ch] [rbp-4h]

sub_402230(argc, argv, envp);
sub_40E640("Give me your code:\n");
sub_40E5F0("%s", Str);
if ( strlen(Str) != 33 )
{
sub_40E640("Wrong!\n");
system("pause");
exit(0);
}
for ( i = 0; i <= 32; ++i )
{
byte_414040[i] = Str[dword_40F040[i]];
byte_414040[i] ^= LOBYTE(dword_40F040[i]);
}
for ( j = 0; j <= 32; ++j )
{
if ( byte_40F0E0[j] != byte_414040[j] )
{
sub_40E640("Wrong!\n");
system("pause");
exit(0);
}
}
sub_40E640("Right!Good Job!\n");
sub_40E640("Here is your flag: %s\n", Str);
system("pause");
return 0;
}

可以看到,第一个for循环是把输入的字符放到了str中,str[dword_40F040[i]]把值给了byte_414040,byte_414040再与dword_40F040[i]进行异或

下面的for 循环是将dword_40F040[i]与byte_40F0E0做比较

参考链接:https://www.cnblogs.com/Mayfly-nymph/p/12806027.html

总体来说

就是将输入的flag使用dword数组作为索引,打乱顺序

再将打乱后的flag数组,与dword数组异或,得到byte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dword = [0x9, 0x0A, 0x0F, 0x17, 0x7, 0x18, 0x0C, 0x6, 0x1, 0x10,\
0x3, 0x11, 0x20,0x1D, 0x0B, 0x1E, 0x1B, 0x16, 4, 0x0D, 0x13, 0x14, \
0x15, 0x2, 0x19, 0x5, 0x1F, 0x8, 0x12, 0x1A, 0x1C, 0x0E, 0]

byte = [ 0x67, 0x79, 0x7B, 0x7F, 0x75, 0x2B,\
0x3C, 0x52, 0x53, 0x79, 0x57, 0x5E, 0x5D, 0x42,\
0x7B, 0x2D, 0x2A, 0x66, 0x42, 0x7E, 0x4C, 0x57,\
0x79, 0x41, 0x6B, 0x7E, 0x65, 0x3C, 0x5C, 0x45,\
0x6F, 0x62, 0x4D]

flag = [0]*33


for i in range(len(dword)):
byte[i] ^= dword[i]

for i in range(len(dword)):
flag[dword[i]] = byte[i]

flag = ''.join([chr(i) for i in flag])

print(flag)

flag{Tr4nsp0sltiON_Clph3r_1s_3z}

原来关于index转换的题目还能这么做,创建一个全为0的flag列表,然后正序的推理……

[ACTF新生赛2020]usualCrypt

查个壳,没有壳,用IDA32打开

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // esi
int v5[3]; // [esp+8h] [ebp-74h] BYREF
__int16 v6; // [esp+14h] [ebp-68h]
char v7; // [esp+16h] [ebp-66h]
char v8[100]; // [esp+18h] [ebp-64h] BYREF

sub_403CF8((int)&unk_40E140);
scanf("%s", v8);
memset(v5, 0, sizeof(v5));
v6 = 0;
v7 = 0;
sub_401080(v8, strlen(v8), v5); //加密函数
v3 = 0;
while ( *((_BYTE *)v5 + v3) == byte_40E0E4[v3] ) //匹配函数
{
if ( ++v3 > strlen((const char *)v5) )
goto LABEL_6;
}
sub_403CF8((int)aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
return sub_403CF8((int)aAreYouHappyYes);
else
return sub_403CF8((int)aAreYouHappyNo);
}

分析一下:

首先是输入将flag放入v8数组中,然后进入了sub_401080这个函数,猜测应该是加密函数,我们继续跟进。

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
int __cdecl sub_401080(int a1, int a2, int a3)
{
int v3; // edi
int v4; // esi
int v5; // edx
int v6; // eax
int v7; // ecx
int v8; // esi
int v9; // esi
int v10; // esi
int v11; // esi
_BYTE *v12; // ecx
int v13; // esi
int v15; // [esp+18h] [ebp+8h]

v3 = 0;
v4 = 0;
sub_401000();
v5 = a2 % 3;
v6 = a1;
v7 = a2 - a2 % 3;
v15 = a2 % 3;
if ( v7 > 0 )
{
do
{
LOBYTE(v5) = *(a1 + v3);
v3 += 3;
v8 = v4 + 1;
*(v8 + a3 - 1) = base[(v5 >> 2) & 0x3F];
*(++v8 + a3 - 1) = base[16 * (*(a1 + v3 - 3) & 3) + ((*(a1 + v3 - 2) >> 4) & 0xF)];
*(++v8 + a3 - 1) = base[4 * (*(a1 + v3 - 2) & 0xF) + ((*(a1 + v3 - 1) >> 6) & 3)];
v5 = *(a1 + v3 - 1) & 0x3F;
v4 = v8 + 1;
*(v4 + a3 - 1) = base[v5];
}
while ( v3 < v7 );
v5 = v15;
}
if ( v5 == 1 )
{
LOBYTE(v7) = *(v3 + a1);
v9 = v4 + 1;
*(v9 + a3 - 1) = base[(v7 >> 2) & 0x3F];
v10 = v9 + 1;
*(v10 + a3 - 1) = base[16 * (*(v3 + a1) & 3)];
*(v10 + a3) = 61;
LABEL_8:
v13 = v10 + 1;
*(v13 + a3) = 61;
v4 = v13 + 1;
goto LABEL_9;
}
if ( v5 == 2 )
{
v11 = v4 + 1;
*(v11 + a3 - 1) = base[(*(v3 + a1) >> 2) & 0x3F];
v12 = (v3 + a1 + 1);
LOBYTE(v6) = *v12;
v10 = v11 + 1;
*(v10 + a3 - 1) = base[16 * (*(v3 + a1) & 3) + ((v6 >> 4) & 0xF)];
*(v10 + a3) = base[4 * (*v12 & 0xF)];
goto LABEL_8;
}
LABEL_9:
*(v4 + a3) = 0;
return sub_401030(a3);
}

一开始是一个sub_401000函数

1
2
3
4
5
6
7
8
9
10
11
12
13
int sub_401000()
{
int result; // eax
char v1; // cl

for ( result = 6; result < 15; ++result )
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = base[result];
base[result] = v1; //怎么这么熟悉,C语言里的替换??
}
return result;
}

这个函数的意思是将base表中的

我们进入这个byte_40E0AA查看,貌似不是普通的base64加密函数

我们已知:

base:ABCDEFGHIJ

byte_40E0AA:KLMNOPQRS…………

查看跳出sub_401000,查看后面代码,可以看出是base64加密

我们再继续往后看

1
return sub_401030(a3);

最后有一个sub_401030函数,我们继续跟进python

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
int __cdecl sub_401030(const char *a1)
{
__int64 v1; // rax
char v2; // al

v1 = '\0';
if ( strlen(a1) )
{
do
{
v2 = a1[HIDWORD(v1)];
if ( v2 < 'a' || v2 > 'z' )
{
if ( v2 < 'A' || v2 > 'Z' )
goto LABEL_9;
LOBYTE(v1) = v2 + 32;
}
else
{
LOBYTE(v1) = v2 - 32;
}
a1[HIDWORD(v1)] = v1;
LABEL_9:
LODWORD(v1) = 0;
++HIDWORD(v1);
}
while ( HIDWORD(v1) < strlen(a1) );
}
return v1;
}

可以看出这个函数的意思就是把加密后的结果大小写字母转换,

看最后的比较函数,

1
2
3
4
5
6
7
8
9
10
11
12
 while ( *(v5 + v3) == byte_40E0E4[v3] )       // 匹配函数
{
if ( ++v3 > strlen(v5) )
goto LABEL_6;
}
my_print(aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
return my_print(aAreYouHappyYes);
else
return my_print(aAreYouHappyNo);
}

这么多应该都是比较函数,我是这么理解的:

如果v5这个字符串与byte_40E0E4这个字符串相等,则会一直执行while循环对比,直到v3=strlen(v5)+1,然后进入LABEL_6比较,相等则v3-1=strlen(v5),就输出正确的提示信息;

如果v5与这个字符串有一个不相等,则直接会退出while循环,这时

然后跟进byte_40E0E4,这个时候长度一定不相等,就输出错误的提示信息。

最后与加密之后对比的字符串为:

1
string = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9"

有个疑问哈,这个z和后面的是分离的,所以怎么分辨那些块是那个字符串,还是可以共用??如果是aMxh3……字符串这他对应的内容是多少,是和string一致,还是比string少一个z……

在询问大佬z1r0之后,得知,A 键可以使字符串连接起来

所以,base64对应的字符串:

1
base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

参考链接:https://blog.csdn.net/yhfgs/article/details/117449856?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0.pc_relevant_default&spm=1001.2101.3001.4242.1&utm_relevant_index=3

我们理一下,

  1. 先把这个string大小写先转换
  2. 修改base64转换表
  3. 加密结果通过转换表得到正常加密的结果
  4. base64解密

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import base64
import string

# 大小写转换
string = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase()

# 换表
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

lis = list(base)

for i in range(6,15):
lis[10+i],lis[i] = lis[i],lis[10+i]

new_base = ''.join(lis)


# base64换表解密
flag = ''
flag += str(base64.b64decode(string.translate(str.maketrans(new_base,base))))
print(flag)

flag{bAse64_h2s_a_Surprise}

[2019红帽杯]easyRE(.fini)

查壳之后没有壳,直接用ida64打开,我一般是直接按Tab键看伪代码的

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
__int64 sub_4009C6()
{
__int64 result; // rax
int i; // [rsp+Ch] [rbp-114h]
__int64 v2; // [rsp+10h] [rbp-110h]
__int64 v3; // [rsp+18h] [rbp-108h]
__int64 v4; // [rsp+20h] [rbp-100h]
__int64 v5; // [rsp+28h] [rbp-F8h]
__int64 v6; // [rsp+30h] [rbp-F0h]
__int64 v7; // [rsp+38h] [rbp-E8h]
__int64 v8; // [rsp+40h] [rbp-E0h]
__int64 v9; // [rsp+48h] [rbp-D8h]
__int64 v10; // [rsp+50h] [rbp-D0h]
__int64 v11; // [rsp+58h] [rbp-C8h]
char v12[13]; // [rsp+60h] [rbp-C0h] BYREF
char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF
char v14[19]; // [rsp+71h] [rbp-AFh] BYREF
char v15[32]; // [rsp+90h] [rbp-90h] BYREF
int v16; // [rsp+B0h] [rbp-70h]
char v17; // [rsp+B4h] [rbp-6Ch]
char v18[72]; // [rsp+C0h] [rbp-60h] BYREF
unsigned __int64 v19; // [rsp+108h] [rbp-18h]

v19 = __readfsqword(0x28u);
qmemcpy(v12, "Iodl>Qnb(ocy", 12);
v12[12] = 127;
qmemcpy(v13, "y.i", 3);
v13[3] = 127;
qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));
memset(v15, 0, sizeof(v15));
v16 = 0;
v17 = 0;
sub_4406E0(0, v15, 37LL);
v17 = 0;
if ( sub_424BA0(v15) == 36 )
{
for ( i = 0; i < sub_424BA0(v15); ++i )
{
if ( (v15[i] ^ i) != v12[i] )
{
result = 4294967294LL;
goto LABEL_13;
}
}
sub_410CC0("continue!");
memset(v18, 0, 65);
sub_4406E0(0, v18, 64LL);
v18[39] = 0;
if ( sub_424BA0(v18) == '\'' )
{
v2 = my_base64(v18);
v3 = my_base64(v2);
v4 = my_base64(v3);
v5 = my_base64(v4);
v6 = my_base64(v5);
v7 = my_base64(v6);
v8 = my_base64(v7);
v9 = my_base64(v8);
v10 = my_base64(v9);
v11 = my_base64(v10);
if ( !sub_400360(v11, off_6CC090) )
{
sub_410CC0("You found me!!!");
sub_410CC0("bye bye~");
}
result = 0LL;
}
else
{
result = 4294967293LL;
}
}
else
{
result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v19 )
sub_444020();
return result;
}

当我发现这个sub_400E44是base64之后,n键改个名字:my_base64

上面有一堆混淆人的伪代码,咱们直接看重点就行,

1
memset(v18, 0, 65);

为v18初始化

1
sub_4406E0(0, v18, 64LL);

结合上下文可以知道这个sub_44065E0是赋值给v18的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if ( sub_424BA0(v18) == '\'' )
{
v2 = my_base64(v18);
v3 = my_base64(v2);
v4 = my_base64(v3);
v5 = my_base64(v4);
v6 = my_base64(v5);
v7 = my_base64(v6);
v8 = my_base64(v7);
v9 = my_base64(v8);
v10 = my_base64(v9);
v11 = my_base64(v10);
if ( !sub_400360(v11, off_6CC090) )
{
sub_410CC0("You found me!!!");
sub_410CC0("bye bye~");
}

然后就是将v18base64加密十次,与off_6cc090比较,我们直接把off_6cc090反向解密10次就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string = 'Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1\
NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaF\
ZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1\
IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSF\
VYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1\
ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1\
RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbG\
JVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE\
5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1\
YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ=='

#十次base64解密之后:?????
string_2 = 'https://bbs.pediy.com/thread-254172.htm'

print(string)

炸了,给我跳出一个网址。在查看z1r0的博客后,有些不理解的地方,不知道他关于真正flag函数是怎么找到的,在询问z1r0之后,z1r0贴心地给了我提示,我总结一下:

1
2
3
4
5
v10 = my_base64(v9);
v11 = my_base64(v10);
if ( !sub_400360(v11, off_6CC090) )
{
sub_410CC0("You found me!!!");

这个off_6cc090就是我们上面要比对的字符串,我们跟进之后:

我们可以先对off_6CC090这个字符串按x,就会弹出下面的框框,可以看到

  1. 引用这个字符串所在的函数(也就是上面10个base64加密的坑人的那个……)
  2. 引用类型r,
  3. 文本(应该是汇编指令)

(看来我得好好的去看看IDA权威指南了,一脸蒙蔽……)

然后看颜色就可以知道,下面的byte_6CC0A0,处在同一个段中,我们跟进,然后切换伪代码视图:

我们继续按x,然后就可以看到引用了,我们继续跟进:

地址为.fini_array:00000000006CBEE8

进程终止代码的一部分。程序正常退出时,系统将安排执行这边的代码!!!

所以这个函数很重要的!!!我们直接点击 sub_400D35这个函数跟进,然后按下tab:

出来了!!

1
if ( (v1 ^ byte_6CC0A0[0]) == 'f' && (HIBYTE(v4) ^ byte_6CC0A3) == 'g' )

瞧瞧这第20行的地方,一个f,一个g,很有希望!!

看上面一行,v4=v1,那就很好理解了:

直接把大佬的原话搬出来:

https://www.zhihu.com/people/xu-xu-xuxu-94

后面我看不懂z1r0博客中exp的十六进制数从哪里来的,我就去寻找资料

https://www.i4k.xyz/article/Palmer9/103940709

说找到这串不随机的数,怎么找的,我就用IDA跳转地址的功能,G就可以了

手动输入了一下,发现还真有

用刚学的知识分析一下:

r代表读取交叉引用,说明sub_400D35函数引用了这串字符,我怎么没看到……

跟进去发现,就是这个byte_6CC0A0……(百度一下眼瞎怎么治)

直接上z1r0的代码,不解释了,看懂就行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
v4 = ''

str1 = 'flag'

key1 = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]

for i in range(4):
v4 += chr(key1[i] ^ ord(str1[i]))

print(v4)

flag = ''

for i in range(25):
flag += chr(key1[i] ^ ord(v4[i % 4]))

print(flag)

看这个代码就清晰多了,key里面的是那些特殊字符的16进制形式,我们需要求出v4,使得v4的前四位能与key中的前四位进行异或操作时,等于flag,所以我们进行了key1[i]与ord(str1[i])的异或操作,将其还原回来,嗯,可以理解……

1
2
3
4
5
6
7
8
v4 = ''

str1 = 'flag'

key1 = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]

for i in range(4):
v4 += chr(key1[i] ^ ord(str1[i]))

然后就是让key1中的每个字符,与v4[i%4]进行异或操作,为什么要求余4?因为v4一共就四位。

1
2
3
4
5
6
flag = ''

for i in range(25):
flag += chr(key1[i] ^ ord(v4[i % 4]))

print(flag)

flag{Act1ve_Defen5e_Test}

这也真“easy”,真不错……

[GUET-CTF2019]re (暴力+次序)

先查壳,发现有upx壳子,然后我们用upx脱个壳

然后放到IDA 64里面查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__int64 __fastcall sub_400E28(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
int v6; // edx
int v7; // ecx
int v8; // er8
int v9; // er9
__int64 result; // rax
__int64 v11[5]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v12; // [rsp+28h] [rbp-8h]

v12 = __readfsqword(0x28u);
memset(&v11[1], 0, 24);
sub_40F950((__int64)"input your flag:", a2, a3, a4, a5, a6);
sub_40FA80((unsigned int)"%s", (unsigned int)v11, v6, v7, v8, v9, 0);
if ( sub_4009AE((char *)v11) )
sub_410350((__int64)"Correct!");
else
sub_410350((__int64)"Wrong!");
result = 0LL;
if ( __readfsqword(0x28u) != v12 )
sub_443550();
return result;
}

不要慌张,我们直接看correct的上一行,根据我的推测,从键盘输入的字符应该是放到了v11中,我们直接看sub_4009AE这个函数

我们需要求的就是a1这个数组了

然后我们直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
lists1 = [1629056,6771600,3682944,10431000,3977328, 5138336,7532250,\
5551632,3409728,13013670,6088797,7884663,8944053,5198490,\
4544518,3645600,10115280,9667504,5364450,13464540, 5488432,\
14479500,6451830,6252576,7763364,7327320,8741520,8871876,\
4086720,9374400,5759124]

lists2 = [166163712,731332800 ,357245568,1074393000,489211344,518971936,\
406741500,294236496,177305856,650683500,298351053,386348487,\
438258597,249527520,445362764,174988800,981182160,493042704,\
257493600,767478780,312840624,1404511500,316139670,619005024,\
372641472,373693320,498266640,452465676,208422720,515592000,\
719890500]

lists = []
for i in range(len(lists1)):

lists.append(chr(int(lists2[i]/lists1[i])))

for i in lists:
print(i,end = '')

flag{e65421110b0a3099a1c039337},提交之后竟然错了。。。

知错就改,z1r0中的博客说a[6]不存在,z1r0然后用暴力枚举,把a[6]给爆破出来了,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
lists1 = [1629056,6771600,3682944,10431000,3977328, 5138336,7532250,\
5551632,3409728,13013670,6088797,7884663,8944053,5198490,\
4544518,3645600,10115280,9667504,5364450,13464540, 5488432,\
14479500,6451830,6252576,7763364,7327320,8741520,8871876,\
4086720,9374400,5759124]

lists2 = [166163712,731332800 ,357245568,1074393000,489211344,518971936,\
406741500,294236496,177305856,650683500,298351053,386348487,\
438258597,249527520,445362764,174988800,981182160,493042704,\
257493600,767478780,312840624,1404511500,316139670,619005024,\
372641472,373693320,498266640,452465676,208422720,515592000,\
719890500]

lists = []
for i in range(len(lists1)):

lists.append(chr(int(lists2[i]/lists1[i])))

flag = "".join(lists)
print(flag)

for i in range(10):
print(flag[0:6]+chr(48+i)+flag[6:len(flag)])

奇怪啊,z1r0说,结果为第二个,为什么还是错的??

返回ADI中,我看到了:

还得注意次序!!

flag{e165421110ba03099a1c039337}

[SUCTF 2019] SignIn(rsa plus)

RSA绝对是当今应用最为广泛的公钥加密算法

这是我第二次碰到rsa算法了,这次不能放过它了

这里我参考了b站油管rsa的介绍

https://www.bilibili.com/video/BV14y4y1272w?from=search&seid=6444314376553406414&spm_id_from=333.337.0.0

看看z1r0的博客,发现一篇文章也说的很好

https://blog.csdn.net/dbs1215/article/details/48953589

  1. 什么是rsa?

rsa是一种加密和解密使用不同密码的方式,因此公钥密码通常车给非对称密码

  1. rsa加密

密文=明文^E mod N

常说的公钥为E和N的组合,我们就用(E,N)来表示公钥

  1. rsa解密

明文=密文^D mod N

对密文进行D次方后除以N的余数就是明文,这就是RSA解密过程,知道D和N就能进行

  1. 一般题目的解题方法

一般的题目中会给出我们E和N,这两个是属于公钥,我们可以先把N放到因式分解工具找出P和Q,然后通过rsatool求出d——需要把N,E,Q,P都放到rsatool中并且调试对应的配置,最后是脚本的编写,具体我会放在后面

1
因式分解工具:http://www.factordb.com/index.php

先查看题目,记得是没有壳的

记住rsa的特性,一个非常长的数字N,还有一个很短的数字E

分析一下题目,v8用来接受输入的字符,然后v8,v9进入了一个sub_96A的函数,我们跟进查看

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
#include <stdio.h>
#include <string.h>

int byte_202010[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};

size_t sub_96A(const char *a1, char *a2)
{
size_t result;
int v3 = 0;
int i;
for (i = 0;; i += 2)
{
result = strlen(a1);
result = strlen(a1);
if (v3 >= result)
break;
a2[i] = byte_202010[a1[v3] >> 4];
a2[i + 1] = byte_202010[a1[v3++] & 0xF];
}
return result;
}
int main(int argc,char **argv)
{
char v8[20];
char v9[101];
scanf("%s", v8);
sub_96A(v8, v9);
printf("%s\n", v9);
return 0;
}
//C语言,16进制位0x,和python一致
//size_t为无符号整数类型
//字符数组的形式参数,用char * a
//字符数组的输出,直接用%s就行了

以上参考z1r0的代码,该函数的功能是将v8的字符串转换为16进制放入v9,然后就是下面的两个函数,gmpz_init_set_str和gmpz_powm

是GNU的高精度算法??

1
2
3
4
5
6
7
8
9
10
11
__gmpz_init_set_str(v7, "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);
__gmpz_init_set_str(v6, v9, 16LL);

__gmpz_init_set_str(v4, "103461035900816914121390101299049044413950405173712170434161686539878160984549", 10LL);

__gmpz_init_set_str(v5, "65537", 10LL);
__gmpz_powm(v6, v6, v5, v4);
if ( __gmpz_cmp(v6, v7) )
puts("GG!");
else
puts("TTTTTTTTTTql!");

将ad939ff59~~这个字符串以16进制写入v7

将1034~~这个数字以10进制写入v4

将65537这个字符串以10进制写入v5

__gmpz_pown(v6,v6,v5,v4),意思是计算v6的v5次方,并对v4取模,写入v6,现在我终于看明白了,v6相当于明文,v5相当于E,v4相当于N,

rsa的加密算法:明文^E%N

__gmpz_cmp是一个比较函数,看名字就知道了

rsa加密之后与ad939ff59~~这个函数作比较

我们先用因式分解工具来算出P和Q

1
2
P:282164587459512124844245113950593348271
Q:366669102002966856876605669837014229419

然后用rsatool求出d

记住要先选择number base,即进制,然后再输入数据。

D = 91646299298871237857836940212608056141193465208586711901499120163393577626813

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
import binascii
N = 103461035900816914121390101299049044413950405173712170434161686539878160984549
E = 65537
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
D = 91646299298871237857836940212608056141193465208586711901499120163393577626813
C = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35

M = gmpy2.powmod(C, D, N)

print(binascii.unhexlify(hex(M)[2:]))

https://blog.csdn.net/weixin_60553183/article/details/122084511

我得理一下,gmpy2是干嘛的。

下面是关于gmpy2的常见函数的使用

https://blog.csdn.net/weixin_43790779/article/details/108473984

powmod是求大整数x的y次幂m取余,

b‘suctf{Pwn*@*hundred_years}’

xor (异或)

首先用exeinfoPE判断一下

是64位的,没有加壳,然后用IDA 64位打开,找到main函数

然后就是分析主函数,输入v6,让v6和global作比较,由题目得知,如果如数v6的长度没有33,则直接跳转到LABLE_12的位置,输出Failed

然后就是分析伪代码

下面是脚本的编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
lists = ['f',0x0A,'k',0x0C,'w','&','O','.','@',0x11,\
'x',0x0D,'Z',';','U',0x11,'p',0x19,'F',0x1F,\
'v','"','M','#','D',0x0E,'g',6,'h',0x0F,'G','2','O']


for i in range(1,len(lists)):
if (isinstance(lists[i],int)):
lists[i] = chr(lists[i])

string = ''.join(lists)

flag = 'f'
for i in range(1,len(lists)):
flag += chr(ord(lists[i]) ^ ord(lists[i-1]))
print(flag)
print(len(lists))
  1. 将伪代码中的单个字符保持不动,连起来的字符分开,十六进制的在前面填上0x进制符号,并删除后面的h,然后放入列表lists

  2. 将列表中的int类型转换位char类型,用isinstance( x, type)方法来比较

  3. 将列表中的元素转换为字符串,如果这时输出,那么十六进制的那一块将转换为空格

  4. 然后将字符串的字符一次进行异或运算,最终输出得到flag

hello word(apk逆向)

写在后面的话:

apk反汇编推荐用jadx-gui和GDAE

–正文–

参考资料:https://www.zhihu.com/question/29370382

  1. 使用apktool

cmd+D,打开dos,找到apk的目录,然后键入

1
apktool d 名字.apk

即可。

解出以上资源

1
2
CD			进入
CD ../ 进入上一层目录

但是我们需要的是.dex文件,所以此时应该再运行

1
apktool d -s -f 名字.apk

-s 不反编译dex文件,而是将其保留

-f 如果目标文件夹存在,则删除后重新反编译

d 反编译apk文件

将修改完的apk重新打包

1
apktool b 目录名 -o newtest.apk

-b build

-o 新的文件名

  1. 使用dex2jar工具

参考链接:https://www.jianshu.com/p/dbe579f6cc84

将apktool反汇编所得文件的classes.dex复制到dex2jar.bat所在目录

我的存放地址是:C:\Users\Lenovo\Desktop\dex2jar-2.0

然后在命令行中键入

1
d2j-dex2jar classes.dex

生成了一个class-dex2jar.jar文件,就是反编译后的java源码文件

  1. 使用jd-gui.exe运行生成的反编译的Java源码

然后用jd-gui.exe运行生成的class-dex2jar.jar文件,就可以看到源码了

reverse_3 (base64)

1
if ( !strncmp(Dest, Str2, v6) )

strncmp()函数,str2与Dest作比较,最多比较前v6个字符串长度

结果为0,则两个字符串相等

1
strncpy(Dest, v5, 40u);

strncpy()函数,v5复制到Dest字符数组中,长度为40u

1
memset(str,'$',7)

memset()函数,将符号‘$’复制到str字符数组中,长度为7

根据大佬写的知乎,发现这个是base64的编码,好家伙,python两行搞完。

1
2
3
4
5
6
7
8
9
10
11
12
13
import base64
str1 = "e3nifIH9b_C@n@dH"
lists = [i for i in str1]

str2 = ''

for i in range(len(lists)):
lists[i] = chr(ord(lists[i])-i)
str2 += lists[i]

print(str2)
str3 = base64.b64decode(str2)
print(str3)

Simple_Rev (ADI小端存储)

参考链接

今天吃了个大亏

ADA里面的字符存储是小端存储

小端存储就是低地址存放到底位上,高地址存放到高位上。

以下是小端存储模式下的0x123456的存储,明显看到次序是颠倒的

所以,遇到这种直接把字符需要小心,先转换一下次序再说

首先我们测一下这个exe文件是否有壳

说句实话,我看不出来,貌似有一个压缩壳,然后是需要64位的Ada使用

打开之后看一下伪代码

主要是进Decry()函数看一下,进去之后就是新世界

这边就是主要算法了

这种的意思是字母大写转换为小写,key由大写转换为小写

通过循环上面的得知,

key = ‘adsfkndcls’ text = ‘killshadow’

看一下算法主题,就是一个while()循环,输入字符,如果碰到换行符直接退出。

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
key = 'adsfkndcls'
text = 'killshadow'

flag = ''

#flag长度
n = len(text)

for i in range(n):

#ASCII码一共128个,依次循环
for j in range(128):

#不是字符,直接下一次循环
if j < ord('A') or j > ord('z') \
or (j < ord('a') and j > ord('Z')):

continue

#枚举
if (j - 39 - ord(key[n % 10]) +97) %26 +97 \
== ord(text[i]):

flag += chr(j)
n += 1
break

print(flag)

就是要把题目给理解透彻了才行

题目的意思是如果不是字母(大写小写皆可),就直接退出,如果是字母,就执行下面的转换,转换的里面还挺复杂的,所以直接就暴力枚举。

判断是不是字母还有点小绕

[GXYCTF2019]luck_guy (ADI小端存储)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
f1 = "GXY{do_not_"

#小端,所以逆一下
f2 = 'fo`guci'[::-1]

lists = [i for i in f2]

for j in range(0,8):
if j%2 == 1:
lists[j] = chr(ord(lists[j]) -2)

else:
lists[j] = chr(ord(lists[j]) -1)

string = ''.join(lists)

print(f1+string)

memset参考文档http://c.biancheng.net/view/231.html

memset()是初始化内存的万能函数,初始化之后,再向内存空间中存放需要的值,一般来说使用“0”初始化内存单元,通常给数组或结构体进行初始化,其实相当于结束标志‘\0’,最后面的参数是长度,一般专业一点会写sizeof(XX)

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
char f1[] = "GXY{do_not_";
char f2[] = "hate_me}";
char flag[20];
memset(flag,0,20);
printf("%s",flag);
strcat(flag,f1);
strcat(flag,f2);
puts(flag);
return 0;
}

所以基础很重要啊!!!

首先我们来分析一下题目,

进入patch_me函数

再进入get_flag函数

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
v7 = __readfsqword(40u);
v0 = time(0LL);
srand(v0);
for ( i = 0; i <= 4; ++i )
{
switch ( rand() % 200 )
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 40uLL);
strcat((char *)&s, f1);
strcat((char *)&s, &f2);
printf("%s", &s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
v6 = 0;
s = 'fo`guci';
strcat(&f2, (const char *)&s);
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )
char_1 = *(&f2 + j) - 2;
else
char_1 = *(&f2 + j) - 1;
*(&f2 + j) = char_1;
}
break;
default:
puts("emmm,you can't find flag 23333");
break;

产生一个随机数,并进入switch结构,我们可以看出,按照4、5、1的顺序,就能求出flag,记得要注意ADI的小端优先

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
flag = 'GXY{do_not_'
f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]

print(f2)

ss = ''
final = ''

for i in range(8):
if i % 2 == 1:
s = chr(f2[i] - 2)
else:
s = chr(f2[i] - 1)
flag += s

print(flag)

flag{do_not_hate_me}

刮开有奖 (ASCII排序+base64)

首先查壳,分析一下是32位的程序,没有壳,所以用ida32打开

DialogFunc是一个函数,咱们跟进去

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
if ( strlen(String) == 8 )
{
str1[0] = 'Z';
str1[1] = 'J';
str2 = 'S';
str3 = 'E';
str4 = 'C';
str5 = 'a';
str6 = 'N';
str7 = 'H';
str8 = '3';
str9 = 'n';
str10 = 'g';
my_results(str1, 0, 10);
memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = base_64(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = base_64(v18, strlen(v18));
if ( String[0] == str1[0] + 34
&& String[1] == str4
&& 4 * String[2] - 141 == 3 * str2
&& String[3] / 4 == 2 * (str7 / 9)
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
{
MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
}
}
return 0;

查看定义的字符的汇编代码

可以发现其实就是一连串的连续空间,就是一个字符数组

然后进入一个函数,看参数,第二个是0,第三个是10,既然看不懂,就直接把它改一改,放到vscode里面运行一下,因为我们知道它的参数了

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
# include <stdio.h>

int my_results (char arr[], int a, int b)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx

result = b;
for ( i = a; i <= b; a = i )
{
v5 = i;
v6 = arr[i];
if ( a < result && i < result )
{
do
{
if ( v6 > arr[result] )
{
if ( i >= result )
break;
++i;
arr[v5] = arr[result];
if ( i >= result )
break;
while ( arr[i] <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = i;
arr[result] = arr[i];
}
--result;
}
while ( i < result );
}
LABEL_13:
arr[result] = v6;
my_results(arr, a, i - 1);
result = b;
++i;
}
return result;
}
int main(){
char arr[20] = {90,74,83,69,67,97,78,72,51,110,103};
puts(arr);
my_results(arr, 0, 10);
puts(arr);
return 0;
}

不怎么接触c语言,昨天才知道,*(a+i)其实相当于数组a[i],a是基准地址,i是偏移量,后面我就知道了,这个函数的形参的第一个其实就是字符数组,之前定义的。

运行完成后,其实就是对定义的字符进行了排序,有ASCII从小到大排序

再看这边,String就是我们输入的数字

用v18这个数组来存储,然后把v18放置在函数中,第二个参数是长度

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
v2 = a2 / 3;
v3 = 0;
if ( a2 % 3 > 0 )
++v2;
v4 = 4 * v2 + 1;
v5 = malloc(v4);
v6 = v5;
v15 = v5;
if ( !v5 )
exit(0);
memset(v5, 0, v4);
v7 = a2;
v8 = v6;
v16 = v6;
if ( a2 > 0 )
{
while ( 1 )
{
v9 = 0;
v10 = 0;
v18 = 0;
do
{
if ( v3 >= v7 )
break;
++v10;
v9 = *(v3 + a1) | (v9 << 8);
++v3;
}
while ( v10 < 3 );
v11 = v9 << (8 * (3 - v10));
v12 = 0;
v17 = v3;
for ( i = 18; i > -6; i -= 6 )
{
if ( v10 >= v12 )
{
*(&v18 + v12) = (v11 >> i) & 0x3F;
v8 = v16;
}
else
{
*(&v18 + v12) = 64;
}
*v8++ = byte_407830[*(&v18 + v12++)];
v16 = v8;
}
v3 = v17;
if ( v17 >= a2 )
break;
v7 = a2;
}
v6 = v15;
}
result = v6;
*v8 = 0;
return result;
}

用z1r0的话就是盲猜是base64解码

这边会有移动,是base64的最明显的特征,把这个函数取名为base_64,后面还有一个base64的编码

这边就很简单了,注意,str1[0]的值是排序完成之后的值

ZJSECaNH3ng

3CEHJNSZagn

str1[0] = 3, string[0] = U

str4 = J, string[1] = J

string [3] = P

1
2
3
4
a = 'Z'
b = 'Z'
print(chr(ord(a)+34))
print(chr(int(ord(b)/9*8)))

最后结合起来string,即flag{UJWP1jMp}

[BJDCTF2020]JustRE (水题)

既然程序看不懂,就找找字符列表中,有没有能看懂的,发现最后有个可疑字符

咱们点进去

内存中的数字直接按住tab是不能显示伪代码的,得点击函数才行

然后就是读一下程序

我认为上面的19999是鼠标点击的次数,点击这么多次后,然后就会弹出flag

sprintf函数,共有三个参数,第二个是格式,第一个是需要赋值的字符串,后面两个是被格式化的变量,所以flag{1999902069a45792d233ac}

简单注册器(apk逆向)

写在后面的话:

apk反汇编推荐用jadx-gui或GDAE

首先用apkide打开apk文件

  1. 打开apkIDE,然后把apk文件拖到右边(不是直接将apk拖入apkIDE)

  2. 等它自动转换后,找到输出目录

直接复制到地址栏跳转,找到MainActivity.class文件

  1. 最后将这个文件用jd-gui打开

so easy

然后就是阅读程序

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
package com.example.flag;

import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

class null implements View.OnClickListener {
public void onClick(View paramView) {
int i = 1;
String str = editview.getText().toString();
if (str.length() != 32 || str.charAt(31) != 'a' || str.charAt(1) != 'b' || str.charAt(0) + str.charAt(2) - 48 != 56)
i = 0;
if (i == 1) {
char[] arrayOfChar = "dd2940c04462b4dd7c450528835cca15".toCharArray();
arrayOfChar[2] = (char)(arrayOfChar[2] + arrayOfChar[3] - 50);
arrayOfChar[4] = (char)(arrayOfChar[2] + arrayOfChar[5] - 48);
arrayOfChar[30] = (char)(arrayOfChar[31] + arrayOfChar[9] - 48);
arrayOfChar[14] = (char)(arrayOfChar[27] + arrayOfChar[28] - 97);
for (i = 0;; i++) {
String str1;
if (i >= 16) {
str1 = String.valueOf(arrayOfChar);
textview.setText("flag{" + str1 + "}");
return;
}
String str2 = str1[31 - i];
str1[31 - i] = str1[i];
str1[i] = str2;
}
}
textview.setText(");
}
}

字符数组转换一下,然后再反向一下

1
2
3
4
5
6
7
8
9
10
11
12
string = "dd2940c04462b4dd7c450528835cca15"

lists = [i for i in string]

lists[2] = chr((ord(lists[2]) + ord(lists[3]) - 50))
lists[4] = chr((ord(lists[2]) + ord(lists[5]) - 48))
lists[30] = chr((ord(lists[31]) + ord(lists[9]) - 48))
lists[14] = chr((ord(lists[27]) + ord(lists[28]) - 97))

string = ''.join(lists)

print(string[::-1])

flag{“59acc538825054c7de4b26440c0999dd”}

findit(apk逆向)

写在后面的话:

apk反汇编推荐用jadx-gui或GDAE

–正文–

好家伙,做一个安卓题目就新换一个工具,这次用的是安卓杀手,

z1r0的博客里说,{ 的ascii码是123,十六进制是0x7b,

1
2
3
4
5
6
texts = [0x70,0x76,0x6b,0x71,0x7b,0x6d,0x31,0x36,0x34,0x36, 0x37, 0x35,\
0x32,0x36,0x32,0x30,0x33,0x33,0x6c,0x34,0x6d,0x34,0x39,0x6c,0x6e,0x70,0x37,\
0x70,0x39,0x6d,0x6e,0x6b,0x32,0x38,0x6b,0x37,0x35,0x7d]

for i in texts:
print(chr(i),end = '')

pvkq{m164675262033l4m49lnp7p9mnk28k75}

说实话结果很像了,

然后就是凯撒加密,偏移量为10,解密之后就是:

flag{c164675262033b4c49bdf7f9cda28a75}

pyre(%的逆推)

在线反汇编pyr

然后分析一下代码

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
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num

for i in range(l - 1):
code[i] = code[i] ^ code[i + 1]

print code
code = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13']

最后输出的code已经给出了

首先是异或一下,从最后一个元素开始

for i in range(l-2,-1,-1),倒数第二个元素和最后一个元素异或,以此类推

然后就是关于%~~公式的逆向了

关于z1r0的分析,就是以上这样,反过来就是(input[i] - i)%128

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
code = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13']

flag = ''

l = len(code)
for i in range(-2,-1,-1):
code[i] = code[i] ^ code[i-1]
print(code)

for i in range(l):
flag = chr((ord(code[i]) - i) % 128)

print(code)
print(flag)

[ACTF新生赛2020]easyre(index的推导)

参考链接:https://www.cnblogs.com/Mayfly-nymph/p/12664201.html

先是查壳,然后万能脱壳工具脱一下,然后放到ADI中看看

好家伙,7.5版本和7.0版本是打开是不一样的

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
 1 int __cdecl main(int argc, const char **argv, const char **envp)
2 {
3 char v4; // [esp+12h] [ebp-2Eh]
4 char v5; // [esp+13h] [ebp-2Dh]
5 char v6; // [esp+14h] [ebp-2Ch]
6 char v7; // [esp+15h] [ebp-2Bh]
7 char v8; // [esp+16h] [ebp-2Ah]
8 char v9; // [esp+17h] [ebp-29h]
9 char v10; // [esp+18h] [ebp-28h]
10 char v11; // [esp+19h] [ebp-27h]
11 char v12; // [esp+1Ah] [ebp-26h]
12 char v13; // [esp+1Bh] [ebp-25h]
13 char v14; // [esp+1Ch] [ebp-24h]
14 char v15; // [esp+1Dh] [ebp-23h]
15 int v16; // [esp+1Eh] [ebp-22h]
16 int v17; // [esp+22h] [ebp-1Eh]
17 int v18; // [esp+26h] [ebp-1Ah]
18 __int16 v19; // [esp+2Ah] [ebp-16h]
19 char v20; // [esp+2Ch] [ebp-14h]
20 char v21; // [esp+2Dh] [ebp-13h]
21 char v22; // [esp+2Eh] [ebp-12h]
22 int v23; // [esp+2Fh] [ebp-11h]
23 int v24; // [esp+33h] [ebp-Dh]
24 int v25; // [esp+37h] [ebp-9h]
25 char v26; // [esp+3Bh] [ebp-5h]
26 int i; // [esp+3Ch] [ebp-4h]
27
28 __main();
29 v4 = 42;
30 v5 = 70;
31 v6 = 39;
32 v7 = 34;
33 v8 = 78;
34 v9 = 44;
35 v10 = 34;
36 v11 = 40;
37 v12 = 73;
38 v13 = 63;
39 v14 = 43;
40 v15 = 64;
41 printf("Please input:");
42 scanf("%s", &v19);
43 if ( (_BYTE)v19 != 65 || HIBYTE(v19) != 67 || v20 != 84 || v21 != 70 || v22 != 123 || v26 != 125 )
44 return 0;
45 v16 = v23;
46 v17 = v24;
47 v18 = v25;
48 for ( i = 0; i <= 11; ++i )
49 {
50 if ( *(&v4 + i) != _data_ start__[*((char *)&v16 + i) - 1] )
51 return 0;
52 }
53 printf("You are correct!");
54 return 0;
55 }

这多清晰。。。

感谢z1r0的指导!

所以第50行相当于,v4[i] != byte_402000[v16[i] - 1]

以下是python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
key = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"' #'一定要加\

encrypt = [42,70,39,34,78,44,34,40,73,63,43,64]

x = []

for i in range(len(encrypt)):

m = key.find(chr(encrypt[i]))+1
x.append(chr(m))

for i in range(len(x)):
print(x[i],end = '')

仔细想了一下,用公式推一下就好理解了:

1
2
3
4
5
v4[i] == key [v16[i] - 1]

key.find(v4[i]) == v16[i] - 1

v16[i] == key.find(v4[i]) +1

v16这个数组就相当于是flag,我们需要做的就是逆着推一下。

flag{U9X_1S_W6@T?}

rsa (非对称解密)

非常6+1的重要!!

参考链接:

https://blog.csdn.net/ao52426055/article/details/110221943

https://blog.csdn.net/kevin66654/article/details/54087647

首先直接把两个文件的后缀改成.txt的

可以看到pub是个公钥解析,我们放到随便一个RSA公钥分解的网站中分解,解除模数和指数

key长度: 256
模数N: 8693448229604811919066606200349480058890565601720302561721665405 8378322103517
指数e: 65537 (0x10001)

然后分解N

[http://factordb.com/index.php?query=8693448229604811919066606200349480058890565601720302561721665405%208378322103517](http://factordb.com/index.php?query=8693448229604811919066606200349480058890565601720302561721665405 8378322103517)

P:285960468890451637935629440372639283459

q: 304008741604601924494328155975272418463

得知p、q、r、e之后,直接用rsatool2解出d

81176168860169991027846870170527607562179635470395365333547868786951080991441

算出来之后

通过这五个值,e、n、p、q、d来计算最后的值

记得要安装一下rsa库

dos直接键入: pip3 install rsa

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
import rsa

e= 65537
n= 86934482296048119190666062003494800588905656017203025617216654058378322103517
p= 285960468890451637935629440372639283459
q= 304008741604601924494328155975272418463
d= 81176168860169991027846870170527607562179635470395365333547868786951080991441

key = rsa.PrivateKey(n,e,d,q,p) #在pkcs标准中,pkcs#1规定,私钥包含(n,e,d,p,q)

with open("E:\\A_Oasis\\逆向工程文件\\Reverse题目\\rsa\\output\\flagenc.txt","rb") as f: #以二进制读模式,读取密文
f = f.read()
print(rsa.decrypt(f,key)) # f:公钥加密结果 key:私钥

b’flag{decrypt_256}\n’

[ACTF新生赛2020]rome(ASCII暴力破解)

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
int func()
{
int result; // eax
int v1[4]; // [esp+14h] [ebp-44h]
unsigned __int8 v2; // [esp+24h] [ebp-34h] BYREF
unsigned __int8 v3; // [esp+25h] [ebp-33h]
unsigned __int8 v4; // [esp+26h] [ebp-32h]
unsigned __int8 v5; // [esp+27h] [ebp-31h]
unsigned __int8 v6; // [esp+28h] [ebp-30h]
int v7; // [esp+29h] [ebp-2Fh]
int v8; // [esp+2Dh] [ebp-2Bh]
int v9; // [esp+31h] [ebp-27h]
int v10; // [esp+35h] [ebp-23h]
unsigned __int8 v11; // [esp+39h] [ebp-1Fh]
char v12[29]; // [esp+3Bh] [ebp-1Dh] BYREF

strcpy(v12, "Qsw3sj_lz4_Ujw@l");
printf("Please input:");
scanf("%s", &v2);
result = v2;
if ( v2 == 'A' )
{
result = v3;
if ( v3 == 'C' )
{
result = v4;
if ( v4 == 'T' )
{
result = v5;
if ( v5 == 'F' )
{
result = v6;
if ( v6 == '{' )
{
result = v11;
if ( v11 == '}' )
{
v1[0] = v7;
v1[1] = v8;
v1[2] = v9;
v1[3] = v10;
*&v12[17] = 0;
while ( *&v12[17] <= 15 )
{
if ( *(v1 + *&v12[17]) > 64 && *(v1 + *&v12[17]) <= 90 )
*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 51) % 26 + 65;
if ( *(v1 + *&v12[17]) > 96 && *(v1 + *&v12[17]) <= 122 )
*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 79) % 26 + 97;
++*&v12[17];
}
*&v12[17] = 0;
while ( *&v12[17] <= 15 )
{
result = v12[*&v12[17]];
if ( *(v1 + *&v12[17]) != result )
return result;
++*&v12[17];
}
return printf("You are correct!");
}
}
}
}
}
}
return result;
}

在检查没有壳之后,直接IDA打开,然后进入这个函数,其实就是输入一段字符之后,进行一系列的转换,根据z1r0的知乎得知,可以运用暴力破解(太棒了)!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
string = 'Qsw3sj_lz4_Ujw@l'

flag = ''

for i in range(len(string)):

for j in range(128):

k = j

if j > 64 and j <= 90:
j = (j - 51) % 26 + 65

if j > 96 and j <= 122:
j = (j - 79) % 26 + 97

if j == ord(string[i]):

flag += chr(k)

print(flag)

字符已经给出

循环这个这个字符串,用变量k来保存j的值,j来循环ASCII码,如果j经过转换之后,与对应的string相等,那就是flag了。

CrackRTF1 (散列算法+Win32API+文件头)

这题对于我这种re新手,确实属于难度的天花板了……

首先是查壳,发现没有壳。

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
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
DWORD v3; // eax
DWORD v4; // eax
char Str[260]; // [esp+4Ch] [ebp-310h] BYREF
int v7; // [esp+150h] [ebp-20Ch]
char String1[260]; // [esp+154h] [ebp-208h] BYREF
char Destination[260]; // [esp+258h] [ebp-104h] BYREF

memset(Destination, 0, sizeof(Destination));
memset(String1, 0, sizeof(String1));
v7 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", Destination);
if ( strlen(Destination) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v7 = atoi(Destination);
if ( v7 < 100000 )
ExitProcess(0);
strcat(Destination, "@DBApp");
v3 = strlen(Destination);
sub_40100A((BYTE *)Destination, v3, String1);
if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(Str, 0, sizeof(Str));
scanf("%s", Str);
if ( strlen(Str) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(Str, Destination);
memset(String1, 0, sizeof(String1));
v4 = strlen(Str);
sub_401019((BYTE *)Str, v4, String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) )
{
if ( !(unsigned __int8)sub_40100F(Str) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}

又触碰盲区了,再参考一下大佬z1r0的博客:

https://www.zhihu.com/people/xu-xu-xuxu-94

这边先是输入第一个password,

1
scanf("%s", Destination);

然后就要当心了

1
v7 = atoi(Destination);

根据z1r0所说,atoi在pawnh中很常见,用于将字符串转换为整形

1
if ( v7 < 100000 )

所以我们确定了第一个password的位数是6位,并且不小于100000

1
strcat(Destination, "@DBApp");

然后是与“@DBApp”连接

1
strcat(Destination, "@DBApp");

进入了一个奇奇怪怪的函数,不要害怕

1
if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )

直接进大本营干这个函数,第二个参数是属于加密的类型,跟进去看

发现,08004是sha1哈希算法,就把main函数的里面的改成sha1(改名很重要)

1
sha1(Destination, v3, String1);

v3是长度,String1就是加密之后的数值了,然后与”6E32D0943418C2C33385BC35A1470250DD8923A9”作比较,python里面需要小写才行

然后就是编写算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hashlib

#大写转小写
string = "6E32D0943418C2C33385BC35A1470250DD8923A9".lower()

a = '@DBApp'

for i in range(100000,999999):

data = str(i) + a

sha1 = hashlib.sha1(data.encode("utf-8"))

flags = sha1.hexdigest()

if flags == string:
print(data)
break

print('done')

解出来之后就是123321@DBApp

在往下看,输入第二个密码,既然知道是第二个密码了,就提前把str改成second_password

1
2
3
4
printf("pls input the first passwd(2): ");
memset(second_password, 0, sizeof(Str));
scanf("%s", Str);
if ( strlen(Str) != 6 )

长度也是6位

1
strcat(second_password, Destination);

把第一个密码的值加到第二个密码后面

1
sub_401019(second_password, v4, String1);

又进入了一个奇奇怪怪的函数,和上面一个差不多,加密之后与”27019e688a4e62a649fd99cadaafdb4e”进行比较

1
if ( CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash) )

这边的编码参数是0x8003,这个是MD5的哈希算法,看似可以直接暴力,但是,题目中并没有像第一个password一样,告诉我们类型以及范围,如果要暴力,就需要把ASCII全部循环一遍,所以还是想想别的办法。

发现这边还有函数,参数还是第二个密码

进去直接好家伙,一堆win32的API,在官网上面找找到底是什么意思。

官方API链接:https://docs.microsoft.com/en-us/windows/win32/api/

先是FindResourceA 函数,粗略的看一遍之后,说的第一个参数是啥啥句柄,第二个参数是资源名称,第三个是资源类型,返回的是指定信息块的句柄

再看SizeofResource,返回值为资源中的字节数

同样的,LoadResource,没见过,最好都看看

返回值为资源关联的数据的句柄。

再看LockResource

返回值为指向资源第一个字节的指针

createFileA,用来创建,或者打开文件

最重要的来了,关于WriteFileA的

还有它的形参:

1
sub_401005(lpString, lpBuffer, nNumberOfBytesToWrite);

这个函数把我们的总password放入第一个形参,lpBuffer是一个指针,

1
2
3
4
5
6
7
8
9
v5 = lstrlenA(lpString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a3 )
break;
*(i + a2) ^= lpString[i % v5];
}
return result;

现在就是这关键的地方了

a2也就是我们的lpBuffer,经过异或之后,成为我们需要生成文件,即rtf的头,才能传入下面WriteFile中,根据z1r0的博客所说,rtf的头一般为{\rtf1\ansi,

而AAA这个文件我们可以用Resource Hacker打开,只要查看开头6个就行了

然后就是匹配算法

1
2
3
4
5
6
7
8
9
rtf = '{\\rtf1'

AAA = [0x05,0x7D,0x41,0x15,0x26,0x01]

flag = ""
for i in range(0, len(rtf)):
flag += chr(ord(rtf[i]) ^ AAA[i])

print(flag)

结果为:~!3a@0

程序的意思是输入第二个密码之后,生成一个rtf文件,最后输出的rtf中,就是最终的答案

如你所见,flag{N0_M0re_Free_Bugs}

login (JS逆向/凯撒)

第一次做网页的逆向题目,有点激动,F12进入源代码查看

哪里不会搜哪里,返回一个element对象??

好吧,只是键入最基本的按钮值而已

主要是下面的rotFlag

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}
</script>

charCodeAt(),返回第一个位置的Unicode编码,

再看看replace()方法,如果找到第一个参数的字符串,就被第二个参数替换

fromCharCode()相当于python里面的chr()

参考链接:https://www.zhihu.com/people/xu-xu-xuxu-94

后面不太懂了,根据z1r0的知乎中写到,flag.replace(/[a-zA-Z]/g,function(c){XXX}),是让flag中的a-z,A-Z字符,被后面的function(c)所替换。

后面的算法就是rot13算法了:

flag{ClientSideLoginsAreEasy@flare-on.com}