欢迎光临散文网 会员登陆 & 注册

Linux驱动读取当前内核中代码段数据(超详细)

2022-03-27 12:59 作者:补给站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文件中就记录了虚拟内存的的每段地址分别对应什么数据。




Linux驱动读取当前内核中代码段数据(超详细)的评论 (共 条)

分享到微博请遵守国家法律