ShadowHook is an Android inline hook library which supports thumb, arm32 and arm64.
ShadowHook is now used in TikTok, Douyin, Toutiao, Xigua Video, Lark.
If you need an Android PLT hook library, please move to ByteHook.
You can refer to the sample app in app module, or refer to the hook/unhook examples of commonly used system functions in systest module.
ShadowHook is published on Maven Central, and uses Prefab package format for native dependencies, which is supported by Android Gradle Plugin 4.0+.
android {
buildFeatures {
prefab true
}
}
dependencies {
implementation 'com.bytedance.android:shadowhook:1.0.9'
}
Note: ShadowHook uses the prefab package schema v2, which is configured by default since Android Gradle Plugin 7.1.0. If you are using Android Gradle Plugin earlier than 7.1.0, please add the following configuration to gradle.properties
:
android.prefabVersion=2.0.0
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)
android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
If 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.
android {
packagingOptions {
exclude '**/libshadowhook.so'
}
}
On 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.
android {
packagingOptions {
pickFirst '**/libshadowhook.so'
}
}
ShadowHook 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.
import com.bytedance.shadowhook.ShadowHook;
public class MySdk {
public static void init() {
ShadowHook.init(new ShadowHook.ConfigBuilder()
.setMode(ShadowHook.Mode.UNIQUE)
.build());
}
}
#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 a function (which has no symbol info in ELF) by absolute address.shadowhook_hook_sym_addr
: hook a function (which has symbol info in ELF) by absolute address.shadowhook_hook_sym_name
: hook a function by symbol name and ELF file name or path name.shadowhook_hook_sym_name_callback
: Similar to shadowhook_hook_sym_name
, but the specified callback function will be called after the hook is completed.shadowhook_unhook
: unhook.For example, let's try to 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)
{
// do something
((type_t)orig)(thiz, thread, args, args_size, result, shorty);
// do something
}
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 error %d - %s", err_num, err_msg);
}
}
void do_unhook()
{
shadowhook_unhook(stub);
stub = NULL;
}
_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.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.ShadowHook is licensed by MIT License.
ShadowHook uses the following third-party source code or libraries: