Skip to content

[Google CTF 2021] CPP WriteUp

Published: at 21:42

打完 CISCN 2021 无事,想起群里之前说到的 DRM,于是和队友一起尝试了一下(

ToC

预处理

由于各种 #xxx 完全没有缩进,因此使用 clang-format 对预处理器进行格式化处理:

Terminal window
1
clang-format --style='{IndentPPDirectives: AfterHash}' cpp.c

缩进后的代码虽然算不上好读,但至少能够分析了:

观察

#if __INCLUDE_LEVEL__ > 12 一行开始,接下来就是大段的 #if S == xx。在每个 #if 之后紧跟的又是 #unset S#defineS,对应的是 S++。每个 S 对应一条不同的指令。

简单观察一条指令,不难发现其每次都会对 0-7 进行 define。比如上面截图里就 defineR0-R7。因此不难想到一个 R 其实是由 8 位构成的,即一个字节。因此之后的整理也就基本基于这个思路了。

分析

分析后的指令对照如下所示:

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

整理后得到如下流程:

1
_1:
2
if (R == 1)
3
R = !R
4
RET
5
}
6
7
if (R == 2)
8
R = !R
9
JMP _59 (return)
10
}
11
12
if (R == 3)
13
R = !R
14
JMP _59 (return)
15
}
16
17
unreachable!()
18
19
_11:
20
return
21
22
############################################
23
// for (X = 1, Y = 0; X != 0; X *= 2, A *= 2)
24
_12:
25
X = 1
26
Y = 0
27
28
while(X != 0) {
29
Z = X & B
30
if (Z != 0) {
31
Y = Y + A
32
}
33
34
X *= 2 // 8 times
35
A *= 2
36
}
37
38
//for (X = 1; X <= 8; X++) {
39
// if (B & (1 << X)) {
40
// Y += A * (1 << X)
41
// }
42
//}
43
############################################
44
45
_22:
46
A = Y
47
JMP _1
48
49
_main:
50
I = 0
51
M = 0
52
N = 1
53
P = 0
54
Q = 0
55
56
_29:
57
B = 229 + I
58
if (B == 0) {
59
if (Q == 0) {
60
return
61
} else {
62
invalid flag
63
}
64
}
65
66
########################
67
A = FLAG[I]
68
B = [I]
69
R = 1
70
71
CALL _12
72
// A = A * [I]
73
########################
74
75
O = M + N
76
M = N
77
N = O
78
// M: 1 1 2 3 5 8 13 21 34 55 89 144 233 121 98 219 61 24 85 109 194 47 241 32 17 49 66
79
// A += fib(I)
80
A = A + M
81
82
B = I + 32
83
C = [B]
84
85
A = A ^ C
86
// P += (FLAG[I]*[I] + fib(I)) ^ [32+I]
87
P = P + A
88
89
B = I + 64
90
A = [B]
91
92
// P == [64+I]
93
A = A ^ P
94
Q = Q | A
95
I++
96
JMP _29

最后得到脚本:

1
function to_byte(n) {
2
return n & 0xff;
3
}
4
5
const first = [
6
0b10111011, 0b01010101, 0b10101011, 0b11000101, 0b10111001, 0b10011101,
7
0b11001001, 0b01101001, 0b10111011, 0b00110111, 0b11011001, 0b11001101,
8
0b00100001, 0b10110011, 0b11001111, 0b11001111, 0b10011111, 0b00001001,
9
0b10110101, 0b00111101, 0b11101011, 0b01111111, 0b01010111, 0b10100001,
10
0b11101011, 0b10000111, 0b01100111,
11
];
12
13
const second = [
14
0b00001000, 0b01100100, 0b01100100, 0b00110101, 0b10010001, 0b01100100,
15
0b11100111, 0b10100000, 0b00000110, 0b10101010, 0b11011101, 0b01110101,
16
0b00010111, 0b10011101, 0b01101101, 0b01011100, 0b01011110, 0b00011001,
17
0b11111101, 0b11101001, 0b00001100, 0b11111001, 0b10110100, 0b10000011,
18
0b10000110, 0b00100010, 0b01000010,
19
];
20
21
const third = [
22
0b11111010, 0b01111011, 0b00011011, 0b10111010, 0b00011110, 0b10110100,
23
0b10110011, 0b01011000, 0b11000110, 0b11110011, 0b10001100, 0b10010000,
24
0b00111011, 0b10111010, 0b00011001, 0b01101110, 0b11001110, 0b11011111,
25
0b11110001, 0b00100101, 0b10001101, 0b01000000, 0b10000000, 0b01110000,
26
0b11100000, 0b01001101, 0b00011100,
27
];
28
29
const possible =
30
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_"
31
.split("")
32
.map(c => c.charCodeAt(0));
33
34
const fib = [
35
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,
36
4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418,
37
].map(to_byte);
38
39
function guess(i) {
40
return possible
41
.filter(c => {
42
let P = i === 0 ? 0 : third[i - 1];
43
P += (to_byte(c * first[i]) + fib[i]) ^ second[i];
44
P = to_byte(P);
45
return P === third[i];
46
})
47
.map(c => String.fromCharCode(c));
48
}
49
50
[...Array(27).keys()]
51
.map(i => guess(i))
52
.map(a => a[0])
53
.join("");

flagCTF{pr3pr0cess0r_pr0fe5sor}