ByteHookAndroid 应用 PLT hook 框架

联合创作 · 2023-09-24 21:09

ByteHook(又名 bhook) 是字节跳动开源的一个针对 Android app 的 PLT hook 框架。它提供了一套 Android app 使用 PLT hook 的整体方案,而不仅仅是替换地址。


字节跳动的大多数 Android app(包括抖音,今日头条,西瓜视频)在线上环境中使用了 ByteHook 作为 PLT hook 方案。


特征



  • 支持 Android 4.1 - 12 (API level 16 - 31)。

  • 支持 armeabi-v7a, arm64-v8a, x86 和 x86_64。

  • 对同一个函数的多个 hook 和 unhook 互相不冲突。

  • 可以 hook 进程中单个、部分或全部的动态库。

  • 自动 hook 新加载的动态库。

  • 自动避免代理函数之间的递归调用和环形调用。

  • 代理函数中支持回溯调用栈。

  • 使用 MIT 许可证授权。


文档


ByteHook Documentation


快速开始


你可以参考 bytehook-sample 中的示例 app。


1. 在 build.gradle 中增加依赖


ByteHook 发布在 Maven Central 上。为了使用 native 依赖项,ByteHook 使用了从 Android Gradle Plugin 4.0+ 开始支持的 Prefab 包格式。



allprojects {
repositories {
mavenCentral()
}
}



android {
buildFeatures {
prefab true
}
}

dependencies {
implementation 'com.bytedance:bytehook:1.0.3'
}


2. 在 CMakeLists.txt 或 Android.mk 中增加依赖



CMakeLists.txt




find_package(bytehook REQUIRED CONFIG)

add_library(mylib SHARED mylib.c)
target_link_libraries(mylib bytehook::bytehook)



Android.mk




include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := mylib.c
LOCAL_SHARED_LIBRARIES += bytehook
include $(BUILD_SHARED_LIBRARY)

$(call import-module,prefab/bytehook)


3. 指定一个或多个你需要的 ABI



android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
}


4. 增加打包选项


如果你是在一个 SDK 工程里使用 ByteHook,你可能需要避免把 libbytehook.so 打包到你的 AAR 里,以免 app 工程打包时遇到重复的 libbytehook.so 文件。



android {
packagingOptions {
exclude '**/libbytehook.so'
}
}


另一方面, 如果你是在一个 APP 工程里使用 ByteHook,你可以需要增加一些选项,用来处理重复的 libbytehook.so 文件引起的冲突。



android {
packagingOptions {
pickFirst '**/libbytehook.so'
}
}


5. 初始化



import com.bytedance.android.bytehook.ByteHook;

public class MySdk {
public static synchronized void init() {
ByteHook.init();
}
}


6. Hook 和 Unhook



#include "bytehook.h"



bytehook_stub_t bytehook_hook_single(
const char *caller_path_name,
const char *callee_path_name,
const char *sym_name,
void *new_func,
bytehook_hooked_t hooked,
void *hooked_arg);

bytehook_stub_t bytehook_hook_partial(
bytehook_caller_allow_filter_t caller_allow_filter,
void *caller_allow_filter_arg,
const char *callee_path_name,
const char *sym_name,
void *new_func,
bytehook_hooked_t hooked,
void *hooked_arg);

bytehook_stub_t bytehook_hook_all(
const char *callee_path_name,
const char *sym_name,
void *new_func,
bytehook_hooked_t hooked,
void *hooked_arg);

int bytehook_unhook(bytehook_stub_t stub);


这里的三个 hook 函数分别用于 hook 进程中的单个、部分和全部的调用者动态库。


注意:



  • 如果需要在代理函数中调用原函数,请始终使用 BYTEHOOK_CALL_PREV() 宏来完成。

  • 确保在代理函数返回前调用 BYTEHOOK_POP_STACK() 宏。在 CPP 源文件中,也可以改为在代理函数的开头调用 BYTEHOOK_STACK_SCOPE() 宏。


 

浏览 29
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报