Linux驱动读取当前内核中代码段数据(超详细)
直接上代码,思路就是得到代码段的起始地址和结束地址,然后先将数据存在一个buffer中,最后写入文件。
kallsym.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
static char *path = NULL;
module_param(path, charp, S_IRUGO);
static int __write_to_file(char *buffer, int size)
{
struct file *filep = NULL;
loff_t pos = 0;
int ret = 0;
filep = filp_open(path, O_RDWR | O_CREAT, 0);
if(filep == NULL) {
printk("%s: Open file %s error\n", __func__, path);
return 0;
}
ret = kernel_write(filep, buffer, size, &pos);
if(ret < size) {
printk("%s: Write file %s error\n", __func__, path);
return 0;
}
filp_close(filep, NULL);
return ret;
}
static int __init kallsyms_init(void)
{
unsigned long stext, etext, size = 0;
char *ptr = NULL;
char *buffer = NULL;
int i = 0;
stext = kallsyms_lookup_name("_stext");
etext = kallsyms_lookup_name("_etext");
printk("%s: the _stext address is %lx\n", __func__, stext);
printk("%s: the _stext address is %lx\n", __func__, etext);
if(!stext || !etext) {
printk("%s: Get text start end failed\n", __func__);
return -EINVAL;
}
size = etext - stext;
ptr = (char *)stext;
buffer = vzalloc(size + 1024);
if(buffer == NULL) {
printk("%s: Alloc temp buffer memory failed\n", __func__);
return 0;
}
for(i = 0; i < size; i++) {
buffer[i] = ptr[i];
}
__write_to_file(buffer, size);
vfree(buffer);
return 0;
}
static void __exit kallsyms_exit(void)
{
printk("%s: good bye\n", __func__);
}
module_init(kallsyms_init);
module_exit(kallsyms_exit);
MODULE_LICENSE("GPL");
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)


Makefile文件
obj-m += kallsym.o
KBUILD_CFLAGS += -g
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
以下代码为dump指定内存地址,大小为offset;
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
static char *path = NULL;
static unsigned long base_addr = 0;
static unsigned int offset = 0;
module_param(path, charp, S_IRUGO);
module_param(base_addr, ulong, S_IRUGO);
module_param(offset, uint, S_IRUGO);
static int __write_to_file(char *buffer, int size)
{
struct file *filep = NULL;
loff_t pos = 0;
int ret = 0;
filep = filp_open(path, O_RDWR | O_CREAT, 0);
if(filep == NULL) {
printk("%s: Open file %s error\n", __func__, path);
return 0;
}
ret = kernel_write(filep, buffer, size, &pos);
if(ret < size) {
printk("%s: Write file %s error\n", __func__, path);
return 0;
}
filp_close(filep, NULL);
return ret;
}
static int __init kallsyms_init(void)
{
unsigned long stext, etext;
char *ptr = NULL;
char *buffer = NULL;
int i = 0;
stext = base_addr;
etext = base_addr + offset;
printk("%s: the _stext address is %lx\n", __func__, stext);
printk("%s: the _stext address is %lx\n", __func__, etext);
ptr = (char *)stext;
buffer = vzalloc(offset + 100);
if(buffer == NULL) {
printk("%s: Alloc temp buffer memory failed\n", __func__);
return 0;
}
for(i = 0; i < offset; i++) {
buffer[i] = ptr[i];
}
__write_to_file(buffer, offset);
vfree(buffer);
return 0;
}
static void __exit kallsyms_exit(void)
{
printk("%s: good bye\n", __func__);
}
module_init(kallsyms_init);
module_exit(kallsyms_exit);
MODULE_LICENSE("GPL");
linux 查看进程数据段,如何读取Linux进程中的代码段和数据段
Linux下的程序的文件格式是ELF,里面分了各种段,有代码段、数据段、等。当运行这个程序时,系统也会给这个进程创建虚拟内存,然后把ELF中的数据分别加载到内存中的对应位置。本文整理了用cpp程序读取内存中的代码段和rodata数据段的方法。
Ptrace
Ptrace是一个Linux系统提供的一个功能强大的API接口,可以让一个进程跟踪或控制另一个进程,调试程序GDB就是在这个系统调用的基础上开发的。
long ptrace(enum ptrace_request request,pid_t pid,void addr, void *data);
参数request 控制ptrace函数的行为,定义在sys/ptrace.h中。
参数pid 指定trace的进程号。
以上两个参数是必须的,之后两个参数分别为地址和数据,其含义由参数request控制。
/proc/pid/mem
mem是内核创建的虚拟文件,是Linux的”一切皆文件”在进程上的体现,但是这个文件无法直接进行读取,需要先利用ptrace进行绑定操作。
用ptrace绑定之后就可以用read来读取这个“文件”了,但是要注意输入读取的地址不对,也读不出数据来。
/proc/pid/maps
下图是Linux的进程内存布局,这是系统给进程虚拟出的一个内存空间,并不是实际的物理内存,maps文件中就记录了虚拟内存的的每段地址分别对应什么数据。

