Skip to content

Commit

Permalink
Add shadowhook_hook_func_addr.
Browse files Browse the repository at this point in the history
  • Loading branch information
caikelun committed Nov 10, 2022
1 parent 2630df0 commit 9ec0323
Show file tree
Hide file tree
Showing 42 changed files with 690 additions and 366 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ShadowHook

![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/release-1.0.3-red.svg?style=flat)
![](https://img.shields.io/badge/release-1.0.4-red.svg?style=flat)
![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat)
![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a-blue.svg?style=flat)

Expand Down Expand Up @@ -55,7 +55,7 @@ android {
}
dependencies {
implementation 'com.bytedance.android:shadowhook:1.0.3'
implementation 'com.bytedance.android:shadowhook:1.0.4'
}
```

Expand Down Expand Up @@ -143,6 +143,11 @@ public class MySdk {
```C
#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,
Expand Down Expand Up @@ -174,8 +179,9 @@ void *shadowhook_hook_sym_name_callback(
int shadowhook_unhook(void *stub);
```
* `shadowhook_hook_sym_addr`: hook a function address.
* `shadowhook_hook_sym_name`: hook the symbol name of a function in a dynamic library.
* `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.
Expand Down
14 changes: 10 additions & 4 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ShadowHook

![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/release-1.0.3-red.svg?style=flat)
![](https://img.shields.io/badge/release-1.0.4-red.svg?style=flat)
![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat)
![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a-blue.svg?style=flat)

Expand Down Expand Up @@ -55,7 +55,7 @@ android {
}
dependencies {
implementation 'com.bytedance.android:shadowhook:1.0.3'
implementation 'com.bytedance.android:shadowhook:1.0.4'
}
```

Expand Down Expand Up @@ -143,6 +143,11 @@ public class MySdk {
```C
#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,
Expand Down Expand Up @@ -174,8 +179,9 @@ void *shadowhook_hook_sym_name_callback(
int shadowhook_unhook(void *stub);
```
* `shadowhook_hook_sym_addr`:hook 某个函数地址。
* `shadowhook_hook_sym_name`:hook 某个动态库中的某个函数符号名。
* `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`:unhook。
Expand Down
16 changes: 3 additions & 13 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ android {
}

dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

if (rootProject.ext.dependencyOnLocalLibrary) {
implementation project(':shadowhook')
Expand All @@ -66,13 +66,3 @@ dependencies {
}

apply from: rootProject.file('gradle/sanitizer.gradle')

if (rootProject.ext.dependencyOnLocalLibrary) {
tasks.whenTaskAdded { task ->
if (task.name == 'preDebugBuild') {
task.dependsOn(':shadowhook:prefabDebugConfigurePackage')
} else if (task.name == 'preReleaseBuild') {
task.dependsOn(':shadowhook:prefabReleaseConfigurePackage')
}
}
}
14 changes: 7 additions & 7 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18.1)
cmake_minimum_required(VERSION 3.22.1)
project(app)
enable_language(ASM)

Expand All @@ -14,25 +14,25 @@ endif()
set(TARGET "hookee")
file(GLOB SRC hookee/*.c hookee/arch/${ARCH}/*.S)
add_library(${TARGET} SHARED ${SRC})
target_compile_features(${TARGET} PUBLIC c_std_11)
target_compile_options(${TARGET} PUBLIC -Weverything -Werror -Wno-unused-macros)
target_compile_features(${TARGET} PUBLIC c_std_17)
target_compile_options(${TARGET} PUBLIC -std=c17 -Weverything -Werror -Wno-unused-macros)
target_include_directories(${TARGET} PUBLIC hookee)
target_link_libraries(${TARGET} log)

# libhookee2.so
set(TARGET "hookee2")
file(GLOB SRC hookee2/*.c)
add_library(${TARGET} SHARED ${SRC})
target_compile_features(${TARGET} PUBLIC c_std_11)
target_compile_options(${TARGET} PUBLIC -Weverything -Werror)
target_compile_features(${TARGET} PUBLIC c_std_17)
target_compile_options(${TARGET} PUBLIC -std=c17 -Weverything -Werror)
target_include_directories(${TARGET} PUBLIC hookee2)
target_link_libraries(${TARGET} log)

# libunittest.so
set(TARGET "unittest")
file(GLOB SRC unittest/*.c)
add_library(${TARGET} SHARED ${SRC})
target_compile_features(${TARGET} PUBLIC c_std_11)
target_compile_options(${TARGET} PUBLIC -Weverything -Werror)
target_compile_features(${TARGET} PUBLIC c_std_17)
target_compile_options(${TARGET} PUBLIC -std=c17 -Weverything -Werror)
target_include_directories(${TARGET} PUBLIC unittest hookee)
target_link_libraries(${TARGET} log hookee shadowhook::shadowhook)
7 changes: 7 additions & 0 deletions app/src/main/cpp/hookee/arch/arm/a32.S
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ ENTRY_GLOBAL_ARM(test_a32_helper_global)
bx lr
END(test_a32_helper_global)

// B A1, hidden function
ENTRY_HIDDEN_ARM(test_hidden_func)
cmp r0, r1
bne test_a32_helper_hidden_tail
bx lr
END(test_hidden_func)

ENTRY_HIDDEN_ARM(test_a32_helper_hidden)
add r0, r0, r1
bx lr
Expand Down
12 changes: 11 additions & 1 deletion app/src/main/cpp/hookee/arch/arm64/a64.S
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ ENTRY_GLOBAL_ARM(test_a64_helper_global)
END(test_a64_helper_global)


// B, hidden function
ENTRY_HIDDEN_ARM(test_hidden_func)
b test_a64_helper_global
nop
nop
nop
ret
END(test_hidden_func)


// B
ENTRY_GLOBAL_ARM(test_a64_b)
b test_a64_helper_global
Expand Down Expand Up @@ -310,4 +320,4 @@ END(test_a64_tbnz_fixaddr)
ENTRY_HIDDEN_ARM(test_a64_helper_hidden_tail)
add x0, x0, x1
ret
END(ttest_a64_helper_global_tail)
END(test_a64_helper_global_tail)
11 changes: 11 additions & 0 deletions app/src/main/cpp/hookee/hookee.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,14 @@ int test_hook_multi_times(int a, int b) {
LOG("**> test_hook_multiple_times called");
return a + b;
}

void *get_hidden_func_addr(void) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpointer-arith"
#if defined(__arm__)
return (void *)test_a32_helper_global + 8;
#elif defined(__aarch64__)
return (void *)test_a64_helper_global + 8;
#endif
#pragma clang diagnostic pop
}
2 changes: 2 additions & 0 deletions app/src/main/cpp/hookee/hookee.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,5 @@ int test_recursion_1(int a, int b);
int test_recursion_2(int a, int b);

int test_hook_multi_times(int a, int b);

void *get_hidden_func_addr(void);
51 changes: 45 additions & 6 deletions app/src/main/cpp/unittest/unittest.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#define LOG(fmt, ...) __android_log_print(ANDROID_LOG_INFO, "shadowhook_tag", fmt, ##__VA_ARGS__)
#pragma clang diagnostic pop
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-variable"

#define LOG(fmt, ...) __android_log_print(ANDROID_LOG_INFO, "shadowhook_tag", fmt, ##__VA_ARGS__)
#define DELIMITER ">>>>>>>>>>>>>>>>>>> %s >>>>>>>>>>>>>>>>>>>"
#define TO_STR_HELPER(x) #x
#define TO_STR(x) TO_STR_HELPER(x)
Expand Down Expand Up @@ -119,7 +120,7 @@ typedef int (*test_t)(int, int);

#define UNHOOK_WITH_TAG(inst, tag) \
do { \
if (NULL == stub_##inst##tag) return -1; \
if (NULL == stub_##inst##tag) break; \
int r_ = shadowhook_unhook(stub_##inst##tag); \
stub_##inst##tag = NULL; \
if (0 != r_) { \
Expand Down Expand Up @@ -225,6 +226,30 @@ static int hook_dlopen(int api_level) {
// end of - hooking dlopen() or do_dlopen()
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// hooking hidden function (without symbol info in ELF)

static test_t test_hidden_func = NULL;
PROXY(hidden_func)

static void run_hidden_func(void) {
if (NULL == test_hidden_func) test_hidden_func = (test_t)get_hidden_func_addr();
RUN(hidden_func);
}

static int hook_hidden_func(void) {
if (NULL == test_hidden_func) test_hidden_func = (test_t)get_hidden_func_addr();
if (NULL != stub_hidden_func) return -1;
stub_hidden_func = shadowhook_hook_func_addr(
(void *)test_hidden_func,
SHADOWHOOK_IS_UNIQUE_MODE ? (void *)unique_proxy_hidden_func : (void *)shared_proxy_hidden_func,
(void **)(&orig_hidden_func));
return NULL == stub_hidden_func ? -1 : 0;
}

// end of - hooking hidden function (without symbol info in ELF)
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// (1) test proxy for instructions

Expand Down Expand Up @@ -458,6 +483,13 @@ static int unittest_hook(int api_level) {

#endif

if (unittest_is_hook_addr) {
if (0 != hook_hidden_func()) {
LOG("hook hidden function FAILED");
return -1;
}
}

if (SHADOWHOOK_IS_SHARED_MODE) {
HOOK(recursion_1);
HOOK(recursion_2);
Expand Down Expand Up @@ -574,6 +606,8 @@ int unittest_unhook(void) {

#endif

UNHOOK(hidden_func);

if (SHADOWHOOK_IS_SHARED_MODE) {
UNHOOK(recursion_1);
UNHOOK(recursion_2);
Expand Down Expand Up @@ -681,18 +715,23 @@ int unittest_run(bool hookee2_loaded) {

#endif

LOG(DELIMITER, "TEST - hidden function");
run_hidden_func();

if (SHADOWHOOK_IS_SHARED_MODE) {
LOG(DELIMITER, "TEST BIZ - recursion");
LOG(DELIMITER, "TEST - recursion");
RUN(recursion_1);
LOG(DELIMITER, "TEST BIZ - hook multi times");
LOG(DELIMITER, "TEST - hook multi times");
RUN(hook_multi_times);
}

if (hookee2_loaded) {
LOG(DELIMITER, "TEST BIZ - hook before dlopen");
LOG(DELIMITER, "TEST - hook before dlopen");
RUN_WITH_DLSYM(libhookee2.so, hook_before_dlopen_1);
RUN_WITH_DLSYM(libhookee2.so, hook_before_dlopen_2);
}

return 0;
}

#pragma clang diagnostic pop
15 changes: 9 additions & 6 deletions app/src/main/cpp/unittest/unittest_jni.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include "shadowhook.h"
#include "unittest.h"

#define HACKER_JNI_VERSION JNI_VERSION_1_6
#define HACKER_JNI_CLASS_NAME "com/bytedance/shadowhook/sample/NativeHandler"

static int unittest_jni_hook_sym_addr(JNIEnv *env, jobject thiz, jint api_level) {
(void)env;
(void)thiz;
Expand Down Expand Up @@ -79,15 +82,15 @@ static void unittest_jni_dump_records(JNIEnv *env, jobject thiz, jstring pathnam

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
(void)reserved;
jint jni_version = JNI_VERSION_1_6;

JNIEnv *env;
if (NULL == vm) return JNI_ERR;
if (JNI_OK != (*vm)->GetEnv(vm, (void **)&env, jni_version)) return JNI_ERR;

JNIEnv *env;
if (JNI_OK != (*vm)->GetEnv(vm, (void **)&env, HACKER_JNI_VERSION)) return JNI_ERR;
if (NULL == env || NULL == *env) return JNI_ERR;

jclass cls = (*env)->FindClass(env, "com/bytedance/shadowhook/sample/NativeHandler");
if (NULL == cls) return JNI_ERR;
jclass cls;
if (NULL == (cls = (*env)->FindClass(env, HACKER_JNI_CLASS_NAME))) return JNI_ERR;

JNINativeMethod m[] = {{"nativeHookSymAddr", "(I)I", (void *)unittest_jni_hook_sym_addr},
{"nativeHookSymName", "(I)I", (void *)unittest_jni_hook_sym_name},
Expand All @@ -96,5 +99,5 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeDumpRecords", "(Ljava/lang/String;)V", (void *)unittest_jni_dump_records}};
if (0 != (*env)->RegisterNatives(env, cls, m, sizeof(m) / sizeof(m[0]))) return JNI_ERR;

return jni_version;
return HACKER_JNI_VERSION;
}
18 changes: 9 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false
id 'com.android.application' version '7.2.2' apply false
id 'com.android.library' version '7.2.2' apply false
}

task clean(type: Delete) {
Expand All @@ -9,20 +9,20 @@ task clean(type: Delete) {

ext {
minSdkVersion = 16
compileSdkVersion = 31
targetSdkVersion = 31
buildToolsVersion = '31.0.0'
compileSdkVersion = 33
targetSdkVersion = 33
buildToolsVersion = '33.0.0'
javaVersion = JavaVersion.VERSION_1_7
ndkVersion = "23.1.7779620"
cmakeVersion = "3.18.1"
ndkVersion = "23.2.8568313"
cmakeVersion = "3.22.1"
abiFilters = "armeabi-v7a,arm64-v8a"
useASAN = false
dependencyOnLocalLibrary = true
shadowhookVersion = "1.0.3"
shadowhookVersion = "1.0.4"

POM_GROUP_ID = "com.bytedance.android"
POM_ARTIFACT_ID = "shadowhook"
POM_VERSION_NAME = "1.0.3"
POM_VERSION_NAME = "1.0.4"

POM_NAME = "shadowhook"
POM_DESCRIPTION = "ShadowHook is an Android inline hook library which supports thumb, arm32 and arm64."
Expand Down
Loading

0 comments on commit 9ec0323

Please sign in to comment.