| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Library for injecting a shared library into a Linux, Windows and MacOS process
Caution
Due to a shift in my personal interests, this repository is no longer maintained and has been archived. If you're looking for a successor project, please check the network graph to see if any forks have continued development.
Warning
Don't use this in production environments. It may stop target processes forever. See Caveats.
I was inspired by linux-inject and the basic idea came from it. However the way to call __libc_dlopen_mode in libc.so.6 is thoroughly different.
Windows version is also here. It uses well-known CreateRemoteThread+LoadLibrary technique to load a DLL into another process with some improvements.
Note: It may work on Windows on ARM though I have not tested it because I have no ARM machines. Let me know if it really works.
The injector connects to the target process using task_for_pid and creates a mach-thread. If dlopen is called in this thread, the target process will fail with an error, however, it is possible to create another thread using pthread_create_from_mach_thread function for Mac >= 10.12 or pthread_create otherwise. In the created thread, the code for loading the library is executed. The second thread is created when injector_inject is called and terminated when injector_detach is called.
$ git clone https://github.com/kubo/injector.git
$ cd injector
$ makeThe make command creates:
| filename | - |
|---|---|
| src/linux/libinjector.a | a static library |
| src/linux/libinjector.so | a shared library |
| cmd/injector | a command line program linked with the static library |
Open a Visual Studio command prompt and run the following commands:
$ git clone https://github.com/kubo/injector.git # Or use any other tool
$ cd injector
$ nmake -f Makefile.win32The nmake command creates:
| filename | - |
|---|---|
| src/windows/injector-static.lib | a static library (release build) |
| src/windows/injector.dll | a shared library (release build) |
| src/windows/injector.lib | an import library for injector.dll |
| src/windows/injectord-static.lib | a static library (debug build) |
| src/windows/injectord.dll | a shared library (debug build) |
| src/windows/injectord.lib | an import library for injectord.dll |
| cmd/injector.exe | a command line program linked the static library (release build) |
On MSYS2:
$ git clone https://github.com/kubo/injector.git
$ cd injector
$ CC=gcc makeCross-compilation on Linux:
$ git clone https://github.com/kubo/injector.git
$ cd injector
$ CC=x86_64-w64-mingw32-gcc OS=Windows_NT makeThe environment variable OS=Windows_NT must be set on Linux.
$ git clone https://github.com/TheOiseth/injector.git
$ cd injector
$ makeThe make command creates:
| filename | - |
|---|---|
| src/macos/libinjector.a | a static library |
| src/macos/libinjector.dylib | a shared library |
| cmd/injector | a command line program linked with the static library |
Important: in order for the injector process to connect to another process using task_for_pid, it is necessary to disable SIP or sign the injector with a self-signed certificate with debugging permission, for this:
$ cd cmd/macos-sign
$ chmod +x genkey.sh
$ ./genkey.sh
$ chmod +x sign.sh
$ ./sign.shIf injector still does not work after signing, reboot the system.
#include <injector.h>
...
injector_t *injector;
void *handle;
/* attach to a process whose process id is 1234. */
if (injector_attach(&injector, 1234) != 0) {
printf("ATTACH ERROR: %s\n", injector_error());
return;
}
/* inject a shared library into the process. */
if (injector_inject(injector, "/path/to/shared/library", NULL) != 0) {
printf("INJECT ERROR: %s\n", injector_error());
}
/* inject another shared library. */
if (injector_inject(injector, "/path/to/another/shared/library", &handle) != 0) {
printf("INJECT ERROR: %s\n", injector_error());
}
...
/* uninject the second shared library. */
if (injector_uninject(injector, handle) != 0) {
printf("UNINJECT ERROR: %s\n", injector_error());
}
/* cleanup */
injector_detach(injector);See Usage section and Sample section in linux-inject and substitute inject with injector in the page.
x86_64:
| injector process \ target process | x86_64 | i386 | x32(*1) |
|---|---|---|---|
| x86_64 | 😃 success(*2) | 😃 success(*3) | 😃 success(*6) |
| i386 | 💀 failure(*4) | 😃 success(*3) | 💀 failure(*5) |
| x32(*1) | 💀 failure(*4) | 😃 success(*6) | 💀 failure(*5) |
*1: x32 ABI
*2: tested on github actions with both glibc and musl.
*3: tested on github actions with glibc.
*4: failure with 64-bit target process isn't supported by 32-bit process.
*5: failure with x32-ABI target process is supported only by x86_64.
*6: tested on a local machine. CONFIG_X86_X32 isn't enabled in github actions.
ARM:
| injector process \ target process | arm64 | armhf | armel |
|---|---|---|---|
| arm64 | 😃 success | 😃 success | 😃 success |
| armhf | 💀 failure(*1) | 😃 success | 😃 success |
| armel | 💀 failure(*1) | 😃 success | 😃 success |
*1: failure with 64-bit target process isn't supported by 32-bit process.
MIPS:
| injector process \ target process | mips64el | mipsel (n32) | mipsel (o32) |
|---|---|---|---|
| mips64el | 😃 success (*1) | 😃 success (*1) | 😃 success (*1) |
| mipsel (n32) | 💀 failure(*2) | 😃 success (*1) | 😃 success (*1) |
| mipsel (o32) | 💀 failure(*2) | 😃 success (*1) | 😃 success (*1) |
*1: tested on debian 11 mips64el on QEMU.
*2: failure with 64-bit target process isn't supported by 32-bit process.
PowerPC:
RISC-V:
Windows x64:
| injector process \ target process | x64 | x86 |
|---|---|---|
| x64 | 😃 success(*2) | 😃 success(*2) |
| x86 | 💀 failure(*1) | 😃 success(*2) |
*1: failure with x64 target process isn't supported by x86 process.
*2: tested on github actions
Windows 11 on Arm:
| injector process \ target process | arm64 | arm64ec | x64 | x86 | arm32 |
|---|---|---|---|---|---|
| arm64 | 😃 success | 💀 failure | 💀 failure | 💀 failure | 😃 success |
| arm64ec | 💀 failure | 😃 success | 😃 success | 💀 failure | 💀 failure |
| x64 | 💀 failure | 😃 success | 😃 success | 💀 failure | 💀 failure |
| x86 | 💀 failure | 💀 failure | 💀 failure | 😃 success | 💀 failure |
| arm32 | 💀 failure | 💀 failure | 💀 failure | 💀 failure | 😃 success |
Wine (on Linux x86_64):
| injector process \ target process | x64 | x86 |
|---|---|---|
| x64 | 😃 success | 💀 failure |
| x86 | 💀 failure | 😃 success |
| injector process \ target process | x64 | arm64 |
|---|---|---|
| x64 | 😃 success(*1) | 💀 failure(*2) |
| arm64 | 💀 failure(*3) | 😃 success |
*1: failure with x86_64 target process isn't supported by x86_64 process on ARM64 machine. Tested on github actions.
*2: failure with arm64 target process isn't supported by x86_64 process.
*3: failure with x86_64 target process isn't supported by arm64 process.
The following restrictions are only on Linux.
Injector doesn't work where ptrace() is disallowed.
Injector calls functions inside of a target process interrupted by ptrace(). If the target process is interrupted while holding a non-reentrant lock and injector calls a function requiring the same lock, the process stops forever. If the lock type is reentrant, the status guarded by the lock may become inconsistent. As far as I checked, dlopen() internally calls malloc() requiring non-reentrant locks. dlopen() also uses a reentrant lock to guard information about loaded files.
On Linux x86_64 injector_inject_in_cloned_thread in place of injector_inject may be a solution of the locking issue. It calls dlopen() in a thread created by clone(). Note that no wonder there are unexpected pitfalls because some resources allocated in pthread_create() lack in the clone()-ed thread. Use it at your own risk.
Files under include and src are licensed under LGPL 2.1 or later.
Files under cmd are licensed under GPL 2 or later.
Files under util are licensed under 2-clause BSD.
| Back | FazBrowse Home | New Git URL |