您好,本站仅作演示所用,请勿下单付款!
商品分类

22.KernelPatch安卓”全版本”内核hook补丁

在内核中写入hook的方式,就是给安卓打补丁,使用 kernelpatch这个工具。kernelpatch 和 Apatch是一家人。Apatch是基于kernelpatch。是同一位作者,也是阿里的大佬。学习kernelpatch , 那么就是使用, Apatch, 跟着magisk的流程差不多。给手机root ,root也是使用 kpatch的相关的工具。root完成后,加入内核补丁。来看内核模块,观察hook的效果,看看有没有,哪些支持的形式。inlinehook都可以。源码编译一次,跑一次。甚至把kernelpatch的源码编译一遍。将要对比他们优劣点 ,对比分析。

pixel6用Apatch刷机流程与内核补丁

适用于大部分安卓设备,不仅限于GKI内核设备。

提供类似 Magisk 模块的 APM 支持。

提供内核补丁模块支持。允许将任何代码注入内核(提供内核函数 inline-hook 和 syscall-table-hook)。

APatch 依赖于 KernelPatch。

APatch 管理器 和 APM 的源代码来自对 KernelSU 管理器 和 KernelSU 的复制和修改。

****************************
****************************
 APatch Boot Image Patcher
****************************
- Patching kernel
+ ./kptools -p -i kernel.ori -S ncmddx1997 -k kpimg -o kernel  //使用了密钥 -S参数, -k 对kernel的img文件补丁, 输出 内核
[+] kernel image_size: 0x0314aa00
[+] kernel uefi header: true
[+] kernel load_offset: 0x00000000
[+] kernel kernel_size: 0x031f0000
[+] kernel page_shift: 12
[+] new kernel image ...
[+] linux_banner 1: Linux version 5.10.189-android13-4-00012-g1217bb583cc5-ab11174560 (build-user@build-host) (Android (8508608, based on r450784e) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6), LLD 14.0.7) #1 SMP PREEMPT Mon Dec 4 18:59:42 UTC 2023
[+] linux_banner offset: 0x24da668
[+] kernel version major: 5, minor: 10, patch: 189
[+] kallsyms_token_table offset: 0x0224f6a8
[+] endian: little
[+] kallsyms_token_index offset: 0x0224fa48
[+] arm64 relocation kernel_va: 0xffffffffffffffff
[?] can't find arm64 relocation table
[+] kallsyms_markers range: [0x0224edc8, 0x0224f6ac), count: 0x00000238
[+] approximate kallsyms_offsets range: [0x01fbe554, 0x0204c534) count: 0x000237f8
[+] kallsyms_names offset: 0x0204c540
[?] can't find kallsyms_num_syms, try: 0x000237ee
[+] names table linux_banner index: 0x00017a1e
[+] linux_banner index: 0
[+] kallsyms_offsets offset: 0x01fbe558
[+] pid_vnr: type: T, offset: 0x00174098
[+] pid_vnr verfied sp_el0, insn: 0xd5384108
[+] layout kimg: 0x0,0x314aa00, kpimg: 0x314b000,0x2c110, extra: 0x3177110,0x80, end: 0x3177190, start: 0x31f0000
[+] kpimg version: b02
[+] kpimg compile time: 01:05:21 Feb 12 2025
[+] kpimg config: android, release
[+] tcp_init_sock: type: T, offset: 0x01406e44
[+] map_start: 0x1406e50, max_size: 0x800
[+] kallsyms_lookup_name: type: T, offset: 0x00292468
[+] printk: type: T, offset: 0x001e90d8
[+] memblock_reserve: type: T, offset: 0x004aa13c
[+] memblock_free: type: T, offset: 0x004a887c
[+] memblock_mark_nomap: type: T, offset: 0x004aa450
[+] memblock_phys_alloc_try_nid: type: T, offset: 0x02cc6074
[?] no symbol: memblock_virt_alloc_try_nid
[+] memblock_alloc_try_nid: type: T, offset: 0x02cc6348
[+] panic: type: T, offset: 0x0012a720
[+] rest_init: type: T, offset: 0x018309fc
[+] kernel_init: type: t, offset: 0x01830adc
[?] no symbol: report_cfi_failure
[?] no symbol: __cfi_slowpath_diag
[+] __cfi_slowpath: type: T, offset: 0x003b9770
[+] copy_process: type: t, offset: 0x00123510
[+] avc_denied: type: t, offset: 0x008944c4
[+] slow_avc_audit: type: T, offset: 0x00892d64
[+] input_handle_event: type: t, offset: 0x00f21c58
[+] root superkey hash: c013e7b3db8b8305725bf888bee8c36973860194af24a072e34afc0bc1b96242
[+] paging_init: type: T, offset: 0x02cb19f4
[+] patch done: kernel
+ patch_rc=0
+ set +x
- Repacking boot image
- Successfully Patched!
 Output file is written to 
 /storage/emulated/0/Download/apatch_patched_11039_0.11.2_grjj.img
