如何从Web URL将.NET托管DLL注入Unity游戏?
远程内存注入DLL(无本地文件)解决方案
要实现从Web URL直接获取DLL并注入目标进程(跳过本地存储),核心是内存中下载DLL + 手动PE映射——因为系统API LoadLibrary 仅支持从本地文件路径加载,无法直接读取内存中的PE数据。以下是具体实现步骤和关键要点:
1. 内存中下载远程DLL
使用网络库(如WinHTTP、libcurl)直接将URL对应的DLL字节数据读取到本地内存缓冲区,完全避免写入磁盘。以WinHTTP为例,核心流程如下:
LPBYTE DownloadRemoteDLL(const wchar_t* url, SIZE_T* outSize) { HINTERNET hSession = WinHttpOpen(L"RemoteInjector", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) return nullptr; // 示例:拆分GitHub原始链接的主机和路径,实际需做通用URL解析 HINTERNET hConnect = WinHttpConnect(hSession, L"raw.githubusercontent.com", INTERNET_DEFAULT_HTTPS_PORT, 0); if (!hConnect) { WinHttpCloseHandle(hSession); return nullptr; } HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/your-repo/path/target.dll", nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); if (!hRequest) { WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return nullptr; } if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return nullptr; } if (!WinHttpReceiveResponse(hRequest, nullptr)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return nullptr; } SIZE_T totalSize = 0; LPBYTE buffer = nullptr; BYTE tempBuffer[4096]; DWORD bytesRead; while (WinHttpReadData(hRequest, tempBuffer, sizeof(tempBuffer), &bytesRead) && bytesRead > 0) { LPBYTE newBuffer = (LPBYTE)realloc(buffer, totalSize + bytesRead); if (!newBuffer) { free(buffer); WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return nullptr; } buffer = newBuffer; memcpy(buffer + totalSize, tempBuffer, bytesRead); totalSize += bytesRead; } *outSize = totalSize; WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return buffer; }
2. 目标进程内存操作
2.1 分配内存
调用 VirtualAllocEx 在目标进程中分配足够容纳DLL数据的内存,初始权限设为 PAGE_READWRITE,后续可调整为执行权限:
LPVOID remoteMem = VirtualAllocEx(hProcess, nullptr, dllSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
2.2 写入DLL数据
用 WriteProcessMemory 将本地内存中的DLL字节写入目标进程的分配内存:
WriteProcessMemory(hProcess, remoteMem, dllBuffer, dllSize, nullptr);
3. 手动PE映射(核心步骤)
由于无法直接调用 LoadLibrary,需要手动实现PE加载逻辑,在目标进程中完成DLL的重定位、导入表解析和入口点调用,核心步骤包括:
- 解析PE头(
IMAGE_DOS_HEADER、IMAGE_NT_HEADERS) - 根据节表在目标进程中分配对应内存并复制节数据
- 处理基址重定位(若DLL编译基址与分配的内存地址不一致)
- 解析导入表,调用目标进程中的
GetProcAddress获取依赖函数地址并填充 - 调用DLL入口点
DllMain
关键坑点
- 权限不足:注入进程需要目标进程的权限至少包含
PROCESS_CREATE_THREAD、PROCESS_VM_OPERATION、PROCESS_VM_WRITE、PROCESS_VM_READ - 位数不兼容:32位注入器无法注入64位进程,反之亦然,必须严格匹配进程位数
- 重定位表缺失:若DLL编译时指定了固定基址且无重定位表,当目标进程中该基址被占用时会注入失败
- 网络拦截:确保注入器有网络访问权限,避免被防火墙或安全软件拦截DLL下载请求
简化替代方案
若手动映射过于复杂,可将下载逻辑+手动映射代码编译成一段独立的shellcode,注入到目标进程后执行,由目标进程自行完成DLL的下载和加载,进一步减少本地操作痕迹。
内容的提问来源于stack exchange,提问作者kinomonke
相关产品推荐
相关产品推荐

