Re

斯内克

输入NickNameNickName长度不超过20

然后初始化内存的值,这里可以得到 food 的更新位置其实是固定的,随机种子为 0xDEADBEEF,然后每次 随机 %20产生 x、y 坐标

读取输入,根据输入加密 shell_code 和 赋值全局变量

这里是移动部分,根据结构体中存储的随机生成的 xy 坐标以及全局的 KeyValue 去移动。范围是[0,19]。则地图大小是 20*20

先简单写个随机数生成脚本生成地图数据,然后我们开始 BFS 搜索路径

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
import copy
import hashlib

map_table = [[17, 0],[12, 10],[3, 11],[15, 9],[13, 18],[4, 10],[12, 10],[14, 16],[3, 7],[19, 14],[10, 11],[0, 15],[16, 11],[0, 16],[13, 3],[17, 12],[15, 3],[16, 14],[3, 19],[13, 17],[18, 9],[10, 17],[9, 8],[12, 4],[6, 3],[3, 11],[3, 6],[16, 5],[0, 1],[7, 4],[16, 10],[13, 7],[4, 19],[10, 8],[4, 13],[0, 12],[6, 15],[16, 7],[16, 6],[5, 16],[0, 9],[1, 12],[10, 12],[2, 9],[10, 8],[6, 15],[18, 13],[19, 10],[10, 0],[18, 11],[6, 4],[17, 12],[12, 19],[10, 9],[14, 4],[2, 16],[2, 3],[18, 15],[5, 14],[8, 4],[1, 15],[10, 13],[15, 4],[18, 1],[11, 9],[1, 19],[16, 16],[6, 14],[15, 1],[1, 13],[11, 13],[5, 4],[0, 13],[13, 18],[17, 7],[14, 4],[10, 12],[10, 6],[2, 18],[15, 9],[8, 7],[6, 4],[4, 7],[18, 3],[8, 18],[16, 1],[15, 14],[9, 16],[2, 4],[10, 3],[6, 13],[10, 3],[17, 11],[6, 2],[8, 19],[8, 16],[16, 9],[18, 6],[16, 10],[13, 17],[3, 2],[19, 19],[6, 18],[10, 5],[0, 16],[14, 16],[16, 4],[14, 7],[6, 9],[2, 17],[18, 16],[3, 15],[17, 12],[4, 13],[5, 4],[8, 14],[16, 9],[19, 17],[16, 14],[1, 1],[9, 0],[12, 15],[18, 1],[6, 2],[9, 18],[15, 7],[9, 13],[8, 7],[9, 8],[12, 6],[19, 18],[6, 8],[14, 1],[19, 18],[8, 10],[1, 5],[10, 1],[12, 3],[5, 16],[4, 11],[13, 1],[8, 1],[0, 9],[2, 10],[2, 12],[14, 3],[18, 7],[11, 17],[7, 1],[3, 13],[7, 13],[18, 10],[16, 2],[11, 11],[9, 8],[2, 9],[3, 6],[1, 5],[10, 5],[5, 18],[17, 16],[15, 1],[1, 1],[3, 8],[5, 19],[16, 8],[13, 19],[1, 14],[0, 8],[4, 13],[2, 6],[19, 2],[16, 3],[11, 12],[2, 17],[1, 9],[13, 14],[14, 13],[14, 12],[3, 13],[5, 3],[5, 2],[18, 6],[13, 11],[1, 14],[11, 4],[12, 17],[4, 1],[1, 2],[17, 11],[9, 4],[2, 17],[9, 3],[19, 17],[11, 17],[2, 12],[7, 18],[18, 19],[17, 3],[14, 8],[14, 17],[0, 4],[7, 18],[8, 2],[17, 7],[7, 12],[15, 10],[9, 0],[0, 14],[15, 19],[9, 8],[9, 1],[10, 8],[19, 11],[0, 9],[5, 8],[10, 13],[0, 9],[2, 12],[7, 13],[7, 11],[18, 13],[16, 4],[2, 8],[3, 16],[17, 9],[3, 0],[11, 12],[16, 0],[13, 10],[1, 14],[13, 1],[14, 9],[6, 19],[14, 8],[1, 2],[6, 17],[17, 16],[16, 18],[15, 12],[15, 8],[5, 17],[3, 14],[0, 13],[3, 3],[11, 16],[17, 10],[2, 6],[6, 6],[19, 19],[15, 18],[19, 5],[11, 6],[12, 7],[14, 7],[2, 16],[1, 16],[8, 10],[15, 9],[12, 12],[16, 0],[18, 14],[8, 18],[16, 3],[6, 15],[14, 19],[1, 5],[4, 10],[6, 18],[16, 1],[3, 12],[18, 4],[8, 16],[5, 15],[5, 18],[16, 1],[19, 8],[4, 10],[18, 6],[16, 16],[9, 9],[3, 16],[7, 2],[5, 14],[19, 12],[16, 10],[3, 16],[12, 8],[7, 13],[8, 6],[3, 9],[19, 16],[19, 19],[11, 13],[6, 5],[1, 9],[17, 15],[14, 14],[7, 8],[1, 15],[13, 5],[16, 5],[14, 0],[7, 12],[1, 3],[10, 2],[5, 9],[18, 6],[14, 16],[15, 0],[1, 19],[8, 6],[12, 14],[4, 14],[11, 4],[0, 18],[2, 16],[1, 8],[16, 15],[3, 8],[3, 5],[13, 19],[1, 14],[15, 1],[2, 0],[10, 1],[3, 2],[0, 15],[7, 2],[4, 14],[8, 9],[2, 0],[12, 10],[13, 6],[8, 6],[12, 12],[5, 16],[16, 13],[9, 14],[12, 19],[16, 14],[18, 10],[16, 3],[9, 16],[18, 6],[10, 16],[2, 12],[0, 11],[12, 11],[10, 16],[8, 17],[15, 5],[3, 3],[12, 8],[19, 2],[9, 14],[8, 14],[11, 9],[16, 13],[3, 10],[16, 2],[15, 3],[5, 13],[1, 13],[2, 6],[0, 0],[2, 19],[11, 9],[0, 11],[15, 4],[9, 13],[0, 0],[2, 14],[7, 4],[15, 10],[15, 15],[7, 16],[18, 6],[16, 11],[1, 4],[13, 7],[14, 3],[7, 13],[4, 9],[9, 16],[0, 13],[0, 0],[15, 3],[9, 8],[12, 14],[0, 2],[16, 8],[5, 1],[7, 15],[12, 18],[12, 14],[3, 7],[0, 13],[19, 10],[3, 14],[19, 17],[3, 4],[11, 14],[2, 1],[7, 4],[9, 2],[4, 6],[10, 14],[15, 0],[10, 17],[2, 16],[11, 2],[10, 18],[2, 2],[5, 7],[7, 10],[0, 2],[13, 3],[4, 1],[3, 1],[14, 7],[11, 10],[3, 2],[10, 7],[1, 6],[8, 0],[19, 18],[10, 12],[3, 19],[5, 7],[18, 15],[16, 19],[0, 9],[5, 11],[17, 5],[8, 15],[19, 17],[17, 13],[5, 1],[3, 17],[11, 18],[4, 3],[6, 19],[3, 15],[14, 11],[0, 2],[3, 11],[19, 19],[5, 11],[11, 17],[3, 12],[0, 3],[14, 1],[3, 19],[1, 8],[17, 7],[8, 10],[7, 0],[2, 17],[8, 17],[7, 14],[3, 13],[18, 11],[3, 0],[17, 15],[12, 7],[2, 15],[16, 9],[14, 7],[18, 16],[5, 18],[17, 0],[9, 14],[16, 15],[2, 16],[4, 17],[17, 3],[3, 10],[11, 10],[8, 9],[18, 2],[7, 15],[18, 8],[3, 9],[13, 9],[0, 0],[15, 4],[14, 18],[11, 0],[11, 2],[7, 5],[16, 11],[2, 6],[15, 3],[16, 13],[7, 6],[10, 11],[12, 8],[19, 3],[5, 7],[9, 12]]
Point_idx = 0
"""
& : 0: 左
( : 1: 右
\ : 2: 上
% : 3: 下
"""

class Snake:
def __init__(self) -> None:
self.x = 0
self.y = 0
self.before_direction = 1 # 前一个按过的方向, 初始时是'(', 也就是1
self.shellcode = b""

def init_shellcode(self):
self.shellcode = open(
r"./SC", "rb"
).read()
assert len(self.shellcode) == 1152

def show(self):
print(
"x: {}, y: {}, before_direction: {}".format(
self.x, self.y, self.before_direction
)
)

# next_stat: 可能的下一个snake的状态
def checkValid(next_stat):
# 不能超出边界
if next_stat.x < 0 or next_stat.x >= 20 or next_stat.y < 0 or next_stat.y >= 20: # [0, 20)
return False
return True

def UpdateSC(SC, direction):
SC = bytearray(SC)
if direction == 0: # 左
return bytes(SC[(n + 6) % 1152] for n in range(1152))
elif direction == 1: # 右
return bytes((byte + 30) & 0xFF for byte in SC)
elif direction == 2: # 上
return bytes((byte - 102) & 0xFF for byte in SC)
elif direction == 3: # 下
return bytes(((byte << 3) | (byte >> 5)) & 0xFF for byte in SC)
else:
raise ValueError("Invalid direction")

# 得到该状态的下一个可能状态
import copy

def getNextValidState(data):
directions = {
0: [(0, -1, 2), (0, 1, 3)], # 当前向左,只能上下
1: [(0, -1, 2), (0, 1, 3)], # 当前向右,只能上下
2: [(-1, 0, 0), (1, 0, 1)], # 当前向上,只能左右
3: [(-1, 0, 0), (1, 0, 1)] # 当前向下,只能左右
}

