ShadowHook
ShadowHook 是一个支持 thumb、arm32 和 arm64 的 Android 内联 hook 库。
ShadowHook 目前在抖音、TikTok、今日头条、西瓜视频和飞书中使用。
如果你需要一个 Android PLT hook 库,请移步 ByteHook。
特性
- 支持 Android 4.1 - 15(API 级别 16 - 35)。
- 支持 armeabi-v7a 和 arm64-v8a。
- 支持整个函数的 hook,但不支持函数中间位置的 hook。
- 支持通过"函数地址"或"库名 + 函数名"指定 hook 位置。
- 自动完成"新加载动态库"的 hook(仅限"库名 + 函数名"),并在 hook 完成后调用可选的回调函数。
- 可以在同一个 hook 点上并发执行多个 hook 和 unhook,而不会相互干扰(仅限共享模式)。
- 自动避免代理函数之间可能出现的递归调用和循环调用(仅限共享模式)。
- 代理函数支持正常方式的堆栈回溯(CFI、EH、FP)。
- 集成符号地址搜索功能。
- 使用 MIT 许可证。
文档
快速开始
你可以参考 app 模块 中的示例应用,或参考 systest 模块 中常用系统函数的 hook/unhook 示例。
1. 在 build.gradle 中添加依赖
ShadowHook 发布在 Maven Central 上,并使用 Prefab 包格式作为 原生依赖,这在 Android Gradle Plugin 4.0+ 中得到支持。
android {
buildFeatures {
prefab true
}
}
dependencies {
implementation 'com.bytedance.android:shadowhook:1.0.10'
}
注意:ShadowHook 使用 prefab 包架构 v2,这在 Android Gradle Plugin 7.1.0 及以后版本中默认配置。如果你使用的是早于 7.1.0 的 Android Gradle Plugin 版本,请在 gradle.properties
中添加以下配置:
android.prefabVersion=2.0.0
2. 在 CMakeLists.txt 或 Android.mk 中添加依赖
CMakeLists.txt
find_package(shadowhook REQUIRED CONFIG)
add_library(mylib SHARED mylib.c)
target_link_libraries(mylib shadowhook::shadowhook)
Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := mylib.c
LOCAL_SHARED_LIBRARIES += shadowhook
include $(BUILD_SHARED_LIBRARY)
$(call import-module,prefab/shadowhook)
3. 指定你需要的一个或多个 ABI
android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
4. 添加打包选项
如果你在 SDK 项目中使用 ShadowHook,你可能需要避免将 libshadowhook.so 打包到你的 AAR 中,以防在打包 app 项目时遇到重复的 libshadowhook.so 文件。
android {
packagingOptions {
exclude '**/libshadowhook.so'
}
}
另一方面,如果您在APP项目中使用ShadowHook,可能需要添加一些选项来处理由重复的libshadowhook.so文件引起的冲突。
android {
packagingOptions {
pickFirst '**/libshadowhook.so'
}
}
5. 初始化
ShadowHook支持两种模式(共享模式和唯一模式)。这两种模式下的代理函数写法略有不同。您可以先尝试唯一模式。
import com.bytedance.shadowhook.ShadowHook;
public class MySdk {
public static void init() {
ShadowHook.init(new ShadowHook.ConfigBuilder()
.setMode(ShadowHook.Mode.UNIQUE)
.build());
}
}
6. Hook和Unhook
#include "shadowhook.h"
void *shadowhook_hook_func_addr(
void *func_addr,
void *new_addr,
void **orig_addr);
void *shadowhook_hook_sym_addr(
void *sym_addr,
void *new_addr,
void **orig_addr);
void *shadowhook_hook_sym_name(
const char *lib_name,
const char *sym_name,
void *new_addr,
void **orig_addr);
typedef void (*shadowhook_hooked_t)(
int error_number,
const char *lib_name,
const char *sym_name,
void *sym_addr,
void *new_addr,
void *orig_addr,
void *arg);
void *shadowhook_hook_sym_name_callback(
const char *lib_name,
const char *sym_name,
void *new_addr,
void **orig_addr,
shadowhook_hooked_t hooked,
void *hooked_arg);
int shadowhook_unhook(void *stub);
shadowhook_hook_func_addr
:通过绝对地址hook一个函数(该函数在ELF中没有符号信息)。shadowhook_hook_sym_addr
:通过绝对地址hook一个函数(该函数在ELF中有符号信息)。shadowhook_hook_sym_name
:通过符号名称和ELF文件名或路径名hook一个函数。shadowhook_hook_sym_name_callback
:类似于shadowhook_hook_sym_name
,但在hook完成后会调用指定的回调函数。shadowhook_unhook
:取消hook。
例如,让我们尝试hook art::ArtMethod::Invoke
:
void *orig = NULL;
void *stub = NULL;
typedef void (*type_t)(void *, void *, uint32_t *, uint32_t, void *, const char *);
void proxy(void *thiz, void *thread, uint32_t *args, uint32_t args_size, void *result, const char *shorty)
{
// 做一些事情
((type_t)orig)(thiz, thread, args, args_size, result, shorty);
// 做一些事情
}
void do_hook()
{
stub = shadowhook_hook_sym_name(
"libart.so",
"_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc",
(void *)proxy,
(void **)&orig);
if(stub == NULL)
{
int err_num = shadowhook_get_errno();
const char *err_msg = shadowhook_to_errmsg(err_num);
LOG("hook错误 %d - %s", err_num, err_msg);
}
}
void do_unhook()
{
shadowhook_unhook(stub);
stub = NULL;
}
_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc
是libart.so中art::ArtMethod::Invoke
函数经过C++名称粉碎处理后的函数符号名。您可以使用readelf查看它。C函数没有名称粉碎的概念。- Android M之前版本中
art::ArtMethod::Invoke
的符号名不同。此示例仅适用于Android M及更高版本。如果您想实现更好的Android版本兼容性,需要自行处理函数符号名的差异。
贡献
许可证
ShadowHook采用MIT许可证授权。
ShadowHook使用以下第三方源代码或库:
- queue.h
BSD 3-句版权许可
版权所有 (c) 1991, 1993 加利福尼亚大学董事会。 - tree.h
BSD 2-句版权许可
版权所有 (c) 2002 Niels Provos provos@citi.umich.edu - linux-syscall-support
BSD 3-句版权许可
版权所有 (c) 2005-2011 Google Inc. - xDL
MIT 许可证
版权所有 (c) 2020-2024 HexHacking 团队