{"id":13434752,"url":"https://github.com/bytedance/android-inline-hook","last_synced_at":"2025-05-14T08:10:21.461Z","repository":{"id":37395630,"uuid":"457619746","full_name":"bytedance/android-inline-hook","owner":"bytedance","description":":fire: ShadowHook is an Android inline hook library which supports thumb, arm32 and arm64.","archived":false,"fork":false,"pushed_at":"2024-12-12T07:31:12.000Z","size":663,"stargazers_count":1861,"open_issues_count":11,"forks_count":316,"subscribers_count":46,"default_branch":"main","last_synced_at":"2025-04-11T03:38:10.493Z","etag":null,"topics":["android","androidinlinehook","arm","arm64","hook","inline","inlinehook","jni","ndk","security","thumb"],"latest_commit_sha":null,"homepage":"https://github.com/bytedance/android-inline-hook/tree/main/doc","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytedance.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-10T03:43:15.000Z","updated_at":"2025-04-11T02:10:01.000Z","dependencies_parsed_at":"2024-09-20T17:41:04.555Z","dependency_job_id":"18b00e58-33eb-4d00-8cd4-6eaa955ed755","html_url":"https://github.com/bytedance/android-inline-hook","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fandroid-inline-hook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fandroid-inline-hook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fandroid-inline-hook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fandroid-inline-hook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytedance","download_url":"https://codeload.github.com/bytedance/android-inline-hook/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254101559,"owners_count":22014908,"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":["android","androidinlinehook","arm","arm64","hook","inline","inlinehook","jni","ndk","security","thumb"],"created_at":"2024-07-31T03:00:22.107Z","updated_at":"2025-05-14T08:10:16.451Z","avatar_url":"https://github.com/bytedance.png","language":"C","funding_links":[],"categories":["HarmonyOS","C","性能监控/优化 分析实践"],"sub_categories":["Windows Manager","基础开源库"],"readme":"# ShadowHook\n\n![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)\n![](https://img.shields.io/badge/release-1.1.1-red.svg?style=flat)\n![](https://img.shields.io/badge/Android-4.1%20--%2015-blue.svg?style=flat)\n![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a-blue.svg?style=flat)\n\n[**简体中文**](README.zh-CN.md)\n\n**ShadowHook** is an Android inline hook library which supports thumb, arm32 and arm64.\n\nShadowHook is now used in TikTok, Douyin, Toutiao, Xigua Video, Lark.\n\nIf you need an Android PLT hook library, please move to [ByteHook](https://github.com/bytedance/bhook).\n\n\n## Features\n\n* Support Android 4.1 - 15 (API level 16 - 35).\n* Support armeabi-v7a and arm64-v8a.\n* Support hook for the whole function, but does not support hook for the middle position of the function.\n* Support to specify the hook location by \"function address\" or \"library name + function name\".\n* Automatically complete the hook of \"newly loaded dynamic library\" (only \"library name + function name\"), and call the optional callback function after the hook is completed.\n* Multiple hooks and unhooks can be executed concurrently on the same hook point without interfering with each other (only in shared mode).\n* Automatically avoid possible recursive calls and circular calls between proxy functions (only in shared mode).\n* The proxy function supports unwinding backtrace in a normal way (CFI, EH, FP).\n* Integrated symbol address search function.\n* MIT licensed.\n\n\n## Documentation\n\n[ShadowHook Manual](doc/manual.md)\n\n\n## Quick Start\n\nYou can refer to the sample app in [app module](app), or refer to the hook/unhook examples of commonly used system functions in [systest module](systest).\n\n### 1. Add dependency in build.gradle\n\nShadowHook is published on [Maven Central](https://search.maven.org/), and uses [Prefab](https://google.github.io/prefab/) package format for [native dependencies](https://developer.android.com/studio/build/native-dependencies), which is supported by [Android Gradle Plugin 4.0+](https://developer.android.com/studio/releases/gradle-plugin?buildsystem=cmake#native-dependencies).\n\n```Gradle\nandroid {\n    buildFeatures {\n        prefab true\n    }\n}\n\ndependencies {\n    implementation 'com.bytedance.android:shadowhook:1.1.1'\n}\n```\n\n**Note**: ShadowHook uses the [prefab package schema v2](https://github.com/google/prefab/releases/tag/v2.0.0), which is configured by default since [Android Gradle Plugin 7.1.0](https://developer.android.com/studio/releases/gradle-plugin?buildsystem=cmake#7-1-0). If you are using Android Gradle Plugin earlier than 7.1.0, please add the following configuration to `gradle.properties`:\n\n```\nandroid.prefabVersion=2.0.0\n```\n\n### 2. Add dependency in CMakeLists.txt or Android.mk\n\n\u003e CMakeLists.txt\n\n```CMake\nfind_package(shadowhook REQUIRED CONFIG)\n\nadd_library(mylib SHARED mylib.c)\ntarget_link_libraries(mylib shadowhook::shadowhook)\n```\n\n\u003e Android.mk\n\n```\ninclude $(CLEAR_VARS)\nLOCAL_MODULE           := mylib\nLOCAL_SRC_FILES        := mylib.c\nLOCAL_SHARED_LIBRARIES += shadowhook\ninclude $(BUILD_SHARED_LIBRARY)\n\n$(call import-module,prefab/shadowhook)\n```\n\n### 3. Specify one or more ABI(s) you need\n\n```Gradle\nandroid {\n    defaultConfig {\n        ndk {\n            abiFilters 'armeabi-v7a', 'arm64-v8a'\n        }\n    }\n}\n```\n\n### 4. Add packaging options\n\nIf you are using ShadowHook in an SDK project, you may need to avoid packaging libshadowhook.so into your AAR, so as not to encounter duplicate libshadowhook.so file when packaging the app project.\n\n```Gradle\nandroid {\n    packagingOptions {\n        exclude '**/libshadowhook.so'\n        exclude '**/libshadowhook_nothing.so'\n    }\n}\n```\n\nOn the other hand, if you are using ShadowHook in an APP project, you may need to add some options to deal with conflicts caused by duplicate libshadowhook.so file.\n\n```Gradle\nandroid {\n    packagingOptions {\n        pickFirst '**/libshadowhook.so'\n        pickFirst '**/libshadowhook_nothing.so'\n    }\n}\n```\n\n### 5. Initialize\n\nShadowHook supports two modes (shared mode and unique mode). The proxy function in the two modes is written slightly differently. You can try the unique mode first. \n\n```Java\nimport com.bytedance.shadowhook.ShadowHook;\n\npublic class MySdk {\n    public static void init() {\n        ShadowHook.init(new ShadowHook.ConfigBuilder()\n            .setMode(ShadowHook.Mode.UNIQUE)\n            .build());\n    }\n}\n```\n\n### 6. Hook and Unhook\n\n```C\n#include \"shadowhook.h\"\n\nvoid *shadowhook_hook_func_addr(\n    void *func_addr,\n    void *new_addr,\n    void **orig_addr);\n\nvoid *shadowhook_hook_sym_addr(\n    void *sym_addr,\n    void *new_addr,\n    void **orig_addr);\n\nvoid *shadowhook_hook_sym_name(\n    const char *lib_name,\n    const char *sym_name,\n    void *new_addr,\n    void **orig_addr);\n\ntypedef void (*shadowhook_hooked_t)(\n    int error_number,\n    const char *lib_name,\n    const char *sym_name,\n    void *sym_addr,\n    void *new_addr,\n    void *orig_addr,\n    void *arg);\n\nvoid *shadowhook_hook_sym_name_callback(\n    const char *lib_name,\n    const char *sym_name,\n    void *new_addr,\n    void **orig_addr,\n    shadowhook_hooked_t hooked,\n    void *hooked_arg);\n\nint shadowhook_unhook(void *stub);\n```\n\n* `shadowhook_hook_func_addr`: hook a function (which has no symbol info in ELF) by absolute address.\n* `shadowhook_hook_sym_addr`: hook a function (which has symbol info in ELF) by absolute address.\n* `shadowhook_hook_sym_name`: hook a function by symbol name and ELF file name or path name.\n* `shadowhook_hook_sym_name_callback`: Similar to `shadowhook_hook_sym_name`, but the specified callback function will be called after the hook is completed.\n* `shadowhook_unhook`: unhook.\n\nFor example, let's try to hook `art::ArtMethod::Invoke`:\n\n```C\nvoid *orig = NULL;\nvoid *stub = NULL;\n\ntypedef void (*type_t)(void *, void *, uint32_t *, uint32_t, void *, const char *);\n\nvoid proxy(void *thiz, void *thread, uint32_t *args, uint32_t args_size, void *result, const char *shorty)\n{\n    // do something\n    ((type_t)orig)(thiz, thread, args, args_size, result, shorty);\n    // do something\n}\n\nvoid do_hook()\n{\n    stub = shadowhook_hook_sym_name(\n               \"libart.so\",\n               \"_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc\",\n               (void *)proxy,\n               (void **)\u0026orig);\n    \n    if(stub == NULL)\n    {\n        int err_num = shadowhook_get_errno();\n        const char *err_msg = shadowhook_to_errmsg(err_num);\n        LOG(\"hook error %d - %s\", err_num, err_msg);\n    }\n}\n\nvoid do_unhook()\n{\n    shadowhook_unhook(stub);\n    stub = NULL;\n}\n```\n\n* `_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc` is the function symbol name of `art::ArtMethod::Invoke` processed by C++ Name Mangler in libart.so. You can use readelf to view it. The C function does not have the concept of Name Mangler.\n* The symbol name of `art::ArtMethod::Invoke` is different in previous versions of Android M. This example is only applicable to Android M and later versions. If you want to achieve better Android version compatibility, you need to handle the difference in function symbol names yourself.\n\n\n## Contributing\n\n* [Code of Conduct](CODE_OF_CONDUCT.md)\n* [Contributing Guide](CONTRIBUTING.md)\n* [Reporting Security vulnerabilities](SECURITY.md)\n\n\n## License\n\nShadowHook is licensed by [MIT License](LICENSE).\n\nShadowHook uses the following third-party source code or libraries:\n\n* [queue.h](shadowhook/src/main/cpp/third_party/bsd/queue.h)  \nBSD 3-Clause License  \nCopyright (c) 1991, 1993 The Regents of the University of California.\n* [tree.h](shadowhook/src/main/cpp/third_party/bsd/tree.h)  \nBSD 2-Clause License  \nCopyright (c) 2002 Niels Provos \u003cprovos@citi.umich.edu\u003e\n* [linux-syscall-support](https://chromium.googlesource.com/linux-syscall-support/)  \nBSD 3-Clause License  \nCopyright (c) 2005-2011 Google Inc.\n* [xDL](https://github.com/hexhacking/xDL)  \nMIT License  \nCopyright (c) 2020-2024 HexHacking Team\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fandroid-inline-hook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytedance%2Fandroid-inline-hook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fandroid-inline-hook/lists"}