Kali Linux 上的系统调用挂钩内核版本 5

如何解决Kali Linux 上的系统调用挂钩内核版本 5

我正在尝试为 Kali Linux 2021-W1(Linux 内核版本 5) 上的 bind() 系统调用设置一个挂钩,但由于某种原因,调用了原始系统调用失败并发生错误。

这是我的代码:

/* includes,license,author... */

void **sys_call_table_addr = (void **) 0xffffffff9e0002c0;

int enable_page_rw(void *ptr){
        unsigned int level;
        pte_t *pte = lookup_address((unsigned long) ptr,&level);
        if(pte->pte &~_PAGE_RW){
            pte->pte |=_PAGE_RW;
        }
        return 0;
}

int disable_page_rw(void *ptr){
        unsigned int level;
        pte_t *pte = lookup_address((unsigned long) ptr,&level);
        pte->pte = pte->pte &~_PAGE_RW;
        return 0;
}

asmlinkage int (*original_bind) (int,const struct sockaddr *,int);
asmlinkage int log_bind(int sockfd,const struct sockaddr *addr,int addrlen) {
        int ret;
        printk(KERN_INFO SOCKETLOG "bind was called");
        return (*original_bind)(sockfd,addr,addrlen);
}

static int __init socketlog_init(void) {
        printk(KERN_INFO SOCKETLOG "socketlog module has been loaded\n");

        enable_page_rw(sys_call_table_addr);
        original_bind = sys_call_table_addr[__NR_bind];
        if (!original_bind) return -1;
        sys_call_table_addr[__NR_bind] = log_bind;
        disable_page_rw(sys_call_table_addr);

        printk(KERN_INFO SOCKETLOG "original_bind = %p",original_bind);
        return 0;
}

static void __exit socketlog_exit(void) {
        printk(KERN_INFO SOCKETLOG "socketlog module has been unloaded\n");

        enable_page_rw(sys_call_table_addr);
        sys_call_table_addr[__NR_bind] = original_bind;
        disable_page_rw(sys_call_table_addr);
}

module_init(socketlog_init);
module_exit(socketlog_exit);

执行sudo insmod socketlog.ko后,可以看到预期的输出:

[  +0.000488] [SOCKETLOG] socketlog module has been loaded
[  +0.000002] [SOCKETLOG] original_bind = 00000000bbf288f1

但是每次调用 bind() 时,我都会得到奇怪的行为:

[  +0.000488] [SOCKETLOG] bind was called
[  +0.000005] BUG: unable to handle page fault for address: 0000000040697fb8 
[  +0.000002] #PF: supervisor read access in kernel mode
[  +0.000001] #PF: error_code(0x0000) - not-present page

正如预期的那样,0x0000000040697fb80x00000000bbf288f1 指向的地址:原始系统调用的内容。我错过了什么?

解决方法

也许您包装系统调用的方式不起作用。例如,在 Linux 5.4.0-59-generic x86_64 架构上,内核中的系统调用是通过一个名为 do_syscall_64() 的通用包装器调用的。它通过pt_regs结构将参数传递给sys_call_table[]中的条目:

__visible void do_syscall_64(unsigned long nr,struct pt_regs *regs)
{
    struct thread_info *ti;

    enter_from_user_mode();
    local_irq_enable();
    ti = current_thread_info();
    if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY)
        nr = syscall_trace_enter(regs);

    if (likely(nr < NR_syscalls)) {
        nr = array_index_nospec(nr,NR_syscalls);
        regs->ax = sys_call_table[nr](regs); <-------- Call to the entry with pt_regs structure
#ifdef CONFIG_X86_X32_ABI
    } else if (likely((nr & __X32_SYSCALL_BIT) &&
              (nr & ~__X32_SYSCALL_BIT) < X32_NR_syscalls)) {
        nr = array_index_nospec(nr & ~__X32_SYSCALL_BIT,X32_NR_syscalls);
        regs->ax = x32_sys_call_table[nr](regs);
#endif
    }

    syscall_return_slowpath(regs);
}

pt_regs 结构嵌入了用户传递给系统调用的参数。所以这可以解释你崩溃的原因:printk(..."bind was called") 工作,因为它不访问参数但在调用原始系统调用条目后不符合预期参数。

如果查看net/socket.cbind()系统调用的源码,它定义为:

SYSCALL_DEFINE3(bind,int,fd,struct sockaddr __user *,umyaddr,addrlen)
{
    return __sys_bind(fd,addrlen);
}

上述宏 SYSCALL_DEFINE3() 扩展为一些包装器,这些包装器从 pt_regs 结构中提取参数。

所以,这里是一个例子,你的模块中的一些修复适用于我的 5.4.0-60-generic Ubuntu x86_64:

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/ptrace.h>
#include <linux/socket.h>
#include <linux/kallsyms.h>


MODULE_LICENSE("Dual BSD/GPL");

typedef int (* syscall_wrapper)(struct pt_regs *);

unsigned long sys_call_table_addr;

#define SOCKETLOG "[SOCKETLOG]"


int enable_page_rw(void *ptr){
  unsigned int level;
  pte_t *pte = lookup_address((unsigned long) ptr,&level);
  if(pte->pte &~_PAGE_RW){
    pte->pte |=_PAGE_RW;
  }
  return 0;
}

int disable_page_rw(void *ptr){
  unsigned int level;
  pte_t *pte = lookup_address((unsigned long) ptr,&level);
  pte->pte = pte->pte &~_PAGE_RW;
  return 0;
}