if data.before_direction not in directions:
raise Exception("before_direction error")

next_stat_arr = []
for dx, dy, new_direction in directions[data.before_direction]:
new_data = copy.deepcopy(data)
new_data.x += dx
new_data.y += dy
if checkValid(new_data):
new_data.before_direction = new_direction
new_data.shellcode = UpdateSC(new_data.shellcode, new_direction)
next_stat_arr.append(new_data)

return next_stat_arr

def check_SC_md5(SC):
print("start check md5")
md5_hex = "9C06C08F882D7981E91D663364CE5E2E"
md5 = hashlib.md5(SC).hexdigest().upper()
print(md5)
return md5 == md5_hex

def solve(data):
global Point_idx
# 判断是否已到达目标点
if (data.x, data.y) == map_table[Point_idx]:
print(f"Eat Point {data.x} {data.y}")
# 检查 shellcode 的 MD5 并写入文件
if check_SC_md5(data.shellcode):
with open(r"C:\Users\Tree\Downloads\Compressed\强网杯2024\SC_Real", "wb") as f:
f.write(data.shellcode)
return True
Point_idx += 1
return solve(data)

# 递归处理下一个有效状态
return any(solve(next_stat) for next_stat in getNextValidState(data))

## 0: 向上 1: 向下 2: 向左 3: 向右
# move = [(0,1),(0,-1),(1,0),(-1,0)]
"""
& : 0: 左
( : 1: 右
\ : 2: 上
% : 3: 下
"""
from collections import deque

# 定义方向向量
move = [(-1, 0), (1, 0), (0, -1), (0, 1)]

def Bfs(start_x, start_y, shellcode, initial_direction):
queue = deque([(start_x, start_y, 0, shellcode, initial_direction, 1, "1")])
visit = {(0, start_x, start_y, initial_direction): 0} # 使用字典代替三维数组记录状态

while queue:
x, y, idx, current_shellcode, current_direction, count, path = queue.popleft()

# 检查是否到达目标点
if (x, y) == tuple(map_table[idx]):
idx += 1
print(f"到达目标点 {x}, {y}, idx: {idx}, 操作数: {count}, 方向: {current_direction}, 路径: {path}")
if check_SC_md5(current_shellcode):
with open(r"C:\Users\Tree\Downloads\Compressed\强网杯2024\SC_Real", "wb") as f:
f.write(current_shellcode)
print("Success!!!!!!")
exit()
if idx == len(map_table):
return count, path

# 尝试直行
new_x, new_y = x + move[current_direction][0], y + move[current_direction][1]
if 0 <= new_x < 20 and 0 <= new_y < 20:
state = (idx, new_x, new_y, current_direction)
if visit.get(state, float('inf')) > count:
visit[state] = count
queue.append((new_x, new_y, idx, current_shellcode, current_direction, count, path))

