NewStar RE WP

UPX

本文wp参考官解UPX | WriteUp - NewStar CTF 2024,为了加深自己理解

64位,upx脱壳

image-20241024084732645

主函数

关注到data,看看data是啥

image-20241024085539001

交叉引用:

image-20241024085606115

得到data

image-20241024085847398

回到主函数看看key是什么

image-20241024090005448

RC4算法:

image-20241024090034459

init_sbox(初始化s盒)

image-20241024090106782

方法一

RC4是一种流加密算法,本质是异或,因此可以a ^ b = c,c ^ b = a,将密文作为输入输入进去,就可以得到原来的flag

跑脚本,按着逻辑写就行

注意这里有一个细节,这里的数都是无符号数,也就是说data = [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]都是无符号数,要给他转化,unsigned char 的范围是 0 到 255,

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
sbox = [0] * 256
v8 = [0] * 256
data = [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,
81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]

data = [(x + 256) % 256 for x in [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,
81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]]

def init_sbox():
s = "NewStar"
length = len(s)
for i in range(256):
sbox[i] = i
for i in range(256):
v8[i] = ord(s[i % length])

j = 0
for i in range(256):
j = (j + sbox[i] + v8[i]) % 256
sbox[i], sbox[j] = sbox[j], sbox[i]

def RC4():
i = 0
j = 0
for h in range(len(data)):
i = (i + 1) % 256
j = (j + sbox[i]) % 256
sbox[j], sbox[i] = sbox[i], sbox[j]
data[h] ^= sbox[(sbox[i] + sbox[j]) % 256]


def main():
init_sbox()
RC4()
for i in range(len(data)):
print(chr(data[i]), end="")

if __name__ == "__main__":
main()

方法二

我们可以直接动调,在中间把输入换成密文

我是linux远程动调,要注意选对linux_server版本

取出data

image-20241024095044191

找到s的起始地址:

image-20241024095309983

shift+f2执行脚本

1
2
3
4
5
6
7
8
9
from ida_bytes import *
addr = 0x55C11B587040 # 这里需要填写自己动调时得到的地址

enc = [0xC4, 0x60, 0xAF, 0xB9, 0xE3, 0xFF, 0x2E, 0x9B, 0xF5, 0x10,
0x56, 0x51, 0x6E, 0xEE, 0x5F, 0x7D, 0x7D, 0x6E, 0x2B, 0x9C,
0x75, 0xB5]
for i in range(22):
patch_byte(addr + i, enc[i])
print('Done')

image-20241024101240174

方法三

动态调试,在RC4的最后一步中

image-20241024101444288

可以把这个异或的值拿出来,跟密文异或

‘空格’转换汇编代码视图,动态调试

image-20241024103021145

image-20241024103056695

image-20241024103125354

1
2
3
import ida_bytes
addr = 0x7FFF00CCA7C7 # 这里也是一样,需要自己动调找相应的地址
print(get_byte(addr), end=',')

可以看到打印出了每次异或的值,但是因为断点的时候第一数据已经运行到了,所以没有第一个数据,但是我们之前查看 [rbp+var_9] 的时候观察到了,所以自己把这个 0xA2 给加上即可。

得到之后

1
2
3
4
5
6
7
8
xor_data = [0xa2, 12, 206, 222, 152, 187, 65, 196, 140,
127, 35, 14, 5, 128, 48, 10, 34, 59, 123, 196, 74, 200]
enc = [0xC4, 0x60, 0xAF, 0xB9, 0xE3, 0xFF, 0x2E, 0x9B, 0xF5, 0x10,
0x56, 0x51, 0x6E, 0xEE, 0x5F, 0x7D, 0x7D, 0x6E, 0x2B, 0x9C,
0x75, 0xB5]
for i in range(len(enc)):
enc[i] ^= xor_data[i]
print(''.join(chr(e) for e in enc))

ptrace

image-20241025152421093

通过 fork() 函数创建子进程,返回值 v11 区分父进程和子进程:

  • 如果 v11 > 0,则表示当前是父进程,v11 记录子进程的 ID。

    通过 wait(stat_loc) 等待子进程停止或退出。

    使用 ptrace(PTRACE_POKEDATA, addr, addr, 3) 操作向地址 addr 写入数据 3,该操作通常用于调试。

    ptrace(PTRACE_CONT, 0, 0, 0) 继续执行子进程,直到下一个停止事件。

    再次等待子进程的状态变更。

  • 如果 v11 == 0,表示当前是子进程。

    ptrace(PTRACE_TRACEME, 0, 0, 0) 告知内核当前进程允许父进程对它进行调试。

    execl("./son", "son", &s, 0) 执行另一个程序 son,并传递变量 s 的地址作为参数。

son文件:

image-20241025153658925

注意sub函数,可疑,看看,这里应该就是产生Flag的地方

image-20241025153805694

dword是4,但是我们需要注意的是之前的ptrace(PTRACE_POKEDATA, addr, addr, 3)会把4修改成3

addr的地址恰好是这个地址

image-20241025153913838

我们可以写解密脚本

1
2
3
4
5
6
7
8
9
data = [0xCC, 0x8D, 0x2C, 0xEC, 0x6F, 0x88, 0xED, 0xEB, 0x2F, 0xED,
0xAE, 0xEB, 0x4E, 0xAC, 0x2C, 0x8D, 0x8D, 0x2F, 0xEB, 0x6D,
0xCD, 0xED, 0xEE, 0xEB, 0x0E, 0x8E, 0x4E, 0x2C, 0x6C, 0xAC,
0xE7, 0xAF]

for i in range(len(data)):
# 也可以是data[i] = (data[i] << 3 | data[i] >> 5) % 256
data[i] = (data[i] << 3 | data[i] >> 5) & 0xff
print(chr(data[i]),end='')

在这里解释下为什么son的a2是s吧

1
execl("./son", "son", &s, 0);

execl 的第一个参数 "./son" 指定要执行的程序路径,后面的 "son"&s 作为命令行参数传递给新程序。execl 将这些参数形成一个新的 argv 数组传递给新程序的 main 函数。因此,新进程的 argv 将会包含以下内容:

  • argv[0]:包含 "son",通常表示程序名称(这是execl的约定,程序自身名称作为 argv[0])。
  • argv[1]:包含 &s 的值,传递给新程序的 main 函数。

sub_600011AD 中:

1
s = *(char **)(a2 + 4);
  • a2argv 的指针,指向 argv[0] 的地址,因此 a2 + 4 指向 argv[1],即传递的 s 地址。

sub_600011AD 中的 a1

int __cdecl sub_600011AD(int a1, int a2) 中,a1 通常是 argc,即参数的数量。一般情况下,a1 会用来表示命令行参数的个数,以便 sub_600011AD 函数可以判断是否接收到正确数量的参数。

a2 作为 argv 的指针,其值表示 argv[0] 的地址。因为每个指针占用 4 个字节(在 32 位系统下),所以 a2 + 4 指向 argv[1],即传递的 s 的地址。这就是为什么 sub_600011AD 使用 a2 + 4 来取得 s 的地址。

ezencrypt

jadx打开

image-20241026112055253

发现加密,点进去

image-20241026112137500

发现先AES加密,key是title,然后Base64编码,让母后doEncCheck,我们没找到doEncCHeck的源码

官解提到

有 native 标签说明函数是 C 语言编写的,主体在 so 文件。涨知识

ida打开

是个RC4算法,RC4加密是个流加密算法,本质时异或,因此在执行一次RC4就能解密,a^b=c c^ b=a

代码如下:

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
key = 'meow'

k = [ord(key[i]) for i in range(len(key))]

flag = [
0xC2, 0x6C, 0x73, 0xF4, 0x3A, 0x45, 0x0E, 0xBA, 0x47, 0x81,
0x2A, 0x26, 0xF6, 0x79, 0x60, 0x78, 0xB3, 0x64, 0x6D, 0xDC,
0xC9, 0x04, 0x32, 0x3B, 0x9F, 0x32, 0x95, 0x60, 0xEE, 0x82,
0x97, 0xE7, 0xCA, 0x3D, 0xAA, 0x95, 0x76, 0xC5, 0x9B, 0x1D,
0x89, 0xDB, 0x98, 0x5D
]

sbox = [i for i in range(256)]

def init_sbox():
v2 = 0
v3 = 0
for i in range(256):
v1 = sbox[i] % 256
v3 = (k[v2] + v1 + v3) % 256
sbox[i] = sbox[v3]
sbox[v3] = v1
v2 += 1
if v2 >= len(k):
v2 = 0

init_sbox()

def encc():
v6 = 0
v5 = 0
for i in range(len(flag)):
v6 = (v6 + 1) % 256
v5 = (sbox[v6] + v5) % 256
sbox[v5], sbox[v6] = sbox[v6], sbox[v5]
flag[i] ^= sbox[(sbox[v5] + sbox[v6]) % 256]

encc()

for i in range(len(flag)):
flag[i] ^= k[i % 4]
print(chr(flag[i]), end='')

https://cyberchef.org/

在这个网站先Base64解码在解密,注意几个参数要跟反编译的参数一样,比如Mode,UTF8等

image-20241026112531940

得到flag

drink_tea wp

无壳, 64 位

image-20241025091202853

主逻辑就是先判断是不是32位长,然后每8位送去加密,关键函数sub_140001180

最后比较是否相等,我们解密就行

sub_140001180:

image-20241025091600355

image-20241025091653776

密文:

image-20241025091741489

写解密代码,这里建议逆向题用c写,因为逆向离不开c语言,方便自己练手,而且有很多比如无符号整数什么的跟c也比较贴切,不建议python,这里保姆级代码讲解,同时复习下C语言:

参考:

drink_tea | WriteUp - NewStar CTF 2024

逆向算法之TEA算法 - Sk2rw - 博客园

tea 加密解密算法(面向ctf-reverse使用,光速学会tea逆向套路)_tea加密 ctf-CSDN博客

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

// unsigned char 表示数组中的每个元素都是 无符号字符,这意味着每个字符的取值范围是 0 到 255。
// 实际上,编译器会根据 "WelcomeToNewStar" 的长度自动推导出数组的大小。长度为 16,再加上终止符 '\0',因此 keys 的大小为 17。
unsigned char keys[] = "WelcomeToNewStar";

// 密文的ascii码,16进制
unsigned char cipher[] = { 0x78,0x20,0xF7,0xB3,0xC5,0x42,0xCE,0xDA,0x85,0x59,0x21,0x1A,0x26,0x56,0x5A,0x59,0x29,0x02,0x0D,0xED,0x07,0xA8,0xB9,0xEE,0x36,0x59,0x11,0x87,0xFD,0x5C,0x23,0x24 };

//解密函数
void decrypt(uint32_t* v, uint32_t* k) {
// v3是*a1也就是a1的前四个字节,v4是a1[1]也就是后四个字节
uint32_t v0 = v[0], v1 = v[1];
// 2654435769怎么来的?ida 中不是1640531527吗?这里可以仔细学学tea的原理,有一个delta,它的值是2654435769
// 在加密过程中sum通常+=2654435769,但是我们这是-=1640531527可以看作= sum - 1640531527 = sum + (-1640531527)
// -1640531527的补码就是2654435769了,我们常用的也是2654435769,不建议这里使用1640531527,容易搞混
uint32_t delta = 2654435769;
// 加密中也循环了32次
uint32_t sum = (32) * delta;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
// 这里跟加密反着来就行
for (uint32_t i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0; v[1] = v1;
}

int main()
{
// k 为加密解密密钥,为 4 个 32 位无符号整数,即密钥长度为 128 位
// v3 += (a2[1] + (v4 >> 5)) ^ (v5 + v4) ^ (*a2 + 16 * v4);
// v4 += (a2[3] + (v3 >> 5)) ^ (v5 + v3) ^ (a2[2] + 16 * v3); uint32_t* v = (uint32_t*)cipher;
// 这里的a2[1,2,3,0]就是key,_DWORD类型什么意思?用来表示 32 位无符号整数(即 unsigned int 或 uint32_t)
// *a2 表示这是一个指针。具体来说,a2 是一个指向 _DWORD 类型 的指针。换句话说,a2 是一个 指向 32 位无符号整数的指针,你可以通过 *a2 来访问或操作它指向的内存位置。
// 这里经过转化后就可以像伪代码那样去访问了,我们要传入的是指针,因为在函数中要改变其值
uint32_t* k = (uint32_t*)keys;
// v 为要加密的数据是 n 个 32 位无符号整数
// a1其实就是四字节的起始指针,因为传入的是unsigned int类型,也对其进行转化,其实就是两个两个字符传入
uint32_t* v = (uint32_t*)cipher;

// ida的伪代码中i+=8,每次处理8个字节,我们这转化成了u类型,4字节,i+=2,循环4次就行了
for (int i = 0; i < 8; i += 2) {
decrypt(v + i, k);
// printf("解密后的数据:%u %u\n", v[i], v[i+1]); //%u是无符号整数类型
}
for (int i = 0; i < 32; i++) printf("%c", cipher[i]);

return 0;
}

image-20241025102522001

MazE re wp

参考MazE | WriteUp - NewStar CTF 2024NewStar CTF week4-CSDN博客

先根据提示阅读Linux下进程间通信方式——pipe(管道) - cs_wu - 博客园管道机制大概是什么

64位无壳

写道注释里

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v4; // rax
size_t v5; // rax
size_t v6; // rax
int v7; // [rsp+Ch] [rbp-3034h] BYREF
int v8; // [rsp+10h] [rbp-3030h] BYREF
__pid_t v9; // [rsp+14h] [rbp-302Ch]
ssize_t v10; // [rsp+18h] [rbp-3028h]
int pipedes[2]; // [rsp+20h] [rbp-3020h] BYREF
int v12[2]; // [rsp+28h] [rbp-3018h] BYREF
char s[16]; // [rsp+30h] [rbp-3010h] BYREF
char v14[16]; // [rsp+1030h] [rbp-2010h] BYREF
char buf[16]; // [rsp+2030h] [rbp-1010h] BYREF
unsigned __int64 v16; // [rsp+3038h] [rbp-8h]

v16 = __readfsqword(0x28u);
if ( pipe(pipedes) == -1 || pipe(v12) == -1 ){
perror("pipe failed");
return 1LL;
}
else {
v9 = fork(); // 创建一个子线程,> 0 为父进程
if ( v9 == -1 ){
perror("fork failed");
return 1LL;
}
else{
if ( v9 ) {
// 进程通信,父进程关闭了 pipedes[0](读取端),保留了 pipedes[1](写入端),关闭v12写
close(pipedes[0]);
close(v12[1]);
read(v12[0], buf, 0x1000uLL);//读
puts("This is a maze game.you need to go from the upper left corner of the maze to the lower right corner.");
puts("The current interface only displays a 3*3 rectangular area centered on the current position.");//这里提示是3*3一个个去生成迷宫的(类似视野)
puts("You can use 'w''a''s''d' on your keyboard to move");
puts("Your flag is flag{md5(path)},and the path is the shortest path");
puts("hint:The path length is 936!!!!So don鈥檛 think about doing it manually");
printf("%s", buf);
while ( 1 ){
__isoc99_scanf("%s", s);
system("clear");
v4 = strlen(s);
write(pipedes[1], s, v4 + 1);
if ( !strcmp(s, "exit") )
break;
memset(buf, 0, 0x64uLL);
read(v12[0], buf, 0x64uLL);
puts(buf);
}
close(v12[0]);
close(pipedes[1]);
}
else{
close(v12[0]);
close(pipedes[1]);
v7 = 1;
v8 = 1;
sub_1469(v14, 1, 1);
sleep(0);
v5 = strlen(v14);
write(v12[1], v14, v5 + 1);
while ( 1 )
{
memset(buf, 0, 0x1000uLL);
v10 = read(pipedes[0], buf, 0x1000uLL);
if ( !strcmp(buf, "exit") )
break;
sub_168F(buf, (unsigned int)v10, &v7, &v8);
memset(v14, 0, 0x1000uLL);
sub_1469(v14, v7, v8);
sleep(0);
v6 = strlen(v14);
write(v12[1], v14, v6 + 1);
}
close(pipedes[0]);
close(v12[1]);
}
return 0LL;
}
}
}

父进程从管道中获得地图输出,从终端读取输入输入到另一个管道;子进程通过管道从父进程获得用户输入,然后将更新后的地图输入到管道。

推测:

sub_1469(v14, 1, 1);:

  • 这个函数在初始化时被调用,参数是 (v14, 1, 1),这可能代表 初始位置(例如,迷宫的左上角)。函数名可能暗示它与迷宫生成或视图更新有关。由于它在主逻辑中被首次调用并且没有先前的状态,因此可以推测它会生成一个初始的迷宫视图。

sub_168F(buf, (unsigned int)v10, &v7, &v8);:

  • 这个函数在读取玩家输入后被调用,参数包含玩家的输入(buf)和当前玩家的位置(v7v8)。通过这个函数,程序能够获取到玩家的移动指令,并可能更新他们的位置。

sub_1469(v14, v7, v8);:

  • 在玩家位置更新后再次调用这个函数,并传递了 v7v8 作为参数,这表明函数会根据新的玩家位置生成更新后的迷宫视图。

我们看一下1469

image-20241101200655512

这就是产生3*3迷宫的的逻辑,下面还有几个函数sub141B

image-20241101200736098

image-20241101200746956

image-20241101200757871

到这迷宫的建立逻辑结束了我们可以写脚本来生成迷宫

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
unk = [
0x8B, 0x98, 0x8D, 0x9B, 0x9B, 0x99, 0xCA, 0xCA, 0x8B, 0x98,
0x8D, 0x9B, 0x94, 0x22, 0x74, 0x25, 0x70, 0x26, 0x76, 0x64,
0x74, 0x72, 0x35, 0x75, 0x63, 0xCC, 0xD9, 0xCE, 0x9A, 0xCD,
0xDB, 0x8A, 0x8E, 0x9D, 0xCD, 0xCF, 0x9E, 0xB3, 0x20, 0x20,
0x34, 0x23, 0x62, 0x35, 0x60, 0x22, 0x61, 0x71, 0x30, 0x3D,
0xC8, 0xDE, 0xCF, 0x99, 0xCF, 0xCE, 0xCA, 0xD9, 0xC8, 0xCF,
0x9A, 0xDD, 0x24, 0x64, 0x31, 0x26, 0x32, 0x35, 0x65, 0x72,
0x24, 0x20, 0x30, 0x36, 0x1D, 0xCE, 0x8B, 0xCD, 0x9E, 0xCF,
0xCB, 0xC9, 0x99, 0x8A, 0xCF, 0xCD, 0x99, 0x70, 0x25, 0x73,
0x37, 0x25, 0x34, 0x72, 0x64, 0x74, 0x60, 0x72, 0x67, 0x8F,
0xCA, 0x9C, 0xCE, 0x9E, 0xDF, 0x99, 0x98, 0x9F, 0x8F, 0x8C,
0x9B, 0x84, 0x30, 0x37, 0x32, 0x71, 0x35, 0x26, 0x24, 0x74,
0x25, 0x62, 0x26, 0x32, 0x8A, 0x8C, 0xCA, 0xCF, 0xDF, 0x8C,
0x8C, 0x8F, 0xCE, 0x9C, 0x8F, 0xDF, 0xB0, 0x76, 0x22, 0x65,
0x75, 0x63, 0x31, 0x24, 0x30, 0x23, 0x22, 0x21, 0x7B, 0x9C,
0xDF, 0xCA, 0xDF, 0x89, 0xCC, 0xDE, 0x8F, 0x89, 0x8A, 0xCB,
0xCF, 0x66, 0x33, 0x34, 0x71, 0x77, 0x75, 0x61, 0x25, 0x26,
0x76, 0x64, 0x34, 0x08, 0x9B, 0xDF, 0x8E, 0x9D, 0x9D, 0xDE,
0xDE, 0x8C, 0xDA, 0x8A, 0x9E, 0x8A, 0x66, 0x25, 0x25, 0x23,
0x64, 0x31, 0x25, 0x23, 0x33, 0x71, 0x65, 0x33, 0x9A, 0xDA,
0x9B, 0xC9, 0xD8, 0x8A, 0xCF, 0x8D, 0xDA, 0x9F, 0xDB, 0x8D,
0xC6, 0x61, 0x60, 0x72, 0x65, 0x71, 0x21, 0x66, 0x37, 0x71,
0x30, 0x77, 0x23, 0xCF, 0xDA, 0x9C, 0xD9, 0x9E, 0x8E, 0x9D,
0xDF, 0xDF, 0xDE, 0x9D, 0x8C, 0xB5, 0x30, 0x26, 0x70, 0x75,
0x35, 0x26, 0x32, 0x35, 0x30, 0x27, 0x65, 0x6F, 0xDE, 0xC8,
0x88, 0x8F, 0x9B, 0x99, 0x9E, 0xDB, 0x9A, 0x99, 0x98, 0x8F,
0x71, 0x33, 0x25, 0x64, 0x30, 0x77, 0x37, 0x21, 0x71, 0x72,
0x24, 0x30, 0x0F, 0xDC, 0xD8, 0x9E, 0x8A, 0xDC, 0xDE, 0x8F,
0xDA, 0xC9, 0xDC, 0x9B, 0xC9, 0x77, 0x20, 0x71, 0x25, 0x76,
0x66, 0x20, 0x30, 0x23, 0x71, 0x25, 0x71, 0xDC, 0xC8, 0x8E,
0xDF, 0xC9, 0x8B, 0xCE, 0xCF, 0x89, 0xD9, 0x9B, 0xCB, 0xD7,
0x65, 0x70, 0x20, 0x23, 0x63, 0x61, 0x61, 0x63, 0x20, 0x31,
0x61, 0x20, 0xD9, 0x9A, 0xDE, 0xDD, 0xCE, 0x9B, 0xCB, 0xD9,
0xDC, 0xDF, 0xDF, 0xCD, 0xF1, 0x24, 0x60, 0x33, 0x72, 0x21,
0x74, 0x72, 0x61, 0x24, 0x31, 0x62, 0x29, 0x9E, 0xCA, 0xDC,
0xCA, 0xDE, 0xCE, 0xDD, 0x98, 0x9B, 0xCF, 0xD9, 0x9E, 0x74,
0x65, 0x62, 0x32, 0x71, 0x70, 0x32, 0x64, 0x64, 0x70, 0x27,
0x63, 0x0F, 0xDB, 0x88, 0x9A, 0xCF, 0xCE, 0xDD, 0x98, 0xCE,
0xCF, 0x98, 0xCF, 0xD8, 0x65, 0x62, 0x27, 0x64, 0x20, 0x32,
0x70, 0x20, 0x21, 0x67, 0x22, 0x35, 0xDF, 0xC9, 0x9F, 0x8A,
0xCB, 0x89, 0xCC, 0xCF, 0xCE, 0xD9, 0x9F, 0xCE, 0xC0, 0x73,
0x63, 0x30, 0x74, 0x22, 0x74, 0x60, 0x61, 0x33, 0x76, 0x30,
0x22, 0xD8, 0xCE, 0xDF, 0xCF, 0x8D, 0xDD, 0xCE, 0x9E, 0xCD,
0x8A, 0xCF, 0xCF, 0xB3, 0x62, 0x65, 0x60, 0x23, 0x61, 0x60,
0x34, 0x32, 0x77, 0x64, 0x70, 0x7C, 0x9F, 0xCA, 0x9B, 0x9D,
0xD8, 0x8E, 0xCB, 0x9C, 0x8A, 0x9A, 0x8A, 0x9C, 0x67, 0x74,
0x65, 0x76, 0x64, 0x64, 0x71, 0x76, 0x23, 0x75, 0x60, 0x22,
0x4B, 0xCB, 0x8B, 0x89, 0x89, 0x8A, 0x9A, 0xCC, 0x9F, 0x9B,
0x9E, 0x89, 0xCE, 0x75, 0x74, 0x23, 0x24, 0x31, 0x65, 0x76,
0x67, 0x30, 0x75, 0x23, 0x24, 0x8B, 0xDB, 0xDD, 0xDC, 0xDE,
0x9A, 0xC9, 0xCB, 0x9B, 0x9B, 0x89, 0xDC, 0xD0, 0x71, 0x62,
0x71, 0x64, 0x24, 0x76, 0x76, 0x75, 0x75, 0x63, 0x20, 0x23,
0x8F, 0xCC, 0xCC, 0x8E, 0xCE, 0x99, 0xDB, 0x8E, 0x9A, 0x9D,
0xDC, 0xCA, 0xA5, 0x63, 0x21, 0x64, 0x21, 0x37, 0x66, 0x21,
0x21, 0x66, 0x71, 0x60, 0x6A, 0xDC, 0x88, 0xCE, 0x9E, 0xCD,
0xCF, 0xDA, 0xDA, 0xD8, 0x8D, 0x8E, 0x8B, 0x77, 0x35, 0x61,
0x25, 0x32, 0x33, 0x20, 0x20, 0x36, 0x71, 0x21, 0x34, 0x08,
0xCD, 0x9E, 0x9E, 0xDC, 0xDE, 0x9E, 0x9E, 0x8C, 0xD8, 0xDE,
0xDB, 0x8A, 0x74, 0x35, 0x35, 0x76, 0x33, 0x30, 0x61, 0x22,
0x31, 0x64, 0x31, 0x62, 0xC9, 0x8B, 0x9B, 0xD9, 0x9A, 0xDF,
0xCF, 0xC9, 0x9D, 0x9F, 0xCB, 0xCC, 0x81, 0x74, 0x30, 0x73,
0x62, 0x21, 0x70, 0x22, 0x64, 0x31, 0x60, 0x66, 0x24, 0xDF,
0xCE, 0xDC, 0xDE, 0xDF, 0xCF, 0xDC, 0x9C, 0x8A, 0x9A, 0x99,
0xDB, 0xE5, 0x30, 0x36, 0x23, 0x60, 0x35, 0x77, 0x31, 0x20,
0x30, 0x37, 0x33, 0x7F, 0x9F, 0xDD, 0xDF, 0xCE, 0x8F, 0xDC,
0xCC, 0xDA, 0xCA, 0xCD, 0xDE, 0x9A, 0x65, 0x26, 0x37, 0x65,
0x25, 0x62, 0x24, 0x21, 0x60, 0x22, 0x33, 0x21, 0x1A, 0xC9,
0x9F, 0x8A, 0xCF, 0xD8, 0x89, 0xCA, 0x8A, 0x89, 0x9E, 0xDA,
0xD8, 0x32, 0x66, 0x24, 0x20, 0x36, 0x74, 0x60, 0x74, 0x26,
0x67, 0x60, 0x61, 0xCC, 0x9F, 0xDA, 0x9F, 0xDD, 0x99, 0xCE,
0xDB, 0x89, 0x9F, 0x8B, 0x8B, 0xD3, 0x37, 0x21, 0x65, 0x66,
0x70, 0x64, 0x65, 0x63, 0x33, 0x34, 0x25, 0x60, 0xCA, 0x9B,
0xDB, 0x88, 0x8C, 0x8F, 0x9F, 0xD8, 0xDA, 0x8E, 0x9F, 0x89,
0xB3, 0x60, 0x71, 0x62, 0x31, 0x71, 0x34, 0x73, 0x32, 0x70,
0x21, 0x27, 0x2A, 0x8A, 0x8A, 0x89, 0x8C, 0xDA, 0xCA, 0xD8,
0x9A, 0xCB, 0xCE, 0xCC, 0x89, 0x70, 0x64, 0x77, 0x25, 0x71,
0x60, 0x33, 0x66, 0x74, 0x74, 0x33, 0x31, 0x5F, 0xCB, 0x89,
0x9C, 0xDF, 0xDB, 0x8C, 0x8B, 0x8F, 0x8F, 0x8D, 0xCC, 0xD9,
0x30, 0x72, 0x64, 0x61, 0x25, 0x62, 0x26, 0x75, 0x25, 0x77,
0x65, 0x24, 0xCE, 0xDD, 0x98, 0x8E, 0xDE, 0xC8, 0x8F, 0x8A,
0x9B, 0xD9, 0x89, 0x9B, 0xD5, 0x22, 0x64, 0x70, 0x34, 0x33,
0x32, 0x20, 0x60, 0x62, 0x25, 0x75, 0x72, 0xC8, 0xC8, 0x8A,
0xCB, 0x9D, 0xDA, 0xCE, 0xCE, 0x98, 0xC8, 0x9F, 0x9A, 0xB3,
0x31, 0x24, 0x70, 0x27, 0x32, 0x25, 0x75, 0x26, 0x31, 0x65,
0x30, 0x3D, 0xDD, 0x9A, 0x9A, 0x8D, 0xDE, 0x8E, 0xCA, 0xC8,
0x8C, 0x9F, 0xDE, 0xDD, 0x70, 0x35, 0x34, 0x22, 0x63, 0x70,
0x34, 0x33, 0x30, 0x25, 0x30, 0x33, 0x1D, 0xCB, 0xDB, 0xD8,
0xCE, 0x8F, 0xCF, 0x89, 0xDC, 0xCA, 0x9F, 0xDC, 0x88, 0x24,
0x64, 0x77, 0x32, 0x20, 0x30, 0x22, 0x21, 0x64, 0x24, 0x33,
0x27, 0xCE, 0x8E, 0x99, 0xDA, 0xCE, 0xCA, 0xCD, 0x8D, 0xDE,
0x8E, 0x9C, 0x8F, 0x80, 0x35, 0x27, 0x76, 0x75, 0x20, 0x73,
0x71, 0x31, 0x25, 0x26, 0x63, 0x72, 0xDB, 0x88, 0x8B, 0xCF,
0xCF, 0xD8, 0xD9, 0xDB, 0xCE, 0xCD, 0x8B, 0xDB, 0xA4, 0x66,
0x66, 0x21, 0x74, 0x22, 0x24, 0x34, 0x61, 0x72, 0x26, 0x20,
0x3F, 0xD9, 0xCA, 0x9B, 0xCB, 0x9C, 0xC9, 0xDB, 0x8E, 0xC8,
0x9F, 0x9B, 0x9F, 0x73, 0x66, 0x20, 0x70, 0x67, 0x30, 0x25,
0x25, 0x32, 0x66, 0x30, 0x61, 0x1C, 0x8F, 0x9E, 0x9A, 0xD9,
0xCD, 0xDF, 0x8E, 0x8D, 0x9B, 0xCF, 0xCB, 0xCB, 0x36, 0x30,
0x25, 0x66, 0x61, 0x34, 0x61, 0x32, 0x76, 0x24, 0x30, 0x63,
0x8A, 0xDF, 0x8F, 0x98, 0x89, 0xDB, 0xDE, 0xCC, 0x8A, 0xCA,
0x8F, 0xD8, 0xC2, 0x60, 0x30, 0x26, 0x31, 0x75, 0x65, 0x26,
0x62, 0x74, 0x60, 0x62, 0x32, 0xCB, 0x9E, 0xDD, 0x8C, 0xDF,
0x9F, 0xC8, 0xCE, 0xCF, 0x8A, 0xD8, 0xCD, 0xA4, 0x75, 0x22,
0x64, 0x24, 0x35, 0x22, 0x63, 0x25, 0x34, 0x76, 0x24, 0x2E,
0x8A, 0x89, 0x88, 0xCB, 0xCF, 0xDD, 0x8B, 0x9A, 0xDE, 0x9C,
0x88, 0xCF, 0x74, 0x22, 0x75, 0x61, 0x65, 0x76, 0x62, 0x71,
0x60, 0x22, 0x74, 0x24, 0x0E, 0x98, 0x9D, 0x9A, 0x9F, 0x9D,
0x8E, 0xCB, 0xDB, 0x99, 0x98, 0x9A, 0x99, 0x76, 0x24, 0x35,
0x24, 0x26, 0x62, 0x70, 0x20, 0x27, 0x30, 0x65, 0x65, 0xDD,
0x88, 0x9B, 0xCE, 0x9C, 0x8E, 0xCF, 0xDB, 0x8C, 0xCC, 0xDE,
0x9A, 0xD7, 0x74, 0x25, 0x60, 0x37, 0x22, 0x34, 0x20, 0x67,
0x61, 0x65, 0x31, 0x70, 0xD9, 0xDA, 0x9E, 0x8D, 0xCE, 0xCF,
0x8B, 0x9C, 0x98, 0xCF, 0x9A, 0xC8, 0xF0, 0x71, 0x24, 0x76,
0x63, 0x60, 0x30, 0x67, 0x74, 0x21, 0x34, 0x32, 0x68, 0xDF,
0x8E, 0x98, 0xCF, 0x8B, 0x9E, 0xDC, 0xD9, 0x8A, 0x8F, 0x8C,
0x9A, 0x61, 0x34, 0x37, 0x23, 0x35, 0x61, 0x27, 0x60, 0x25,
0x65, 0x23, 0x36, 0x1E, 0xDF, 0x98, 0xDB, 0x9F, 0xCA, 0xC8,
0x98, 0xDF, 0x9A, 0x88, 0xCA, 0xD9, 0x35, 0x66, 0x66, 0x75,
0x30, 0x73, 0x34, 0x74, 0x34, 0x22, 0x72, 0x61, 0xDB, 0x89,
0x9F, 0xCA, 0x9E, 0xD9, 0xC9, 0x8B, 0xCE, 0x89, 0x9A, 0xCB,
0xC4, 0x67, 0x63, 0x64, 0x65, 0x22, 0x35, 0x31, 0x70, 0x23,
0x73, 0x64, 0x63, 0x99, 0xCA, 0xCA, 0x8B, 0x98, 0x8D, 0x9B,
0x9B, 0x99, 0xCA, 0xCA, 0x8B, 0xE7
]

dword1 = [ -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]

dword2 = [ -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0]

maze = []

def sub_1329(a1, a2):
v3 = "tgrddf55"
return a1[a2] ^ ord(v3[a2 % 8])

def sub_13A1(a1, a2, a3):
return (sub_1329(a1, (99 * a2 + a3) // 8) >> (7 - (99 * a2 + a3) % 8)) & 0x1

def sub_141B(a1, a2, a3):
v4 = sub_13A1(a1, a2, a3)
if v4 == 0 :
return 48
elif v4 == 1 :
return 49
else:
return 101

def create_maze(a, i, j):
for k in range(3):
a[k] = sub_141B(unk, dword1[k] + i, dword2[k] + j)
a[3] = 10
for k in range(4, 7, 1):
a[k] = sub_141B(unk, dword1[k] + i, dword2[k] + j)
a[7] = 10
for k in range(8, 11, 1):
a[k] = sub_141B(unk, dword1[k] + i, dword2[k] + j)
a[11] = 10

for i in range(1, 98 , 3):
row1 = []
row2 = []
row3 = []
for j in range(1, 98, 3):
a = [0] * 12
create_maze(a, i, j)
row1.extend([a[0], a[1], a[2]])
row2.extend([a[4], a[5], a[6]])
row3.extend([a[8], a[9], a[10]])
maze.extend(row1)
maze.extend(row2)
maze.extend(row3)

for i in range(len(maze)):
print(chr(maze[i]),end=',')


这里我只写到了迷宫建立,因为我对python的数据结构不是很熟,比较熟练c++,我用了c++实现bfs和dfs

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
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;
const int N = 110;

int map[N][N], v[N][N];
int maze[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
typedef pair<pair<int, int>, string> PII;
queue<PII> q;

string bfs() {
int dx[4] = { -1, 0, 1, 0 };
int dy[4] = { 0, 1, 0, -1 };
memset(v, -1, sizeof v);
q.push({ { 1,1 }, "" });
v[1][1] = 0;
while (!q.empty()) {
PII p = q.front();
q.pop();
if (p.first.first == 97 && p.first.second == 97) return p.second;
for (int i = 0; i < 4; i++) {
int x = p.first.first + dx[i], y = p.first.second + dy[i];
if (x >= 0 && x < 99 && y >= 0 && y < 99 && map[x][y] == 0 && v[x][y] == -1) {
if (i == 0) q.push({ { x,y }, p.second + "a"});
else if (i == 1) q.push({ { x,y }, p.second + "s"});
else if(i == 2) q.push({ { x,y }, p.second + "d"});
else q.push({ { x,y }, p.second + "w"});
v[x][y] = 0;
}
}
}
return "";
}

int main() {
for (int i = 0; i < 99; i++) {
for (int j = 0; j < 99; j++) {
map[i][j] = maze[99 * i + j];
}
}
cout << bfs() << endl;
}

dfs

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
#include <iostream>

using namespace std;
int maze[] = []//自己复制一下
int map[99][99];
char t[10000];
int r = 0;
int dx[4] = { -1, 0, 1, 0 };
int dy[4] = { 0, 1, 0, -1 };
char op[4] = { 'w', 'd', 's', 'a' };
bool check(int qx, int qy) {
if (qx >= 0 && qx < 99 && qy >= 0 && qy < 99) {
if (map[qx][qy] == 0) return 1;
}
return 0;
}
void dfs(int x, int y) {
if (x == 97 && y == 97) {
for (int i = 0; i < r; i++) cout << t[i];
cout << endl;
return;
}
for (int i = 0; i < 4; i++) {
int qx = dx[i] + x;
int qy = dy[i] + y;
if (check(qx, qy)) {
t[r] = op[i];
r++;
map[x][y] = 1;
dfs(qx, qy);
map[x][y] = 0;
r--;
t[r] = 0;
}
}
}
int main() {
for (int i = 0; i < 99; i++) {
for (int j = 0; j < 99; j++) {
map[i][j] = maze[99 * i + j];
}
}
dfs(1, 1);
return 0;
}

得结果

1
4ed5a17ee7aeb95fcf12a3b96a9d4e6f

easygui re wp

参考题解:NewStar CTF week4-CSDN博客

提示先去看消息机制:深入理解windows 消息机制_⒉消息队列发送消息,消息的标识可以从键盘获取,-CSDN博客大概看下

64位无壳

shift+f12没找到关键字符串,看看函数有个winmain点进去,都是些系统函数

image-20241101093330470

发现sub_140001490不是点进去发现主要逻辑。

gui要注意MessageBox函数,一般这些函数就是解题的关键,比如点击verify就弹出了一个MessageBox

直接靠messagebox x交叉引用定位也行:

image-20241101093551011

sub函数内部:

image-20241101093624718

阅读代码

image-20241101093717639

发现有个反调试器,一般碰见这种,我们需要直接nop或者jz改为jnz…这里我直接nop了

下面的逻辑就是

1
2
3
4
5
6
7
8
9
10
11
DlgItem = GetDlgItem(hWndParent, 101);
WindowTextW = GetWindowTextW(DlgItem, String, 100);
if ( WindowTextW <= 44 )
{
sub_140001000(String, (unsigned int)WindowTextW, v93);
v12 = 0;
if ( v93[1] == -57 )
v12 = v93[0] == -33;
v13 = 0;
if ( v93[2] == 77 )
v13 = v12;

可以理解,v93其实就是密文,这个代码那么长其实就是干校验密文

发现一个sub_140001000函数

WindowTextW<=44再对比下面的代码可以推测(也可以看sub_140001000内部推测),WindowTextW是密文长度44位(输入长度)

看sub_140001000内部

image-20241101094217858

这段代码做的是给Src赋值,a1也就是上面的string每两个字节赋值给Src

每个元素占用2个字节,因此 a1 + 2 * i 表示第 i 个元素的地址。

然后加载v29 常量

最后将 Src[j] 的值作为索引,从 v29 数组中读取一个字节的数据,并将其存储回 Src[j] 中。

也就是说,我们也可以反过来根据Src去找v29的值,最后可能解密用到

下面是第一次加密:

image-20241101095005184

紧接着两个dowhile

image-20241101094717433

第一个dowhile 我们发现我们所输入的字符串应该是44长度,根本用不了Src[v19+303],这段我们可以先不关注

第二个dowhile 是对v29进行变形

再看到下面:

image-20241101094912609

也就是加密过程是通过Src异或完成的

return (unsigned __int64)memcpy(a3, Src, v7);

我推测是要把Src赋值给a3也就是v93,后面动态调试也验证了

那么如何解出这道题?

我们可以用获取的密文(v93)去动态调试在程序运行到第一个dowhile循环的时候去替代Src

为什么这样做,因为第二次加密是个异或,我们再异或一次就得到第二次解密的完的密文,因为两个dowhile的操作都不影响Src(第一个Src操作影响不到,第二次是对v29的操作),我们可以直接到第一次加密处写解密代码。

下面下几个断点

image-20241101095546537

输入aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

这里有一个坑点就是这个输入框输入的最大长度是42,但我们要输入44位,可以修改寄存器的值

image-20241101095936296

image-20241101100001695

改成2C:

image-20241101100025560

运行到:

image-20241101100647502

替换Src:

这里我用脚本,地址根据你自己的地址来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 导入IDA Python API
import ida_bytes

# 指定起始地址和字节数组
start_address = 0X000000E3CE76EB50
bytes_to_write = [
0xdf, 0xc7, 0x4d, 0x14, 0xc1, 0xec, 0x08, 0xe4, 0x5f, 0x3f,
0x03, 0xb4, 0x90, 0x4a, 0xb9, 0x8f, 0x8f, 0xfa, 0x71, 0x43,
0xc7, 0xf1, 0x9d, 0xdd, 0x4f, 0xc0, 0x12, 0x44, 0x5c, 0x9d,
0x88, 0x36, 0x2d, 0x16, 0x1d, 0xed, 0xbc, 0xef, 0xbb, 0x5b,
0x9f, 0x77, 0xeb, 0x58
]

# 将字节逐个写入内存
for i, byte in enumerate(bytes_to_write):
ida_bytes.patch_byte(start_address + i, byte)

print("Memory modification completed.")

image-20241101100715912

得到第二次解密后的:

image-20241101100809436

shift+e提出然后到第一次加密的地方写解密脚本

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
v29 = [
0x31, 0x74, 0x54, 0x20, 0x03, 0x53, 0x78, 0x70, 0x3A, 0x35,
0x65, 0x42, 0x04, 0x6B, 0x1F, 0x43, 0x06, 0x37, 0x00, 0x76,
0x21, 0x08, 0x0B, 0x13, 0x52, 0x4B, 0x2F, 0x1A, 0x59, 0x2C,
0x56, 0x51, 0x7F, 0x3B, 0x0E, 0x05, 0x26, 0x15, 0x25, 0x63,
0x64, 0x7A, 0x3C, 0x29, 0x41, 0x2A, 0x12, 0x17, 0x2E, 0x39,
0x57, 0x3D, 0x66, 0x33, 0x44, 0x6C, 0x6F, 0x47, 0x16, 0x71,
0x5F, 0x1C, 0x14, 0x5A, 0x0C, 0x4F, 0x01, 0x30, 0x1B, 0x68,
0x0F, 0x62, 0x3F, 0x18, 0x69, 0x6D, 0x7E, 0x5D, 0x6A, 0x28,
0x22, 0x5B, 0x55, 0x72, 0x09, 0x5E, 0x02, 0x3E, 0x50, 0x7B,
0x46, 0x45, 0x38, 0x10, 0x48, 0x79, 0x60, 0x36, 0x61, 0x6E,
0x2D, 0x49, 0x7C, 0x2B, 0x34, 0x27, 0x11, 0x7D, 0x0D, 0x0A,
0x77, 0x73, 0x58, 0x5C, 0x4C, 0x32, 0x4D, 0x1E, 0x24, 0x40,
0x67, 0x4A, 0x4E, 0x1D, 0x07, 0x75, 0x19, 0x23, 0xA0, 0xF4,
0x8F, 0xF8, 0x30
]

Src = [
0x6F, 0x81, 0xA6, 0xC5, 0x63, 0xAC, 0x4B, 0xC7, 0x8F, 0x29,
0x87, 0xA4, 0x27, 0xAA, 0xA6, 0x69, 0x4F, 0x27, 0xAE, 0xEC,
0x27, 0x2E, 0xE7, 0xA9, 0x69, 0x87, 0x2E, 0xE5, 0x2F, 0x24,
0xE6, 0x6F, 0x44, 0x87, 0xA9, 0x89, 0x4F, 0x26, 0x47, 0x21,
0xAB, 0x01, 0xA7, 0xAE
]

enc = [
0xdf, 0xc7, 0x4d, 0x14, 0xc1, 0xec, 0x8, 0xe4, 0x5f, 0x3f,
0x3, 0xb4, 0x90, 0x4a, 0xb9, 0x8f, 0x8f, 0xfa, 0x71, 0x43,
0xc7, 0xf1, 0x9d, 0xdd, 0x4f, 0xc0, 0x12, 0x44, 0x5c, 0x9d,
0x88, 0x36, 0x2d, 0x16, 0x1d, 0xed, 0xbc, 0xef, 0xbb, 0x5b,
0x9f, 0x77, 0xeb, 0x58
]

for k in range(0, 44, 4):
a = Src[k]
b = Src[k + 1]
c = Src[k + 2]
d = Src[k + 3]
Src[k + 3] = ((a >> 5) & 0x7) | ((d << 3) & 0xf8)
Src[k + 2] = ((d >> 5) & 0x7) | ((c << 3) & 0xf8)
Src[k + 1] = ((c >> 5) & 0x7) | ((b << 3) & 0xf8)
Src[k] = ((b >> 5) & 0x7) | ((a << 3) & 0xf8)

# 这个上面讲了
for i in range(len(Src)):
print(chr(v29.index(Src[i])),end='')

print()

for i in range(44):
print('a',end='')

这个解密很容易踩坑,我第一次写就踩了

比如Src[k+3] = ((a>>5) & 0x7) | ((d<<3)&0xf8),原来的加密中是

1
2
3
4
5
6
7
8
9
10
11
12
for ( k = 0i64; k < v4; k += 4i64 )
{
v11 = Src[k + 3];
v12 = Src[k + 2];
v13 = ((unsigned __int8)Src[k] >> 3) | (32 * v11);
v14 = 32 * Src[k + 1];
Src[k + 1] = (32 * Src[k]) | ((unsigned __int8)Src[k + 1] >> 3);
v15 = 32 * v12;
Src[k + 2] = v14 | HIBYTE(v15);
Src[k] = v13;
Src[k + 3] = v15 | (v11 >> 3);
}

Src[k+3]由v15和v11组成也就是Src[k+3]和Src[k+2]因此我写出了Src[k+3] = ((c>>5) & 0x7) | ((d<<3)&0xf8)这样的代码,实际是错的

因为其实原来的加密的意思是Src[k+3]由Src[k+2]的低5位和Src[k+3]的高3位组成,Src[k]由Src[k+3]的低5位和Src[k]的高3位组成

那么我们要还原Src[k+3]也就是由rc[k+3]的高3位和Src[k+3]的低5位拼接,这样才是正确的

这里解密写成这样也行:

1
2
3
4
5
6
7
8
9
for k in range(0, 44, 4):
a = Src[k]
b = Src[k + 1]
c = Src[k + 2]
d = Src[k + 3]
Src[k + 3] = ((a >> 5) & 0xff) | ((d << 3) & 0xff)
Src[k + 2] = ((d >> 5) & 0xff) | ((c << 3) & 0xff)
Src[k + 1] = ((c >> 5) & 0xff) | ((b << 3) & 0xff)
Src[k] = ((b >> 5) & 0xff) | ((a << 3) & 0xff)
1
0x7是低三位的意思,0x8f也差不多

全用0xff因为与的目的其实跟mod 256差不多,因为向高位移位的话如果不与可能会把高位的也搞进去比如

1111 0000 << 3 为 111 1000 0000其实我们最大是8位,但是|的时候不做处理会把高位也放进去

得到也是flag{GU!_r3v3R5e_3nG1n3er1ng_i5_v3ry_s1mpl3}

这道题很质量