Linux Kprobes探索与实践一

最近因为工作方面接触到Linux kprobes,但是没有实践分析过其原理,以及它到底有没有动态替换相应的指令,所以想从二进制层面分析一下。刚好在第二回我们讲述了中断描述表,而Linux kernel kprobes本质即利用INT 3异常以及单步调试异常实现。因此,在正常的章节中穿插一次Linux kprobes的探索实践篇。Linux kprobes是Linux kernel的原生实现,不像ftrace,eBPF那种tracer需要编译器的协助,在编译kernel的时候会隐藏的插入一些指令在kernel中。闭上眼睛思考一下,其实这个很可怕,如果编译器没有武德给你的程序插入一些后门指令,后果可想而知。这里先简单描述一下Linux kprobes的实现流程,然后编译Linux kernel vmlinuz以及一个探测点kernel module,解剖Linux kernel vmlinuz中锚点的地址处的指令是否像所说的那样被替换成INT 3指令(0xcc)。

Linux kprobes注册 kprobe后,kprobes会备份被探测点的指令(程序原本正常的指令),并用断点指令(例如x86_64上的INT 3)替换被探测指令点的第一个字节。当CPU遇到断点指令时会发生陷阱,保存CPU的寄存器,并通过notifier_call_chain机制将控制权传递给 kprobes。kprobes执行与kprobe相关的“pre_handler”,将kprobe结构的地址和保存的寄存器传递给处理程序。接下来,kprobe单步执行前面所备份的被探测指令(程序原本正常的指令)。在指令单步执行后,kprobes执行与kprobe 关联的“post_handler”(如果有)。然后继续执行探测点之后的指令。所以将本来执行一条指令扩展成执行<pre_handler—>指令 —> post_hander>这样三步过程。

现在我们来编译一个支持Linux kprobes的vmlinuz,如下图1,图2所示配置kprobes=y, tracer=n。将tracer配置为n的目的避免tracer干扰kprobes的原生实现。

                                                                    图1 Enable Kprobes

                                                                图 2 Disable Tracer

配置完成后依次运行如下命令完成Linux kernel的编译,内核模块以及内核文件的安装,需要重启系统才能生效。但是默认情况下各Linux发行版kernel都默认支持kprobes。这个编译部分只是为了让大家如何编译一个支持kprobes的kernel。

                    make "-j$(cat /proc/cpuinfo | grep "processor" | wc -l)

                    make module_install

                    make install 

接下来,就需要按照Linux kprobes的要求实现一个内核模块,并注册到系统中(这个可以参考各种资料获得)。本次探索中也只实现了简单的pre_handler、post_handler函数,通过传递给这两个函数的kprobes参数,打印探测点地址的信息,运行结果如下图3所示。p->addr是锚点的探测点地址,即会被动态替换一个字节内容的起始地址。被探测点函数名称为_do_fork。动态替换指令的kprobes实现部分可以下次再细细写一个,涉及Linux kernel的一

                                                                             图3

些核心概念,比较有意思。从图3可以看到内存地址0xffffff8709dd60~0xffffff8709dd6四个字节的值依次是cc、57、41、46,第一个字节确实是INT 3指令编码cc。但是需要思考一下,这个会不会编译出来的kernel vmlinuz在这个地址处原本就是cc,不是被kprobe内核模块动态替换的。因此,我们还需要反汇编刚才编译出来的vmlinuz,从中找到_do_fork函数的汇编代码,看看原始_do_fork原始的第一字节内容是什么。利用GDB加载刚编译出来的vmlinux,注意这里不是vmlinuz,是vmlinux,因为vmlinux里面才有符号表等用于反汇编的信息。下面是见证神奇的时候到,请看下图4         

                                                     图 4

从上图4中可以看到vmlinuz的前4个字节内存地址为0xffffff8709dd60~0xffffff8709dd6,相应地址对应的数值为41、56、41、56。图4与图3对比即可得出vmlinuz中的_do_fork函数被kprobes注册为探测点地址的第一个字节41(push)确实被动态替换成了cc (INT 3)。所以当CPU执行到INT 3断点指令就会陷入相应的Trap处理函数,该处理函数中会调用kprobes的handler函数完成上述所有操作,见图5所示。

                                                                                图5

如果大家还想思考验证一下其它问题,可以这样一步步去求证。下一回,接着操作系统正常系列继续走。

======================================================================

各位看官如果对本系列有兴趣,大家一起学习交流,可以加一下该系列微信公众号,鼓励继续写的动力。声明此公众号是个人申请用于交流学习底层技术,不会涉及其他商业行为。

微信公众号链接:

Linux Kprobes探索与实践一 (qq.com)icon-default.png?t=M666https://mp.weixin.qq.com/s?__biz=Mzg5NzczMTQ2Mw==&mid=2247483718&idx=1&sn=8f642f8b8829f02c2f90676c1f686af7&chksm=c06c1faef71b96b87de1935f31a6a3740929ad8222fabe76a18de8a1affdd92f37e2431f92e4&token=1533507501&lang=zh_CN#rd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过Kprobes模拟Linux的内核态内存故障,可以采取以下步骤: 1. 前置步骤 在开始模拟之前,需要确保系统中已经安装了Kprobes工具,并且已经启用了内核调试选项。可以使用以下命令来检查系统中是否安装了Kprobes工具: ``` which kprobe ``` 如果输出了路径信息,则表示系统中已经安装了Kprobes工具。 2. 指令和过程 接下来,可以使用以下指令和过程来模拟内核态内存故障: (1)编写测试代码 首先,需要编写一个测试代码,该代码会故意访问非法的内存地址,触发内核态内存故障。例如,可以在代码中使用以下指令: ``` char *ptr = NULL; *ptr = 'a'; ``` 这段代码会将空指针ptr所指向的内存地址写入字符'a',由于ptr为NULL,因此会导致内存访问非法。 (2)为测试代码添加Kprobe 接下来,可以使用Kprobes工具为测试代码添加Kprobe。Kprobe是一种在内核函数执行前或执行后插入代码的机制,可以用来跟踪和分析内核代码的执行过程。可以使用以下指令为测试代码添加Kprobe: ``` echo 'p:myprobe do_fault_error_handler' > /sys/kernel/debug/tracing/kprobe_events ``` 这段指令会在内核态故障处理函数do_fault_error_handler执行前插入一段代码,用于捕获内存故障。 (3)运行测试代码 最后,可以运行测试代码,触发内核态内存故障。可以使用以下指令来编译和运行测试代码: ``` gcc -o test test.c ./test ``` 运行测试代码后,Kprobes会捕获内核态内存故障,并且可以在/var/log/messages中查看相关日志信息。 需要注意的是,在使用Kprobes进行内核态内存故障模拟时,一定要注意对系统的影响,并且遵守安全操作规范,避免数据丢失或者系统崩溃等问题。同时,也要保证故障不会对生产环境造成影响。操作时应当十分小心谨慎。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值