# 尝试转向
for new_direction in range(4):
if new_direction not in [current_direction, current_direction ^ 1]:
new_x, new_y = x + move[new_direction][0], y + move[new_direction][1]
if 0 <= new_x < 20 and 0 <= new_y < 20:
state = (idx, new_x, new_y, new_direction)
new_count = count + 1
if visit.get(state, float('inf')) > new_count:
visit[state] = new_count
new_shellcode = UpdateSC(current_shellcode, new_direction)
new_path = path + chr(new_direction + ord('0'))
queue.append((new_x, new_y, idx, new_shellcode, new_direction, new_count, new_path))
return None, None # 没找到路径

if __name__ == "__main__":
snake_data = Snake()
snake_data.init_shellcode()

result = Bfs(10, 10, snake_data.shellcode, 1)

if result:
min_count, best_path = result
print(f"找到最短路径!操作数: {min_count}\n路径: {best_path}")
else:
print("未找到有效路径")

import sys
sys.setrecursionlimit(10000000)

解出来的 ShellCode 是一个 XXTea,简单解一下

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

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4],uint32_t sum) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9;
for (i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0; v[1] = v1;
}

int main() {
uint32_t enc[] = { 0x98D9A098, 0x711B97BA, 0x2F44819B, 0xDF37B855};
uint32_t key[] = { 0x63313357, 0x2E336D30, 0x51203220, 0x38734257 };

enc[2] ^= enc[1]; enc[3] ^= enc[0]; enc[1] ^= enc[3]; enc[0] ^= enc[2];
decipher(32, enc, key, 32*0x9E3779B9);
decipher(32, enc+2, key, 64*0x9E3779B9);
printf("%s", (char*)enc);
return 0;
}
//flag{G0@d_Snake}

解得flag{G0@d_Snake}

Mips

加密在 emusub_33D48E 里,有花指令简单去一下

是一个类似 RC4 的加密,尝试直接解失败。经过尝试模拟加密可以知道密文一一对应。所以尝试爆破

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

unsigned char deadbeef[256] = {0xDE, 0xAD, 0xBE, 0xEF};

