linux内核hack-运行中动态添加系统调用

简介:

LINUX中每次添加一个系统调用都要完成重新编译内核,然后制作initrd等工作,不得不说这是一件繁重的工作,很多人本来已经构思好了自己的一个系统调用,要添加到内核,然后却被这些工作所中断,毫不夸张的说,制作initrd就很麻烦,虽然基于cpio的initrd可以利用几条命令完成,然而只要有一个错误,你就不得不重启系统。
     我们都知道,内核模块运行在内核态,可以访问所有的内存空间,那么能不能在系统运行期间,不用重新编译内核,而运用内核模块机制实现添加系统调用呢?答案是肯定的,因为一个基本原理:内核态能读写所有的内存,内存全部在我们手中,没有什么事情做不到, 那么怎么做到呢?
     如果我们了解了系统调用执行的过程,那么我们就知道在执行一个系统调用之前,有两个限制,第一就是系统调用数量在编译时定死,系统调用号必须在这个被允许的系统调用号区间内,第二就是系统调用表的地址未导出。 由于系统调用入口也是一种中断/异常,因此我们看一下代码,看个究竟,基于i386的内核代码在arch/i386/kernel/entry.S(基于2.6.8内核,虽然有点老,但能说明问题),我们看一下系统调用的入口

 
通过以上的代码可以看出,如果我们想添加一个新的系统调用,第一,它的系统调用号不能超过nr_syscalls,第二,它的地址必须在系统调用表地址加上系统调用号*4的位置处, 也就是说,满足这两个条件,内核逻辑就会将执行流路由到我们调用的系统调用服务程序。
     如果我们希望在系统运行期动态添加一个系统调用,那么就必须破除上述的两个神话。第一,我们必须修改nr_syscalls的值,第二,我们必须修改sys_call_table的值,并且新的sys_call_table内容值必须保留原有的sys_call_table内容值。 这个需求怎么做到呢?很简单,扫面二进制机器码!记住,内存在我们手中,还要记住,我们的这次行为不是攻击行为,只是为了调试一个新增加的系统调用而不想重新编译内核...!!! 
     到底怎么做到呢?首先,我们只需要修改掉system_call中的cmpl $(nr_syscalls), %eax语句中的nr_syscalls,我们首先从/proc/kallsym中取得system_call的地址,然后在其下面搜索cmpl $(nr_syscalls), %eax的机器码,搜到后将nr_syscalls修改;其次我们在/boot/Sysmap中取得sys_call_table的地址,然后在system_call的下面搜索这个地址的机器码,取得后我们将其修改为新的系统调用表的地址,需要指出的是,新的系统调用表的前nr_syscalls个字段必须和原始的系统调用表sys_call_table的相同。另外,如何获得sys_call_table的地址,这个技术值得商榷,其实有很多方法,本文使用最直接的方式,那就是从/boot/Sysmap中获取。
     有一个细节,那就是如何在system_call附近寻找匹配检测系统调用号范围的机器码呢?最简单的方式莫过于模拟,那就是写一个程序,调用cmpl $(nr_syscalls), %eax,其中nr_syscalls在2.6.8中为284,那么我们就写下面的代码:
 
编译后使用objdump得到了3d 1c 01 00 00 cmp    $0x11c,%eax这样的机器码/汇编码,于是我们可以断定,机器特征码为3d 1c 01 00 00 。类似的,sys_call_table的地址也可以这样来求得,不过记住,没有必要,既然你有root权限了,还有必要这样吗?
     那么到底怎么做到的呢?请看模块dynamic_add_syscall:
 
编译上述模块,然后加载:
insmod dynamic_add_syscall.ko entry_addr=0xc01061d8 table_addr=0xc02dad1c nowa_num=0x11c want_num=0x21c 
上述的地址信息都是从/boot/Sysmap以及/proc/kallsym以及内核源码中得到的。现在我们希望增加一个系统调用,该怎么办呢?
     很简单,再写一个模块newsyscall:
 
编译此模块,然后加载,为了测试我们新增加的系统调用sys_force,特写一个用户态程序:
 
编译为test,当我们执行test 284 123之后,用dmesg看一下,会发现最后一行打印:new sys----:123,表明成功,我们成功增加了一个系统调用,可喜!
后记: 
还是那句话,既然彻底理解了原理,那就没有什么是不可能的,我们不必为了实现一个系统调用而重新编译内核,完全没有必要,我们可以先使用上述的方式将新系统调用调试通过,然后最终再通过重新编译内核的方式添加进内核,OK?

         虽然修改内存机器码并不是可取的方式,不是常规的方式,然而再次重申,我们这不是在进行攻击,而是为了让自己添加和调试新的系统调用更方便,只要达到目的,有什么不可以呢?难道仅仅因为LKML上以及教科书上建议就非要重新编译内核吗?适合自己的才是最好的,我们需要的是提高工作效率! 
     还是那些人,然而还是那些人!有那么重要吗?信口开河!人要生活,而不仅仅是生存!


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271019



相关文章
|
7月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
672 1
|
7月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
7月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
7月前
|
传感器 监控 Ubuntu
10 月发布,Ubuntu 23.10 已升级到 Linux Kernel 6.3 内核
硬件方面,Linux 6.3 引入了在 HID 中引入了原生的 Steam Deck 控制器接口,允许罗技 G923 Xbox 版赛车方向盘在 Linux 上运行;改善 8BitDo Pro 2 有线控制器的行为;并为一系列华硕 Ryzen 主板添加传感器监控。
|
7月前
|
Ubuntu Linux
Ubuntu24.04LTS默认采用Linux 6.8内核,实验性版本可通过PPA获得
IT之家提醒,当下的 Ubuntu 23.10 也是一个“短期支持版本”,该版本将在今年 7 月终止支持,而今年 4 月推出的 Ubuntu 24.04 LTS 长期支持版本将获得 5 年的更新支持。
|
7月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
434 0
|
7月前
|
Web App开发 缓存 Rust
|
7月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
7月前
|
Ubuntu 机器人 物联网
Linux Ubuntu 22.04 LTS 测试版实时内核已可申请
请注意,在启用实时内核后您需要手动配置 grub 以恢复到原始内核。更多内容请参考: