Reverse

flower-or-tea

题如其名,打开是32位C程序,发现有简单的花指令,把E8或E9都patch90即可,生成正确的代码.

在main中分析如下:

image-20231207013412091

进入sub_4010C3看看:

image-20231207013447749

main的代码有点抽象,不过sub里是一个XTEA,这个好说.

简单来说就是将flag分成2半,重新组合顺序,然后进行XTEA.很久之后写WP有点忘记了,其实逻辑不难,就是IDA逆出来的代码抽象.

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

int sub_4010C3(unsigned int loop_cnt, unsigned int *a2, uint32_t *key) {
int result; // eax
unsigned int i; // [esp+8h] [ebp-10h]
unsigned int v0; // [esp+Ch] [ebp-Ch]
unsigned int v1; // [esp+10h] [ebp-8h]
unsigned int sum; // [esp+14h] [ebp-4h]

v1 = *a2; // reversed
v0 = a2[1]; // wtf?
sum = 0x31415927 * loop_cnt;
for (i = 0; i < loop_cnt; ++i) {
sum -= 0x31415927;
v1 -= (key[sum & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (v0 << 4)));
v0 -= sum ^ (key[(sum >> 11) & 3] + sum) ^
(v1 + ((v1 >> 5) ^ (v1 << 4)));
}
*a2 = v1;
result = 4;
a2[1] = v0;
return result;
}


int main() {
uint32_t v4[100];
v4[0] = -1694939573;
v4[1] = -1005078370;
v4[2] = -1307072749;
v4[3] = -918836760;
v4[4] = -1795955634;
v4[5] = -1244910923;
v4[6] = 1146217516;
v4[7] = 2055874714;
v4[8] = 1405669384;
v4[9] = 1846639433;
v4[10] = -1677731948;
v4[11] = 1593781753;
v4[12] = 401024305;
v4[13] = -541222535;
v4[14] = -1886971078;
v4[15] = 1944634796;
v4[16] = -1299812186;
v4[17] = 1526113129;
v4[18] = 754440740;
v4[19] = 880502447;
v4[20] = -1178055328;
v4[21] = -1860267729;
v4[22] = -1118163045;
v4[23] = -879332550;
v4[24] = -979801922;
v4[25] = -1610607639;
v4[26] = -1053864284;
v4[27] = -561628656;
v4[28] = -1597713004;
v4[29] = 1132501052;
v4[30] = 2117039688;
v4[31] = -447882103;
v4[32] = 1059563152;
v4[33] = -1249037927;
v4[34] = 1615521047;
v4[35] = -1668269692;
v4[36] = -186628991;
v4[37] = 1022684671;
v4[38] = 0;
v4[39] = 0;
uint32_t key[4] = {
32, 27, 39, 44
};

// 注:题目程序中有花指令,逐个nop掉后分析程序,备注在IDA数据库中

for (int i = 0; i < 38 / 2; ++i) {
sub_4010C3(54, &v4[2 * i], (uint32_t *) key);
}

char flag[100];
for (int i = 0; i < 38 / 2; ++i) {
flag[i] = v4[2 * i];
flag[38 - 1 - i] = v4[2 * i + 1];
}
for (int i = 0; i < 38; ++i) {
printf("%c", flag[i]);
}
return 0;
}

结束…

myself

这个题回头一看怎么是看汇编做的…

分析main,发现有一个SMC:

image-20231207014504668

patch掉后如下,不知道为啥函数出不来:

image-20231207014630225

这里把汇编和分析时加的注释放上来(比较宽可以复制到编辑器中查看):

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
.text:001913B0     ; =============== S U B R O U T I N E =======================================
.text:001913B0
.text:001913B0
.text:001913B0 sub_1913B0 proc near ; CODE XREF: _main+8C↓p
.text:001913B0 ; DATA XREF: sub_191010+1C7↑o ...
.text:001913B0 000 push ebp
.text:001913B0 sub_1913B0 endp ; sp-analysis failed
.text:001913B0
.text:001913B1 mov ebp, esp
.text:001913B3 sub esp, 0Ch
.text:001913B6 push ebx
.text:001913B7 push esi
.text:001913B8 xor ebx, ebx ; ebx is (i) in for(int i=0;i<8;++i) ???
.text:001913BA push edi
.text:001913BB mov [ebp-4], ebx ; v0=0
.text:001913BE xchg ax, ax
.text:001913C0
.text:001913C0 loc_1913C0: ; CODE XREF: .text:00191433↓j
.text:001913C0 mov ecx, [ebp+8] ; ecx = str
.text:001913C3 xor edi, edi ; edi = 0
.text:001913C5 mov esi, [ecx+ebx*4] ; esi = ((int *)str)[ebx]
.text:001913C5 ; esi == v[0]
.text:001913C8 lea eax, [ecx+ebx*4] ; eax = &((int *)str)[ebx]
.text:001913CB lea ebx, [ebx+1] ; ebx++
.text:001913CE mov [ebp-8], eax ; v1 = eax // addr[0]
.text:001913D1 lea eax, [ecx+ebx*4] ; eax = &((int*)str)[ebx]
.text:001913D1 ; eax --> v[1]
.text:001913D4 mov [ebp-12], eax ; v2 = eax // addr[1]
.text:001913D7 lea ebx, [edi+20h] ; ebx = edi + 0x20 == 0x20 ???
.text:001913DA mov eax, [eax] ; eax = *eax
.text:001913DC nop dword ptr [eax+00h]
.text:001913E0
.text:001913E0 loc_1913E0: ; CODE XREF: .text:0019141B↓j
.text:001913E0 mov ecx, eax ; TEA加密??? 这是内层循环
.text:001913E2 lea edi, [edi-61C88647h] ; -=delta值,相当于+=默认的delta
.text:001913E8 shl ecx, 4
.text:001913EB lea edx, [edi+eax]
.text:001913EE add ecx, 2
.text:001913F1 xor edx, ecx ; till now:
.text:001913F1 ; edx = (sum+v[1])^((v[0]<<4)+2);
.text:001913F3 mov ecx, eax
.text:001913F5 shr ecx, 5
.text:001913F8 add ecx, 2
.text:001913FB xor edx, ecx
.text:001913FD add esi, edx ; before: esi == v[0] ???
.text:001913FD ; till now:
.text:001913FD ; v[0] += (sum+v[1])^((v[1]<<4)+2)^(v[1] << 5) + 2
.text:001913FD ; v[0] <=> esi
.text:001913FF mov ecx, esi ; ecx = v[0] // v[0] has changed
.text:00191401 shl ecx, 4
.text:00191404 add ecx, 3
.text:00191407 lea edx, [edi+esi] ; edx = sum + v[0]
.text:0019140A xor edx, ecx
.text:0019140C mov ecx, esi
.text:0019140E shr ecx, 5
.text:00191411 add ecx, 4
.text:00191414 xor edx, ecx
.text:00191416 add eax, edx
.text:00191418 sub ebx, 1
.text:0019141B jnz short loc_1913E0
.text:0019141D mov ecx, [ebp-8]
.text:00191420 mov ebx, [ebp-4] ; v0中保存了外层循环的循环变量ebx,类似于压栈
.text:00191423 add ebx, 2
.text:00191426 mov [ebp-4], ebx
.text:00191429 mov [ecx], esi
.text:0019142B mov ecx, [ebp-0Ch]
.text:0019142E mov [ecx], eax
.text:00191430 cmp ebx, 8
.text:00191433 jl short loc_1913C0
.text:00191435 pop edi
.text:00191436 pop esi
.text:00191437 pop ebx
.text:00191438 mov esp, ebp
.text:0019143A pop ebp
.text:0019143B retn
.text:0019143B ; ---------------------------------------------------------------------------

第一次分析汇编(被迫的),累死了…

分析的结果如下(人肉反编译QWQ):

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

// 没错,这段汇编对应的函数就是一个TEA加密...

void TEA_encrypt(uint32_t *v) {
// uint32_t key[4]={2,2,3,4};

// uint32_t v0 = v[0], v1 = v[1];
uint32_t sum = 0, delta = 0x61C88647;
uint32_t ecx = v[0], edx;
for (int i = 0; i < 32; i++) {
sum -= delta;
/*
ecx = (v[1] << 4) + 2;
edx = sum + v[1];
edx ^= ecx;
// edx = (sum+v[1])^((v[0]<<4)+2);

ecx = v[1];
ecx = (ecx << 5) + 2;
edx ^= ecx;
// edx ^= ecx

v[0] += edx;
*/
// 标准TEA加密
v[0] += (sum + v[1]) ^ ((v[1] << 4) + 2) ^ ((v[1] >> 5) + 2);

v[1] += ((v[0] << 4) + 3) ^ (sum + v[0]) ^ ((v[0] >> 5) + 4);
}

// v[0] = v0;
// v[1] = v1;
}

那就TEA解密呗…

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

void decrypt(uint32_t *v, uint32_t *k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 32;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}

v[0] = v0;
v[1] = v1;
}

// test
int main() {
// 两个32位无符号整数,即待加密的64bit明文数据
unsigned char v[] = {
240, 249, 189, 189, 196, 148, 97, 226, 37, 145,
121, 128, 25, 194, 15, 31, 21, 24, 106, 235,
197, 114, 245, 132, 133, 58, 204, 64, 187, 42,
163, 210, 0
};
// 四个32位无符号整数,即128bit的key
uint32_t k[4] = {2, 2, 3, 4};

uint32_t *p = (uint32_t *) v;

for (int i = 0; i < 4; ++i) {
decrypt(p, k);
p += 2;
}
puts((char*)v);
return 0;
}

结束…

eazymath

很久前做的,忘记了,反正看了半天记得就是一个矩阵求逆…

然后有一个字符table的映射,这里记得好像存在多解?所以写的爆破(其实应该是我懒得逆逻辑…)

解密脚本:

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


int main() {
// IDA备注
/*
v8 = __readfsqword(0x28u);
puts("welcome_to_math");
__isoc99_scanf("%s", flag);
check((__int64)flag, (__int64)table); // char in flag must in table
checkposition(flag, table, (__int64)position);// convert to [index of table]
exchange(position, (__int64)&number); // pos[i] = number[pos[i]]
a2o(position, (__int64)last); // uint8_t index value to uint32_t value
//
//
for ( i = 0; i <= 4; ++i )
{
for ( j = 0; j <= 4; ++j )
{
v7[5 * i + j] = 0;
for ( k = 0; k <= 4; ++k )
v7[5 * i + j] = ((unsigned __int8)v7[5 * i + j]
+ (unsigned __int8)last[5 * i + k] * (unsigned __int8)matrix[5 * k + j]) & 0x1F;
if ( i == j && v7[5 * i + j] != 1 )
exit(0);
if ( i != j && v7[5 * i + j] )
exit(0);
}
}
puts("congratulation");
*/

// 根据matrix矩阵求出的flag矩阵
// flag为matrix矩阵模32下的逆阵
// 参考https://www.cnblogs.com/lcbwwy/p/13125084.html
// https://www.cnblogs.com/Higgerw/p/14464825.html#:~:text=%E6%A8%A1%E6%84%8F%E4%B9%89%E4%B8%8B%E7%9A%84%E9%80%86%E7%9F%A9%E9%98%B5%E8%AE%A1%E7%AE%97%20%E5%8F%82%E8%80%83%E8%87%AA%20https%3A%2F%2Fwww.cnblogs.com%2Flcbwwy%2Fp%2F13125084.html%20%E6%9C%80%E8%BF%91%E5%A4%8D%E4%B9%A0%E5%88%B0Hill%E5%AF%86%E7%A0%81%E7%AE%97%E6%B3%95%EF%BC%8C%E6%B3%A8%E6%84%8F%E5%88%B0%E8%A7%A3%E5%AF%86%E6%A0%B8%E5%BF%83%E6%98%AF%E5%8F%AF%E9%80%86%E7%9A%84%E5%8A%A0%E5%AF%86%E7%9F%A9%E9%98%B5%20K%20K%20%E7%9A%84%E6%A8%A126%E6%84%8F%E4%B9%89%E4%B8%8B%E7%9A%84%E6%B1%82%E9%80%86%20K%E2%88%921,%EF%BC%8C%E8%BF%9B%E4%B8%80%E6%AD%A5%E8%AE%A1%E7%AE%97%E5%85%B6%E5%85%B3%E4%BA%8E26%E7%9A%84%E6%A8%A1%E9%80%86%20%7CK%7C%E2%88%921%20%7C%20K%20%7C%20%E2%88%92%201%20%E3%80%82
// 利用网站https://zh.planetcalc.com/3324/
int flag[5][5] = {
11, 19, 9, 5, 12,
14, 6, 22, 27, 16,
26, 28, 29, 29, 11,
4, 31, 22, 13, 8,
27, 29, 10, 16, 16
};
char table[] = "01234_asdzxcpoityumnbAOZWXGMY";
int number[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 22, 26, 27,
28, 29, 31, 32, 50, 51, 52, 53, 54, 55, 56
};
int index = 0;
// 输出方阵
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
for (int k = 30; k <= 127; ++k) {
for (int t = 0; t < strlen(table); ++t) {
if (table[t] == k) {
if (flag[i][j] == number[t]) {
printf("%c", k);
index++;
}
}
}
}
// putchar('\n');
}
}
printf("\n%d", index);
return 0;
}

砍树

安卓逆向,其实不难.

赛后很久后才写WP,没环境了,解题思路在解密脚本里了…

(路径parent_directory是我的个人隐私~doge)

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

/*
* jadx中分析发现,加密方法public static native int I0o0I(String str, String str2);
* 为 native 方法,所以需要去找对应的.so库
* 使用`apktool.bat d 砍树.apk`命令进行反编译,在文件夹
* parent_directory\砍树\lib\arm64-v8a
* 中找到libezreeeee.so文件,使用IDA进行分析,最终发现使用key进行异或
* 编写解密脚本即可
*/
int main() {
unsigned char enc[] =
{
0, 32, 32, 23, 27, 54, 14, 54, 38, 23,
4, 42, 41, 7, 38, 21, 82, 51, 45, 15,
58, 39, 17, 6, 51, 7, 70, 23, 61, 10,
60, 56, 46, 34, 24, 0
};
unsigned char key[] = "Sycloverforerver";
for (int i = 0; i < 35; ++i) {
enc[i] ^= key[i % 7];
putchar(enc[i]);
}
return 0;
}