unsigned char *enc(unsigned char *input, int xor_val) {
unsigned char SBox[256] = {0x36, 0x68, 0x32, 0x44, 0x12, 0x61, 0x6f, 0xdf, 0xba, 0xe9, 0x98, 0x28, 0x3d, 0xa8, 0xe6, 0x1e, 0x4d, 0xf2, 0xb1, 0x7e, 0xc2, 0x6a, 0x96, 0x8c, 0x37, 0x19, 0x14, 0x42, 0xa2, 0x11, 0xe5, 0x5b, 0x9d, 0x23, 0x3, 0x83, 0xf8, 0xd8, 0x9, 0x8a, 0x3c, 0x7d, 0x1a, 0x46, 0x49, 0xdc, 0x76, 0x63, 0x3e, 0x4, 0x9a, 0xc, 0x43, 0x4b, 0x72, 0x5f, 0x53, 0x21, 0x74, 0x66, 0x4f, 0xa7, 0xf6, 0x7b, 0x94, 0xa3, 0x47, 0x8f, 0xf4, 0x52, 0x2a, 0x89, 0x30, 0x33, 0x27, 0x2c, 0xf5, 0x75, 0x17, 0x79, 0x5e, 0x7f, 0x9c, 0xcb, 0x55, 0xbb, 0x60, 0x38, 0xb8, 0xd2, 0xd4, 0x8b, 0xbf, 0x1f, 0x41, 0x45, 0x0, 0x82, 0x69, 0x40, 0xe1, 0x9f, 0xe2, 0xd3, 0x4a, 0x1c, 0x71, 0x62, 0x18, 0x24, 0x97, 0x84, 0xa, 0x8e, 0x3f, 0xf, 0x1, 0x86, 0xe, 0x67, 0xc9, 0x99, 0x88, 0xb0, 0x6e, 0x54, 0x92, 0xef, 0x9b, 0xd5, 0xa5, 0xb, 0xdd, 0xbd, 0xae, 0xcc, 0xc8, 0x3a, 0x65, 0x56, 0xe0, 0xf1, 0x6, 0x1b, 0xfa, 0xbc, 0xc4, 0x91, 0xc1, 0x2e, 0x13, 0xf0, 0x58, 0xee, 0xac, 0xec, 0xa6, 0x26, 0x39, 0xb5, 0xaf, 0xc3, 0x10, 0x5a, 0xd, 0x5d, 0x29, 0x15, 0x6b, 0x50, 0xb2, 0xfe, 0xaa, 0x90, 0xa9, 0x51, 0xd0, 0xb6, 0xc6, 0x34, 0xfc, 0xa0, 0xb3, 0x35, 0xea, 0x7, 0xa4, 0x22, 0x80, 0x6d, 0x81, 0x57, 0x87, 0x25, 0xc7, 0x4c, 0xd6, 0xce, 0x77, 0xd7, 0xad, 0x78, 0x7a, 0x85, 0xa1, 0xf3, 0xe8, 0x5c, 0x73, 0x48, 0xda, 0x31, 0x4e, 0x2d, 0x93, 0x16, 0x2, 0x70, 0x1d, 0xfb, 0xcd, 0xe3, 0xf7, 0x64, 0xf9, 0xc5, 0x8, 0x9e, 0x95, 0x2b, 0xe4, 0x20, 0xd1, 0xfd, 0x7c, 0x2f, 0xbe, 0xb9, 0xdb, 0xde, 0xe7, 0xd9, 0x3b, 0xeb, 0xff, 0xb7, 0xca, 0xb4, 0x5, 0xc0, 0xab, 0xcf, 0xed, 0x6c, 0x8d, 0x59};
int i, j, v5 = 0, v6 = 0;
unsigned char v7 = 0, v8 = 0, temp = 0, temp2 = 0, temp3 = 0, t1 = 0;
unsigned char *v14 = (unsigned char *)malloc(256);
unsigned char v12, v3;

// 加密过程
for (j = 0; j < 22; j++) {
v12 = SBox[++v7];
v8 += v12;
SBox[v7] = SBox[v8];
SBox[v8] = v12;
v3 = (( ((((input[j + 5] << 7) | (input[j + 5] >> 1)) << 6) ^ 0x0FFFFFFC0) | ((((input[j + 5] << 7) | (input[j + 5] >> 1)) & 0xff) >> 2) ^ 0x3B) ^ 0x0FFFFFFBE);
temp = (((v3 << 5) | (v3 >> 3)) ^ 0xFFFFFFAD) & 0xff;
temp2 = (((temp << 4) | (temp >> 4)) ^ 0x0FFFFFFDE) & 0xff;
temp3 = ((temp2 << 3) | (temp2 >> 5));
v14[j] = SBox[(SBox[v7] + v12) & 0xff] ^ deadbeef[j & 3] ^ temp3;
}
for (int i = 0; i < 22; i++) {
v14[i] ^= xor_val;
}

return v14;
}

int main() {
unsigned char *input = (unsigned char *)malloc(30);
memcpy(input, "flag{AAAAAAAAAAAAAAAAAAAAA}", 27);
unsigned char result[30] = {0xC4, 0xEE, 0x3C, 0xBB, 0xE7, 0xFD, 0x67, 0x1D, 0xF8, 0x97, 0x68, 0x9D, 0x0B, 0x7F, 0xC7, 0x80, 0xDF, 0xF9, 0x4B, 0xA0, 0x46, 0x91};
unsigned temp = 0;
temp = result[7];
result[7] = result[11];
result[11] = temp;

temp = result[12];
result[12] = result[16];
result[16] = temp;

for (int k = 0; k < 256; k++) {
for (int i = 0; i < 22; i++) {
int j = 0;
for (; j < 256; j++) {
input[5 + i] = j;
unsigned char *encrypted = enc(input, k);
if (result[i] == encrypted[i]) {
printf("%c", j);
break;
}
}
if (j == 256) {
printf("?");
}
}
printf("\n");
}
return 0;
}

Boxx

根据以下生成地图,1是墙 2是人 3是箱子 4是位置

根据地图手动走出来的结果是212139211325313,四个字符打出来是 qwb!

flag{qwb!_fec2d316d20dbacbe0cdff8fb6ff07b9}