作为我项目的一部分,我需要读取内核以获取系统调用表和系统调用地址的内存地址。或者实际上我需要提取系统调用表的内容和所有系统调用。
直到现在我才将GDB用于此目的。有没有办法让我可以使用内核模块。我是新的内核模块编程。寻求专家的建议。
答案 0 :(得分:10)
首先让我先说读任意内核内存是棘手的事情!并且有很多方法可以做到这一点,其复杂程度和灵活性各不相同。
在内核版本的System.map文件中搜索它:
# grep sys_call_table /boot/System.map-2.6.18-238.12.1.el5
c06254e0 R sys_call_table
有了这个,硬编码地址:
unsigned long *syscall_table = (unsigned long *)0xc06254e0;
然后,假设您#include <linux/syscalls.h>
,您可以使用__NR_syscall
定义来获取代码中这些系统调用的地址:
syscall_table[__NR_close]
这是最简单的方法,但到目前为止灵活性最低。该模块仅适用于该确切的内核。如果你将它发送到另一个内核,你就有可能得到一个内核OOP。
看看这个:
他使用一种方法来强制内核内存地址范围来查找sys_call_stable。原样,它只适用于32位(64位具有不同的内核内存地址范围)。
这种方法有点灵活,但随着内核语义的改变,可能会破坏道路。
加载模块时,可以读取内核的System.map文件。我在我写的 tpe-lkm 模块中演示了这一点。该项目托管在github上。
查看此文件中的find_symbol_address_from_file():
https://github.com/cormander/tpe-lkm/blob/master/symbols.c
非常灵活,因为你可以找到你想要的任何符号,但是从内核空间读取文件是一个很大的“不可以”。不要问我为什么,但人们总是告诉我。您还冒着它看到的System.map无效的风险,并可能导致内核OOP。此外,代码是......凌乱。
从内核版本2.6.30开始,内核导出kallsyms_on_each_symbol()。我们可以感谢ksplice人员。有了这个,你找不到sys_call_table(它出于某种原因不在那里),但你可以找到大多数其他符号。
非常灵活,非常稳定的查找符号地址的方法,但理解起来有些复杂;)
我在 tpe-lkm 项目中演示了这一点。看看这个文件中的find_symbol_callback()和find_symbol_address()函数: