{"id":13685825,"url":"https://github.com/kubo/plthook","last_synced_at":"2025-05-01T04:32:24.649Z","repository":{"id":12743438,"uuid":"15416524","full_name":"kubo/plthook","owner":"kubo","description":"Hook function calls by replacing PLT(Procedure Linkage Table) entries.","archived":false,"fork":false,"pushed_at":"2024-09-02T14:29:02.000Z","size":290,"stargazers_count":759,"open_issues_count":9,"forks_count":155,"subscribers_count":39,"default_branch":"master","last_synced_at":"2024-11-12T07:38:39.507Z","etag":null,"topics":["hook","hooking"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kubo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-12-24T10:34:19.000Z","updated_at":"2024-11-09T13:29:07.000Z","dependencies_parsed_at":"2024-01-14T16:08:49.046Z","dependency_job_id":"8bf2a04c-c8ad-4799-a0ac-27a578e0cfe9","html_url":"https://github.com/kubo/plthook","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/kubo%2Fplthook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubo%2Fplthook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubo%2Fplthook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubo%2Fplthook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kubo","download_url":"https://codeload.github.com/kubo/plthook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251824615,"owners_count":21649901,"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":["hook","hooking"],"created_at":"2024-08-02T14:00:57.699Z","updated_at":"2025-05-01T04:32:24.232Z","avatar_url":"https://github.com/kubo.png","language":"C","funding_links":[],"categories":["Awesome Repositories"],"sub_categories":["ELF binary format"],"readme":"PLTHook\n=======\n\n[![tests](https://github.com/kubo/plthook/actions/workflows/run-tests.yml/badge.svg)](https://github.com/kubo/plthook/actions/workflows/run-tests.yml)\n\nWhat is plthook.\n----------------\n\nA utility library to hook library function calls issued by\nspecified object files (executable and libraries). This modifies\nPLT (Procedure Linkage Table) entries in [ELF][] format used on most Unixes\nor [IAT (Import Address Table)][IAT] entries in PE format used on Windows.\n\n[IAT]: https://en.wikipedia.org/wiki/Portable_Executable#Import_Table\n[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format\n\n### What is PLT (or IAT)\n\nNote: This isn't precise explanation. Some details are omitted.\n\nWhen a function calls another function in another file, it is called via PLT (on\nUnix using ELF) or IAT (on Windows).\n\n![figure1](images/figure1.png)\n\nIn order to call `foo_func()` in `libfoo.so`, the address of the callee must be\nknown. When callers are in the same file, the relative address to the callee is\nknown at compile time regardless of the absolute address at run time. So\n`some_func()` calls `foo_func()` using relative addressing.\n\nWhen callers are in other files, the address of the callee cannot be known at\ncompile time. To resolve it, each file has a mapping from external function names\nto addresses. The callers directly look at the address in the PLT entry for\n`foo_func()` and jump to the address.\n\nThe addresses in PLT entries are resolved (1) at process startup or (2) at first\nfunction call (lazy binding). It depends on OSes or on settings.\n\n### What plthook does.\n\n![figure2](images/figure2.png)\n\nPlthook changes the address in PLT entries as above.\nWhen `foo_func()` is called from `program`, `hook_foo_func()` is called instead.\nIt doesn't change function calls from `libfoo.so` and `libbar.so`.\n\n### How to call original functions from hook functions.\n\n#### When hook functions are outside of modified files\n\n![figure3](images/figure3.png)\n\nWhen the hook function `hook_foo_func()` is in `libbar.so`, just call the\noriginal function `foo_func()`. It looks the PLT entry in `libbar.so` and jumps\nto the original.\n\n#### When hook functions are inside of modified files\n\n![figure4](images/figure4.png)\n\nWhen the hook function `hook_foo_func()` is in `program`, do not call the\noriginal function `foo_func()` because it jumps to `hook_foo_func()` repeatedly\nand crashes the process after memory for stack is exhausted. You need to get the\naddress of the original function and set it to the function pointer variable\n`foo_func_addr`. Use the fourth argument of `plthook_replace()` to get the\naddress on Windows. Use the return value of `dlsym(RTLD_DEFAULT, \"foo_func\")` on\nUnixes. The fourth argument of `plthook_replace()` isn't available on Unixes\nbecause it doesn't set the address of the original before the address in the PLT\nentry is resolved.\n\nChanges\n-------\n\n**2024-09-02:** Fix issues on macOS ([#48])\n\n**2024-08-05:** Add `plthook_enum_with_prot()` to enumerate entries with memory protection information. (plthook_elf.c and plthook_osx.c)\n\n**2023-06-01:** Add riscv support. (plthook_elf.c) ([#45])\n\n**2022-09-19:** Drop macOS 32-bit application support. Drop support for macOS 10.14 Mojave or before.\n\n**2022-08-12:** Support LC_DYLD_CHAINED_FIXUPS on macOS intel\n\n**2020-03-30:** Check _start also in plthook_open_by_handle() (plthook_elf.c) ([#29])\n\n**2020-03-09:** Add support for uClibc. ([#28])\n\n**2019-11-14:** Fix potential incorrect parsing of /proc/self/maps on linux. ([#24])\n\n**2019-11-14:** Fix possible double-close issue in plthook_elf.c ([#23])\n\n**2019-09-27:** Fix resource leaks when the format of /proc/self/maps is unexpected on Linux. ([#20])\n\n**2019-09-26:** Fix SEGV when plthook_open(..., \"/usr/lib/libc.dylib\") on macOS. ([#19])\n\n**2019-02-17:** Support `plthook_open_by_address()` and change\ninternal logic of `plthook_open()` on Android.\n\n**2019-02-17:** Stop checking RELRO and check memory protection at\nruntime instead.\n\n**2019-02-03:** Fix crash when programs are compiled with compiler options\n`-Wl,-z,relro` and `-fno-plt` with the help of [JC Liang][]. ([#10][])\n\n**2018-02-06:** Android support was contributed by [Daniel Deptford][].\n\n**2017-10-01:** `plthook_elf.c` was rewritten. Plthook had needed to\nread files on filesystem to get various information about target\nobject files. It now do it only for full RELRO object files.\nNote that plthook before 2017-10-01 gets segmentation fault while\nhooking a [prelinked file](https://en.wikipedia.org/wiki/Prelink#Linux) on Linux.\n\n**2017-09-18:** Fixed for processes on [valgrind](https://valgrind.org) on Linux.\n\nUsage\n-----\n\nIf you have a library `libfoo.so.1` and want to intercept\na function call `recv()` without modifying the library,\nput `plthook.h` and `plthook_elf.c`, `plthook_win32.c` or `plthook_osx.c`\nin your source tree and add the following code.\n\n```c\n#include \"plthook.h\"\n\n/* This function is called instead of recv() called by libfoo.so.1  */\nstatic ssize_t my_recv(int sockfd, void *buf, size_t len, int flags)\n{\n    ssize_t rv;\n    \n    ... do your task: logging, etc. ...\n    rv = recv(sockfd, buf, len, flags); /* call real recv(). */\n    ... do your task: logging, check received data, etc. ...\n    return rv;\n}\n    \nint install_hook_function()\n{\n    plthook_t *plthook;\n    \n    if (plthook_open(\u0026plthook, \"libfoo.so.1\") != 0) {\n        printf(\"plthook_open error: %s\\n\", plthook_error());\n        return -1;\n    }\n    if (plthook_replace(plthook, \"recv\", (void*)my_recv, NULL) != 0) {\n        printf(\"plthook_replace error: %s\\n\", plthook_error());\n        plthook_close(plthook);\n        return -1;\n    }\n    plthook_close(plthook);\n    return 0;\n}\n```\n\nThe above code doesn't work when `my_recv()` is in the file opened by\n`plthook_open()` as described [here](#when-hook-functions-are-inside-of-modified-files).\nUse the following code instead in the case.\n\n```c\nstatic ssize_t (*recv_func)(int sockfd, void *buf, size_t len, int flags);\n\n/* This function is called instead of recv() called by libfoo.so.1  */\nstatic ssize_t my_recv(int sockfd, void *buf, size_t len, int flags)\n{\n    ssize_t rv;\n    \n    ... do your task: logging, etc. ...\n    rv = (*recv_func)(sockfd, buf, len, flags); /* call real recv(). */\n    ... do your task: logging, check received data, etc. ...\n    return rv;\n}\n    \nint install_hook_function()\n{\n    plthook_t *plthook;\n    \n    if (plthook_open_by_address(\u0026plthook, \u0026recv_func) != 0) {\n        printf(\"plthook_open error: %s\\n\", plthook_error());\n        return -1;\n    }\n    if (plthook_replace(plthook, \"recv\", (void*)my_recv, (void**)\u0026recv_func) != 0) {\n        printf(\"plthook_replace error: %s\\n\", plthook_error());\n        plthook_close(plthook);\n        return -1;\n    }\n#ifndef WIN32\n    // The address passed to the fourth argument of plthook_replace() is\n    // available on Windows. But not on Unixes. Get the real address by dlsym().\n    recv_func = (ssize_t (*)(int, void *, size_t, int))dlsym(RTLD_DEFAULT, \"recv\");\n#endif\n    plthook_close(plthook);\n    return 0;\n}\n```\n\nNote that built-in functions cannot be hooked. For example the C\ncompiler in macOS Sierra compiles `ceil()` as inline assembly code,\nnot as function call of `ceil` in the system library.\n\nWhen a functions is imported by [ordinal][] on Windows,\nthe function name is specified by `export_dll_name:@ordinal`.\nFor example `api-ms-win-shcore-path-l1-1-0.dll:@170`.\n\n[ordinal]: https://msdn.microsoft.com/en-us/library/e7tsx612.aspx\n\nAnother Usage\n-------------\n\nPLTHook provides a function enumerating PLT/IAT entries.\n\n```c\nvoid print_plt_entries(const char *filename)\n{\n    plthook_t *plthook;\n    unsigned int pos = 0; /* This must be initialized with zero. */\n    const char *name;\n    void **addr;\n\n    if (plthook_open(\u0026plthook, filename) != 0) {\n        printf(\"plthook_open error: %s\\n\", plthook_error());\n        return -1;\n    }\n    while (plthook_enum(plthook, \u0026pos, \u0026name, \u0026addr) == 0) {\n        printf(\"%p(%p) %s\\n\", addr, *addr, name);\n    }\n    plthook_close(plthook);\n    return 0;\n}\n```\n\nSupported Platforms\n-------------------\n\n| Platform | source file | status |\n| -------- | ----------- | ------ |\n| Linux i386 and x86_64 | plthook_elf.c | tested using [github actions] |\n| Linux arm, aarch64, powerpc and powerpc64le | plthook_elf.c | tested on [QEMU][] using [github actions] |\n| Windows 32-bit and x64 (MSVC) | plthook_win32.c | tested using [github actions] |\n| macOS (intel) (*4) | plthook_osx.c | tested using [github actions] |\n| macOS (arm) | plthook_osx.c | tested using [github actions] |\n| Windows 32-bit and x64 (Mingw32 and Cygwin) | plthook_win32.c | perhaps(*2) |\n| Solaris x86_64 | plthook_elf.c | perhaps(*1) |\n| FreeBSD i386 and x86_64 except i386 program on x86_64 OS | plthook_elf.c | perhaps(*1) |\n| Android(*3) | plthook_elf.c | perhaps(*2) |\n\n*1 Tested on a local VM before.  \n*2 Tested on travis-ci.org before.  \n*3 Contributed by [Daniel Deptford][].  \n*4 macOS 10.14 Mojave support was dropped on 2022-09-19.  \n\n[QEMU]: http://www.qemu.org/\n[Daniel Deptford]: https://github.com/redmercury\n[JC Liang]: https://github.com/tntljc\n[#10]: https://github.com/kubo/plthook/pull/10\n[#19]: https://github.com/kubo/plthook/issues/19\n[#20]: https://github.com/kubo/plthook/issues/20\n[#23]: https://github.com/kubo/plthook/pull/23\n[#24]: https://github.com/kubo/plthook/issues/24\n[#28]: https://github.com/kubo/plthook/pull/28\n[#29]: https://github.com/kubo/plthook/issues/29\n[#45]: https://github.com/kubo/plthook/pull/45\n[#48]: https://github.com/kubo/plthook/issues/48\n[github actions]: https://github.com/kubo/plthook/actions/workflows/run-tests.yml\n\nLicense\n-------\n\n2-clause BSD-style license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkubo%2Fplthook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkubo%2Fplthook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkubo%2Fplthook/lists"}