现代 app 的壳中有大量的 syscall 的直接调用,想要知道其中的调用参数以及结果有以下方法:
1、使用 frida 进行内存搜索 svc 0 指令的机器码(01 00 00 D4),然后自己想办法干掉
2、使用 seccomp 进行拦截,使用 seccomp 的过程中可能会遇到一些奇奇怪怪的问题
3、使用内核模块在内核态进行拦截
在 Apatch 之前编写的内核模块需要针对单独的内核进行编译,并且编译环境还需要完整内核的依赖文件,这种方法还需要修改内核设置并将内核放入到系统映像中重新刷机。非常复杂,使用 Apatch 编译的内核模块加载方便且具有一定的通用性。
下载官方的 github
04aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1L8h3q4^5x3e0t1I4i4K6u0r3d9$3g2J5L8X3g2D9f1r3q4@1j5$3S2Q4x3V1k6@1M7X3g2W2i4K6u0r3k6r3g2$3
下载 gun 编译工具链
ce4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1k6i4k6W2L8r3!0H3k6i4u0Q4x3X3g2S2M7X3#2Q4x3X3g2U0L8$3#2Q4x3V1k6V1L8%4N6F1L8r3!0S2k6s2y4Q4x3V1k6Q4x3X3c8Q4x3V1k6S2M7X3#2Q4x3X3c8Y4L8Y4g2Q4x3X3c8@1L8$3!0D9j5$3S2S2K9h3&6Q4x3X3c8V1L8%4N6F1L8r3!0S2k6s2x3`.
添加环境
打开官方目录中的 kpms/demo-hello,使用 make 编译
会在本目录下生成 hello.kpm 文件,把该文件 push 到手机里,然后在 Apatch 内核模块页面加载
加载成功后可以在 adb shell(root 权限)下使用 dmesg 指令输出内核日志
在官方目录中 kpms/demo-syscall 下有关于 openat 的 hook
我们注意到在 init 中有两种 apatch 提供的 hook 方式,一种是fp_hook_syscalln,一种是inline_hook_syscalln。
笔者的需求是监控 readlinkat 的入参和栈回溯,那么可以使用inline_hook_syscalln 实现
这里复制一下一整个目录,修改一下目录名
将 syscall.c 中无关的内容去除,新增一个before_readlinkat 函数,根据参数表
编写 log 输出
这里说明一下get_task_comm_func 函数,这个是内核导出函数get_task_comm
需要在前面定义函数类型,然后通过kallsyms_lookup_name 函数获取函数指针调用(相当于 dlsym 获取函数指针)
内核导出函数列表可以查看/proc/kallsyms 文件
我们想要定位哪里调用的 svc 就需要用到栈回溯,由于内核中没有直接可以进行栈回溯的函数,这个需要我们自己实现,arm64 下的栈回溯实现主要是靠 fp 寄存器。
首先知道,arm64 寄存器中 x29 是 fp 寄存器,x30 是 lr 寄存器,其中 lr 寄存器存储了函数的返回地址,如果是调用多层函数的话那么会把 lr 寄存器和 fp 寄存器中的值存储到栈中并将地址存储到 fp 寄存器中,具体如下图

那么我们只需要反复读取 fp 寄存器中的值就可以拿到以往 lr 寄存器中的值。
栈回溯代码如下
此处解释一下几个函数
1、get_task_mm 获取进程 mm_struct(用户态虚拟内存) 防止被销毁
2、access_process_vm 读写用户态中的内存空间,第一个参数是 task 也就进程状态,第二个参数是目标地址,第三个参数是为读写数据分配的缓冲区地址 ,第四个参数是读写数据的长度,第五个参数是 0(读)1(写)
3、 mmput 只用于释放 get_task_mm() 获取的对象 。
实现效果如图:

export PATH=$PATH:/opt/arm-gnu-toolchain/bin/aarch64-none-elf-
export PATH=$PATH:/opt/arm-gnu-toolchain/bin/aarch64-none-elf-
make
void before_readlinkat(hook_fargs4_t *args, void *udata){
const char __user *filename = (typeof(filename))syscall_argn(args, 1);
char buf[1024];
compat_strncpy_from_user(buf, filename, sizeof(buf));
struct task_struct *task = current;
pid_t pid = -1, tgid = -1;
if (__task_pid_nr_ns) {
pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0);
tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0);
}
char comm[1024];
get_task_comm_func(comm, sizeof(comm), task);
pr_info("readlinkat pid: %d, filename: %s, process: %s", pid, buf, comm);
struct pt_regs *regs = _task_pt_reg(task);
unwind_user_stack(task, pid);
}
void before_readlinkat(hook_fargs4_t *args, void *udata){
const char __user *filename = (typeof(filename))syscall_argn(args, 1);
char buf[1024];
compat_strncpy_from_user(buf, filename, sizeof(buf));
struct task_struct *task = current;
pid_t pid = -1, tgid = -1;
if (__task_pid_nr_ns) {
pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0);
tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0);
}
char comm[1024];
get_task_comm_func(comm, sizeof(comm), task);
pr_info("readlinkat pid: %d, filename: %s, process: %s", pid, buf, comm);
struct pt_regs *regs = _task_pt_reg(task);
unwind_user_stack(task, pid);
}
typedef struct mm_struct *(*get_task_mm)(struct task_struct *task);
get_task_mm get_task_mm_func;
get_task_comm_func = (typeof(__get_task_comm))kallsyms_lookup_name("__get_task_comm");
typedef struct mm_struct *(*get_task_mm)(struct task_struct *task);
get_task_mm get_task_mm_func;
get_task_comm_func = (typeof(__get_task_comm))kallsyms_lookup_name("__get_task_comm");
cat /proc/kallsyms
typedef int (*access_process_vm) (struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
access_process_vm access_process_vm_func;
typedef struct mm_struct *(*get_task_mm)(struct task_struct *task);
get_task_mm get_task_mm_func;
typedef void (*mmput) (struct mm_struct *mm);
mmput mmput_func;
struct user_frame {
unsigned long fp;
unsigned long lr;
};
bool unwind_user_stack(struct task_struct *task, pid_t pid){
struct user_frame frame;
int i;
struct pt_regs *regs = _task_pt_reg(task);
frame.fp = regs->regs[29];
frame.lr = regs->regs[30];
unsigned long pc = regs->pc;
struct mm_struct* mm = get_task_mm_func(task);
if(!mm)return false;
for(i = 0; i < 16; i++){
if(i == 0){
pr_info("pid: %d, frame[%d]: lr: %llx, fp: %llx pc: %llx\n", pid, i, frame.lr, frame.fp, pc);
}else{
pr_info("pid: %d, frame[%d]: lr: %llx, fp: %llx\n", pid, i, frame.lr, frame.fp);
}
if(!frame.fp || !frame.lr){
break;
}
if(access_process_vm_func(task, frame.fp, &frame, sizeof(struct user_frame), 0) != sizeof(frame)){
break;
}
}
mmput_func(mm);
}
// init
access_process_vm_func = (typeof(access_process_vm))kallsyms_lookup_name("access_process_vm");
get_task_mm_func = (typeof(get_task_mm))kallsyms_lookup_name("get_task_mm");
mmput_func = (typeof(mmput))kallsyms_lookup_name("mmput");
typedef int (*access_process_vm) (struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
access_process_vm access_process_vm_func;
typedef struct mm_struct *(*get_task_mm)(struct task_struct *task);
get_task_mm get_task_mm_func;
typedef void (*mmput) (struct mm_struct *mm);
mmput mmput_func;
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2025-8-5 17:05
被孤恒编辑
,原因: 标题少了一部分