****************************

使用了 kpimg 这样的工具可能加入了一些节区。或者多少东西。repack,从新打包。就patch 完成。就放到 download的目录下。最好的方法。

– 手动加载内核模块观察系统调用hook效果

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* 
 * Copyright (C) 2023 bmax121. All Rights Reserved.
 */

#include <compiler.h>
#include <kpmodule.h>
#include <linux/printk.h>
#include <common.h>
#include <kputils.h>
#include <linux/string.h>

///< The name of the module, each KPM must has a unique name.
KPM_NAME("kpm-hello-demo");

///< The version of the module.
KPM_VERSION("1.0.0");

///< The license type.
KPM_LICENSE("GPL v2");

///< The author.
KPM_AUTHOR("bmax121");

///< The description.
KPM_DESCRIPTION("KernelPatch Module Example");

/**
 * @brief hello world initialization
 * @details 
 * 
 * @param args 
 * @param reserved 
 * @return int 
 */
static long hello_init(const char *args, const char *event, void *__user reserved)
{
    pr_info("kpm hello init, event: %s, args: %s\n", event, args);
    pr_info("kernelpatch version: %x\n", kpver);
    return 0;
}

static long hello_control0(const char *args, char *__user out_msg, int outlen)
{
    pr_info("kpm hello control0, args: %s\n", args);
    char echo[64] = "echo: ";
    strncat(echo, args, 48);
    compat_copy_to_user(out_msg, echo, sizeof(echo));
    return 0;
}

static long hello_control1(void *a1, void *a2, void *a3)
{
    pr_info("kpm hello control1, a1: %llx, a2: %llx, a3: %llx\n", a1, a2, a3);
    return 0;
}

static long hello_exit(void *__user reserved)
{
    pr_info("kpm hello exit\n");
    return 0;
}

KPM_INIT(hello_init);
KPM_CTL0(hello_control0);
KPM_CTL1(hello_control1);
KPM_EXIT(hello_exit);

字符串—》

以上是kpm-hello-demo.c 的原始文件

以下是逐行解释代码中的每一行:

/* SPDX-License-Identifier: GPL-2.0-or-later */

    这是一个 SPDX许可证标识符,声明该代码使用的许可证是 GPL-2.0或更晚版本。SPDX(软件包数据交换)是一个标准化格式,用于声明源代码的许可证。

/* 
 * Copyright (C) 2023 bmax121. All Rights Reserved.
 */

    这行是版权声明,标明该代码的版权所有者是 bmax121,并且版权归其所有。2023 是版权年份。

#include <compiler.h>
#include <kpmodule.h>
#include <linux/printk.h>
#include <common.h>
#include <kputils.h>
#include <linux/string.h>

    这些是 头文件,包含了该模块所需的各种功能。它们提供了各种系统级的操作:

        <compiler.h>: 提供与编译器相关的工具或宏。

        <kpmodule.h>: 可能是自定义的内核模块接口头文件,定义了与 KPM(Kernel Patch Module)相关的功能。

        <linux/printk.h>: 提供 pr_info 等打印函数,用于打印信息到内核日志。

        <common.h>: 包含常用的定义和函数。

        <kputils.h>: 可能包含与 KPM 相关的工具函数。

        <linux/string.h>: 提供字符串操作函数(例如 strncat)。

///< The name of the module, each KPM must has a unique name.
KPM_NAME("kpm-hello-demo");

    使用 KPM_NAME 宏定义模块的名称为 kpm-hello-demo。每个 KPM 模块必须有一个唯一的名称。

///< The version of the module.
KPM_VERSION("1.0.0");

    使用 KPM_VERSION 宏定义模块的版本为 1.0.0。

///< The license type.
KPM_LICENSE("GPL v2");

    使用 KPM_LICENSE 宏定义该模块的许可证类型为 GPL v2,即该模块遵循 GNU 通用公共许可证 v2。

