├── .github └── workflows │ └── inject.yml ├── LICENSE ├── README.md ├── pics └── inject.gif └── src ├── .clang-format ├── inject.cc ├── inject.sln └── inject.vcxproj /.github/workflows/inject.yml: -------------------------------------------------------------------------------- 1 | name: Builds 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | actions: read 7 | contents: read 8 | security-events: write 9 | 10 | jobs: 11 | Windows: 12 | name: Windows latest 13 | runs-on: windows-latest 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | platform: ['x86', 'x64'] 18 | configuration: ['Debug', 'Release'] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | with: 23 | submodules: recursive 24 | 25 | - name: Initialize CodeQL 26 | uses: github/codeql-action/init@v1 27 | with: 28 | languages: cpp 29 | 30 | - name: Setup vs prompt 31 | uses: ilammy/msvc-dev-cmd@v1 32 | 33 | - name: Build 34 | run: msbuild /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }} src\inject.sln 35 | 36 | - name: Perform CodeQL Analysis 37 | uses: github/codeql-action/analyze@v1 38 | 39 | - name: Upload artifacts 40 | uses: actions/upload-artifact@v2 41 | with: 42 | name: bin-${{ matrix.platform }}.${{matrix.configuration }} 43 | path: | 44 | src/**/${{ matrix.configuration }}/inject.exe 45 | src/**/${{ matrix.configuration }}/inject.pdb -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Axel Souchet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # inject 2 | ![Builds](https://github.com/0vercl0k/inject/workflows/Builds/badge.svg) 3 | 4 | ## Overview 5 | Yet another Windows DLL injector I wrote to support some work I was doing with [wtf](https://github.com/0vercl0k/wtf). 6 | 7 |

8 | 9 |

10 | 11 | ## Authors 12 | 13 | * Axel '[0vercl0k](https://twitter.com/0vercl0k)' Souchet 14 | -------------------------------------------------------------------------------- /pics/inject.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0vercl0k/inject/6d768847533394e7f3decdcc3c15769625cf4a35/pics/inject.gif -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /src/inject.cc: -------------------------------------------------------------------------------- 1 | // Axel '0vercl0k' Souchet - March 14 2020 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | HANDLE OpenRemoteProcess(const uint32_t ProcessId) { 12 | const uint32_t ProcessRights = 13 | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | 14 | PROCESS_VM_WRITE | PROCESS_VM_READ; 15 | const HANDLE Process = OpenProcess(ProcessRights, false, ProcessId); 16 | 17 | if (Process == nullptr) { 18 | printf("Failed to open the remote process.\n"); 19 | return INVALID_HANDLE_VALUE; 20 | } 21 | 22 | return Process; 23 | } 24 | 25 | PVOID AllocateMemInRemoteProcess(HANDLE RemoteProcess, 26 | const std::filesystem::path &Path) { 27 | const PVOID RemoteDllPath = VirtualAllocEx(RemoteProcess, nullptr, 0x1000, MEM_COMMIT | MEM_RESERVE, 28 | PAGE_READWRITE); 29 | 30 | if (RemoteDllPath == nullptr) { 31 | printf("VirtualAllocEx failed.\n"); 32 | return nullptr; 33 | } 34 | 35 | const std::string DllPath = Path.string(); 36 | const size_t DllPathLen = DllPath.size() + 1; 37 | SIZE_T BytesWritten; 38 | if (!WriteProcessMemory(RemoteProcess, RemoteDllPath, DllPath.c_str(), 39 | DllPathLen, 40 | &BytesWritten)) { 41 | VirtualFreeEx(RemoteProcess, RemoteDllPath, 0, MEM_RELEASE); 42 | printf("WriteProcessMemory failed.\n"); 43 | return nullptr; 44 | } 45 | 46 | return RemoteDllPath; 47 | } 48 | 49 | HANDLE CreateThreadInRemoteProcess(HANDLE RemoteProcess, PVOID RemoteDllPath) { 50 | const HMODULE Kernelbase = GetModuleHandleA("kernelbase"); 51 | if (Kernelbase == nullptr) { 52 | printf("GetModuleHandleA failed.\n"); 53 | return INVALID_HANDLE_VALUE; 54 | } 55 | 56 | const PVOID LoadLibraryA = PVOID(GetProcAddress(Kernelbase, "LoadLibraryA")); 57 | if (LoadLibraryA == nullptr) { 58 | printf("GetProcAddress failed.\n"); 59 | return INVALID_HANDLE_VALUE; 60 | } 61 | 62 | DWORD Tid = 0; 63 | const HANDLE Thread = CreateRemoteThread(RemoteProcess, nullptr, 0, 64 | LPTHREAD_START_ROUTINE(LoadLibraryA), 65 | RemoteDllPath, 0, &Tid); 66 | 67 | if (Thread == nullptr) { 68 | printf("CreateRemoteThread failed.\n"); 69 | return INVALID_HANDLE_VALUE; 70 | } 71 | 72 | printf("Thread with ID %d has been created.\n", Tid); 73 | 74 | return Thread; 75 | } 76 | 77 | bool InjectDll(const uint32_t ProcessId, const std::filesystem::path &Path) { 78 | bool InjectResult = false; 79 | 80 | HANDLE RemoteProcess = OpenRemoteProcess(ProcessId); 81 | if (RemoteProcess == INVALID_HANDLE_VALUE) { 82 | return InjectResult; 83 | } 84 | 85 | const PVOID RemoteDllPath = AllocateMemInRemoteProcess(RemoteProcess, Path); 86 | if (RemoteDllPath == nullptr) { 87 | CloseHandle(RemoteProcess); 88 | return InjectResult; 89 | } 90 | 91 | const HANDLE Thread = CreateThreadInRemoteProcess(RemoteProcess, RemoteDllPath); 92 | if (Thread == INVALID_HANDLE_VALUE) { 93 | VirtualFreeEx(RemoteProcess, RemoteDllPath, 0, MEM_RELEASE); 94 | CloseHandle(RemoteProcess); 95 | return InjectResult; 96 | } 97 | 98 | WaitForSingleObject(Thread, INFINITE); 99 | 100 | DWORD ExitCode = 0; 101 | GetExitCodeThread(Thread, &ExitCode); 102 | InjectResult = true; 103 | 104 | if (ExitCode == 0) { 105 | printf("/!\\ The thread failed to load the dll. "); 106 | InjectResult = false; 107 | } 108 | 109 | CloseHandle(Thread); 110 | VirtualFreeEx(RemoteProcess, RemoteDllPath, 0, MEM_RELEASE); 111 | CloseHandle(RemoteProcess); 112 | return InjectResult; 113 | } 114 | 115 | bool Pid2Name(const char *ProcessName, uint32_t &Pid) { 116 | PROCESSENTRY32 Pe32; 117 | HANDLE Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 118 | if (Snap == INVALID_HANDLE_VALUE) { 119 | return false; 120 | } 121 | 122 | Pe32.dwSize = sizeof(PROCESSENTRY32); 123 | if (!Process32First(Snap, &Pe32)) { 124 | CloseHandle(Snap); 125 | return false; 126 | } 127 | 128 | bool FoundPid = false; 129 | do { 130 | const bool Match = _stricmp(Pe32.szExeFile, ProcessName) == 0; 131 | if (Match) { 132 | if (FoundPid) { 133 | printf("There are several instances of %s, pid %d will be used.\n", 134 | Pe32.szExeFile, Pid); 135 | } else { 136 | FoundPid = true; 137 | Pid = Pe32.th32ProcessID; 138 | } 139 | } 140 | } while (Process32Next(Snap, &Pe32)); 141 | 142 | CloseHandle(Snap); 143 | return FoundPid; 144 | } 145 | 146 | int main(int Argc, const char *Argv[]) { 147 | if (Argc != 3) { 148 | printf("./injectdll \n"); 149 | return EXIT_FAILURE; 150 | } 151 | 152 | uint32_t ProcessId = strtol(Argv[1], nullptr, 0); 153 | if (ProcessId == 0) { 154 | const bool Success = Pid2Name(Argv[1], ProcessId); 155 | if (!Success) { 156 | printf("Pid2Name failed, exiting.\n"); 157 | return EXIT_FAILURE; 158 | } 159 | } 160 | 161 | std::vector Dlls; 162 | if (std::filesystem::is_directory(Argv[2])) { 163 | const std::filesystem::directory_iterator DirIt(Argv[2]); 164 | for (const auto &DirEntry : DirIt) { 165 | if (DirEntry.path().extension().string() == ".dll") { 166 | Dlls.emplace_back(DirEntry); 167 | } 168 | } 169 | } else { 170 | Dlls.emplace_back(Argv[2]); 171 | } 172 | 173 | for (const std::filesystem::path &Dll : Dlls) { 174 | const std::filesystem::path DllAbsolute = std::filesystem::absolute(Dll); 175 | const bool Succeed = InjectDll(ProcessId, DllAbsolute); 176 | if (!Succeed) { 177 | printf("Error while injecting %ls in %d\n", DllAbsolute.c_str(), 178 | ProcessId); 179 | return EXIT_FAILURE; 180 | } 181 | 182 | printf("Successfully injected %ls in %d\n", DllAbsolute.c_str(), ProcessId); 183 | } 184 | 185 | printf("Done!\n"); 186 | return EXIT_SUCCESS; 187 | } -------------------------------------------------------------------------------- /src/inject.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31424.327 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "inject.vcxproj", "{CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Debug|x64.ActiveCfg = Debug|x64 17 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Debug|x64.Build.0 = Debug|x64 18 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Debug|x86.ActiveCfg = Debug|Win32 19 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Debug|x86.Build.0 = Debug|Win32 20 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Release|x64.ActiveCfg = Release|x64 21 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Release|x64.Build.0 = Release|x64 22 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Release|x86.ActiveCfg = Release|Win32 23 | {CFF27EB6-C404-4E7E-9EE7-72FEDE08E737}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {8B53551B-C77B-4FDD-8910-6FA2351A8EEE} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/inject.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {cff27eb6-c404-4e7e-9ee7-72fede08e737} 25 | inject 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | MultiByte 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | MultiByte 41 | 42 | 43 | Application 44 | true 45 | v142 46 | MultiByte 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | MultiByte 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | stdcpplatest 92 | MultiThreadedDebug 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | stdcpplatest 108 | MultiThreaded 109 | 110 | 111 | Console 112 | true 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | true 121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | stdcpplatest 124 | MultiThreadedDebug 125 | 126 | 127 | Console 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | true 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 138 | true 139 | stdcpplatest 140 | MultiThreaded 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | --------------------------------------------------------------------------------