├── .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 | 
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 |
--------------------------------------------------------------------------------