///< The author.
KPM_AUTHOR("bmax121");

    使用 KPM_AUTHOR 宏定义该模块的作者是 bmax121。

///< The description.
KPM_DESCRIPTION("KernelPatch Module Example");

    使用 KPM_DESCRIPTION 宏定义模块的描述为 "KernelPatch Module Example",即这是一个内核补丁模块的示例。

/**
 * @brief hello world initialization
 * @details 
 * 
 * @param args 
 * @param reserved 
 * @return int 
 */

    这是一个函数注释块,描述了 hello_init 函数的功能:

        @brief 提供函数的简短描述。

        @details 提供函数的详细描述(这里没有详细描述)。

        @param 描述函数参数。

        @return 描述函数返回值。

static long hello_init(const char *args, const char *event, void *__user reserved)
{
    pr_info("kpm hello init, event: %s, args: %s\n", event, args);
    pr_info("kernelpatch version: %x\n", kpver);
    return 0;
}

    hello_init 是一个初始化函数,接受事件和参数,并通过 pr_info 输出日志。

        输出事件 (event) 和参数 (args) 的内容。

        输出内核补丁的版本号(通过 kpver 变量)。

        返回 0 表示成功。

static long hello_control0(const char *args, char *__user out_msg, int outlen)
{
    pr_info("kpm hello control0, args: %s\n", args);
    char echo[64] = "echo: ";
    strncat(echo, args, 48);
    compat_copy_to_user(out_msg, echo, sizeof(echo));
    return 0;
}

    hello_control0 是一个控制函数,接受参数并将其与 "echo: " 组合,然后将结果复制到用户空间:

        使用 pr_info 输出传入的 args。

        创建一个 64 字节的缓冲区 echo,将 "echo: " 和参数合并。

        使用 strncat 将 args 附加到 echo 中,最多 48 字符。

        使用 compat_copy_to_user 将 echo 内容复制到用户空间 out_msg。

static long hello_control1(void *a1, void *a2, void *a3)
{
    pr_info("kpm hello control1, a1: %llx, a2: %llx, a3: %llx\n", a1, a2, a3);
    return 0;
}

    hello_control1 是一个控制函数,接受三个指针类型的参数(a1, a2, a3),并输出它们的值:

        使用 pr_info 输出这三个参数的十六进制值。

        返回 0 表示成功。

static long hello_exit(void *__user reserved)
{
    pr_info("kpm hello exit\n");
    return 0;
}

    hello_exit 是模块的退出函数:

        使用 pr_info 打印模块退出的日志。

        返回 0 表示退出成功。

KPM_INIT(hello_init);

    使用 KPM_INIT 宏将 hello_init 函数指定为模块的初始化函数。

KPM_CTL0(hello_control0);

    使用 KPM_CTL0 宏将 hello_control0 函数绑定为控制函数 0。

KPM_CTL1(hello_control1);

    使用 KPM_CTL1 宏将 hello_control1 函数绑定为控制函数 1。

KPM_EXIT(hello_exit);

    使用 KPM_EXIT 宏将 hello_exit 函数绑定为模块退出时的清理函数。

这些代码是一个简单的内核补丁模块示例,展示了如何初始化模块、控制它以及在退出时清理它。

KernelPatch/kpms/demo-syscallhook/syscallhook.c

/* SPDX-License-Identifier: GPL-2.0-or-later */  // 指定代码遵循 GPL-2.0 或更高版本许可证,允许修改和分发。
/* Copyright (C) 2023 bmax121. All Rights Reserved. */  // 版权声明,代码的版权所有者是 bmax121,版权归其所有。
#include <compiler.h>  // 包含与编译器相关的工具或宏,可能是特定于架构的编译器优化。
#include <kpmodule.h>  // 引入内核补丁模块接口的头文件,定义了 KPM 模块相关功能。
#include <linux/printk.h>  // 提供用于打印日志的函数,如 pr_info、pr_warn 等。
#include <uapi/asm-generic/unistd.h>  // 包含系统调用号定义,主要用于内核与用户空间的接口。
#include <linux/uaccess.h>  // 提供用户空间与内核空间之间数据拷贝的函数。
#include <syscall.h>  // 包含系统调用的封装和定义,允许进行系统调用操作。
#include <linux/string.h>  // 提供字符串操作函数,如 `strncpy`、`strncat` 等。
#include <kputils.h>  // 可能包含与 KPM 相关的工具函数,提供辅助功能。
#include <asm/current.h>  // 提供当前任务的相关信息,如当前进程、线程等。