syscall_wrapper original_bind;

//asmlinkage int log_bind(int sockfd,const struct sockaddr *addr,int addrlen) {
int log_bind(struct pt_regs *regs) {
  printk(KERN_INFO SOCKETLOG "bind was called");
  return (*original_bind)(regs);
}

static int __init socketlog_init(void) {

  printk(KERN_INFO SOCKETLOG "socketlog module has been loaded\n");

  sys_call_table_addr = kallsyms_lookup_name("sys_call_table");

  printk(KERN_INFO SOCKETLOG "sys_call_table@%lx\n",sys_call_table_addr);

  enable_page_rw((void *)sys_call_table_addr);
  original_bind = ((syscall_wrapper *)sys_call_table_addr)[__NR_bind];
  if (!original_bind) return -1;
  ((syscall_wrapper *)sys_call_table_addr)[__NR_bind] = log_bind;
  disable_page_rw((void *)sys_call_table_addr);

  printk(KERN_INFO SOCKETLOG "original_bind = %p",original_bind);
  return 0;
}

static void __exit socketlog_exit(void) {
  printk(KERN_INFO SOCKETLOG "socketlog module has been unloaded\n");

  enable_page_rw((void *)sys_call_table_addr);
  ((syscall_wrapper *)sys_call_table_addr)[__NR_bind] = original_bind;
  disable_page_rw((void *)sys_call_table_addr);
}

module_init(socketlog_init);
module_exit(socketlog_exit);

通过测试:

$ sudo insmod ./bind_ovl.ko
$ dmesg
[ 2253.201888] [SOCKETLOG]socketlog module has been loaded
[ 2253.209486] [SOCKETLOG]sys_call_table@ffffffff88c013a0
[ 2253.209489] [SOCKETLOG]original_bind = 00000000f54304a9

例如,在重新加载 WEB 页面后,我得到:

$ dmesg
[ 2136.946042] [SOCKETLOG]socketlog module has been unloaded
[ 2253.201888] [SOCKETLOG]socketlog module has been loaded
[ 2253.209486] [SOCKETLOG]sys_call_table@ffffffff88c013a0
[ 2253.209489] [SOCKETLOG]original_bind = 00000000f54304a9
[ 2281.716581] [SOCKETLOG]bind was called
[ 2295.607476] [SOCKETLOG]bind was called
[ 2301.947866] [SOCKETLOG]bind was called
[ 2304.088116] [SOCKETLOG]bind was called
[ 2309.599634] [SOCKETLOG]bind was called
[ 2310.946833] [SOCKETLOG]bind was called

卸载模块后:

$ sudo rmmod bind_ovl
$ dmesg
[...]
[ 2390.908456] [SOCKETLOG]bind was called
[ 2398.921475] [SOCKETLOG]bind was called
[ 2398.928855] [SOCKETLOG]socketlog module has been unloaded

您当然可以通过显示传递给系统调用的参数来增强过载。在 x86_64 上,系统调用最多通过处理器寄存器传递 6 个参数。我们可以在 pt_regs 结构中检索它们。后者在 arch/x86/include/asm/ptrace.h 中定义为:

struct pt_regs {
/*
 * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
 * unless syscall needs a complete,fully filled "struct pt_regs".
 */
    unsigned long r15;
    unsigned long r14;
    unsigned long r13;
    unsigned long r12;
    unsigned long bp;
    unsigned long bx;
/* These regs are callee-clobbered. Always saved on kernel entry. */
    unsigned long r11;
    unsigned long r10;
    unsigned long r9;
    unsigned long r8;
    unsigned long ax;
    unsigned long cx;
    unsigned long dx;
    unsigned long si;
    unsigned long di;
/*
 * On syscall entry,this is syscall#. On CPU exception,this is error code.
 * On hw interrupt,it's IRQ number:
 */
    unsigned long orig_ax;
/* Return frame for iretq */
    unsigned long ip;
    unsigned long cs;
    unsigned long flags;
    unsigned long sp;
    unsigned long ss;
/* top of stack page */
};

系统调用的参数传递约定是:param#0 到 param#5 分别传入RDIRSIRDXR10R8R9 寄存器。

根据这个规则,对于bind()系统调用,参数在以下寄存器中:

  • RDI = int(套接字描述符)
  • RSI = struct sockaddr *addr
  • RDX = socklen_t addrlen

然后您可以使用以下内容增强日志功能:

int log_bind(struct pt_regs *regs) {
  printk(KERN_INFO SOCKETLOG "bind was called(%d,%p,%u)",(int)(regs->di),(void *)(regs->si),(unsigned int)(regs->dx));
  return (*original_bind)(regs);
}

来自模块的痕迹变得更加详细:

[ 3259.589915] [SOCKETLOG]socketlog module has been loaded
[ 3259.594631] [SOCKETLOG]sys_call_table@ffffffff88c013a0
[ 3259.594634] [SOCKETLOG]original_bind = 00000000f54304a9
[ 3274.368906] [SOCKETLOG]bind was called(149,0000000091c163d5,12)
[ 3276.040330] [SOCKETLOG]bind was called(149,0000000075b17cb4,12)
[ 3278.203942] [SOCKETLOG]bind was called(188,12)
[ 3287.014980] [SOCKETLOG]bind was called(214,12)
[ 3287.021167] [SOCKETLOG]bind was called(214,12)
[ 3298.395713] [SOCKETLOG]bind was called(3,000000008c2a9103,12)
[ 3298.403249] [SOCKETLOG]socketlog module has been unloaded

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res