find_sys_call_table
和 kallsyms_lookup_name
都可以用于查找内核符号,但它们的具体作用和使用场景有所不同。以下是两者的详细对比:
1. find_sys_call_table
作用
find_sys_call_table
是一种通过遍历内核内存或者其他方式来手动查找系统调用表地址的技术。这种方法通常在某些情况下使用,比如系统没有启用 kallsyms_lookup_name
或者内核版本不支持直接符号查找。
使用场景
- 内核版本不支持
kallsyms_lookup_name
:在某些老版本内核中,kallsyms_lookup_name
可能不可用或者被禁用。 - 无符号信息的内核:某些内核可能没有编译符号信息,这时无法通过符号名直接查找地址。
- 调试和分析工具:在某些情况下,调试工具可能需要手动查找系统调用表。
实现方法
find_sys_call_table
通常通过扫描内存中的特定模式来找到系统调用表。以下是一个简化的示例,展示了如何通过遍历内存来找到 sys_call_table
:
unsigned long **find_sys_call_table(void) {
unsigned long offset;
unsigned long **sct;
for (offset = PAGE_OFFSET; offset < ULLONG_MAX; offset = sizeof(void *)) {
sct = (unsigned long **)offset;
if (sct[__NR_close] == (unsigned long *) sys_close) {
return sct;
}
}
return NULL;
}
这个示例通过遍历从 PAGE_OFFSET
开始的内核内存地址空间,查找包含 sys_close
函数地址的位置,来确定系统调用表的位置。
2. kallsyms_lookup_name
作用
kallsyms_lookup_name
是内核提供的一个函数,用于通过符号名称查找其地址。这在调试和开发内核模块时非常方便,能够直接获取符号(如函数、变量等)的地址。
使用场景
- 内核开发和调试:在开发内核模块时,通过符号名称快速查找函数或变量的地址。
- 符号查找:需要查找特定符号的地址时,如
sys_call_table
的地址。
使用方法
使用 kallsyms_lookup_name
需要确保内核配置启用了 CONFIG_KALLSYMS
和 CONFIG_KALLSYMS_ALL
,并且函数是GPL导出的。以下是一个示例代码:
#include <linux/kallsyms.h>
#include <linux/module.h>
static int __init init_module_func(void) {
unsigned long address;
address = kallsyms_lookup_name("sys_call_table");
if (address) {
printk(KERN_INFO "sys_call_table address: %lxn", address);
} else {
printk(KERN_ERR "sys_call_table not foundn");
}
return 0;
}
static void __exit cleanup_module_func(void) {
printk(KERN_INFO "Module exitingn");
}
module_init(init_module_func);
module_exit(cleanup_module_func);
MODULE_LICENSE("GPL");
总结
- 查找方法:
find_sys_call_table
通过遍历内存查找特定模式找到系统调用表,而kallsyms_lookup_name
通过符号名称直接查找地址。 - 适用场景:
find_sys_call_table
适用于符号信息不可用或者不支持kallsyms_lookup_name
的情况,而kallsyms_lookup_name
适用于开发和调试,需要通过符号名称快速查找地址的情况。 - 实现复杂度:
find_sys_call_table
通常实现较复杂,需要了解内核内存布局和系统调用表特征;kallsyms_lookup_name
使用方便,只需提供符号名称即可。
两者在使用场景和实现复杂度上有显著区别,应根据具体需求选择合适的方法。