KPM_NAME("kpm-syscall-hook-demo");  // 定义模块名称为 "kpm-syscall-hook-demo",每个 KPM 必须有唯一名称。
KPM_VERSION("1.0.0");  // 定义模块版本号为 "1.0.0"。
KPM_LICENSE("GPL v2");  // 定义模块使用的许可证为 "GPL v2"。
KPM_AUTHOR("bmax121");  // 定义模块的作者为 "bmax121"。
KPM_DESCRIPTION("KernelPatch Module System Call Hook Example");  // 定义模块描述。

const char *margs = 0;  // 定义一个全局字符串指针 margs 用于存储传入的参数。
enum hook_type hook_type = NONE;  // 定义一个枚举类型 hook_type,用于标识钩子类型,初始为 NONE。

enum pid_type  // 定义一个枚举类型 pid_type,表示不同类型的进程 ID。
{
    PIDTYPE_PID,  // 进程 ID
    PIDTYPE_TGID,  // 线程组 ID
    PIDTYPE_PGID,  // 进程组 ID
    PIDTYPE_SID,  // 会话 ID
    PIDTYPE_MAX,  // 最大值
};

struct pid_namespace;  // 前向声明 pid_namespace 结构体,表示 PID 命名空间。
pid_t (*__task_pid_nr_ns)(struct task_struct *task, enum pid_type type, struct pid_namespace *ns) = 0;  // 定义一个函数指针,用于获取进程 ID(通过 __task_pid_nr_ns)。

void before_openat_0(hook_fargs4_t *args, void *udata)  // 定义一个钩子函数,处理 openat 系统调用的前置操作。
{
    int dfd = (int)syscall_argn(args, 0);  // 获取 openat 系统调用的第一个参数 dfd。[解析参数1]
    const char __user *filename = (typeof(filename))syscall_argn(args, 1);  // 获取文件名参数。[解析参数2]
    int flag = (int)syscall_argn(args, 2);  // 获取标志参数。[解析参数3]
    umode_t mode = (int)syscall_argn(args, 3);  // 获取模式参数。 [解析参数4]

    char buf[1024];  // 创建一个缓冲区用于存储文件名。
    compat_strncpy_from_user(buf, filename, sizeof(buf));  // 从用户空间复制文件名到缓冲区。

    struct task_struct *task = current;  // 获取当前任务(进程)。
    pid_t pid = -1, tgid = -1;  // 定义进程 ID 和线程组 ID。
    if (__task_pid_nr_ns) {  // 如果函数指针有效,获取进程 ID 和线程组 ID。
        pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0);
        tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0);
    }

    args->local.data0 = (uint64_t)task;  // 保存当前任务信息到 args 中。

    pr_info("hook_chain_0 task: %llx, pid: %d, tgid: %d, openat dfd: %d, filename: %s, flag: %x, mode: %d\n", task, pid, tgid, dfd, buf, flag, mode);  // 打印日志信息,显示钩子调用的详细信息。
}

uint64_t open_counts = 0;  // 定义一个全局计数器 open_counts,用于记录 openat 调用次数。

void before_openat_1(hook_fargs4_t *args, void *udata)  // 定义另一个 openat 钩子函数。
{
    uint64_t *pcount = (uint64_t *)udata; // 获取传递的计数器指针
    (*pcount)++ ; // 增加计数器
    pr_info("hook_chain_1 before openat task: %llx, count: %llx\n", args->local.data0, *pcount); //打印任务信息和当前计数器

void after_openat_1(hook_fargs4_t *args, void *udata) // 定义另一个 openat 钩子函数。
{
     pr_info("hook_chain_1 after openat task: %llx\n", args->local.data0); // 打印任务信息.
}

static long syscall_hook_demo_init(const char *args, const char *event, void *__user reserved) // 定义模块的初始化函数.
{
    margs = args; // 保存传入的参数.
    pr_info("kpm-syscall-hook-demo init ...., args: %s\n", margs); // 打印初始化日志

    __task_pid_nr_ns = (typeof(__task_pid_nr_ns))kallsyms_lookup_name("_task_pid_nr_ns"); // 查找系统调用函数 __task_pid_nr_ns 的地址
    pr_info("kernel funciton __task_pid_nr_ns addr: %llx\n", __task_pid_nr_ns); // 打印系统调用函数地址
    
    if (!margs) { // 如果没有传入参数, 跳过钩子安装
       pr_warn("no args specified, skip hook\n");
       return 0;
      }

     hook_err_t err = HOOK_NO_ERR; // 定义错误类型变量, 初始化无错误

    if (!strcmp("function_pointer_hook", margs)) { // 如果参数为"function_pointer_hook",则使用函数指针钩子.
        pr_info("function pointer hook ...");
        hook_type = FUNCTION_POINTER_CHAIN; // 设置钩子类型为函数指针链
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0); // 勾住 openat 系统调用,参数1--地址,参数2--参数,参数3---回调函数.
        if (err) goto out; // 如果钩子安装失败, 跳转到 out.
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_1, after_openat_1, &open_counts); // 安装另一个钩子
    } else if (!strcmp("inline_hook", margs)) {  // 如果参数为 "inline_hook", 则使用内联钩子.
        pr_info ("inline hook ...");
        hook_type = INLINE_CHAIN; // 设置钩子类型为内联链
        err = inline_hook_syscalln(__NR_openat, 4, before_openat_0, 0,0); // 勾住 openat 系统调用
    } else {
        pr_warn("unknown args: %s\n", margs);  // 如果传入参数未知, 打印警告
        return 0;
    }

out:
    if (err) { // 如果钩子安装出错,信息打印错误日志
        pr_err("hook openat error: %d\n",err);
    } else {
        pr_info("hook openat success\n"); // 打印成功日志
    }
    return 0;
}

static long syscall_hook_control0(const char *args, char *__user out_msg, int outlen) // 控制函数, 用于接受命令并且打印日志
{
    pr_info("syscall_hook control, args:%s\n",args); // 打印传入的参数
    return 0;
}

