0x00 前言

一般难度比较低的比赛呢

就不要去想VMP了(

VPM都是纸老虎

查壳能看到不少消息

善用工具(

0x01 解

先查壳,发现VMP,但是工具给的是UPX

实际对比一下真有VMP的,可以发现还是不同的

所以按UPX处理,这里用010editor之类的二进制编辑软件把VPM全部改为UPX

之后就可以愉快脱壳了

然后拖IDA会发现main函数惨不忍睹

去Exports窗口可以发现有四个TlsCallback函数

发现除了TlsCallBlack_3全部都是爆红的

查看发现有花

在loop处按d,然后将E2这条指令nop掉,然后在函数开头按p就可以解析了

解密main,算SMC(好臭的srand)

之后看TlsCallback_1

发现也有花

这里在call处按d,然后将00401135(不包含)到00401130(包含)都给nop掉就行了

有base64的影子了(srand:哼哼,啊啊啊啊)

之后是TlsCallback_2,同样有花

这边是004011F1按d,然后将004011F1004011ED都给nop掉

没看太懂

先复原main看看吧,用idapython

1
2
3
4
from idc import *
for i in range(0x401890,0x401990+0x40):
patch_byte(i,get_wide_byte(i)^0x66)
print("done!")

这边直接看sub_4016B0

一个个看

第一个sub_401460是base64加密(换表了)

第二个sub_4012A0是RC4

最后一个sub_401A10是XTEA

密文在unk_404000里面,长度为64

1
2
3
4
5
6
7
8
9
10
unsigned char ida_chars[] =
{
0x59, 0x1B, 0xFD, 0xB4, 0x6B, 0xB8, 0xBE, 0xD9, 0xB3, 0xD3,
0x77, 0xD6, 0xF0, 0x65, 0x5F, 0x18, 0xA0, 0x9D, 0x3A, 0x53,
0x6D, 0x4A, 0x7B, 0x26, 0x74, 0x3A, 0x9C, 0x4E, 0x20, 0x43,
0x19, 0xD8, 0x72, 0xED, 0x95, 0xB5, 0x9C, 0x05, 0x22, 0x56,
0xCB, 0x7A, 0x11, 0x91, 0x9F, 0x7A, 0xBC, 0x0C, 0x4A, 0x69,
0x6D, 0xCE, 0x3D, 0xB4, 0xAB, 0x29, 0x61, 0xFA, 0x62, 0x32,
0xB4, 0xEC, 0x4C, 0xB6
};

之后就挺清晰的了,加密过程如下:

1
2
3
4
5
先执行TlsCallback_1将Base64换表
然后执行TlsCallback_2获取RC4的key
换表base64
RC4
XTEA

由于使用了随机数(固定种子)来获取RC4的key和base64的换表,而且放在了TlsCallback里面,所以这边直接写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
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
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <string.h>


void rc4_init(uint8_t* s, uint8_t* key, unsigned long len)
{
int i = 0;
int j = 0;
uint8_t k[256] = {0};
uint8_t temp = 0;
for (i = 0; i < 256; i++)
{
s[i] = i;
k[i] = key[i % len];
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}

void rc4_crypt(uint8_t* s, uint8_t* data, unsigned long len)
{
int i = 0, j = 0, t = 0;
uint8_t k = 0;
uint8_t temp;
for (k = 0; k < len; k++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
t = (s[i] + s[j]) % 256;
data[k] ^= s[t];
}
}


void XTEAdecipher(unsigned int num_rounds, uint32_t v[2], uint32_t key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x61C88647, sum = 0xcdab8c44;
for (i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0; v[1] = v1;
}

unsigned char findPos(const unsigned char* base64_map, unsigned char c)//查找下标所在位置
{
for (int i = 0; i < strlen((const char*)base64_map); i++)
{
if (base64_map[i] == c)
return i;
}
return 0;
}
unsigned char* base64_decode(const char* code0, unsigned char* base64_map)
{
unsigned char* code = (unsigned char*)code0;
// unsigned char base64_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
long len, str_len, flag = 0;
unsigned char* res;
len = strlen((const char*)code);
if (code[len - 1] == '=')
{
if (code[len - 2] == '=')
{
flag = 1;
str_len = len / 4 * 3 - 2;
}

else
{
flag = 2;
str_len = len / 4 * 3 - 1;
}

}
else
str_len = len / 4 * 3;
res = (unsigned char*)malloc(sizeof(unsigned char) * str_len + 1);
unsigned char a[4];
for (int i = 0, j = 0; j < str_len - flag; j += 3, i += 4)
{
a[0] = findPos(base64_map, code[i]);
a[1] = findPos(base64_map, code[i + 1]);
a[2] = findPos(base64_map, code[i + 2]);
a[3] = findPos(base64_map, code[i + 3]);
res[j] = a[0] << 2 | a[1] >> 4;
res[j + 1] = a[1] << 4 | a[2] >> 2;
res[j + 2] = a[2] << 6 | a[3];
}

switch (flag)
{
case 0:
break;
case 1:
{
a[0] = findPos(base64_map,code[len - 4]);
a[1] = findPos(base64_map,code[len - 3]);
res[str_len - 1] = a[0] << 2 | a[1] >> 4;
break;
}
case 2: {
a[0] = findPos(base64_map,code[len - 4]);
a[1] = findPos(base64_map,code[len - 3]);
a[2] = findPos(base64_map,code[len - 2]);
res[str_len - 2] = a[0] << 2 | a[1] >> 4;
res[str_len - 1] = a[1] << 4 | a[2] >> 2;
break;
}
}
res[str_len] = '\0';
return res;
}


int main()
{
srand(0x1919810);
uint8_t key[16];
uint8_t key1[16];
for (int i = 0; i < 16; i++)
{

key[i] = rand() % 0xff;
key1[i] = rand() % 0xff;

}
uint8_t enc[64] = { 0x59, 0x1B, 0xFD, 0xB4, 0x6B, 0xB8, 0xBE, 0xD9, 0xB3, 0xD3, 0x77, 0xD6, 0xF0, 0x65, 0x5F, 0x18, 0xA0, 0x9D, 0x3A, 0x53, 0x6D, 0x4A, 0x7B, 0x26, 0x74, 0x3A, 0x9C, 0x4E, 0x20, 0x43, 0x19, 0xD8, 0x72, 0xED, 0x95, 0xB5, 0x9C, 0x05, 0x22, 0x56, 0xCB, 0x7A, 0x11, 0x91, 0x9F, 0x7A, 0xBC, 0x0C, 0x4A, 0x69, 0x6D, 0xCE, 0x3D, 0xB4, 0xAB, 0x29, 0x61, 0xFA, 0x62, 0x32, 0xB4, 0xEC, 0x4C, 0xB6 };
uint8_t s[256] = { 0 };
for (size_t i = 0; i < 64; i += 8)
{
XTEAdecipher(100,(uint32_t*)(enc + i), (uint32_t*)key1);
}

rc4_init(s, key, 16);
rc4_crypt(s, enc, 64);

for (int i = 0; i < 64; i++)
{
printf("%c", enc[i]);
}
printf("\n");
int v6 = 0;
int v4 = 0;
srand(0x114514);
unsigned char b64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char tmp;
for(int i =0;i<100;i++){
v6 = rand() % 64;
v4 = rand() % 64;
tmp = b64[v6];
b64[v6] = b64[v4];
b64[v4] = tmp;
}
for (int i = 0; i < 64; i++)
{
printf("%c", b64[i]);
}
printf("\n");
printf("%s", base64_decode((char *)enc,b64));
return 0;
}
// flag{C0ngr@tulat1on!Y0u_Re_suCces3fu1Ly_Signln!}