Skip to content

Commit 0e9b217

Browse files
提升兼容性并精简api
1 parent 1c31db6 commit 0e9b217

File tree

13 files changed

+1293
-1183
lines changed

13 files changed

+1293
-1183
lines changed

LICENSE

Lines changed: 339 additions & 339 deletions
Large diffs are not rendered by default.

Makefile

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
export TARGET_COMPILE=aarch64-none-elf-
2-
3-
ifndef TARGET_COMPILE
4-
$(error TARGET_COMPILE not set)
5-
endif
6-
7-
ifndef KP_DIR
8-
KP_DIR = ../..
9-
endif
10-
11-
12-
CC = $(TARGET_COMPILE)gcc
13-
LD = $(TARGET_COMPILE)ld
14-
15-
INCLUDE_DIRS := . include patch/include linux/include linux/arch/arm64/include linux/tools/arch/arm64/include
16-
17-
INCLUDE_FLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(KP_DIR)/kernel/$(dir))
18-
19-
objs := kernel_trace.o
20-
21-
all: kernel_trace.kpm
22-
23-
kernel_trace.kpm: ${objs}
24-
${CC} -r -o $@ $^
25-
26-
%.o: %.c
27-
${CC} $(CFLAGS) $(INCLUDE_FLAGS) -c -O2 -o $@ $<
28-
29-
.PHONY: clean
30-
clean:
31-
rm -rf *.kpm
1+
export TARGET_COMPILE=aarch64-none-elf-
2+
3+
ifndef TARGET_COMPILE
4+
$(error TARGET_COMPILE not set)
5+
endif
6+
7+
ifndef KP_DIR
8+
KP_DIR = ../..
9+
endif
10+
11+
12+
CC = $(TARGET_COMPILE)gcc
13+
LD = $(TARGET_COMPILE)ld
14+
15+
INCLUDE_DIRS := . include patch/include linux/include linux/arch/arm64/include linux/tools/arch/arm64/include
16+
17+
INCLUDE_FLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(KP_DIR)/kernel/$(dir))
18+
19+
objs := kernel_trace.o
20+
21+
all: kernel_trace.kpm
22+
23+
kernel_trace.kpm: ${objs}
24+
${CC} -r -o $@ $^
25+
26+
%.o: %.c
27+
${CC} $(CFLAGS) $(INCLUDE_FLAGS) -c -O2 -o $@ $<
28+
29+
.PHONY: clean
30+
clean:
31+
rm -rf *.kpm
3232
find . -name "*.o" | xargs rm -f

README.md

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,41 @@
1-
# Kernel-Trace
2-
一个基于uprobe,能同时hook大量用户地址空间函数的kpm内核模块
3-
4-
5-
# 如何使用
6-
在成功加载本项目的kpm模块后,可通过 **dmesg | grep +Test-Log+** 命令查看模块日志,再使用项目user目录下的uprobe_trace_user.h文件提供的用户层接口进行编程即可。trace的输出结果在tracefs文件系统下,可通过 **mount | grep tracefs** 命令查看tracefs所在位置,一般都是在/sys/kernel/tracing,通过 **echo "1" >> /sys/kernel/tracing/tracing_on** 开启日志后通过 **cat /sys/kernel/tracing/trace_pipe | grep +Test-Log+** 查看trace的结果。
7-
8-
**set_module_base**函数用于设置要hook so的基址(打印函数偏移需要用到)。
9-
10-
**set_target_uid**函数用于设置要hook的app的uid(过滤输出需要)。
11-
12-
**set_target_file**函数用于设置要hook so的路径(必须是完整路径)。
13-
14-
**set_fun_info**函数第一个参数是要设置函数的uprobe偏移,计算方法见文末,第二个参数为函数偏移,第三个参数为自定义函数名,
15-
第四个参数是对应函数地址处的第一条汇编指令(即在函数地址处读取的4个字节),为空即不修正uprobe在该函数地址处的备份指令。
16-
17-
**clear_all_uprobes**函数用于清除所有的uprobe挂载点。
18-
19-
上述函数的返回结果有SET_TRACE_SUCCESS、SET_TRACE_ERROR两种,分别表示设置成功和失败。
20-
21-
# 使用示例
22-
编程思路可以参考[示例](https://github.com/AndroidReverser-Test/KernelTraceDemo/blob/main/app/src/main/cpp/kerneltracedemo.cpp)
23-
24-
# 支持的内核版本
25-
目前只在5.10以及5.15两个版本通过测试,理论上5.10以上版本都能正常使用。
26-
27-
# 一些疑惑
28-
~~在内核使用uprobe_register函数注册uprobe挂载点的时候在一些特殊情况下会出现实际注册的函数偏移与传入的函数偏移不一致的问题,至于为什么会这样, 我翻阅linux内核源码发现问题出现于内存地址计算错误,从这里开始内存地址就出现了偏差,我推测是内存页计算有偏差,但是具体原因不清楚。~~
29-
答案已经找到了,原来是我一开始就理解错了,传递给uprobe_register函数的偏移值压根就不是函数的文件偏移,而是要经过其他运算得到,简单来说就是函数地址减去所在内存段的基地址再加上该内存段内存区域的偏移量所得的值。
30-
计算示例如下:
31-
以下图片展示了一个so文件在maps文件中的区域段
32-
![计算示例](./pic/偏移计算.JPG)
33-
假如一个函数的地址为0x7626323000,那要hook这个函数那传给uprobe_register函数的偏移值应该为0x7626323000-0x7626322000+0x90000=0x91000.
34-
35-
## uprobe无法对加固过的so进行hook?
36-
在对应so的代码段没有被加密的情况下,uprobe是能正确获取到将要被**brk #5**覆盖的原始汇编指令,但当so的代码段是在运行时才解密时,
37-
uprobe获取到的汇编指令往往都是没有解密前的密文汇编指令,这些密文汇编指令当然是无法被执行的,这就会引发app的直接崩溃。至于为什么
38-
uprobe不是实时获取内存中的汇编指令,原因尚不清楚。
39-
40-
## 解决方案
41-
将为用户提供的set_fun_info函数增加一个fix_insn参数用于让用户自行设置指定函数地址的第一条原始汇编指令,
42-
再通过用户提供的这些正确的汇编指令来为uprobe直接设置其要备份的汇编指令。这样就能直接解决uprobe不能实时获取
43-
内存中的汇编指令的问题。
1+
# Kernel-Trace
2+
一个基于uprobe,能同时hook大量用户地址空间函数的kpm内核模块
3+
4+
5+
# 如何使用
6+
在成功加载本项目的kpm模块后,可通过 **dmesg | grep +Test-Log+** 命令查看模块日志,再使用项目user目录下的uprobe_trace_user.h文件提供的用户层接口进行编程即可。trace的输出结果在tracefs文件系统下,可通过 **mount | grep tracefs** 命令查看tracefs所在位置,一般都是在/sys/kernel/tracing,通过 **echo "1" >> /sys/kernel/tracing/tracing_on** 开启日志后通过 **cat /sys/kernel/tracing/trace_pipe | grep +Test-Log+** 查看trace的结果。
7+
8+
**trace_init**函数用于设置要hook so的基本信息(包括目标so模块基址,hook的app的uid,目标so模块的完整路径,替代so模块的完整路径)。
9+
10+
**set_fun_info**函数用于设置要hook函数的信息(包括函数的uprobe偏移,计算方法见文末,以及目标函数的偏移和自定义的函数名)。
11+
12+
**clear_all_uprobes**函数用于清除所有的uprobe挂载点。
13+
14+
上述函数的返回结果有SET_TRACE_SUCCESS、SET_TRACE_ERROR两种,分别表示设置成功和失败。
15+
16+
# 使用示例
17+
编程思路可以参考[示例](https://github.com/AndroidReverser-Test/KernelTraceDemo/blob/main/app/src/main/cpp/kerneltracedemo.cpp)
18+
19+
# 支持的内核版本
20+
目前只在5.10以及5.15两个版本通过测试,理论上5.10以上版本都能正常使用。2026/01/17更新,理论上支持6系内核(在部分机型上可能会有bug)。
21+
22+
# 函数的uprobe偏移
23+
简单来说就是函数地址减去所在内存段的基地址再加上该内存段内存区域的偏移量所得的值。
24+
计算示例如下:
25+
以下图片展示了一个so文件在maps文件中的区域段
26+
![计算示例](./pic/偏移计算.JPG)
27+
假如一个函数的地址为0x7626323000,那要hook这个函数那传给uprobe_register函数的偏移值应该为0x7626323000-0x7626322000+0x90000=0x91000.
28+
29+
## uprobe无法对加固过的so进行hook?
30+
在对应so的代码段没有被加密的情况下,uprobe是能正确获取到将要被**brk #5**覆盖的原始汇编指令,但当so的代码段是在运行时才解密时,
31+
uprobe获取到的汇编指令往往都是没有解密前的密文汇编指令,这些密文汇编指令当然是无法被执行的,这就会引发app的直接崩溃。
32+
33+
## 解决方案
34+
让用户提供替代so模块。
35+
简单地说就是不再让uprobe在缓存中获取所需的汇编指令, 而是直接让uprobe读取本地文件来获取所需要的正确的汇编指令。
36+
一般的so模块就算是静态加密的, 运行时也会解密,用户只需将包含正确汇编指令的so模块dump下放到自己设置的指定路径即可。
37+
这样就能直接解决uprobe不能实时获取内存中的汇编指令的问题。
38+
39+
## 一些bug
40+
对一些app使用模块后在退出时如果没有先使用UprobeClearer清除设置的uprobe挂载点而重新打开app有可能会出现设备卡住的情况。
41+
有可能部分设备没有兼容,加载模块会失败,或者是调用api后卡住。

UprobeClearer/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# UprobeClearer
2-
一个可执行文件,用于一键清除所有的uprobes挂载点,防止app因残留的uprobe点崩溃。
3-
4-
5-
# 构建
1+
# UprobeClearer
2+
一个可执行文件,用于一键清除所有的uprobes挂载点,防止app因残留的uprobe点崩溃。
3+
4+
5+
# 构建
66
将ndk所在路径设置为环境变量后,在当前项目路径下执行ndk-build即可自动生成相应可执行文件。

UprobeClearer/jni/Android.mk

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
LOCAL_PATH := $(call my-dir)
2-
3-
include $(CLEAR_VARS)
4-
5-
MAIN_LOCAL_PATH := $(call my-dir)
6-
LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)/Headers
7-
8-
include $(CLEAR_VARS)
9-
10-
LOCAL_MODULE := UprobeClearer
11-
12-
# Code optimization
13-
LOCAL_CPPFLAGS := -fvisibility=hidden -ffunction-sections -fdata-sections -w
14-
LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all -llog
15-
LOCAL_CPPFLAGS += -fexceptions -Werror -Wpedantic -s -std=c++17
16-
17-
LOCAL_SRC_FILES := uprobe_clear.cpp
18-
19-
LOCAL_LDLIBS := -llog -landroid
20-
1+
LOCAL_PATH := $(call my-dir)
2+
3+
include $(CLEAR_VARS)
4+
5+
MAIN_LOCAL_PATH := $(call my-dir)
6+
LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)/Headers
7+
8+
include $(CLEAR_VARS)
9+
10+
LOCAL_MODULE := UprobeClearer
11+
12+
# Code optimization
13+
LOCAL_CPPFLAGS := -fvisibility=hidden -ffunction-sections -fdata-sections -w
14+
LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all -llog
15+
LOCAL_CPPFLAGS += -fexceptions -Werror -Wpedantic -s -std=c++17
16+
17+
LOCAL_SRC_FILES := uprobe_clear.cpp
18+
19+
LOCAL_LDLIBS := -llog -landroid
20+
2121
include $(BUILD_EXECUTABLE)

UprobeClearer/jni/Application.mk

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
APP_ABI := arm64-v8a
2-
APP_STL := c++_static
3-
APP_PLATFORM = android-27
4-
APP_OPTIM := release
1+
APP_ABI := arm64-v8a
2+
APP_STL := c++_static
3+
APP_PLATFORM = android-27
4+
APP_OPTIM := release
55
APP_PIE := true
Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,43 @@
1-
#include <sys/syscall.h>
2-
#include <unistd.h>
3-
4-
5-
#define TRACE_FLAG 511
6-
#define MAX_HOOK_NUM 1000
7-
#define SET_TRACE_SUCCESS 1000
8-
#define SET_TRACE_ERROR 1001
9-
10-
enum trace_info {
11-
SET_TARGET_FILE,
12-
SET_MODULE_BASE,
13-
SET_FUN_INFO,
14-
FIX_ORI_INS,
15-
SET_TARGET_UPROBE,
16-
SET_TARGET_UID,
17-
CLEAR_UPROBE,
18-
};
19-
20-
// unsigned long start, size_t len, unsigned char *vec
21-
22-
int set_module_base(unsigned long module_base){
23-
int ret = syscall(__NR_mincore,module_base,TRACE_FLAG+SET_MODULE_BASE,"");
24-
return ret;
25-
}
26-
27-
int set_target_uid(uid_t uid){
28-
int ret = syscall(__NR_mincore,uid,TRACE_FLAG+SET_TARGET_UID,"");
29-
return ret;
30-
}
31-
32-
int set_target_file(char* file_name){
33-
int ret = syscall(__NR_mincore,0,TRACE_FLAG+SET_TARGET_FILE,file_name);
34-
return ret;
35-
}
36-
37-
int set_fun_info(unsigned long uprobe_offset,unsigned long fun_offset,char *fun_name,char *fix_insn){
38-
int insert_key_ret = syscall(__NR_mincore,fun_offset,TRACE_FLAG+SET_FUN_INFO,fun_name);
39-
if(insert_key_ret==SET_TRACE_SUCCESS){
40-
if(fix_insn){
41-
int fix_insn_ret = syscall(__NR_mincore,uprobe_offset,TRACE_FLAG+FIX_ORI_INS,fix_insn);
42-
if(fix_insn_ret == SET_TRACE_ERROR){
43-
return SET_TRACE_ERROR;
44-
}
45-
}
46-
int ret = syscall(__NR_mincore,uprobe_offset,TRACE_FLAG+SET_TARGET_UPROBE,"");
47-
return ret;
48-
}
49-
return SET_TRACE_ERROR;
50-
}
51-
52-
int clear_all_uprobes(){
53-
int ret = syscall(__NR_mincore,0,TRACE_FLAG+CLEAR_UPROBE,"");
54-
return ret;
1+
#include <sys/syscall.h>
2+
#include <unistd.h>
3+
4+
5+
#define TRACE_FLAG 511
6+
#define MAX_HOOK_NUM 2000
7+
#define SET_TRACE_SUCCESS 1000
8+
#define SET_TRACE_ERROR 1001
9+
10+
enum trace_info {
11+
SET_TRACE_INFO,
12+
SET_FUN_INFO,
13+
CLEAR_UPROBE,
14+
};
15+
16+
struct trace_init_info {
17+
uid_t uid;
18+
unsigned long module_base;
19+
char* tfile_name;
20+
char* fix_file_name;
21+
};
22+
23+
struct uprobe_item_info {
24+
unsigned long uprobe_offset;
25+
unsigned long fun_offset;
26+
char *fun_name;
27+
};
28+
29+
int clear_all_uprobes(){
30+
int ret = syscall(__NR_mincore,0,TRACE_FLAG+CLEAR_UPROBE,"");
31+
return ret;
32+
}
33+
34+
int trace_init(trace_init_info *base_info){
35+
clear_all_uprobes();
36+
int ret = syscall(__NR_mincore,0,TRACE_FLAG+SET_TRACE_INFO,base_info);
37+
return ret;
38+
}
39+
40+
int set_fun_info(uprobe_item_info *uprobe_item){
41+
int ret = syscall(__NR_mincore,0,TRACE_FLAG+SET_FUN_INFO,uprobe_item);
42+
return ret;
5543
}

UprobeClearer/jni/uprobe_clear.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
#include <stdio.h>
2-
#include <cstring>
3-
#include <unistd.h>
4-
5-
#include "Headers/uprobe_trace_user.h"
6-
7-
int main(int argc, char const *argv[])
8-
{
9-
clear_all_uprobes();
10-
printf("success clear all uprobes\n");
11-
return 0;
1+
#include <stdio.h>
2+
#include <cstring>
3+
#include <unistd.h>
4+
5+
#include "Headers/uprobe_trace_user.h"
6+
7+
int main(int argc, char const *argv[])
8+
{
9+
clear_all_uprobes();
10+
printf("success clear all uprobes\n");
11+
12+
13+
return 0;
1214
}

0 commit comments

Comments
 (0)