static long syscall_hook_demo_exit(void *__user reserved)  //模块退出函数, 用于卸载钩子
{
    pr_info("kpm-syscall-hook-demo exit ....\n"); // 打印退出日志

    if ( hook_type == INLINE_CHAIN) {   // 如果钩子类型是内联链, 卸载内联钩子
       inline_unhook_syscalln(__NR_openat,before_openat_0,00;
    } else if (hook_type == FUNCTION_POINTER_CHAIN) {  // 如果钩子类型是函数指针链, 卸载函数指针钩子
        fp_unhook_syscalln(__NR_openat, before_openat_0,0);
        fp_unhook_syscalln(__NR_openat, before_openat_1, after_openat_1);
    } else {
    }
    return 0;
}

KPM_INIT(syscall_hook_demo_init); // 初始化模块化时候调用 syscall_hook_demo_init 函数
KPM_CTL0(syscall_hook_control0); // 控制时 调用syscall_hook_control0 函数
KMP_EXIT(syscall_hook_demo_exit); // 退出时调用 syscall_hook_demo_exit 函数






该代码是一个示例 内核补丁模块 (KPM),用于挂钩和拦截 openat 系统调用。具体的逻辑和原理如下:

1. 模块初始化与配置

  • 模块信息:通过 KPM_NAMEKPM_VERSIONKPM_LICENSEKPM_AUTHORKPM_DESCRIPTION 宏,定义了模块的基本信息,如名称、版本、许可证、作者和描述。
  • syscall_hook_demo_init 函数:该函数是模块的初始化函数,接收传入的参数并决定使用哪种类型的钩子(例如,函数指针钩子内联钩子)。它通过 kallsyms_lookup_name 查找内核函数的地址(如 __task_pid_nr_ns),并安装系统调用钩子。

2. 系统调用钩子

  • before_openat_0before_openat_1:这些是钩子函数,会在调用 openat 系统调用之前被调用。它们提取系统调用的参数(如文件描述符、文件名、标志和模式),然后打印出相关信息。before_openat_1 还会计数调用次数。
  • after_openat_1:这是 openat 调用后的钩子函数,用于打印调用后的任务信息。

3. 钩子类型

  • 函数指针钩子 (FUNCTION_POINTER_CHAIN):将钩子函数注册到系统调用表中,使用函数指针的方式来挂钩 openat 系统调用。这种方式通过 fp_hook_syscalln 来实现。
  • 内联钩子 (INLINE_CHAIN):通过内联方式修改系统调用的执行流,将钩子直接插入系统调用的执行路径。

4. 控制和退出

  • syscall_hook_control0:这是一个控制函数,接受参数并打印日志信息。它允许在模块加载后通过控制接口与模块交互。
  • syscall_hook_demo_exit:这是模块的退出函数,用于卸载挂钩的系统调用。如果使用内联钩子,它将调用 inline_unhook_syscalln 来卸载钩子;如果使用函数指针钩子,它将通过 fp_unhook_syscalln 卸载。

5. 钩子原理

  • 系统调用钩子:钩子允许模块在系统调用执行前、执行中或执行后插入自定义代码。这里的钩子拦截了 openat 系统调用,通过访问和修改参数,甚至统计调用次数。
  • 内核空间与用户空间交互:该模块利用 pr_infopr_warn 打印调试信息,并通过 kallsyms_lookup_name 动态查找内核符号。还使用 compat_strncpy_from_user 等函数在内核空间和用户空间之间传递数据。

6. 总结

该内核模块展示了如何通过 函数指针钩子内联钩子 技术,拦截和修改系统调用(如 openat)。模块在初始化时安装钩子,在退出时卸载钩子,并提供控制接口来与模块进行交互。

22.KernelPatch安卓"全版本"内核hook补丁

卸载模块的样子. –> syscall_hook_demo_exit

下面的 kmp-syscall-hook-demo exit —– // 这个卸载函数成功了.

内核模块系统调用与inlinehook回调开发

inlinehook 的本质就是地址的hook.

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* 
 * Copyright (C) 2023 bmax121. All Rights Reserved.
 */

#include <log.h>
#include <compiler.h>
#include <kpmodule.h>
#include <hook.h>
#include <linux/printk.h>

KPM_NAME("kpm-inline-hook-demo");
KPM_VERSION("1.0.0");
KPM_LICENSE("GPL v2");
KPM_AUTHOR("bmax121");
KPM_DESCRIPTION("KernelPatch Module Inline Hook Example");

init __noinline add(int a, int b)
{
    logkd("origin add called\n");
    int ret = a + b;
    return ret;
}

void before_add(hook_fargs2_t *args,void *udata)  // 被调用前的处理函数
{
    logkd("before and arg0: %d, arg1: %d\n",(int)args->arg0, (int)args->arg1);
}

void after_add(hook_fargs2_t *args, void *udata)  // 被调用之后的处理函数
{
    logkd("after add arg0: %d, arg1: %d, ret: %d\n",(int)args->arg0, (int)args->arg1, (int)args->ret);
    args->ret = 100;  // 这是我hook修改的地方
}

// 初始化函数
static long inline_hook_demo_init(const char *args, const char *event, void *__user reserved)
{
    logkd("kpm inline-hook-demo init\n");
    
    int a = 20;
    int b = 10;
    
    int ret = add(a,b);  // 这是调用的过程
    logkd("%d + %d = %d\n", a, b, ret);  // 这是打日志
    
    hook_err_t arr = hook_wrap2(void *)add/*这里确实是高, 直接将add转换为地址*/, before_add , after_add, 0 ) ;  // 这是开始hook,在内核中, 你得直接去找其他函数的地址
    logkd("hook err : %d\n", err); // 观察一下
    
    ret = add(a,b);   // 执行嗯,这里输出一下
    logkd("%d + %d = %d\n", a, b, ret);
    
    return 0;
}

static long inline_hook_control0(const char *args, char *__user out_msg, int outlen) // 控制函数,当模块被控制时候,通过用户空间命令,他会打印传递的参数 args.
{
    pr_info("kpm control, args: %s\n", args);
    return 0;
}

static long inline_hook_demo_exit(void *__user reserved)
{
    unhook((void *)add);
    
    int a = 20;
    int b = 10;
    
    int ret = add(a,b);
    logkd("%d + %d = %d\n", a, b, ret);
    
    logkd("kpm inline-hook-demo exit\n");
}

// 模块钩子的注册
KPM_INIT(inline_hook_demo_init);
KPM_CTL0(inline_hook_control0);
KPM_EXIT(inline_hook_demo_exit);


  
22.KernelPatch安卓"全版本"内核hook补丁

内核模块开发编译运行完整流程与源码解析

如果和ebpf一样,那么, 一次性hook 200多个, 全部都hook上, 那么怎么办不能一个个写对把, 这个就得一个个写,

22.KernelPatch安卓"全版本"内核hook补丁

inline hook , 就是直接找地址hook , 然后hook_wrap2

static long inline_hook_demo_init(const char *args, const char *event, void *__user reserved)
{
    logkd("kpm inline-hook-demo init\n");

    int a = 20;
    int b = 10;

    int ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    hook_err_t err = hook_wrap2((void *)add, before_add, after_add, 0);  // 使用了hook_wrap2这个函数, hook_wrap2是怎么实现就要看源码.
    logkd("hook err: %d\n", err);

    ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    return 0;
}

hook上就好了

用户态用的函数都在这里面.

编译 Build kptools

calleng@calleng-GB-BNi7HG6-1060:~/下载$ cd KernelPatch-0.11.1-dev
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev$ ls
banner  doc  kernel  kpms  LICENSE  README.md  tools  user  version
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev$ export TARGET_COMPILE=aarch64-none-elf-
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev$ cd kernel
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kernel$ export ANDROID=1
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kernel$ make
cp -Rf patch/include/uapi ../user
cp -f include/preset.h ../tools
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/setup.o base/setup.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -o base/setup1.o base/setup1.S
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -o base/cache.o base/cache.S
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/tlsf.o base/tlsf.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/start.o base/start.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/map.o base/map.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -o base/map1.o base/map1.S
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/hook.o base/hook.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/fphook.o base/fphook.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/hmem.o base/hmem.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/predata.o base/predata.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/symbol.o base/symbol.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/baselib.o base/baselib.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o base/sha256.o base/sha256.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/patch.o patch/patch.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/accctl.o patch/common/accctl.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/hotpatch.o patch/common/hotpatch.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/pmem.o patch/common/pmem.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/secpass.o patch/common/secpass.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/selinuxhook.o patch/common/selinuxhook.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/supercall.o patch/common/supercall.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/syscall.o patch/common/syscall.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/taskob.o patch/common/taskob.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/common/utils.o patch/common/utils.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/module/insn.o patch/module/insn.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/module/module.o patch/module/module.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/module/relo.o patch/module/relo.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/ksyms/execv.o patch/ksyms/execv.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/ksyms/libs.o patch/ksyms/libs.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/ksyms/misc.o patch/ksyms/misc.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/ksyms/task_cred.o patch/ksyms/task_cred.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/android/sucompat.o patch/android/sucompat.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/android/supercall.o patch/android/supercall.c
aarch64-none-elf-gcc -Wall -fno-builtin -std=gnu11 -nostdinc -g -DANDROID -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/arm64/include -Ilinux/tools/arch/arm64/include -c -O2 -o patch/android/userd.o patch/android/userd.c
aarch64-none-elf-ld -nostdlib -static -no-pie -Tkpimg.lds -o kpimg.elf base/setup.o base/setup1.o base/cache.o base/tlsf.o base/start.o base/map.o base/map1.o base/hook.o base/fphook.o base/hmem.o base/predata.o base/symbol.o base/baselib.o base/sha256.o patch/patch.o patch/common/accctl.o patch/common/hotpatch.o patch/common/pmem.o patch/common/secpass.o patch/common/selinuxhook.o patch/common/supercall.o patch/common/syscall.o patch/common/taskob.o patch/common/utils.o patch/module/insn.o patch/module/module.o patch/module/relo.o patch/ksyms/execv.o patch/ksyms/libs.o patch/ksyms/misc.o patch/ksyms/task_cred.o patch/android/sucompat.o patch/android/supercall.o patch/android/userd.o
aarch64-none-elf-ld: warning: kpimg.elf has a LOAD segment with RWX permissions
aarch64-none-elf-objcopy -O binary -S kpimg.elf kpimg

calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kernel$ file kpimg.elf
kpimg.elf: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped

calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kernel$ file kpimg
kpimg: data

修改路径为相对于 user/CMakeLists.txt

编译 Building kpatch

calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev$ export ANDROID=1
cd tools
make
cc -o kptools image.o kallsym.o kptools.o order.o insn.o patch.o symbol.o kpm.o common.o sha256.o
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/tools$ ls
CMakeLists.txt  elf        image.o  kallsym.c  kpm.h      kptools.o  order.o  preset.h  sha256.o
common.c        fls_ffs.h  insn.c   kallsym.h  kpm.o      Makefile   patch.c  ptrace.h  symbol.c
common.h        image.c    insn.h   kallsym.o  kptools    order.c    patch.h  sha256.c  symbol.h
common.o        image.h    insn.o   kpm.c      kptools.c  order.h    patch.o  sha256.h  symbol.o
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/tools$ file kptools
kptools: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8a320c3d936a66d961bb0324a95cac4f2cc0eaf8, for GNU/Linux 3.2.0, not stripped

编译 Build kpimg

在 CMakeLists.txt 末尾,加上下面的这段

calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/user$ vim CMakeLists.txt
因为 CMakeLists.txt 在 user/ 下,而 include 路径在 ../../kernel/patch/include,你加的这一行:

include_directories(${CMAKE_SOURCE_DIR}/kernel/patch/include)

可能在交叉编译环境中不被解释为相对路径。

请尝试替换为 相对 user 目录的路径:
🔁 请修改:

include_directories(${CMAKE_SOURCE_DIR}/../kernel/patch/include)

因为你是在 user 子目录中,CMAKE_SOURCE_DIR 会指向 KernelPatch-0.11.1-dev/user,所以需要回退到上一层。
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/user/build/android$ rm -rf *
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/user/build/android$ cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DANDROID_PLATFORM=android-33 \
      -DANDROID_ABI=arm64-v8a ../..
-- The C compiler identification is Clang 17.0.2
-- The CXX compiler identification is Clang 17.0.2
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /media/calleng/8f93e36b-93d5-4178-b393-88323a7c217b/home/calleng/Android/Sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/linux-x86_64/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /media/calleng/8f93e36b-93d5-4178-b393-88323a7c217b/home/calleng/Android/Sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /home/calleng/下载/KernelPatch-0.11.1-dev/user/build/android
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/user/build/android$ cmake --build .
[  6%] Building C object CMakeFiles/kp.dir/kpatch.c.o
[ 13%] Building C object CMakeFiles/kp.dir/kpm.c.o
[ 20%] Building C object CMakeFiles/kp.dir/su.c.o
[ 26%] Building C object CMakeFiles/kp.dir/android/android_user.c.o
[ 33%] Building C object CMakeFiles/kp.dir/android/sumgr.c.o
[ 40%] Linking C static library libkp.a
[ 40%] Built target kp
[ 46%] Building C object CMakeFiles/kpatch.dir/kpatch.c.o
[ 53%] Building C object CMakeFiles/kpatch.dir/kpm.c.o
[ 60%] Building C object CMakeFiles/kpatch.dir/su.c.o
[ 66%] Building C object CMakeFiles/kpatch.dir/android/android_user.c.o
[ 73%] Building C object CMakeFiles/kpatch.dir/android/sumgr.c.o
[ 80%] Building C object CMakeFiles/kpatch.dir/main.c.o
[ 86%] Linking C executable kpatch
[ 86%] Built target kpatch
[ 93%] Building CXX object CMakeFiles/apjni.dir/android/apjni.cpp.o
[100%] Linking CXX shared library libapjni.so
[100%] Built target apjni


calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/user/build/android$ file kpatch
kpatch: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, stripped

编译 Build KernelPatch Module

calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kpms/demo-hello$ export TARGET_COMPILE=aarch64-none-elf-
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kpms/demo-hello$ make
aarch64-none-elf-gcc  -I../../kernel/. -I../../kernel/include -I../../kernel/patch/include -I../../kernel/linux/include -I../../kernel/linux/arch/arm64/include -I../../kernel/linux/tools/arch/arm64/include -Thello.lds -c -O2 -o hello.o hello.c
aarch64-none-elf-gcc -r -o hello.kpm hello.o
calleng@calleng-GB-BNi7HG6-1060:~/下载/KernelPatch-0.11.1-dev/kpms/demo-hello$ ls
hello.c  hello.kpm  hello.lds  hello.o  Makefile

KernelPatch与eBPF相比优劣分析

对比的小结

既然源码都可以自己编译了, 那么是不是,可以自己修改逻辑自己玩一下.

就是你无法hook所有的系统调用, 你每hook一个系统调用都要从头写 , ebpf的话就可以hook很多的系统调用, ebpf他没有办法hook一个地址, 但是可以hook系统调用

kernelpatch 就是一个安卓强版本, 可以用在所有的版本上, 3.10 -6.8

ebpf 非常简单,清晰, 联合GPT 是非常好玩的

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

联系我们

888-888-8888

在线咨询:点击这里给我发消息

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部