ByteCTF 2024 RE WP

ByteCTF 2024 RE WP

babyapk

概要:

我们知道在使用flutter框架开发应用程序时,flutter使用的是dart语言,在运行时使用了dart虚拟机来执行dart代码,所以应用程序在启动时会对会对Dart代码创建一个快照,这样可以加速后续的启动时间和提高性能。其实这个快照就是预先编译好的dart代码的一部分,存储在so文件中。

在逆向flutter框架开发的应用程序时,仅仅解压.so文件是不行的,因为快照数据是以一种优化的形式存储的,需要使用专门的工具来解析这些.so文件中的dart快照数据,从而恢复应用程序的原始dart代码。

所以这个时候我们引入blutter,想要去得到最初的dart代码,以及也可以拿到有利于帮助我们在ida中对so文件进行分析的ida_scripts文件(其实比赛的时候reflutter和blutter都试过了)

但是两个都出了报错问题,网上也没有找到相应的解决办法,当时想的是可能出题人把里面的什么地方给动了,然后就卡了。

去试了很多方法,队友使用x64 Native Tools Command Prompt成功了

至今没有被解决的环境问题,会少一个frida脚本,但是总体不影响分析,就是没办法使用frida hook

image-20240925020823043

生成的文件如下

image-20240925021025612

打开main.dart

在void test中看到bytectf字样,直接定位

然后结合不同的指令最后跳转执行后的输出提示,

我们可以找到关键点

1
2
3
4
264d28: r0 = m3N4B5V6()
0x264d28: bl #0x265088 ; [package:babyapk/src/rust/api/simple.dart] ::m3N4B5V6
0x264d2c: tbnz w0, #4, #0x264d44
0x264d30: r1 = "You Got it!!!!"

发现这个方法在[package:babyapk/src/rust/api/simple.dart] 中,结合这个给的路径,我们找到simple.dart

如下

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
// lib: , url: package:babyapk/src/rust/api/simple.dart

// class id: 1048594, size: 0x8
class :: {

static _ m3N4B5V6(/* No info */) {
** addr: 0x265088, size: 0x98
0x265088: EnterFrame
0x265088: stp fp, lr, [SP, #-0x10]!
0x26508c: mov fp, SP
0x265090: AllocStack(0x8)
0x265090: sub SP, SP, #8
0x265094: SetupParameters(dynamic _ /* r1 => r2, fp-0x8 */)
0x265094: mov x2, x1
0x265098: stur x1, [fp, #-8]
0x26509c: CheckStackOverflow
0x26509c: ldr x16, [THR, #0x38] ; THR::stack_limit
0x2650a0: cmp SP, x16
0x2650a4: b.ls #0x265118
0x2650a8: r0 = InitLateStaticField(0x4d8) // [package:babyapk/src/rust/frb_generated.dart] RustLib::instance
0x2650a8: ldr x0, [THR, #0x68] ; THR::field_table_values
0x2650ac: ldr x0, [x0, #0x9b0]
0x2650b0: ldr x16, [PP, #0x40] ; [pp+0x40] Sentinel
0x2650b4: cmp w0, w16
0x2650b8: b.ne #0x2650c8
0x2650bc: add x2, PP, #8, lsl #12 ; [pp+0x8278] Field <RustLib.instance>: static late final (offset: 0x4d8)
0x2650c0: ldr x2, [x2, #0x278]
0x2650c4: bl #0x3b9dc8
0x2650c8: LoadField: r1 = r0->field_b
0x2650c8: ldur w1, [x0, #0xb]
0x2650cc: DecompressPointer r1
0x2650cc: add x1, x1, HEAP, lsl #32
0x2650d0: cmp w1, NULL
0x2650d4: b.eq #0x2650f8
0x2650d8: LoadField: r0 = r1->field_f
0x2650d8: ldur w0, [x1, #0xf]
0x2650dc: DecompressPointer r0
0x2650dc: add x0, x0, HEAP, lsl #32
0x2650e0: mov x1, x0
0x2650e4: ldur x2, [fp, #-8]
0x2650e8: r0 = crateApiSimpleM3N4B5V6()
0x2650e8: bl #0x26519c ; [package:babyapk/src/rust/frb_generated.dart] RustLibApiImpl::crateApiSimpleM3N4B5V6
0x2650ec: LeaveFrame
0x2650ec: mov SP, fp
0x2650f0: ldp fp, lr, [SP], #0x10
0x2650f4: ret
0x2650f4: ret
0x2650f8: r0 = StateError()
0x2650f8: bl #0x188914 ; AllocateStateErrorStub -> StateError (size=0x10)
0x2650fc: mov x1, x0
0x265100: r0 = "flutter_rust_bridge has not been initialized. Did you forget to call `await RustLib.init();`\? (If you have configured a different lib name, change `RustLib` to your name.)"
0x265100: add x0, PP, #8, lsl #12 ; [pp+0x8420] "flutter_rust_bridge has not been initialized. Did you forget to call `await RustLib.init();`\? (If you have configured a different lib name, change `RustLib` to your name.)"
0x265104: ldr x0, [x0, #0x420]
0x265108: StoreField: r1->field_b = r0
0x265108: stur w0, [x1, #0xb]
0x26510c: mov x0, x1
0x265110: r0 = Throw()
0x265110: bl #0x3b9f2c ; ThrowStub
0x265114: brk #0
0x265118: r0 = StackOverflowSharedWithoutFPURegs()
0x265118: bl #0x3bbe84 ; StackOverflowSharedWithoutFPURegsStub
0x26511c: b #0x2650a8
}
}


继续找到关键点(从函数名中也可看出)

1
2
3
// 0x2650e8: r0 = crateApiSimpleM3N4B5V6()
// 0x2650e8: bl #0x26519c ; [package:babyapk/src/rust/frb_generated.dart]

所以我们继续打开frb_generated.dart

找到对应处

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
crateApiSimpleM3N4B5V6(/* No info */) {
** addr: 0x26519c, size: 0xf0
0x26519c: EnterFrame
0x26519c: stp fp, lr, [SP, #-0x10]!
0x2651a0: mov fp, SP
0x2651a4: AllocStack(0x40)
0x2651a4: sub SP, SP, #0x40
0x2651a8: SetupParameters(RustLibApiImpl this /* r1 => r0, fp-0x8 */, dynamic _ /* r2 => r2, fp-0x10 */)
0x2651a8: mov x0, x1
0x2651ac: stur x1, [fp, #-8]
0x2651b0: stur x2, [fp, #-0x10]
0x2651b4: CheckStackOverflow
0x2651b4: ldr x16, [THR, #0x38] ; THR::stack_limit
0x2651b8: cmp SP, x16
0x2651bc: b.ls #0x265284
0x2651c0: r1 = 2
0x2651c0: movz x1, #0x2
0x2651c4: r0 = AllocateContext()
0x2651c4: bl #0x3bace0 ; AllocateContextStub
0x2651c8: mov x3, x0
0x2651cc: ldur x0, [fp, #-8]
0x2651d0: stur x3, [fp, #-0x18]
0x2651d4: StoreField: r3->field_f = r0
0x2651d4: stur w0, [x3, #0xf]
0x2651d8: ldur x1, [fp, #-0x10]
0x2651dc: StoreField: r3->field_13 = r1
0x2651dc: stur w1, [x3, #0x13]
0x2651e0: LoadField: r4 = r0->field_b
0x2651e0: ldur w4, [x0, #0xb]
0x2651e4: DecompressPointer r4
0x2651e4: add x4, x4, HEAP, lsl #32
0x2651e8: mov x2, x0
0x2651ec: stur x4, [fp, #-0x10]
0x2651f0: r1 = Function 'sse_decode_bool':.
0x2651f0: add x1, PP, #0xd, lsl #12 ; [pp+0xd058] AnonymousClosure: (0x267bdc), in [package:babyapk/src/rust/frb_generated.dart] RustLibApiImpl::sse_decode_bool (0x267c18)
0x2651f4: ldr x1, [x1, #0x58]
0x2651f8: r0 = AllocateClosure()
0x2651f8: bl #0x3bb0a4 ; AllocateClosureStub
0x2651fc: r1 = <bool, Object, WireSyncRust2DartSse, bool, Object>
0x2651fc: add x1, PP, #0xd, lsl #12 ; [pp+0xd060] TypeArguments: <bool, Object, WireSyncRust2DartSse, bool, Object>
0x265200: ldr x1, [x1, #0x60]
0x265204: stur x0, [fp, #-0x20]
0x265208: r0 = SseCodec()
0x265208: bl #0x26634c ; AllocateSseCodecStub -> SseCodec<C3X0, C3X1> (size=0x14)
0x26520c: mov x3, x0
0x265210: ldur x0, [fp, #-0x20]
0x265214: stur x3, [fp, #-0x28]
0x265218: StoreField: r3->field_b = r0
0x265218: stur w0, [x3, #0xb]
0x26521c: ldur x2, [fp, #-0x18]
0x265220: r1 = Function '<anonymous closure>':.
0x265220: add x1, PP, #0xd, lsl #12 ; [pp+0xd068] AnonymousClosure: (0x266358), in [package:babyapk/src/rust/frb_generated.dart] RustLibApiImpl::crateApiSimpleM3N4B5V6 (0x26519c)
0x265224: ldr x1, [x1, #0x68]
0x265228: r0 = AllocateClosure()
0x265228: bl #0x3bb0a4 ; AllocateClosureStub
0x26522c: r1 = <bool, Object, WireSyncRust2DartSse>
0x26522c: add x1, PP, #0xd, lsl #12 ; [pp+0xd070] TypeArguments: <bool, Object, WireSyncRust2DartSse>
0x265230: ldr x1, [x1, #0x70]
0x265234: stur x0, [fp, #-0x18]
0x265238: r0 = SyncTask()
0x265238: bl #0x266340 ; AllocateSyncTaskStub -> SyncTask<X0, X1, X2> (size=0x18)
0x26523c: mov x1, x0
0x265240: ldur x0, [fp, #-0x18]
0x265244: StoreField: r1->field_13 = r0
0x265244: stur w0, [x1, #0x13]
0x265248: ldur x0, [fp, #-0x28]
0x26524c: StoreField: r1->field_b = r0
0x26524c: stur w0, [x1, #0xb]
0x265250: ldur x0, [fp, #-8]
0x265254: StoreField: r1->field_f = r0
0x265254: stur w0, [x1, #0xf]
0x265258: r16 = <bool, Object, WireSyncRust2DartSse>
0x265258: add x16, PP, #0xd, lsl #12 ; [pp+0xd070] TypeArguments: <bool, Object, WireSyncRust2DartSse>
0x26525c: ldr x16, [x16, #0x70]
0x265260: ldur lr, [fp, #-0x10]
0x265264: stp lr, x16, [SP, #8]
0x265268: str x1, [SP]
0x26526c: r4 = const [0x3, 0x2, 0x2, 0x2, null]
0x26526c: add x4, PP, #0xd, lsl #12 ; [pp+0xd078] List(5) [0x3, 0x2, 0x2, 0x2, Null]
0x265270: ldr x4, [x4, #0x78]
0x265274: r0 = executeSync()
0x265274: bl #0x2652ac ; [package:flutter_rust_bridge/src/main_components/handler.dart] BaseHandler::executeSync
0x265278: LeaveFrame
0x265278: mov SP, fp
0x26527c: ldp fp, lr, [SP], #0x10
0x265280: ret
0x265280: ret
0x265284: r0 = StackOverflowSharedWithoutFPURegs()
0x265284: bl #0x3bbe84 ; StackOverflowSharedWithoutFPURegsStub
0x265288: b #0x2651c0

根据这里其实都是在进行与rust库的交互操作,到这个地方其实可以直接去librust_lib_babyapk.so文件中找找了

直接去字符串里面找api字样

得到

image-20240925022837030

然后即找到正确的加密函数

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
__int64 __fastcall sub_3AEE0(unsigned __int8 *a1, __int64 a2)
{
__int64 v2; // x9
__int64 v3; // x9
__int64 v4; // x9
__int64 v5; // x9
__int64 v6; // x9
__int64 v7; // x9
__int64 v8; // x9
__int64 v9; // x9
unsigned int v10; // w11
int v11; // w13
__int64 v12; // x9
__int64 v13; // x9
__int64 v14; // x9
__int64 v15; // x9
__int64 v16; // x9
unsigned int v18; // w10
int v19; // w13
__int64 v20; // x9
__int64 v21; // x9
__int64 v22; // x9
__int64 v23; // x9
__int64 v24; // x9
unsigned int v25; // w10
int v26; // w13
__int64 v27; // x9
__int64 v28; // x9
__int64 v29; // x9
__int64 v30; // x9
__int64 v31; // x9
unsigned int v32; // w8
int v33; // w11
unsigned __int64 v34; // x20
__int64 v35; // x21
unsigned int v36; // w22
int v37; // w8
__int64 v38; // x10
int v39; // w9
unsigned __int64 v40; // x8
__int64 v41; // x9
unsigned __int64 v42; // x10
unsigned __int64 v43; // x8
int v44; // w12
int v45; // w14
int v46; // w3
int v47; // w13
int v48; // w2
int v49; // w16
int v50; // w15
int v51; // w17
int v52; // w6
int v53; // w4
int v54; // w12
int *v55; // x13
__int64 v57; // [xsp+8h] [xbp-48h] BYREF
__int64 v58; // [xsp+10h] [xbp-40h]
unsigned __int64 v59; // [xsp+18h] [xbp-38h]

v57 = 0LL;
v58 = 4LL;
if ( a2 != 36 )
return 0LL;
v2 = byte_18E46[*a1];
if ( v2 == 36 )
return 0LL;
v3 = byte_18E46[a1[v2]] + v2;
if ( v3 == 36 )
return 0LL;
v4 = v3 + byte_18E46[a1[v3]];
if ( v4 == 36 )
return 0LL;
v5 = v4 + byte_18E46[a1[v4]];
if ( v5 == 36 )
return 0LL;
v6 = v5 + byte_18E46[a1[v5]];
if ( v6 == 36 )
return 0LL;
v7 = v6 + byte_18E46[a1[v6]];
if ( v7 == 36 )
return 0LL;
v8 = v7 + byte_18E46[a1[v7]];
if ( v8 == 36 )
return 0LL;
v9 = v8 + byte_18E46[a1[v8]];
if ( v9 == 36 )
return 0LL;
v10 = a1[v9];
if ( (a1[v9] & 0x80000000) != 0 )
{
if ( v10 < 0xE0 )
{
v10 = a1[v9 + 1] & 0x3F | ((v10 & 0x1F) << 6);
}
else
{
v11 = a1[v9 + 2] & 0x3F | ((a1[v9 + 1] & 0x3F) << 6);
if ( v10 < 0xF0 )
v10 = v11 | ((v10 & 0x1F) << 12);
else
v10 = a1[v9 + 3] & 0x3F | (v11 << 6) & 0xFFE3FFFF | ((v10 & 7) << 18);
}
}
if ( v10 != 45 )
return 0LL;
v12 = v9 + byte_18E46[a1[v9]];
if ( v12 == 36 )
return 0LL;
v13 = v12 + byte_18E46[a1[v12]];
if ( v13 == 36 )
return 0LL;
v14 = v13 + byte_18E46[a1[v13]];
if ( v14 == 36 )
return 0LL;
v15 = v14 + byte_18E46[a1[v14]];
if ( v15 == 36 )
return 0LL;
v16 = v15 + byte_18E46[a1[v15]];
if ( v16 == 36 )
return 0LL;
v18 = a1[v16];
if ( (a1[v16] & 0x80000000) != 0 )
{
if ( v18 < 0xE0 )
{
v18 = a1[v16 + 1] & 0x3F | ((v18 & 0x1F) << 6);
}
else
{
v19 = a1[v16 + 2] & 0x3F | ((a1[v16 + 1] & 0x3F) << 6);
if ( v18 < 0xF0 )
v18 = v19 | ((v18 & 0x1F) << 12);
else
v18 = a1[v16 + 3] & 0x3F | (v19 << 6) & 0xFFE3FFFF | ((v18 & 7) << 18);
}
}
if ( v18 != 45 )
return 0LL;
v20 = v16 + byte_18E46[a1[v16]];
if ( v20 == 36 )
return 0LL;
v21 = v20 + byte_18E46[a1[v20]];
if ( v21 == 36 )
return 0LL;
v22 = v21 + byte_18E46[a1[v21]];
if ( v22 == 36 )
return 0LL;
v23 = v22 + byte_18E46[a1[v22]];
if ( v23 == 36 )
return 0LL;
v24 = v23 + byte_18E46[a1[v23]];
if ( v24 == 36 )
return 0LL;
v25 = a1[v24];
if ( (a1[v24] & 0x80000000) != 0 )
{
if ( v25 < 0xE0 )
{
v25 = a1[v24 + 1] & 0x3F | ((v25 & 0x1F) << 6);
}
else
{
v26 = a1[v24 + 2] & 0x3F | ((a1[v24 + 1] & 0x3F) << 6);
if ( v25 < 0xF0 )
v25 = v26 | ((v25 & 0x1F) << 12);
else
v25 = a1[v24 + 3] & 0x3F | (v26 << 6) & 0xFFE3FFFF | ((v25 & 7) << 18);
}
}
if ( v25 != 45 )
return 0LL;
v27 = v24 + byte_18E46[a1[v24]];
if ( v27 == 36 )
return 0LL;
v28 = v27 + byte_18E46[a1[v27]];
if ( v28 == 36 )
return 0LL;
v29 = v28 + byte_18E46[a1[v28]];
if ( v29 == 36 )
return 0LL;
v30 = v29 + byte_18E46[a1[v29]];
if ( v30 == 36 )
return 0LL;
v31 = v30 + byte_18E46[a1[v30]];
if ( v31 == 36 )
return 0LL;
v32 = a1[v31];
if ( (a1[v31] & 0x80000000) != 0 )
{
if ( v32 < 0xE0 )
{
v32 = a1[v31 + 1] & 0x3F | ((v32 & 0x1F) << 6);
}
else
{
v33 = a1[v31 + 2] & 0x3F | ((a1[v31 + 1] & 0x3F) << 6);
if ( v32 < 0xF0 )
v32 = v33 | ((v32 & 0x1F) << 12);
else
v32 = a1[v31 + 3] & 0x3F | (v33 << 6) & 0xFFE3FFFF | ((v32 & 7) << 18);
}
}
if ( v32 != 45 )
return 0LL;
v34 = 0LL;
v35 = 0LL;
while ( 1 )
{
v36 = a1[v35];
if ( (a1[v35] & 0x80000000) != 0 )
{
v37 = a1[v35 + 1] & 0x3F;
if ( v36 < 0xE0 )
{
v35 += 2LL;
v36 = v37 & 0xFFFFF83F | ((v36 & 0x1F) << 6);
}
else
{
v38 = v35 + 3;
v39 = a1[v35 + 2] & 0x3F | (v37 << 6);
if ( v36 < 0xF0 )
{
v36 = v39 | ((v36 & 0x1F) << 12);
v35 += 3LL;
}
else
{
v35 += 4LL;
v36 = a1[v38] & 0x3F | (v39 << 6) & 0xFFE3FFFF | ((v36 & 7) << 18);
}
}
}
else
{
++v35;
}
if ( v36 != 45 )
break;
LABEL_55:
if ( v35 == 36 )
goto LABEL_67;
}
if ( v36 != 1114112 )
{
if ( v34 == v57 )
sub_3B688(&v57);
*(v58 + 4 * v34++) = v36;
v59 = v34;
goto LABEL_55;
}
LABEL_67:
v40 = v34 >> 3;
v41 = 0LL;
if ( (v34 & 7) != 0 )
++v40;
v42 = v40 + 1;
v43 = 8LL;
while ( --v42 )
{
if ( v43 > v34 )
goto LABEL_88;
if ( v43 - 8 >= 0x19 )
{
v43 = 40LL;
v34 = 32LL;
LABEL_88:
sub_7674C(v43, v34, &off_801E0);
}
v45 = *(v58 + v41 * 4 + 8);
v44 = *(v58 + v41 * 4 + 12);
v46 = *(v58 + v41 * 4);
v47 = *(v58 + v41 * 4 + 4);
v48 = *(v58 + v41 * 4 + 16);
v49 = *(v58 + v41 * 4 + 20);
v50 = *(v58 + v41 * 4 + 24);
v51 = *(v58 + v41 * 4 + 28);
if ( v51 + v47 * v44 * v49 - (v46 + v50 + v45 * v48) == dword_18F60[v41] )
{
v52 = v46 * v49;
if ( v44 - v48 - v46 * v49 + v51 * v47 + v45 + v50 == dword_18F60[v41 + 1]
&& v52 - (v48 + v51 * v47) + v45 + v50 * v44 == dword_18F60[v41 + 2] )
{
v53 = v48 * v46;
if ( v47 + v48 * v46 - (v51 + v45) + v50 * v49 * v44 == dword_18F60[v41 + 3]
&& v49 * v44 + v47 + v45 * v48 - (v50 + v51 * v46) == dword_18F60[v41 + 4]
&& v52 + v47 * v44 + v45 - (v50 + v48 * v51) == dword_18F60[v41 + 5]
&& v51 - v47 + v45 * v49 + v50 - v53 * v44 == dword_18F60[v41 + 6] )
{
v43 += 8LL;
v54 = v44 - v51 - (v47 + v49);
v55 = &dword_18F60[v41];
v41 += 8LL;
if ( v54 + v53 + v50 * v45 == v55[7] )
continue;
}
}
}
if ( v57 )
sub_3B870(v58, 4 * v57, 4LL);
return 0LL;
}
if ( v57 )
sub_3B870(v58, 4 * v57, 4LL);
return 1LL;
}

主要思路就是使用z3得到数据然后再在里面随机插入4个“-“

看着比较恼火,但是真正需要使用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
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
from itertools import combinations

# 原始字符串
original_string = "32e750c8fb214562af22973fb5176b9c"

# 定义用于验证的 byte 数组(byte_18E46)
byte_18E46 = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
# 验证逻辑函数
def validate_hyphen_positions(input_str):
byte = byte_18E46
input_bytes = [ord(c) for c in input_str]

# 模拟你提供的验证逻辑
v2 = byte[input_bytes[0]]
if v2 == 36:
return False
v3 = byte[input_bytes[v2]] + v2
if v3 == 36:
return False
v4 = v3 + byte[input_bytes[v3]]
if v4 == 36:
return False
v5 = v4 + byte[input_bytes[v4]]
if v5 == 36:
return False
v6 = v5 + byte[input_bytes[v5]]
if v6 == 36:
return False
v7 = v6 + byte[input_bytes[v6]]
if v7 == 36:
return False
v8 = v7 + byte[input_bytes[v7]]
if v8 == 36:
return False
v9 = v8 + byte[input_bytes[v8]]
if v9 == 36:
return False
v10 = input_bytes[v9]
if v10 != ord('-'):
return False
v12 = v9 + byte[input_bytes[v9]]
if v12 == 36:
return False
v13 = v12 + byte[input_bytes[v12]]
if v13 == 36:
return False
v14 = v13 + byte[input_bytes[v13]]
if v14 == 36:
return False
v15 = v14 + byte[input_bytes[v14]]
if v15 == 36:
return False
v16 = v15 + byte[input_bytes[v15]]
if v16 == 36:
return False
v18 = input_bytes[v16]
if v18 != ord('-'):
return False
v20 = v16 + byte[input_bytes[v16]]
if v20 == 36:
return False
v21 = v20 + byte[input_bytes[v20]]
if v21 == 36:
return False
v22 = v21 + byte[input_bytes[v21]]
if v22 == 36:
return False
v23 = v22 + byte[input_bytes[v22]]
if v23 == 36:
return False
v24 = v23 + byte[input_bytes[v23]]
if v24 == 36:
return False
v25 = input_bytes[v24]
if v25 != ord('-'):
return False
v27 = v24 + byte[input_bytes[v24]]
if v27 == 36:
return False
v28 = v27 + byte[input_bytes[v27]]
if v28 == 36:
return False
v29 = v28 + byte[input_bytes[v28]]
if v29 == 36:
return False
v30 = v29 + byte[input_bytes[v29]]
if v30 == 36:
return False
v31 = v30 + byte[input_bytes[v30]]
if v31 == 36:
return False
v32 = input_bytes[v31]
if v32 != ord('-'):
return False

return True


# 生成插入 '-' 的位置的组合
positions = list(combinations(range(len(original_string) + 1), 4)) # 选择 4 个插入位置

# 计数器
count = 0
valid_count = 0 # 成功验证的组合计数器

# 遍历所有组合
for pos in positions:
temp_str = original_string
# 插入时要注意位置的偏移,每次插入后,字符串长度增加
for i, p in enumerate(pos):
temp_str = temp_str[:p + i] + '-' + temp_str[p + i:] # 插入 '-' 并调整位置索引

# 验证插入的 '-' 是否符合条件
if validate_hyphen_positions(temp_str):
print(f"Valid combination: {temp_str}")
valid_count += 1 # 计数通过验证的组合

# 计数
count += 1

# 打印总次数
print(f"Total combinations: {count}")
print(f"Total valid combinations: {valid_count}")

flag:ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}

最后根据其他人的wp去了解了一下会涉及到的这几个dart文件一般的作用(from AI) :)

  1. main.dart:这是应用程序的主要入口点,通常包含了应用程序启动时执行的逻辑。它通常是开发者编写的核心业务逻辑所在的地方,也是逆向分析时的重要切入点。因此,在大多数情况下,main.dart 是逆向分析过程中首先关注的文件之一。
  2. frb_generated.dart:从文件名来看,这似乎是由某种工具自动生成的文件,可能是为了处理与 Rust 代码相关的逻辑。因为 Flutter 与 Rust 的集成通常涉及到通过 FFI(Foreign Function Interface)调用 Rust 代码,所以这个文件可能是为了生成与 Rust 代码接口相关的 Dart 代码,使得可以在 Dart 中调用 Rust 函数。
  3. frb_generated.io.dart:这个文件可能是与 Rust 代码中涉及到 I/O 操作相关的 Dart 代码。Rust 语言因其内存安全性和高性能特性,常被用来处理底层或复杂的计算任务,包括网络通信、文件操作等 I/O 密集型任务。因此,这个文件可能是为了处理 Rust 代码中的 I/O 逻辑。
  4. api/simple.dart:这个文件名表明它可能定义了一些简单的 API 接口或逻辑。它可能是为了封装一些简单的业务逻辑或对外提供的服务接口,这些接口可能是通过 Rust 实现的,然后再通过 Dart 提供一个友好的调用方式。

ByteBuffer

题目提示:

ByteDance uses ByteXXX to name its products. For data transmission, ByteDance uses FlatBuffer based ByteBuffer, an extremely efficient and compact serialization technique. We have intercepted one of the traffic but can’t decode it. Can you analyze the ByteBuffer structure and recover something? flag is ByteCTF{recovered numbers}

翻译成对应中文:

字节跳动使用 ByteXXX 来命名其产品。对于数据传输,字节跳动使用基于 FlatBuffer 的 ByteBuffer,这是一种非常高效和紧凑的序列化技术。我们截获了其中一个流量,但无法解码。你能分析 ByteBuffer 结构并恢复一些东西吗? flag 是 ByteCTF{recovered numbers}

因为这个题去了解了一些相关的知识

什么是序列化:

参考:Google FlatBuffers? 什么还没听过! - 知乎 (zhihu.com)

首先网络传输的本质决定了我们在进行数据传输的时候需要序列化.
序列化: 把对象转化为一段buffer, obj—->buf
反序列化:把buffer转化为一个对象 buf—>obj

  • 序列化:把对象转换为字节序列的过程。
  • 反序列化:把字节序列恢复为对象的过程。

简单来说序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,流的概念这里不用多说(就是I/O),我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)!
常用的序列化还有:protobuf,json

flatbuffer是什么:

flatbuffer允许我们我们在多种语言之间共享数据结构,我们可以定义一个schema文件(拓展名为.fbs)来描述我们的数据结构,然后我们可以通过使用flatbuffer的编译工具flatc来把这个scheme文件生成针对不同编程语言的源代码,这些文件包含了用于序列化和反序列化的代码,或者二进制格式文件,即bin文件

而这道题的题目就是这么生成的

所以正常思路我们想的是通过.bin文件还原得到.fbs文件

结果不是……

最后看wp,结果纯脑洞题了

直接使用010Editor打开bin文件

往下翻发现在字符串窗口有很多edge和dot字样

分为edge和dot 即线和点

我们的思路就是通过提取bin文件中线和点的坐标最后绘制成图片

分析思路:

这样的数据构造会重复很多次

image-20240925015401347

经过提取我们可以获得一个dot点的列表和一个edge边的列表,我们将边的列表里面的每一个元素所对应的点连接起来,最后再生成图片即可

参考wp(放一个其他战队的wp):

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

data = open('ByteBuffer.bin','rb').read()

edge_start = 0x3ac
dot_start = 0x1230
Edge = []
Dot = []
def readEdge(offset):
e = struct.unpack_from("<IIIIII",data,offset)
p1 = e[2]
p2 = e[3]
name_len = e[5]
name = data[offset+24:offset+24+name_len].decode()
Edge.append({
"p1":p1,
"p2":p2,
"name":name,
})
name_pad = ((name_len ) // 4 + 1 )* 4
return offset+24+name_pad

def readDot(offset):
e = struct.unpack_from("<IIIII",data,offset)
x = e[1]
y = e[2]
name_len = e[4]
name = data[offset+20:offset+20+name_len].decode()
Dot.append({
"x":x,
"y":y,
"name":name,
})
name_pad = ((name_len ) // 4 + 1 )* 4
return offset+20+name_pad

offset = edge_start
while(offset < 0x1204):
offset = readEdge(offset)
print(offset)
readEdge(0x1210)
offset = dot_start
while(offset < 0x1f88):
offset = readDot(offset)
readDot(0x1f90)

for e in Edge:
print(e)

for d in Dot:
print(d)

from PIL import ImageDraw,Image

def findDot(dot_id):
for d in Dot:
if "Dot #"+str(dot_id) == d['name']:
return d['x'],d['y']

im = Image.new('RGB', (2000, 200), (128, 128, 128))
draw = ImageDraw.Draw(im)
for e in Edge:
d1 = findDot(e['p1'])
d2 = findDot(e['p2'])
print(d1+d2)
draw.line((d1+d2), fill=(255, 255, 0), width=5)

im.save('1.png') # </IIIII",data,offset)
# </IIIIII",data,offset)

运行结果:

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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
976
1012
1048
1084
1120
1156
1192
1228
1264
1300
1336
1372
1408
1444
1480
1516
1552
1588
1624
1660
1696
1732
1768
1804
1840
1876
1912
1948
1984
2020
2056
2092
2128
2164
2200
2236
2272
2308
2344
2380
2416
2452
2488
2524
2560
2596
2632
2668
2704
2740
2776
2812
2848
2884
2920
2956
2992
3028
3064
3100
3136
3172
3208
3244
3280
3316
3352
3388
3424
3460
3496
3532
3568
3604
3640
3676
3712
3748
3784
3820
3856
3892
3928
3964
4000
4036
4072
4108
4144
4180
4216
4252
4288
4324
4356
4388
4420
4452
4484
4516
4548
4580
4612
{'p1': 119, 'p2': 117, 'name': 'Edge #103'}
{'p1': 119, 'p2': 118, 'name': 'Edge #102'}
{'p1': 117, 'p2': 114, 'name': 'Edge #101'}
{'p1': 116, 'p2': 115, 'name': 'Edge #100'}
{'p1': 115, 'p2': 114, 'name': 'Edge #99'}
{'p1': 113, 'p2': 111, 'name': 'Edge #98'}
{'p1': 113, 'p2': 112, 'name': 'Edge #97'}
{'p1': 112, 'p2': 108, 'name': 'Edge #96'}
{'p1': 111, 'p2': 108, 'name': 'Edge #95'}
{'p1': 110, 'p2': 109, 'name': 'Edge #94'}
{'p1': 109, 'p2': 108, 'name': 'Edge #93'}
{'p1': 107, 'p2': 105, 'name': 'Edge #92'}
{'p1': 107, 'p2': 106, 'name': 'Edge #91'}
{'p1': 106, 'p2': 102, 'name': 'Edge #90'}
{'p1': 105, 'p2': 102, 'name': 'Edge #89'}
{'p1': 105, 'p2': 104, 'name': 'Edge #88'}
{'p1': 104, 'p2': 103, 'name': 'Edge #87'}
{'p1': 103, 'p2': 102, 'name': 'Edge #86'}
{'p1': 101, 'p2': 99, 'name': 'Edge #85'}
{'p1': 101, 'p2': 100, 'name': 'Edge #84'}
{'p1': 99, 'p2': 96, 'name': 'Edge #83'}
{'p1': 98, 'p2': 97, 'name': 'Edge #82'}
{'p1': 97, 'p2': 96, 'name': 'Edge #81'}
{'p1': 94, 'p2': 92, 'name': 'Edge #80'}
{'p1': 93, 'p2': 92, 'name': 'Edge #79'}
{'p1': 91, 'p2': 90, 'name': 'Edge #78'}
{'p1': 90, 'p2': 89, 'name': 'Edge #77'}
{'p1': 89, 'p2': 88, 'name': 'Edge #76'}
{'p1': 86, 'p2': 81, 'name': 'Edge #75'}
{'p1': 86, 'p2': 85, 'name': 'Edge #74'}
{'p1': 85, 'p2': 84, 'name': 'Edge #73'}
{'p1': 84, 'p2': 83, 'name': 'Edge #72'}
{'p1': 83, 'p2': 82, 'name': 'Edge #71'}
{'p1': 82, 'p2': 81, 'name': 'Edge #70'}
{'p1': 80, 'p2': 78, 'name': 'Edge #69'}
{'p1': 80, 'p2': 79, 'name': 'Edge #68'}
{'p1': 78, 'p2': 75, 'name': 'Edge #67'}
{'p1': 78, 'p2': 77, 'name': 'Edge #66'}
{'p1': 77, 'p2': 76, 'name': 'Edge #65'}
{'p1': 76, 'p2': 75, 'name': 'Edge #64'}
{'p1': 74, 'p2': 73, 'name': 'Edge #63'}
{'p1': 73, 'p2': 69, 'name': 'Edge #62'}
{'p1': 72, 'p2': 69, 'name': 'Edge #61'}
{'p1': 72, 'p2': 71, 'name': 'Edge #60'}
{'p1': 71, 'p2': 70, 'name': 'Edge #59'}
{'p1': 68, 'p2': 66, 'name': 'Edge #58'}
{'p1': 68, 'p2': 67, 'name': 'Edge #57'}
{'p1': 66, 'p2': 63, 'name': 'Edge #56'}
{'p1': 66, 'p2': 65, 'name': 'Edge #55'}
{'p1': 65, 'p2': 64, 'name': 'Edge #54'}
{'p1': 64, 'p2': 63, 'name': 'Edge #53'}
{'p1': 62, 'p2': 60, 'name': 'Edge #52'}
{'p1': 62, 'p2': 61, 'name': 'Edge #51'}
{'p1': 61, 'p2': 57, 'name': 'Edge #50'}
{'p1': 60, 'p2': 57, 'name': 'Edge #49'}
{'p1': 59, 'p2': 58, 'name': 'Edge #48'}
{'p1': 58, 'p2': 57, 'name': 'Edge #47'}
{'p1': 56, 'p2': 51, 'name': 'Edge #46'}
{'p1': 56, 'p2': 55, 'name': 'Edge #45'}
{'p1': 55, 'p2': 54, 'name': 'Edge #44'}
{'p1': 54, 'p2': 53, 'name': 'Edge #43'}
{'p1': 53, 'p2': 52, 'name': 'Edge #42'}
{'p1': 52, 'p2': 51, 'name': 'Edge #41'}
{'p1': 50, 'p2': 48, 'name': 'Edge #40'}
{'p1': 50, 'p2': 49, 'name': 'Edge #39'}
{'p1': 48, 'p2': 45, 'name': 'Edge #38'}
{'p1': 47, 'p2': 46, 'name': 'Edge #37'}
{'p1': 46, 'p2': 45, 'name': 'Edge #36'}
{'p1': 44, 'p2': 42, 'name': 'Edge #35'}
{'p1': 44, 'p2': 43, 'name': 'Edge #34'}
{'p1': 43, 'p2': 39, 'name': 'Edge #33'}
{'p1': 42, 'p2': 39, 'name': 'Edge #32'}
{'p1': 42, 'p2': 41, 'name': 'Edge #31'}
{'p1': 41, 'p2': 40, 'name': 'Edge #30'}
{'p1': 40, 'p2': 39, 'name': 'Edge #29'}
{'p1': 37, 'p2': 35, 'name': 'Edge #28'}
{'p1': 36, 'p2': 35, 'name': 'Edge #27'}
{'p1': 34, 'p2': 33, 'name': 'Edge #26'}
{'p1': 33, 'p2': 29, 'name': 'Edge #25'}
{'p1': 32, 'p2': 29, 'name': 'Edge #24'}
{'p1': 32, 'p2': 31, 'name': 'Edge #23'}
{'p1': 31, 'p2': 30, 'name': 'Edge #22'}
{'p1': 28, 'p2': 26, 'name': 'Edge #21'}
{'p1': 27, 'p2': 26, 'name': 'Edge #20'}
{'p1': 26, 'p2': 24, 'name': 'Edge #19'}
{'p1': 25, 'p2': 24, 'name': 'Edge #18'}
{'p1': 23, 'p2': 21, 'name': 'Edge #17'}
{'p1': 23, 'p2': 22, 'name': 'Edge #16'}
{'p1': 21, 'p2': 18, 'name': 'Edge #15'}
{'p1': 20, 'p2': 19, 'name': 'Edge #14'}
{'p1': 19, 'p2': 18, 'name': 'Edge #13'}
{'p1': 17, 'p2': 16, 'name': 'Edge #12'}
{'p1': 16, 'p2': 15, 'name': 'Edge #11'}
{'p1': 15, 'p2': 14, 'name': 'Edge #10'}
{'p1': 12, 'p2': 11, 'name': 'Edge #9'}
{'p1': 11, 'p2': 7, 'name': 'Edge #8'}
{'p1': 10, 'p2': 7, 'name': 'Edge #7'}
{'p1': 10, 'p2': 9, 'name': 'Edge #6'}
{'p1': 9, 'p2': 8, 'name': 'Edge #5'}
{'p1': 6, 'p2': 1, 'name': 'Edge #4'}
{'p1': 6, 'p2': 5, 'name': 'Edge #3'}
{'p1': 4, 'p2': 3, 'name': 'Edge #2'}
{'p1': 3, 'p2': 1, 'name': 'Edge #1'}
{'p1': 2, 'p2': 1, 'name': 'Edge #0'}
{'x': 1600, 'y': 75, 'name': 'Dot #120'}
{'x': 1575, 'y': 125, 'name': 'Dot #119'}
{'x': 1525, 'y': 125, 'name': 'Dot #118'}
{'x': 1575, 'y': 75, 'name': 'Dot #117'}
{'x': 1575, 'y': 25, 'name': 'Dot #116'}
{'x': 1525, 'y': 25, 'name': 'Dot #115'}
{'x': 1525, 'y': 75, 'name': 'Dot #114'}
{'x': 1500, 'y': 125, 'name': 'Dot #113'}
{'x': 1450, 'y': 125, 'name': 'Dot #112'}
{'x': 1500, 'y': 75, 'name': 'Dot #111'}
{'x': 1500, 'y': 25, 'name': 'Dot #110'}
{'x': 1450, 'y': 25, 'name': 'Dot #109'}
{'x': 1450, 'y': 75, 'name': 'Dot #108'}
{'x': 1425, 'y': 125, 'name': 'Dot #107'}
{'x': 1375, 'y': 125, 'name': 'Dot #106'}
{'x': 1425, 'y': 75, 'name': 'Dot #105'}
{'x': 1425, 'y': 25, 'name': 'Dot #104'}
{'x': 1375, 'y': 25, 'name': 'Dot #103'}
{'x': 1375, 'y': 75, 'name': 'Dot #102'}
{'x': 1350, 'y': 125, 'name': 'Dot #101'}
{'x': 1300, 'y': 125, 'name': 'Dot #100'}
{'x': 1350, 'y': 75, 'name': 'Dot #99'}
{'x': 1350, 'y': 25, 'name': 'Dot #98'}
{'x': 1300, 'y': 25, 'name': 'Dot #97'}
{'x': 1300, 'y': 75, 'name': 'Dot #96'}
{'x': 1275, 'y': 75, 'name': 'Dot #95'}
{'x': 1225, 'y': 125, 'name': 'Dot #94'}
{'x': 1225, 'y': 25, 'name': 'Dot #93'}
{'x': 1225, 'y': 75, 'name': 'Dot #92'}
{'x': 1200, 'y': 125, 'name': 'Dot #91'}
{'x': 1200, 'y': 75, 'name': 'Dot #90'}
{'x': 1200, 'y': 25, 'name': 'Dot #89'}
{'x': 1150, 'y': 25, 'name': 'Dot #88'}
{'x': 1150, 'y': 75, 'name': 'Dot #87'}
{'x': 1075, 'y': 125, 'name': 'Dot #86'}
{'x': 1125, 'y': 125, 'name': 'Dot #85'}
{'x': 1125, 'y': 75, 'name': 'Dot #84'}
{'x': 1125, 'y': 25, 'name': 'Dot #83'}
{'x': 1075, 'y': 25, 'name': 'Dot #82'}
{'x': 1075, 'y': 75, 'name': 'Dot #81'}
{'x': 1050, 'y': 125, 'name': 'Dot #80'}
{'x': 1000, 'y': 125, 'name': 'Dot #79'}
{'x': 1050, 'y': 75, 'name': 'Dot #78'}
{'x': 1050, 'y': 25, 'name': 'Dot #77'}
{'x': 1000, 'y': 25, 'name': 'Dot #76'}
{'x': 1000, 'y': 75, 'name': 'Dot #75'}
{'x': 975, 'y': 125, 'name': 'Dot #74'}
{'x': 925, 'y': 125, 'name': 'Dot #73'}
{'x': 975, 'y': 75, 'name': 'Dot #72'}
{'x': 975, 'y': 25, 'name': 'Dot #71'}
{'x': 925, 'y': 25, 'name': 'Dot #70'}
{'x': 925, 'y': 75, 'name': 'Dot #69'}
{'x': 900, 'y': 125, 'name': 'Dot #68'}
{'x': 850, 'y': 125, 'name': 'Dot #67'}
{'x': 900, 'y': 75, 'name': 'Dot #66'}
{'x': 900, 'y': 25, 'name': 'Dot #65'}
{'x': 850, 'y': 25, 'name': 'Dot #64'}
{'x': 850, 'y': 75, 'name': 'Dot #63'}
{'x': 825, 'y': 125, 'name': 'Dot #62'}
{'x': 775, 'y': 125, 'name': 'Dot #61'}
{'x': 825, 'y': 75, 'name': 'Dot #60'}
{'x': 825, 'y': 25, 'name': 'Dot #59'}
{'x': 775, 'y': 25, 'name': 'Dot #58'}
{'x': 775, 'y': 75, 'name': 'Dot #57'}
{'x': 700, 'y': 125, 'name': 'Dot #56'}
{'x': 750, 'y': 125, 'name': 'Dot #55'}
{'x': 750, 'y': 75, 'name': 'Dot #54'}
{'x': 750, 'y': 25, 'name': 'Dot #53'}
{'x': 700, 'y': 25, 'name': 'Dot #52'}
{'x': 700, 'y': 75, 'name': 'Dot #51'}
{'x': 675, 'y': 125, 'name': 'Dot #50'}
{'x': 625, 'y': 125, 'name': 'Dot #49'}
{'x': 675, 'y': 75, 'name': 'Dot #48'}
{'x': 675, 'y': 25, 'name': 'Dot #47'}
{'x': 625, 'y': 25, 'name': 'Dot #46'}
{'x': 625, 'y': 75, 'name': 'Dot #45'}
{'x': 600, 'y': 125, 'name': 'Dot #44'}
{'x': 550, 'y': 125, 'name': 'Dot #43'}
{'x': 600, 'y': 75, 'name': 'Dot #42'}
{'x': 600, 'y': 25, 'name': 'Dot #41'}
{'x': 550, 'y': 25, 'name': 'Dot #40'}
{'x': 550, 'y': 75, 'name': 'Dot #39'}
{'x': 525, 'y': 75, 'name': 'Dot #38'}
{'x': 475, 'y': 125, 'name': 'Dot #37'}
{'x': 475, 'y': 25, 'name': 'Dot #36'}
{'x': 475, 'y': 75, 'name': 'Dot #35'}
{'x': 450, 'y': 125, 'name': 'Dot #34'}
{'x': 400, 'y': 125, 'name': 'Dot #33'}
{'x': 450, 'y': 75, 'name': 'Dot #32'}
{'x': 450, 'y': 25, 'name': 'Dot #31'}
{'x': 400, 'y': 25, 'name': 'Dot #30'}
{'x': 400, 'y': 75, 'name': 'Dot #29'}
{'x': 375, 'y': 125, 'name': 'Dot #28'}
{'x': 375, 'y': 25, 'name': 'Dot #27'}
{'x': 375, 'y': 75, 'name': 'Dot #26'}
{'x': 325, 'y': 25, 'name': 'Dot #25'}
{'x': 325, 'y': 75, 'name': 'Dot #24'}
{'x': 300, 'y': 125, 'name': 'Dot #23'}
{'x': 250, 'y': 125, 'name': 'Dot #22'}
{'x': 300, 'y': 75, 'name': 'Dot #21'}
{'x': 300, 'y': 25, 'name': 'Dot #20'}
{'x': 250, 'y': 25, 'name': 'Dot #19'}
{'x': 250, 'y': 75, 'name': 'Dot #18'}
{'x': 225, 'y': 125, 'name': 'Dot #17'}
{'x': 225, 'y': 75, 'name': 'Dot #16'}
{'x': 225, 'y': 25, 'name': 'Dot #15'}
{'x': 175, 'y': 25, 'name': 'Dot #14'}
{'x': 175, 'y': 75, 'name': 'Dot #13'}
{'x': 150, 'y': 125, 'name': 'Dot #12'}
{'x': 100, 'y': 125, 'name': 'Dot #11'}
{'x': 150, 'y': 75, 'name': 'Dot #10'}
{'x': 150, 'y': 25, 'name': 'Dot #9'}
{'x': 100, 'y': 25, 'name': 'Dot #8'}
{'x': 100, 'y': 75, 'name': 'Dot #7'}
{'x': 75, 'y': 125, 'name': 'Dot #6'}
{'x': 25, 'y': 125, 'name': 'Dot #5'}
{'x': 25, 'y': 25, 'name': 'Dot #4'}
{'x': 75, 'y': 25, 'name': 'Dot #3'}
{'x': 75, 'y': 75, 'name': 'Dot #1'}
{'x': 25, 'y': 75, 'name': 'Dot #2'}
(1575, 125, 1575, 75)
(1575, 125, 1525, 125)
(1575, 75, 1525, 75)
(1575, 25, 1525, 25)
(1525, 25, 1525, 75)
(1500, 125, 1500, 75)
(1500, 125, 1450, 125)
(1450, 125, 1450, 75)
(1500, 75, 1450, 75)
(1500, 25, 1450, 25)
(1450, 25, 1450, 75)
(1425, 125, 1425, 75)
(1425, 125, 1375, 125)
(1375, 125, 1375, 75)
(1425, 75, 1375, 75)
(1425, 75, 1425, 25)
(1425, 25, 1375, 25)
(1375, 25, 1375, 75)
(1350, 125, 1350, 75)
(1350, 125, 1300, 125)
(1350, 75, 1300, 75)
(1350, 25, 1300, 25)
(1300, 25, 1300, 75)
(1225, 125, 1225, 75)
(1225, 25, 1225, 75)
(1200, 125, 1200, 75)
(1200, 75, 1200, 25)
(1200, 25, 1150, 25)
(1075, 125, 1075, 75)
(1075, 125, 1125, 125)
(1125, 125, 1125, 75)
(1125, 75, 1125, 25)
(1125, 25, 1075, 25)
(1075, 25, 1075, 75)
(1050, 125, 1050, 75)
(1050, 125, 1000, 125)
(1050, 75, 1000, 75)
(1050, 75, 1050, 25)
(1050, 25, 1000, 25)
(1000, 25, 1000, 75)
(975, 125, 925, 125)
(925, 125, 925, 75)
(975, 75, 925, 75)
(975, 75, 975, 25)
(975, 25, 925, 25)
(900, 125, 900, 75)
(900, 125, 850, 125)
(900, 75, 850, 75)
(900, 75, 900, 25)
(900, 25, 850, 25)
(850, 25, 850, 75)
(825, 125, 825, 75)
(825, 125, 775, 125)
(775, 125, 775, 75)
(825, 75, 775, 75)
(825, 25, 775, 25)
(775, 25, 775, 75)
(700, 125, 700, 75)
(700, 125, 750, 125)
(750, 125, 750, 75)
(750, 75, 750, 25)
(750, 25, 700, 25)
(700, 25, 700, 75)
(675, 125, 675, 75)
(675, 125, 625, 125)
(675, 75, 625, 75)
(675, 25, 625, 25)
(625, 25, 625, 75)
(600, 125, 600, 75)
(600, 125, 550, 125)
(550, 125, 550, 75)
(600, 75, 550, 75)
(600, 75, 600, 25)
(600, 25, 550, 25)
(550, 25, 550, 75)
(475, 125, 475, 75)
(475, 25, 475, 75)
(450, 125, 400, 125)
(400, 125, 400, 75)
(450, 75, 400, 75)
(450, 75, 450, 25)
(450, 25, 400, 25)
(375, 125, 375, 75)
(375, 25, 375, 75)
(375, 75, 325, 75)
(325, 25, 325, 75)
(300, 125, 300, 75)
(300, 125, 250, 125)
(300, 75, 250, 75)
(300, 25, 250, 25)
(250, 25, 250, 75)
(225, 125, 225, 75)
(225, 75, 225, 25)
(225, 25, 175, 25)
(150, 125, 100, 125)
(100, 125, 100, 75)
(150, 75, 100, 75)
(150, 75, 150, 25)
(150, 25, 100, 25)
(75, 125, 75, 75)
(75, 125, 25, 125)
(25, 25, 75, 25)
(75, 25, 75, 75)
(25, 75, 75, 75)

在当前

文件夹下生成图片

image-20240924085822933

点击查看,得到flag

image-20240924085745641

flag:ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}

ByteKit

题目提示:

One of our physical server have been hacked, we re-install the OS but there is still something there. Can you find it?

  1. execute “./run_qemu.sh” and login with username root and empty password
  2. after login, execute “./getflag.sh
  3. it will reboot
  4. after reboot, re-login with root and empty password, execute “./getflag.sh “ again, and you will get your flag.

中文:

我们的其中一台物理服务器被黑了,我们重装了操作系统,但似乎还有一些问题。你能找到它吗?

  1. 执行 “./run_qemu.sh” 并使用用户名 root 和空密码登录。
  2. 登录后,执行 “./getflag.sh <你的输入>”。
  3. 它将会重启。
  4. 重启后,再次使用 root 和空密码登录,重新执行 “./getflag.sh <你的输入>”,然后你会得到你的标志(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
BYTECTF_INPUT_GUID=93e91ed6-1a7a-46a1-b880-c5d281700ea2
BYTECTF_OUTPUT_GUID=93e91ed6-1a7a-46a1-b880-c5c281700ea2
BYTECTF_INPUT_VAR_FILE="/sys/firmware/efi/efivars/ByteCTFIn-$BYTECTF_INPUT_GUID"
BYTECTF_OUTPUT_VAR_FILE="/sys/firmware/efi/efivars/ByteCTFOut-$BYTECTF_OUTPUT_GUID"

if [ "$1" == "" ]; then
echo "$0 <your input>"
exit 1
fi

input=$1
echo "your input is $input"

if [ -f $BYTECTF_OUTPUT_VAR_FILE ]; then
flag1=$input
flag2=`cat $BYTECTF_OUTPUT_VAR_FILE | base64 | cut -c -24`
echo "ByteCTF{$flag1$flag2}"
chattr -i $BYTECTF_OUTPUT_VAR_FILE
rm -f $BYTECTF_OUTPUT_VAR_FILE
exit 0
fi

if [ -f $BYTECTF_INPUT_VAR_FILE ]; then
chattr -i $BYTECTF_INPUT_VAR_FILE
rm -f $BYTECTF_INPUT_VAR_FILE
fi

echo -en "\x07\x00\x00\x00$input" | sudo tee $BYTECTF_INPUT_VAR_FILE > /dev/null
echo "system will reboot in 10 seconds"
sh -c "sleep 10; reboot" &

对题目所给的另一个文件使用

binwalk -e bios.bin

提取里面的所有文件

image-20240925151106208

发现一个可执行文件

使用命令提取出来

uefi retools的使用参考:

UEFI_RETool:一款针对UEFI固件的逆向工程分析工具 - FreeBuf网络安全行业门户

其实直接执行下面的指令即可

1
2
git clone https://github.com/yeggor/UEFI_RETool.git
pip install -r requirements.txt

配置好后使用工具:

1
python3 uefi_retool.py get-images ./bios.bin

得到目标文件

image-20240925164040504

image-20240925164056580

image-20240925163959448

使用IDA打开其中的ByteKitLoaderDxe,这个通常用于在 UEFI 架构中,DXE(Driver Execution Environment)是指在早期阶段加载的一个环境,它负责初始化硬件驱动程序和其他关键服务。

我们直接看到_ModuleEntryPoint,在 UEFI 架构中,每个 UEFI 模块都有一个 _ModuleEntryPoint,这个入口点定义了模块初始化时的行为,它指向了模块的入口点,即模块开始执行的第一个函数。

发现ollvm

image-20240925164545879

使用D810去除ollvm(选择ollvm模式)

最后得到加密逻辑

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
EFI_STATUS __fastcall ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
int j; // eax
int i; // eax
__int64 v5; // rsi
unsigned __int64 v6; // r9
unsigned __int8 *v7; // rax
unsigned int v8; // ebx
unsigned __int64 m; // rcx
__int64 k; // r10
unsigned __int64 v11; // r8
__int64 v12; // rsi
int n; // eax
__int64 v16; // [rsp+50h] [rbp-138h]
__int64 v17; // [rsp+50h] [rbp-138h]
__int64 v18; // [rsp+68h] [rbp-120h]
__int64 v19; // [rsp+78h] [rbp-110h] BYREF
__int64 *v20; // [rsp+80h] [rbp-108h]
unsigned int v21; // [rsp+88h] [rbp-100h]
int v22; // [rsp+8Ch] [rbp-FCh]
unsigned int v23; // [rsp+90h] [rbp-F8h]
unsigned int v24; // [rsp+94h] [rbp-F4h]
__int64 v25; // [rsp+98h] [rbp-F0h]
int v26; // [rsp+A0h] [rbp-E8h]
int v27; // [rsp+A4h] [rbp-E4h]
__int64 v28; // [rsp+A8h] [rbp-E0h]
__int64 v29; // [rsp+B0h] [rbp-D8h]
__int64 v30; // [rsp+B8h] [rbp-D0h]
__int64 v31; // [rsp+C0h] [rbp-C8h]
__int64 v32; // [rsp+C8h] [rbp-C0h]
unsigned __int64 v33; // [rsp+D0h] [rbp-B8h]
__int64 v34; // [rsp+D8h] [rbp-B0h]
int v35; // [rsp+E8h] [rbp-A0h]
unsigned int v36; // [rsp+ECh] [rbp-9Ch]
__int64 v37[5]; // [rsp+F8h] [rbp-90h] BYREF

v37[4] = &SystemTable->Hdr.Revision;
v37[1] = v37;
v26 = 0;
LOBYTE(v31) = 1;
LOBYTE(v32) = ImageHandle != 0i64;
qword_1CA90 = SystemTable;
LOBYTE(v33) = 1;
LOBYTE(v34) = SystemTable != 0i64;
qword_1CA80 = SystemTable->BootServices;
LOBYTE(v25) = 1;
LOBYTE(v19) = qword_1CA80 != 0;
v20 = 0i64;
for ( i = -1227761683; i != 23738806; i = 23738806 )
qword_1CA88 = SystemTable->RuntimeServices;
LOBYTE(v24) = 0;
v35 = 0;
for ( j = -494123489; j == -494123489; j = 857817886 )
;
if ( sub_200() != 0 )
{
v16 = (*(qword_1CA80 + 64))(4i64, dword_3A28, &qword_1CA78);
if ( v16 >= 0 )
{
sub_AD1(qword_1CA78, &unk_3A37, dword_3A28);
qword_1CA64 = qword_1CA78;
qword_1CA6C = qword_1CA78 + dword_3A28;
v5 = 0i64;
}
else
{
v5 = v16;
}
v28 = v5;
if ( v28 >= 0 )
{
v36 = dword_3A28;
if ( v36 >= 5 && (v31 = qword_1CA78) != 0 )
{
for ( k = 0i64; ; k = v19 + 1 )
{
v19 = k;
v27 = dword_3A28;
if ( k >= dword_3A28 )
break;
v25 = v19 % 11;
*(qword_1CA78 + v19) ^= *(&unk_3A20 + v19 % 11 + 12);
}
v32 = qword_1CA78;
v33 = (v27 - 4);
v8 = -1;
v7 = qword_1CA78;
for ( m = 0i64; m < v33; ++m )
{
v21 = v8 >> 8;
v22 = dword_1CAC0[*v7 ^ v8];
v23 = v22 ^ (v8 >> 8);
++v7;
v8 = v23;
}
v24 = ~v8;
v34 = qword_1CA78 + dword_3A28;
if ( v24 == *(v34 - 4) )
v11 = 0i64;
else
v11 = 0x8000000000000015ui64;
v6 = v11;
}
else
{
v6 = 0x8000000000000002ui64;
}
v29 = v6;
if ( v29 >= 0 )
{
v20 = &v19;
v18 = (*(qword_1CA80 + 200))(0i64, ImageHandle, &unk_1CA5C, qword_1CA78, dword_3A28, &v19);
LOBYTE(v25) = v18 < 0;
if ( v25 )
{
v12 = v18;
}
else
{
(*(qword_1CA80 + 208))(v19, 0i64, 0i64);
v12 = 0i64;
}
v30 = v12;
if ( v30 >= 0 )
{
v17 = qword_1CA80;
for ( n = 2125084176; n != 898532110; n = 898532110 )
(*(v17 + 72))(qword_1CA78);
}
}
}
}
v37[3] = 0i64;
return 0i64;
}

idapython:

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

startaddr = 0x3A37
keyaddr = 0x3A2C
isize = 0x6c4

for i in range(isize):
patch_byte(startaddr + i, get_byte(startaddr + i) ^ get_byte(keyaddr + i % 11))

fp = open(r"G:\bytectf\ByteKit\ByteKit\image.efi", "wb+")
fp.write(get_bytes(startaddr, isize))
fp.close()

print("success")

将得到的使用IDA打开

image-20240925232716853

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
unsigned __int64 v22[4]; // [rsp+48h] [rbp-20h] BYREF

qword_5F8 = SystemTable;
BootServices = SystemTable->BootServices;
RuntimeServices = SystemTable->RuntimeServices;
qword_5D0 = ImageHandle;
qword_5F0 = BootServices;
qword_5D8 = RuntimeServices;
qword_5E8 = 0i64;
qword_5E0 = 0i64;
v22[0] = 256i64;
if ( (BootServices->AllocatePool)(6i64, 256i64, &qword_5E8) >= 0 )
{
v4 = (*(qword_5D8 + 72))(L"ByteCTFIn", &unk_580, v21, v22, qword_5E8);
v5 = qword_5E8;
if ( v4 >= 0
&& (v6 = v22[0], v22[0] > 4)
&& (qword_5E8 == "KEY:" || (v20 = qword_5E8, v7 = sub_240(qword_5E8, "KEY:", 4i64), v5 = v20, !v7)) )
{
qword_5E0 = v6;
}
else
{
(*(qword_5F0 + 72))(v5);
}
}
if ( !qword_5E8 )
return 0x8000000000000015ui64;
v9 = qword_5E0;
if ( qword_5E0 <= 4 )
return 0x8000000000000015ui64;
v10 = qword_4A0;
v11 = qword_5E0 - 1;
v12 = &qword_4A0[27];
v13 = qword_4A0;
do
{
v14 = v13[1];
v15 = v14 + v13[2];
while ( v15 > v14 )
{
if ( v14 >= 0 && v11 >= v14 )
*(v14 + qword_5E8) ^= *v13;
++v14;
}
v13 += 3;
}
while ( v12 != v13 );
if ( v9 != 32 )
return 0x8000000000000015ui64;
v16 = qword_5E8;
if ( qword_5E8 != &unk_5A0 && (sub_240(qword_5E8, &unk_5A0, 32i64) || !v16) )
return 0x8000000000000015ui64;
do
{
v17 = v10[1];
v18 = 31 - v17;
v19 = 31 - (v10[2] + v17);
while ( v18 > v19 )
{
if ( v18 <= 0x1F )
*(qword_5E8 + v18) ^= *v10;
--v18;
}
v10 += 3;
}
while ( v12 != v10 );
if ( (*(qword_5D8 + 88))(L"ByteCTFOut", &unk_5C0, 7i64, 32i64, qword_5E8) >= 0 )
return 0i64;
else
return 0x8000000000000015ui64;
}

其实主要加密的地方就是在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v13 = qword_4A0;
do
{
v14 = v13[1];
v15 = v14 + v13[2];
while ( v15 > v14 )
{
if ( v14 >= 0 && v11 >= v14 )
*(v14 + input) ^= *v13;
++v14;
}
v13 += 3;
}
while ( v12 != v13 );

就是一个异或的加密,需要注意异或的数据是v13的每一组的第一个数据,每三个数据分为一组

第一个数据是异或数据,第二个是下标,第三个是长度

将v13提取出来

key = [

[0x62, 1, 0x0B],

[0x79, 2, 3],

[0x74, 3, 7],

[0x65, 4, 0x0E],

[0x64, 5, 0x0D],

[0x61, 6, 0x0A],

[0x6E, 7, 0x0F],

[0x63, 8, 0x0C],

[0x65, 9, 0x0A]

]分别对应xorkey, index, xorlen

具体加密过程例如:

data = [ 0x4B, 0x27, 0x42, 0x55, 0x48, 0x6E, 0x41, 0x29, 0x1F, 0x5E, 0x04, 0x04, 0x6B, 0x3E, 0x57, 0x5F, 0x08, 0x07, 0x5F, 0x3A, 0x31, 0x17, 0x40, 0x30, 0x5F, 0x7A, 0x75, 0x67, 0x36, 0x36, 0x36, 0x36]

第一个密钥 [0x62, 1, 0x0B]
  • XOR密钥: 0x62
  • 起始索引: 1
  • 长度: 0x0B (即11)

解密从索引 1 开始的 11 个字节:

1
2
3
for j in range(1, 1 + 11):
if j < len(data):
data[j] ^= 0x62
1
2
3
4
5
6
7
8
9
10
11
data[1] = 0x27 ^ 0x62 = 0x45
data[2] = 0x42 ^ 0x62 = 0x20
data[3] = 0x55 ^ 0x62 = 0x13
data[4] = 0x48 ^ 0x62 = 0x26
data[5] = 0x6E ^ 0x62 = 0x2C
data[6] = 0x41 ^ 0x62 = 0x23
data[7] = 0x29 ^ 0x62 = 0x4B
data[8] = 0x1F ^ 0x62 = 0x73
data[9] = 0x5E ^ 0x62 = 0x1C
data[10] = 0x04 ^ 0x62 = 0x66
data[11] = 0x04 ^ 0x62 = 0x66

第二个密钥 [0x79, 2, 3]

  • XOR密钥: 0x79
  • 起始索引: 2
  • 长度: 3

解密从索引 2 开始的 3 个字节:

1
2
3
for j in range(2, 2 + 3):
if j < len(data):
data[j] ^= 0x79
1
2
3
data[2] = 0x42 ^ 0x79 = 0x39
data[3] = 0x55 ^ 0x79 = 0x26
data[4] = 0x48 ^ 0x79 = 0x31

解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
from idaapi import *
startaddr=0x5A0
keyaddr=0x4A0
keyarr=[]
for i in range(0,27,3):
tmp=[get_qword(keyaddr+i*8),get_qword(keyaddr+(i+1)*8),get_qword(keyaddr+(i+2)*8)]
keyarr.append(tmp)
#print(keyarr) #[[xorkey,index,xorlen],...]
for i in range(len(keyarr)):
for j in range(keyarr[i][1],keyarr[i][1]+keyarr[i][2]):
patch_byte(startaddr+j,get_byte(startaddr+j)^keyarr[i][0])
print(get_bytes(startaddr,32))

得到结果:b’KEY:By71d@nnc6_Wan77_y@0_zug6666’

image-20240926010835140

flag:ByteCTF{KEY:By71d@nnc6_Wan77_y@0_zug6666BwAAAEsnQlVIbkEpH15qamZW}


ByteCTF 2024 RE WP
http://example.com/2024/09/26/ByteCTF wp/
作者
John Doe
发布于
2024年9月26日
许可协议