如何在不重新编译内核,不rmmod内核模块的情况下修改系统调用
为了解决这个问题,最终实现了两种解决方式:
1.Linux系统调用劫持
2.Kprobes内核调试技术(并非真正的修改)
下面分别说下:
Linux系统调用劫持:
其实就是修改内核符号表,来达到一个劫持的作用。因为系统调用实际上是触发了一个0x80的软中断,然后转到了系统调用处理程序的入口system_call()。system_call()会检查系统调用号来得出到底是调用哪种服务,然后会根据内核符号表跳转到所需要调用的内核函数的入口地址,所以,如果我们这个时候修改了内核符号表,使其跳转到我们自己的函数上,就可以完成劫持。
不过2.6之后,内核符号表便不再导出了,所以需要我们在内存中找到它的位置。具体查找的方式为:查找到中断向量表中的0x80中断服务函数的位置,然后在这个中断服务函数代码中查找根据内核符号表跳转的指令,从指令中可以分析出内核符号表的位置。
下面的是一个简单的劫持mkdir系统调用的测试,通过加载hook.ko内核模块,劫持mkdir系统调用,然后使用mkdir命令创建一个目录,来测试是否截齿成功。如果成功的话会输出“PID xxx called sys mkdir ! By qiankun”。结果测试成功。下面是经过。
kprobes内核调试技术
首先声明两点:
1.这种方式其实并非修改,而是只是在运行的内核中动态的插入探测点,当内核运行到该探测点后可以执行用户预定义的回调函数。执行完毕后返回正常的执行流程。所以说他其实并非真正的修改了原有的系统调用。但是可以达到一定类似于修改了的效果,暂且算作一种“伪修改”吧。
2.我在测试的时候使用的是kprobes中的jprobe探测方式,其实其他的内核调试技术比如systemtap等应该能够实现这种功能,但是我就不一一实现了。
Kprobes是一个轻量级的内核调试工具,利用kprobes技术可以再运行的内核中动态的插入探测点,在探测点进行用户预定义的操作。
Kprobes使用主要可以分为三部分:
1.注册探测点部分。
2.调试处理部分。
3.注销探测点部分。
下面是使用kprobes中jprobe探测方式,对sys_open和sys_write进行添加探测点。这样可以一定程度上影响sys_open和sys_write的最后结果,达到类似修改的目的。下面是测试过程,可以看到,每当内核调用sys_write和sys_open的时候,都会先调用我们的探测函数。