linux内核查找符号

在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的,在使用C来写应用时,可以通过#include和链接动态库的形式形成一个动态链接文件,其中#include是在预编译阶段提供函数声明,而动态库是在链接阶段提供符号定义,在程序运行的时候加载动态库,动态链接和重定向,这个版本的内核module和应用层工作非常类似,内核本身就是一个动态库将所有非static的全部导出。好景不长,从Linux内核的2.6某版本开始,内核引入了导出符号的机制,在内核中使用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL导出的符号可以在其他内核模块中直接使用,主要增加了许可证的限制。但是并不是所有的符号都被导出了,只有EXPORT_SYMBOL/GPL也就是在Module.symvers中的才能被外部module使用,同时还需要包含相应的头文件在预处理中提供声明。但是使用这时候如果想要使用未导出的符号呢?

1.kallsyms_lookup_name读取
依赖于CONFIG_KALLSYMS,kallsyms_lookup_name在大多数情况下是被导出了,可以通过它来找到符号的地址:kallsyms_lookup_name(“vfs_open”).

2.通过/proc/kallsyms
这是一个proc文件系统节点,依赖CONFIG_KALLSYMS,读该节点的时候会将整个符号表都翻译成可读文本显示出来,awk '/vfs_open/{print $1}' /proc/kallsyms.为了限制普通用户得到内核符号的地址,会通过kernel.kptr_restrict来限制读取权限:

kernel.kptr_restrict:0普通用户就可以读取正确的符号地址
kernel.kptr_restrict:1 拥有CAP_SYSLOG可以读取正确的地址
kernel.kptr_restrict:2 所有的用户都读取不到正确的地址

3.通过/boot/System.map-xxx
大多数发行版系统都会提供该文件,记录了符号表信息,和/proc/kallsyms中的信息是一致的,但是这是个普通文件,可以通过查找该文件得到符号的位置。不依赖于CONFIG_KALLSYMS,但是要求文件信息和正在运行的内核是一致的。

4.利用kprobe
但是Kprobe也是依赖于CONFIG_KALLSYMS,当使能了CONFIG_KALLSYMS但是kallsyms_lookup_name没有导出时可以利用kprobe的接口先找到kallsyms_lookup_name的地址,之后再通过它去找其余的符号地址。

int noop_pre(struct kprobe *p, struct pt_regs *regs){ 
	return 0;
}
static struct kprobe kp = {   
	.symbol_name = "kallsyms_lookup_name",  
};
unsigned long (*kallsyms_lookup_name_fun)(const char *name) = NULL;
int find_kallsyms_lookup_name(void){ 
	int ret = -1; 
	kp.pre_handler = noop_pre;
	 ret = register_kprobe(&kp);
	  if (ret < 0) {  
	  printk(KERN_INFO "register_kprobe failed, error:%d\n", ret); 
	   return ret; 
	   } 
	   printk(KERN_INFO "kallsyms_lookup_name addr: %p\n", kp.addr); 
	   kallsyms_lookup_name_fun = (void*)kp.addr; 
	   unregister_kprobe(&kp);
	    return ret;
}

有没有可能取消CONFIG_KALLSYMS配置呢?通过menuconfig我们看到依赖它的功能有:MODULE,KPROBE,FTRACE,TRACE_EVENT,STACKTRACE_SUPPORT,DEBUG_KERNEL等非常多的基础设置功能,特别是MODULE允许模块加载,如果没有使能符号功能,module就无法使用内核的符号,这时候module又能做什么呢?它能做的非常有限,使用不了内核的基础设施:workqueue,timer等,只能另起炉灶或者洒洒水这样的事。

普通个人用的桌面或者服务器上应该默认配置这个功能,不过在嵌入式系统中可能会禁掉这个功能,毕竟内存有限,设备固定,全部都编译成一个小size的镜像。
在这时候还能怎么进行根据符号查找呢?毕竟这时候符号数据记录已经没有了,没有办法通过符号名称进行地址查找了,只能根据指令特征进行查找。目前没有一个完整的方法来找到想要的任意符号的地址,只能通过特定的指令来找到可能的位置,但不保证一定是想要的地址,参阅下面寻找系统调用表的方法。

https://blog.csdn.net/dog250/article/details/6451762

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页