5mc

virtureprotect动态修改函数,用ida动态调试,给输入的数据下硬件断点运行分析就可以发现正确的逻辑。

image-20250211014951000

但是不能反汇编,选中按c恢复成汇编代码。

image-20250211015025210

直接读汇编写出加密代码,注意一下细节,每次循环左移的值都是不一样的,以防万一还是每次加密都细看了一下。一共有四种加密方法,四种加密循环进行一共十六次加密,顺序大概是box()–>index()–>shift(stat==0)–>shift(stat==1)–>……。直接写出逆向函数就行,密文就在比对的位置。

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

//加密函数
int box(unsigned char* data) {
unsigned char sbox[] = { 0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7,
0x3D, 0x18, 0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4,
0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3,
0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA,
0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9, 0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97,
0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD, 0xC4, 0x08,
0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60,
0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53,
0x83, 0x4D, 0xB2, 0x10, 0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5,
0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD,
0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A,
0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7
};

for (int i = 0; i < 32;i++) {
data[i] = sbox[data[i]];
}
return 0;
}
int index(unsigned char* data) {
unsigned char tmp[32], table[32] = { 0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E,0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A };
for (int i = 0; i < 32; i++) {
tmp[table[i]] = data[i];
}
for (int i = 0; i < 32; i++) {
data[table[i]] = tmp[i];
}

return 0;
}

int shift(int l, int r, unsigned char* data,int stat) {
unsigned char indext2[] = { 0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF, 0x18,
0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4 },
indextb2[] = { 0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8, 0x1E,
0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43 };
if (stat == 0) {
for (int i = 0; i < 32; i++) {
unsigned char c;
c = data[i] ^ indext2[i];
data[i] = c + indextb2[i];
data[i] = (data[i] << l) | (data[i] >> r);
}
}
else {
for (int i = 0; i < 32; i++) {
data[i] = (data[i] + indextb2[i]) ^ indext2[i];
data[i] = (data[i] << l) | (data[i] >> r);
}
}

return 0;
}
//解密函数

int rebox(unsigned char* data) {
unsigned char sbox[] = { 0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7,
0x3D, 0x18, 0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4,
0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3,
0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA,
0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9, 0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97,
0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD, 0xC4, 0x08,
0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60,
0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53,
0x83, 0x4D, 0xB2, 0x10, 0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5,
0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD,
0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A,
0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7
};
for (int i = 0; i < 32;i++) {
for (int j = 0; j < 256;j++) {
if (data[i] == sbox[j]) {
data[i] = j;
break;
}

}
}
return 0;
}

int reindex(unsigned char *data) {
unsigned char tmp[32], table[32] = { 0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E,0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A };
for (int i = 0; i < 32; i++) {
tmp[i] = data[table[i]];
}
for (int i = 0; i < 32; i++) {
data[i] = tmp[table[i]];
}
return 0;
}

int reshift(int l, int r, unsigned char* data,int stat) {
unsigned char indext2[] = { 0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF, 0x18,
0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4 },
indextb2[] = { 0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8, 0x1E,
0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43 };
if (stat == 1) {
for (int i = 0; i < 32; i++) {
unsigned char c;
data[i] = (data[i] >> l) | (data[i] << r);
c = data[i] - indextb2[i];
data[i] = c ^ indext2[i];
}
}
else {
for (int i = 0; i < 32; i++) {
unsigned char c;
data[i] = (data[i] >> l) | (data[i] << r);
data[i] = (data[i] ^ indext2[i]) - indextb2[i];
}
}

return 0;
}

void prlhex(unsigned char* data,const char *hit) {
printf("\n--------------------------------------------------------------------------------------\n");
printf("--------%s\n", hit);
for (int i = 0; i < 32; i++) {
printf("%02x ", data[i]);
}
}

int main() {
unsigned char data[] = { 0x5B, 0x2D, 0xE9, 0x66, 0xED, 0x39, 0x90, 0x23, 0xAF, 0xDA, 0xEB, 0x2E, 0xD1, 0x0D, 0xBB, 0xBD, 0x57, 0x52, 0x02, 0xB0, 0xBA, 0x9D, 0x52, 0xFA, 0x67, 0xEE, 0xA3, 0x85, 0xA9, 0x84, 0xE2, 0x6F };
reshift(1, 7, data,0); //逆向解密
reshift(2, 6, data,1);
reindex(data);
rebox(data);
reshift(5, 3, data,0);
reshift(3, 5, data,1);
reindex(data);
rebox(data);
reshift(4, 4, data,0);
reshift(6, 2, data,1);
reindex(data);
rebox(data);
reshift(7, 1, data,0);
reshift(3, 5, data,1);
reindex(data);
rebox(data);
for (int i = 0; i < 32; i++) {
printf("%c", data[i]);
}
return 0;
}
//flag{Master_of_5mc_XoR_aDD_r0r!}

sf5

有四个加密函数被存储在了数组v28里,并以每次加密次数为索引获取加密前的数据然后进行按位或操作(Buf1[v3++] & 3),以这个结果为索引加载数组v28中的函数进行加密。先分析四个加密函数,

image-20250211014819413

v28[0]是一个盒的查找替换,v28[1]以一个索引表对数据进行打乱,v28[2]把输入与两串常量异或并相加,v28[3]把数据每一字节循环右移了3位。值得注意的是这里的v28[2]是有点难看懂的,要结合汇编动调才能完全理解,下面是一些理解。

image-20250211014737831

加密逻辑大概如下

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

int enc1(uint8_t* data) {
uint8_t sbox[256] = { 0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7, 0x3D, 0x18,
0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4, 0xDE, 0xCA, 0x56, 0x92,
0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3, 0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1,
0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA, 0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1,
0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8, 0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9,
0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97, 0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B,
0x19, 0xCD, 0xC4, 0x08, 0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76,
0xBF, 0x60, 0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F, 0x46, 0xE9,
0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53, 0x83, 0x4D, 0xB2, 0x10,
0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5, 0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94,
0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD, 0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32,
0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A, 0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5,
0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D, 0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98,
0x09, 0x80, 0xE2, 0xC7 };
for (int i = 0; i < 32; i++) {
data[i] = sbox[data[i]];
}
return 0;
}

int enc2(uint8_t* data) {
unsigned char tmp[32], table[32] = { 0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E,0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A };
for (int i = 0; i < 32; i++) {
tmp[table[i]] = data[i];
}
for (int i = 0; i < 32; i++) {
data[table[i]] = tmp[i];
}
return 0;
}

int enc3(uint8_t* data) {
uint8_t index1[] = { 0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF,
0x18, 0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4 };
uint8_t index2[] = { 0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8,
0x1E, 0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43 };
for (int i = 0; i < 32; i++) {
data[i] ^= index1[i];
data[i] += index2[i];

}
return 0;

}
int enc4(uint8_t* data) {
for (int i = 0; i < 32; i++) {
data[i] = (data[i] >> 3) | (data[i] << 5);
}
return 0
}


因为不知道明文,我们每一次的解密有4种可能性,题目也提示dfs,我们就用dfs遍历解密路径就行。我们可以检查在解密后31减去解密次数与3进行与操作(data[31-step] & 3)是不是当前解密函数的下标,以确定路径,减少遍历的时间。结尾检查flag输出即可。

写出解密函数和dfs,脚本如下。

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

void prlhex(uint8_t* data, const char* hit);

int refun4(uint8_t* data) {
for (int i = 0; i < 32; i++) {
data[i] = (data[i] << 3) | (data[i] >> 5);
}
return 0;
}

int refun2(uint8_t *data) {
unsigned char tmp[32], table[32] = { 0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E,0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A };
for (int i = 0; i < 32; i++) {
tmp[i] = data[table[i]];
}
for (int i = 0; i < 32; i++) {
data[i] = tmp[table[i]];
}

return 0;
}

int refun3(uint8_t* data) {
uint8_t index1[] = { 0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF,
0x18, 0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4 };
uint8_t index2[] = { 0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8,
0x1E, 0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43 };
for (int i = 0; i < 32; i++) {

data[i] = (data[i] - index2[i]) ^ index1[i];

}
return 0;
}

int refun1(uint8_t* data) {
uint8_t sbox[256] = { 0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7, 0x3D, 0x18,
0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4, 0xDE, 0xCA, 0x56, 0x92,
0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3, 0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1,
0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA, 0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1,
0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8, 0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9,
0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97, 0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B,
0x19, 0xCD, 0xC4, 0x08, 0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76,
0xBF, 0x60, 0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F, 0x46, 0xE9,
0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53, 0x83, 0x4D, 0xB2, 0x10,
0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5, 0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94,
0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD, 0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32,
0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A, 0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5,
0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D, 0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98,
0x09, 0x80, 0xE2, 0xC7 };
for (int i = 0; i < 32;i++) {
for (int j = 0; j < 256;j++) {
if (data[i] == sbox[j]) {
data[i] = j;
break;
}

}
}
return 0;
}

int backupdata(uint8_t *data,uint8_t *data2) {
for (int i = 0; i < 32; i++) {
data[i] = data2[i];
}
return 0;
}

int (*refun[4])(uint8_t*) = { refun1, refun2, refun3, refun4 };

int check(unsigned char* data) {
if (!strncmp((char*)data, "flag", 4)) {
prlhex(data, "result"); //flag
}
return 0;
}

int dfs(uint8_t* data, int step, int* path) {
if (step == 32) {
check(data); //检查结果
return 1;
}

uint8_t backup[256];
backupdata(backup, data); //备份密文

for (int i = 0; i < 4; i++) { //四个解密函数进行解密
refun[i](data);
if ((data[31-step] & 3) == i) { //用&3剪枝
path[step] = i;
dfs(data, step + 1, path);
}
backupdata(data,backup);
}

return 0;
}

void prlhex(uint8_t* data,const char *hit) {
printf("\n------------------------------------------------------------------------------\n");
printf("--------%s\n", hit);
for (int i = 0; i < 32; i++) {
printf("%c", data[i]);
}
}

int main() {

uint8_t ciphertext[] = { 0x65, 0x3E, 0x43, 0xB8, 0xBA, 0xDB, 0xF6, 0x88, 0x25, 0x1B, 0x28, 0xC7, 0xC0, 0x54, 0xA6, 0x4A,
0x90, 0x37, 0xBC, 0x29, 0x41, 0xAA, 0x28, 0xDB, 0x9A, 0x59, 0x63, 0x9E, 0x4B, 0xCF, 0x2E, 0x41 };
int path[32];

dfs(ciphertext, 0, path);

return 0;
}
//flag{Ea5y_enCrypt_And_decrYpt!!}

easy-re

拿下来是一个Android elf文件,用真机运行几次发现报错先分析代码。

看了一下main函数才知道要带参数运行。加了许多混淆,c代码难以阅读,不过还是看到了一些rc4加密。字符串也被加密了,写个脚本用于dnmp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var inter =setInterval(function() { dump(); }, 3);
function dump() {

var libxx = Process.getModuleByName("easy-re");
var exe_s_size=0x0
console.log("*****************************************************");
console.log("name: " +libxx.name);
console.log("base: " +libxx.base);
console.log("size: " +ptr(libxx.size));
var file_path =  libxx.name + "_" + libxx.base + "_" + ptr(libxx.size) + ".so";
console.log(file_path);
var file_handle = new File(file_path, "wb");
if (file_handle && file_handle != null) {
    Memory.protect(ptr(libxx.base), libxx.size, 'rwx');

    var buffer = ptr(libxx.base).add(exe_s_size).readByteArray(libxx.size-exe_s_size);
    file_handle.write(buffer);
    file_handle.flush();
    file_handle.close();
    console.log("[dump]:", file_path);
}
clearInterval(inter)
}

再用Sofixer修复一下偏移。

重新在ida中分析,在Init_array有一个ptrace检测,可以通过字符串看出来。如果程序执行被检测到ptrace就会出现异常的结果。

image-20250211012945175

c代码太难看了,尝试动调,发现ida调试是可以用的(ptrace检测没有直接结束程序),我们可以用Ida调试elf并利用trace来分析程序算法。Trace结果过长就不展示了。

大概逻辑就是flag_char ^ index ^一个表 ^ 异或前一个char,那个表估计是rc4的。主要的难点是这个表,当前调试是被ptrace检测的,测试过多次,直接使用常规frida调试也是被检测了的。

由于ptrace检测,不是很好patch,打算用环境变量加载frida_gadget来启动frida,PRE_LOAD=/data/local/tmp/frida-gadget.so ./easy-re AAAAAABAAAAAAAAAAAAAAAAAAAAAAAAB

hook脚本

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
function time(num)
{
let sum=0
for(let i=0;i<num*1024;i++){
sum+=i;
}
}
var mInterval = setInterval(function () {
    var sgame = Process.findModuleByName("easy-re");
    if (sgame == null) {
        console.log("无");
        return;
    }
    clearInterval(mInterval);
    //  var addr = sgame.base.add(0x1400012A0-0x140000000) //windows
    var addr = sgame.base.add(0x05BC0309280 - 0x005BC0307000)
    console.log("" + addr);
    console.log(Instruction.parse(addr).toString());
    Interceptor.attach(addr, {
        onEnter: function (args) {
            var rax = this.context.x10;
            console.log( rax,",");
            time(5451)
        }
    })

    addr = sgame.base.add(0x5BC03094F0 - 0x005BC0307000)
    console.log("" + addr);
    console.log(Instruction.parse(addr).toString());
    Interceptor.attach(addr, {
        onEnter: function (args) {
            var rax = this.context.x1;
            // var mm=[68,39,43,160,45,33,116,240,251,156,45,31,225,255,45,22,140,155,112,144,214,47,152,233,164,146,168,3,253,29,123,37]
            // ptr(rax).writeByteArray(mm);
        }
    })
addr = sgame.base.add(0x5DF1A811A0 - 0x05DF1A7F000)
    console.log("" + addr);
    console.log(Instruction.parse(addr).toString());
    Interceptor.attach(addr, {
        onEnter: function (args) {
            var rax = this.context.x8;
             console.log(hexdump(ptr(rax), { length: 50, ansi: true }));
             time(5451)
        }
    })
}, 1)

直接可以拿到表

image-20250211013915246

写出解密代码

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>

char flag[]="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
unsigned char mm[32] = {
    0x50, 0x4C, 0x8B, 0x94, 0x86, 0x6D, 0x72, 0xFB, 0x54, 0xF3, 0x17, 0x0F, 0xEE, 0xE4, 0xC5, 0x1E,
    0xB8, 0x1A, 0xC7, 0xDF, 0x2D, 0x3D, 0x4E, 0x51, 0xE7, 0xAD, 0x97, 0x55, 0xF3, 0xF5, 0x41, 0x79
};
unsigned char box[]={0x36,0x71,0xf4,0x67,0xfa,0x9a,0xf9,0x0a,0x5e,0xa0,0xb6,0xb0,0x11,0xab,0x7a,0x2d,0xd0,0xd3,0x0a,0xca,0xe8,0x91,0x9a,0xc2,0x64,0x8e,0x12,0x08,0xba,0x46,0x4a,0x6e};
int main(){
    // int n=0;
   unsigned char xor2=0;
   unsigned char keys[40];
    for (size_t i = 0; i < 32; i++)
    {
        if (i!=0) {
        xor2^=mm[i-1];
        keys[i]=xor2;
    }
    }
        for (size_t i = 0; i <32; i++)
    {
        // flag[i]^=i;
        if (i!=0)
        {
            mm[i]^=keys[i];
        }    
    }
    for (size_t i = 0; i < 32; i++)
    {
        mm[i]^=i;
        mm[i]^=box[i];
        printf("%c", mm[i]);
    }
}
//flag{welcome-re-world!go!go!go!}