{"id":13840038,"url":"https://github.com/gaffe23/linux-inject","last_synced_at":"2026-01-11T00:17:17.051Z","repository":{"id":27297337,"uuid":"30771169","full_name":"gaffe23/linux-inject","owner":"gaffe23","description":"Tool for injecting a shared object into a Linux process","archived":false,"fork":false,"pushed_at":"2022-02-23T12:39:01.000Z","size":262,"stargazers_count":1114,"open_issues_count":16,"forks_count":249,"subscribers_count":51,"default_branch":"master","last_synced_at":"2024-11-01T10:42:50.414Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gaffe23.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-13T19:04:46.000Z","updated_at":"2024-11-01T08:44:44.000Z","dependencies_parsed_at":"2022-07-08T10:43:59.186Z","dependency_job_id":null,"html_url":"https://github.com/gaffe23/linux-inject","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaffe23%2Flinux-inject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaffe23%2Flinux-inject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaffe23%2Flinux-inject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gaffe23%2Flinux-inject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gaffe23","download_url":"https://codeload.github.com/gaffe23/linux-inject/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225705161,"owners_count":17511235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T17:00:41.075Z","updated_at":"2026-01-11T00:17:16.984Z","avatar_url":"https://github.com/gaffe23.png","language":"C","readme":"# linux-inject\n**Tool for injecting a shared object into a Linux process**\n\n* Provides the Linux equivalent of using `CreateRemoteThread()` on Windows to inject a DLL into a running process\n\n* Performs injection using `ptrace()` rather than `LD_PRELOAD`, since the target process is already running at the time of injection\n\n* Supports x86, x86_64, and ARM\n\n* Does not require the target process to have been built with `-ldl` flag, because it loads the shared object using `__libc_dlopen_mode()` from libc rather than `dlopen()` from libdl\n\n## Caveat about `ptrace()`\n\n* On many Linux distributions, the kernel is configured by default to prevent any process from calling `ptrace()` on another process that it did not create (e.g. via `fork()`).\n\n* This is a security feature meant to prevent exactly the kind of mischief that this tool causes.\n\n* You can temporarily disable it until the next reboot using the following command:\n\n        echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope\n\n## Compiling\n\n* Simply running `make` should automatically select and build for the correct architecture, but if this fails (or you would like to select the target manually), run one of the following make commands:\n\n    * arm:\n\n            make arm\n\n    * x86:\n\n            make x86\n\n    * x86_64:\n\n            make x86_64\n\n## Usage\n\n    ./inject [-n process-name] [-p pid] [library-to-inject]\n\n## Sample\n\n* In one terminal, start up the sample target app, which simply outputs \"sleeping...\" each second:\n\n        ./sample-target\n\n* In another terminal, inject sample-library.so into the target app:\n\n        ./inject -n sample-target sample-library.so\n\n*  The output should look something like this:\n\n * First terminal:\n\n            $ ./sample-target\n            sleeping...\n            sleeping...\n            I just got loaded\n            sleeping...\n            sleeping...\n\n * Second terminal:\n\n            $ ./inject -n sample-target sample-library.so\n            targeting process \"sample-target\" with pid 31490\n            library \"sample-library.so\" successfully injected\n            $\n\n* If the injection fails, make sure your machine is configured to allow processes to `ptrace()` other processes that they did not create. See the \"Caveat about `ptrace()`\" section above.\n\n* You can verify that the injection was successful by checking `/proc/[pid]/maps`:\n\n        $ cat /proc/$(pgrep sample-target)/maps\n        [...]\n        7f37d5cc6000-7f37d5cc7000 r-xp 00000000 ca:01 267321                     /home/ubuntu/linux-inject/sample-library.so\n        7f37d5cc7000-7f37d5ec6000 ---p 00001000 ca:01 267321                     /home/ubuntu/linux-inject/sample-library.so\n        7f37d5ec6000-7f37d5ec7000 r--p 00000000 ca:01 267321                     /home/ubuntu/linux-inject/sample-library.so\n        7f37d5ec7000-7f37d5ec8000 rw-p 00001000 ca:01 267321                     /home/ubuntu/linux-inject/sample-library.so\n        [...]\n\n* You can also attach `gdb` to the target app and run `info sharedlibrary` to see what shared libraries the process currently has loaded:\n\n        $ gdb -p $(pgrep sample-target)\n        [...]\n        (gdb) info sharedlibrary\n        From                To                  Syms Read   Shared Object Library\n        0x00007f37d628ded0  0x00007f37d628e9ce  Yes         /lib/x86_64-linux-gnu/libdl.so.2\n        0x00007f37d5ee74a0  0x00007f37d602c583  Yes         /lib/x86_64-linux-gnu/libc.so.6\n        0x00007f37d6491ae0  0x00007f37d64ac4e0  Yes         /lib64/ld-linux-x86-64.so.2\n        0x00007f37d5cc6670  0x00007f37d5cc67b9  Yes         /home/ubuntu/linux-inject/sample-library.so\n        (gdb)\n\n## Compatibility\n\n* The x86 and x86_64 versions work on Ubuntu 14.04.02 x86_64.\n\n* The x86 and x86_64 versions work on Arch x86_64.\n\n* The ARM version works on Arch on both armv6 and armv7.\n\n* None of the versions seem to work on Debian. `__libc_dlopen_mode()` in Debian's libc does not load shared libraries in the same manner as Arch's and Ubuntu's versions do. I tested this on both x86_64 and armv6.\n\n## TODOs / Known Issues\n\n* Better support for targeting multi-thread/multi-process apps\n * I seem to get crashes when trying to inject into larger applications\n * Needs further investigation\n\n* Support both ARM and Thumb mode\n * Currently only supports ARM mode\n * Should just be a matter of checking LSB of PC and acting accordingly\n\n* Do better checking to verify that the specified shared object has actually been injected into the target process\n * Check `/proc/[pid]/maps` rather than just looking at the return value of `__libc_dlopen_mode()`\n\n* Support more distros\n * Currently only working on Ubuntu and Arch for certain architectures\n * See \"Compatibility\" section above\n\n* Possibly support more architectures?\n * 64-bit ARM\n * MIPS\n","funding_links":[],"categories":["C (286)","C"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaffe23%2Flinux-inject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaffe23%2Flinux-inject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaffe23%2Flinux-inject/lists"}