国赛2021
👴是废物,只做了两个简单题,也没抢到血

REVERSE

glass

apk 丢进 jadx 里可以知道关键逻辑在 so 层

简单梳理可以得到逻辑概况

init 不需要知道具体实现细节, dump 出 secreat 即可

xor1 中 input 与 secreat 进行某种异或操作

xor2 中也是异或,不过分成了两段异或,前一段是 input 每3位进行一些异或,再每一位异或 secreat

最后再与cmp比较

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

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

unsigned char cmp[] =
{
0xA3, 0x1A, 0xE3, 0x69, 0x2F, 0xBB, 0x1A, 0x84, 0x65, 0xC2,
0xAD, 0xAD, 0x9E, 0x96, 0x05, 0x02, 0x1F, 0x8E, 0x36, 0x4F,
0xE1, 0xEB, 0xAF, 0xF0, 0xEA, 0xC4, 0xA8, 0x2D, 0x42, 0xC7,
0x6E, 0x3F, 0xB0, 0xD3, 0xCC, 0x78, 0xF9, 0x98, 0x3F
};

int main()
{
xor2(cmp, 39, key, 8);
xor1(v7, cmp, 39);
printf("%s",cmp);
}

void xor1(unsigned char* v7, _BYTE *input, int a3)
{
int v3; // r3
int v4; // r4
int v5; // r5

v3 = 0;
v4 = 0;
while ( a3 )
{
--a3;
v4 = (v4 + 1) % 256;
v5 = *(unsigned __int8 *)(v7 + v4);
v3 = (v3 + v5) % 256;
*(_BYTE *)(v7 + v4) = *(_BYTE *)(v7 + v3);
*(_BYTE *)(v7 + v3) = v5;
*input++ ^= *(_BYTE *)(v7 + (unsigned __int8)(v5 + *(_BYTE *)(v7 + v4)));
}
return ;
}

void xor2(_BYTE * input, int a2, char* key, int a4)
{
int i; // r4
_BYTE* v5; // r6
char v6; // r5
char v7; // lr
char v8; // r12
int j; // lr
int k; // r6

for ( j = 0; j < 39; j += 8 )
{
for ( k = 0; (8 & ~(8 >> 31)) != k && j + k < 39; ++k )
input[k+j] ^= key[k];
}
for ( i = 0; i < 39; i += 3 )
{

// input[i] =input[i] ^input[i+2]
// input[i+1] =input[i]^input[i+1]^input[i+2];
// input[i+2] = input[i+1]^input[i+2]

unsigned char b=input[i]^input[i+1];
unsigned char a=input[i+1]^input[i+2];
unsigned char c=input[i]^input[i+2]^input[i+1];
input[i]=a;
input[i+1]=b;
input[i+2]=c;

}

return;
}

运行结果

测试截图

所以最终结果为

CISCN{6654d84617f627c88846c172e0f4d46c}

baby bc

百度可知 bc 是 LLVM bitcode 文件

所以执行下行代码可以得到可执行文件

clang -o baby baby.bc

将编译完的文件丢进 IDA 可以看见清晰的逻辑层次

细细分析以下,可以知道输入长度为25 输入限制为0-5

在 fill_numbner 中,经过输入测试,得知

输入用作填充 map ,如果在原来的 map 非 0 的地方填充非 0 ,则填充失败,这是第一个条件

在 docheck 中 还有四个条件

第一个是 map 中每一横排两两不重复

第二个是 map 中每一竖列两两不重复

第三个条件是按照 row 索引表 为1的地方要大于它右边的那一位 2则小于

第四个条件是按照 col 索引表 为1的地方要小于它下边的那一位 2则大于

综合以上条件

为所求幻方

所以输入为

1425353142350212150442315

验证正确

所以

CISCN{8a04b4597ad08b83211d3adfa1f61431}

为所求

文章作者: Usher
文章链接: https://usher2008.github.io/2021/05/16/%E5%9B%BD%E8%B5%9B2021/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Usher