QWB2024-Re Part Record

First Post:

Last Update:

unname

本身 apk 进去看见导入了一个动态库,直接解压就能找到对应的文件了。细节这里不过多赘述,主要是概述一下调试部分。

如果直接用 IDA 去附加调试这个应用会发现找不到对应的 so,查了一下资料发现,在 AndroidManifest.xml 下配置了一个 android:extractNativeLibs="false" ,这会导致导入动态库的时候直接从 apk 进行加载,所以 IDA 附加以后找不到对应的模块,只能看到 apk 本身。

所以要先用 apktool 解包,然后把 AndroidManifest.xml 的配置稍微改一下再重新打包:

1
2
apktool d app-release.apk -o app-release
apktool b app-release -o app-debug.apk

这里改的主要是 application 标签:

1
<application android:debuggable="true" android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:extractNativeLibs="true" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplication">

加了一个 debuggable 的标签,另外改了 extractNativeLibs

然后还需要重新签一下名。

1
2
3
4
5
# 生成密钥库
keytool -genkey -dname "CN=ClientName, OU=OrganizationUnit, O=Organization, L=Locality, S=State, C=CountryCode" -alias qwb.keystore -keyalg RSA -validity 20000 -keystore qwb.keystore

# 重新签名 app-debug1.apk 是签后名,app-debug.apk 是要签的应用
jarsigner -verbose -keystore qwb.keystore -signedjar ./app-debug1.apk ./app-debug.apk qwb.keystore

不过这样签出来的应用在我的设备上还是装不上,会报如下内容:

Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary

查了一下,似乎是因为 Android 11 以上的设备不允许 resources.arsc 压缩或者没有对齐到 4 byte,一般方案似乎是用 zipalign 对齐一下:

1
zipalign -v 4 ./app-debug1.apk ./app-debug2.apk

不过这个操作似乎有些问题,在我的设备上如果通过这个方法对齐,则需要重新签名,但是重新签名以后又再次报了未对齐,最后上 GitHub 找了个项目能一把梭:

https://github.com/patrickfav/uber-apk-signer

1
java -jar ./uber-apk-signer-1.3.0.jar -a /home/tokameine/Desktop/qwb/app-debug1.apk --out /home/tokameine/Desktop/qwb/app-debug2.apk

操作是一样的:

  • 先用 apktool 解包
  • 修改需要改的配置
  • apktool 重新打包作为 debug1.apk
  • 用 uber-apk-signer 对其进行签名
    不过这个工具还是依赖 zipalign 和 keytool,环境下需要有这两个工具。

签完后的应用就可以直接安装了。

然后再把设备端口映射到本地:

1
adb forward tcp:23946 tcp:23946

端口号是 IDA 对应的端口,然后 IDA 就可以附加调试动态库了。

不过这中间遇到了点奇怪的事情,如果我先下了断点然后跑飞程序,应用会不停的报出一些异常,最终程序会退出;但如果我直接跑飞,然后再下断点,似乎又没问题了,诡异……
不过总之,最后成功附加上去了。
不过还有一个地方要警惕的是,我的设备在被中断以后会主动报未响应,熄屏会导致进程被回收,所以过程中需要注意进程开启的状态。

然后就是一边调试一份分析算法了,这步就不细写了,基本上就是读代码调试然后确定入参出参了,所以笔者也没进一步复现了。

额外

参考神的博客:Qforst-安卓apk反编译修改重打包签名
还说了另外一个方法去给所有应用挂 debugable,这里留个备份:

对于Root后的手机,可以使用Magisk对手机设置全局可调式。安装“MagiskHide Props Config”插件,该插件支持我们方便的修改prop值(不需要手动刷mprop)。该插件在Magisk插件市场中即可搜索安装。安装后,用ADB设置ro.debuggable为1即可调试任意程序

1
2
3
4
adb shell                            //adb进入命令行模式
su //切换至超级用户
magisk resetprop ro.debuggable 1 //设置debuggable
stop;start; //一定要通过该方式重启

dotdot

好逆天啊,但是挺有趣的。

C# 写的,所以反编译倒是没什么困难:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static void Main(string[] args)
{
try
{
BBB();
byte[] array = new byte[16];
byte[] array2 = new byte[16];
byte[] array3 = new byte[16];
AAA(v31, array2);
Array.Cle0ar(array, 0, 0);
AAA(array, array3);
if (!CCC(v4, array2, 16) || !CCC(v5, array3, 16))
{
Environment.Exit(-1);
}
v7 = DDD("License.dat");
EEE(Encoding.UTF8.GetBytes(v6), v7);
MemoryStream memoryStream = new MemoryStream(v7);
BinaryFormatter binaryFormatter = new BinaryFormatter();
memoryStream.Position = 0L;
binaryFormatter.Deserialize(memoryStream);
memoryStream.Close();
Console.WriteLine(Encoding.UTF8.GetString(v10));
}
catch (Exception)
{

}
}

BBB 里会获得输入然后对变量赋值,然后主要是 AAA 这个函数比较复杂,不太能直接逆,主要是其中的这个部分:

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
void Gen_table(unsigned int* aaa,int i,int j)
{
int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

num = v11[i][j * 4][aaa[4 * j]];
num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

num = v13[i][j * 4][aaa[4 * j]];
num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
}

这部分套到 4 轮里生成 16 字节:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void AAA2(unsigned int* aaa, unsigned int* bbb)
{
int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;
for (int i = 0; i < 9; i++) {
GGG(aaa);
for (j = 0; j < 4; j++) {
Gen_table(aaa, i, j);
}
}
GGG(aaa);
for (int ii = 0; ii < 16; ii++)
{
aaa[ii] = v14[9][ii][aaa[ii]];
}
for (int ii = 0; ii < 16; ii++)
{
bbb[ii] = aaa[ii];
}
}

GGG 是字节置换,这个可逆没什么问题,但是 Gen_table 函数看了半天都还是不可逆,但是如果考虑对这个函数进行爆破的话,由于是 4个字节映射到 4 个字节上,如果直接对整个 4 字节空间进行爆破的话还是太慢了,但是考虑到生成方式是一组字节决定另外一组字节,那么只要有一个字节不符合就能提前结束,能加快一点效率,最后差不多是这样:

先把结果置换回去,然后再进爆破:

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
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
#include <stdio.h>
#include "data.h"

int GGG(unsigned int* v16)
{
unsigned char array2[] = {0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11};
unsigned char array[16] = { 0 };
for (int i = 0; i < 16; i++)
{
array[i] = v16[array2[i]];
}
for (int i = 0; i < 16; i++)
{
v16[i] = array[i];
}
return 0;
}

int GGG_recover(unsigned char* v16) {
unsigned char array[16] = {};
unsigned char array2[16] = {0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3};
for (int i = 0; i < 16; i++)
{
array[i] = v16[array2[i]];
}
for (int i = 0; i < 16; i++)
{
v16[i] = array[i];
}
return 0;
}

void Gen_table(unsigned int* aaa,int i,int j)
{
int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

num = v11[i][j * 4][aaa[4 * j]];
num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

num = v13[i][j * 4][aaa[4 * j]];
num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

}

void AAA(unsigned int* aaa, unsigned int* bbb)
{
int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

for (int i = 0; i < 9; i++) {
GGG(aaa);
for (j = 0; j < 4; j++) {
num = v11[i][j * 4][aaa[4 * j]];
num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);

tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

num = v13[i][j * 4][aaa[4 * j]];
num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
}
}
GGG(aaa);
for (int ii = 0; ii < 16; ii++)
{
aaa[ii] = v14[9][ii][aaa[ii]];
}
for (int ii = 0; ii < 16; ii++)
{
bbb[ii] = aaa[ii];
}
}

void AAA2(unsigned int* aaa, unsigned int* bbb)
{
int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

for (int i = 0; i < 9; i++) {
GGG(aaa);
for (j = 0; j < 4; j++) {
Gen_table(aaa, i, j);
}
}
GGG(aaa);
for (int ii = 0; ii < 16; ii++)
{
aaa[ii] = v14[9][ii][aaa[ii]];
}
for (int ii = 0; ii < 16; ii++)
{
bbb[ii] = aaa[ii];
}
}

int main() {
unsigned int v31[16];
unsigned int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;
unsigned int now;
unsigned int bbb[16] = { 0 };
unsigned char recover[16] = { 84,66,248,146,8,40,193,220,66,252,121,175,82,198,11,34 };
int count = 0;
GGG_recover(recover);
for (int i = 8; i >= 0; i--)
{
for (int j = 0; j < 4; j++)
{
int flag = 0;
for (int i1 = 0; i1 < 256; i1++)
{
for (int i2 = 0; i2 < 256; i2++)
{
for (int i3 = 0; i3 < 256; i3++)
{
for (int i4 = 0; i4 < 256; i4++)
{
num = v13[i][j * 4][i1];
num2 = v13[i][j * 4 + 1][i2];
num3 = v13[i][j * 4 + 2][i3];
num4 = v13[i][j * 4 + 3][i4];

tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];

now = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
if (now != recover[4 * j])
{
continue;
}

tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
now = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
if (now != recover[4 * j+1])
{
continue;
}
tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
now = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
if (now != recover[4 * j + 2])
{
continue;
}
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
now = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
if (now != recover[4 * j + 3])
{
continue;
}

printf("success %d\n", count++);

printf("%d %d %d %d\n",i1,i2,i3,i4);
recover[4 * j] = i1 & 0xff;
recover[4 * j + 1] = i2 & 0xff;
recover[4 * j + 2] = i3 & 0xff;
recover[4 * j + 3] = i4 & 0xff;
flag = 1;
break;
}
if (flag) { break; }
}
if (flag) { break; }
}
if (flag) { break; }
}
if(!flag){printf("tell me \n");}
flag = 0;
for (int i1 = 0; i1 < 256; i1++)
{
for (int i2 = 0; i2 < 256; i2++)
{
for (int i3 = 0; i3 < 256; i3++)
{
for (int i4 = 0; i4 < 256; i4++)
{
num = v11[i][j * 4][i1];
num2 = v11[i][j * 4 + 1][i2];
num3 = v11[i][j * 4 + 2][i3];
num4 = v11[i][j * 4 + 3][i4];
tmp1 = (num >> 28) & 15;
tmp2 = (num2 >> 28) & 15;
tmp3 = (num3 >> 28) & 15;
tmp4 = (num4 >> 28) & 15;
num5 = v12[i][24 * j][tmp1][tmp2];
num6 = v12[i][24 * j + 1][tmp3][tmp4];
tmp1 = (num >> 24) & 15;
tmp2 = (num2 >> 24) & 15;
tmp3 = (num3 >> 24) & 15;
tmp4 = (num4 >> 24) & 15;
num7 = v12[i][24 * j + 2][tmp1][tmp2];
num8 = v12[i][24 * j + 3][tmp3][tmp4];
now = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
if (now != recover[4 * j])
{
continue;
}
tmp1 = (num >> 20) & 15;
tmp2 = (num2 >> 20) & 15;
tmp3 = (num3 >> 20) & 15;
tmp4 = (num4 >> 20) & 15;
num5 = v12[i][24 * j + 6][tmp1][tmp2];
num6 = v12[i][24 * j + 7][tmp3][tmp4];
tmp1 = (num >> 16) & 15;
tmp2 = (num2 >> 16) & 15;
tmp3 = (num3 >> 16) & 15;
tmp4 = (num4 >> 16) & 15;
num7 = v12[i][24 * j + 8][tmp1][tmp2];
num8 = v12[i][24 * j + 9][tmp3][tmp4];
now = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
if (now != recover[4 * j + 1])
{
continue;
}
tmp1 = (num >> 12) & 15;
tmp2 = (num2 >> 12) & 15;
tmp3 = (num3 >> 12) & 15;
tmp4 = (num4 >> 12) & 15;
num5 = v12[i][24 * j + 12][tmp1][tmp2];
num6 = v12[i][24 * j + 13][tmp3][tmp4];
tmp1 = (num >> 8) & 15;
tmp2 = (num2 >> 8) & 15;
tmp3 = (num3 >> 8) & 15;
tmp4 = (num4 >> 8) & 15;
num7 = v12[i][24 * j + 14][tmp1][tmp2];
num8 = v12[i][24 * j + 15][tmp3][tmp4];
now = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
if (now != recover[4 * j + 2])
{
continue;
}
tmp1 = (num >> 4) & 15;
tmp2 = (num2 >> 4) & 15;
tmp3 = (num3 >> 4) & 15;
tmp4 = (num4 >> 4) & 15;
num5 = v12[i][24 * j + 18][tmp1][tmp2];
num6 = v12[i][24 * j + 19][tmp3][tmp4];
tmp1 = num & 15;
tmp2 = num2 & 15;
tmp3 = num3 & 15;
tmp4 = num4 & 15;
num7 = v12[i][24 * j + 20][tmp1][tmp2];
num8 = v12[i][24 * j + 21][tmp3][tmp4];
now = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
if (now != recover[4 * j + 3])
{
continue;
}
printf("success %d\n", count++);
recover[4 * j] = i1 & 0xff;
recover[4 * j + 1] = i2 & 0xff;
recover[4 * j + 2] = i3 & 0xff;
recover[4 * j + 3] = i4 & 0xff;
printf("%d %d %d %d\n",i1,i2,i3,i4);
flag = 1;
break;
}
if (flag) { break; }
}
if (flag) { break; }
}
if (flag) { break; }
}
if(!flag){printf("tell me \n");
}
}
GGG_recover(recover);
}
for (int i = 0; i < 16; i++)
{
printf("%d,", recover[i]);
}
printf("\nend!!\n");
// scanf_s("%s", recover,16);
}

开 O3 优化以后快了不少:

![[8.png]]

得到 WelcomeToQWB2023 ,然后拿去用 RC4 解 License.dat ,但是输入以后调试就会发现程序会在反序列化的时候出现异常,不过道理上猜测是应该要拿去调用 FFF 的,所以直接开算 参数 b:

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
private static int FFF(string a, string b)
{
if (b.Length != 21)
{
return 1;
}
if (!v6.Equals(a))
{
return 1;
}
string s = b.PadRight((b.Length / 8 + ((b.Length % 8 > 0) ? 1 : 0)) * 8);
byte[] bytes = Encoding.UTF8.GetBytes(s);
byte[] bytes2 = Encoding.UTF8.GetBytes(a);
uint[] array = new uint[4];
for (int i = 0; i < 4; i++)
{
array[i] = BitConverter.ToUInt32(bytes2, i * 4);
}
uint num = 3735928559u;
int num2 = bytes.Length / 8;
byte[] array2 = new byte[bytes.Length];
for (int j = 0; j < num2; j++)
{
uint num3 = BitConverter.ToUInt32(bytes, j * 8);
uint num4 = BitConverter.ToUInt32(bytes, j * 8 + 4);
uint num5 = 0u;
for (int k = 0; k < 32; k++)
{
num5 += num;
num3 += ((num4 << 4) + array[0]) ^ (num4 + num5) ^ ((num4 >> 5) + array[1]);
num4 += ((num3 << 4) + array[2]) ^ (num3 + num5) ^ ((num3 >> 5) + array[3]);
}
Array.Copy(BitConverter.GetBytes(num3), 0, array2, j * 8, 4);
Array.Copy(BitConverter.GetBytes(num4), 0, array2, j * 8 + 4, 4);
}
for (int l = 0; l < array2.Length; l++)
{
if (v28[l] != array2[l])
{
return 1;
}
}
byte[] array3 = MD5.Create().ComputeHash(v7);
for (int m = 0; m < v10.Length; m++)
{
v10[m] = (byte)(v10[m] ^ array3[m % array3.Length]);
}
return 1;
}

一个标准的 TEA ,解出来 b 是:dotN3t_Is_1nt3r3sting

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
void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0xDEADBEEF*32, i; /* set up */
uint32_t delta = 0xDEADBEEF; /* a key schedule constant */
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */
for (i = 0; i < 32; i++) { /* basic cycle start */
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
} /* end cycle */
v[0] = v0; v[1] = v1;
}
int main() {

unsigned char v28[]=
{
69, 182, 171, 33, 121, 107, 254, 150, 92, 29,
4, 178, 138, 166, 184, 106, 53, 241, 42, 191,
23, 211, 3, 107
};
char keystr[] = "WelcomeToQWB2023";
unsigned int key[4];
unsigned int* keyptr = (unsigned int*)keystr;
key[0] = keyptr[0];
key[1] = keyptr[1];
key[2] = keyptr[2];
key[3] = keyptr[3];
unsigned int* v = (unsigned int*)v28;
decrypt(v, key);
decrypt(&v[2], key);
decrypt(&v[4], key);//dotN3t_Is_1nt3r3sting
}

不过也不是 flag,所以还是只能想办法修复序列化的结果了。

往反序列化函数里面跟:

![[5.png]]

在这里会发现,报出异常之前读取到的字节会表示类型为 string,但是跟进去之后会发现读到了长度 0 的输入,导致后续再读取下一个对象的时候读到 0 ,然后报错。所以只需要修复这里就能恢复了:

![[2.png]]

每个对象都有固定格式的,字符串的情况下,第一个 06 是类型,第二个 06 是对象 id,然后有一个 4 字节的长度参数,然后跟上具体的值。考虑到 FFF 正好就是两个参数,所以在这里把这两个丢进去,然后动调到 v10 异或结束以后,就能在内存里看到解了:

![[3.png]]