当前位置: 首页 > article >正文

获取指定进程中的数据

此文章是对《打印指定进程中的数据》的扩展,增加了用户空间的控制接口,可以实现从用户空间发送指令,指定要获取数据的进程id和内存地址,然后将取到的数据返回给用户空间。

下面是驱动部分的代码


#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/device.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/fs_struct.h>
#include <linux/miscdevice.h>
#include <linux/sched/signal.h>

#define CM_MINOR 234

/*
pid     进程id
addr    内存地址
buf     保存取到的内容
buf_len 内存长度
*/
static int mem_print(int pid, long long addr, char* buf, int buf_len)
{
    int offset = 0;
    void *p_addr = NULL;
    unsigned long pfn = 0;
	struct task_struct * p;
    pgd_t *pgd = NULL;
    p4d_t *p4d = NULL;
    pud_t *pud = NULL;
    pmd_t *pmd = NULL;
    pte_t *pte = NULL;
    struct page *page = NULL;
    struct mm_struct *mm = NULL;
    struct fs_struct *fs = NULL;
 
    rcu_read_lock();
    // 遍历系统中的每个进程
	for_each_process(p) {
		// 不是目标进程
		if (pid != p->pid)
		{
			continue;
		}
 
		printk("------\n");
		printk("state - %lX\n", p->state);
		printk("pid - %X\n", p->pid);
 
		fs = p->fs;
		if (NULL != fs)
		{
			struct path cur_path = fs->pwd;
			if (NULL != cur_path.dentry)
			{
				struct dentry *dentry = cur_path.dentry;
				while (NULL != dentry)
				{
					printk("d_iname = %s ,", dentry->d_iname);
 
					if (0 == strcmp("/", dentry->d_iname))
					{
						break;
					}
 
					dentry = dentry->d_parent; // 父目录
				}
			}
		}
 
		mm = p->mm;
		if (NULL != mm)
		{
			//struct vm_area_struct *vm_area = mm->mmap;
 
			pgd = pgd_offset(mm, addr);
			printk("pgd = %ld, %p\n", pgd, pgd);
 
			p4d = p4d_offset(pgd, addr);
 
			pud = pud_offset(p4d, addr);
			printk("pud = %ld, %p\n", pud, pud);
			
			pmd = pmd_offset(pud, addr);
			printk("pmd = %d, %p\n", pmd, pmd);
 
			pte = pte_offset_kernel(pmd, addr); // 页表的线性地址
 
			page = pte_page(*pte); // 页框的线性地址
			if (NULL != page)
			{
				printk("page = %lx\n", page);
 
				printk("flags = %u\n", page->flags);
 
				// 地址在页框内的偏移
				offset = addr & 0xFFF;
				printk("offset = %d\n", offset);
 
				pfn = page_to_pfn(page);
				printk("pfn = %x\n", pfn);
 
				p_addr = page_address(page);
				printk("p_addr = %lx\n", p_addr);
 
				printk("data: %s\n", p_addr + offset);

                memcpy(buf, p_addr + offset, buf_len);
			}
		}
	}

    rcu_read_unlock();
 
	return 0;
}

static ssize_t cm_read(struct file *file, __user char *buffer, size_t count,
			loff_t *ppos)
{
    int retval = 0;
    int pid = 0;
    long long addr = 0;

    // 申请空间
    char *buf = (char *) __get_free_page(GFP_USER);

    if (!buf)
		return -ENOMEM;
    
    // 读取用户空间的数据:4字节进程id,8字节目标数据内存地址
    if (copy_from_user(buf, buffer, 12))
		goto out;
    
    memcpy(&pid, buf, 4);
    memcpy(&addr, buf+4, 8);

	// 读取指定内容
    mem_print(pid, addr, buf, count);

    // 返回给用户空间
    copy_to_user(buffer, buf, count);

 out:
	free_page((unsigned long)buf);

	return retval;
}


static int cm_open(struct inode *inode, struct file *file)
{
    int retval = 0;
    printk("cm_open\n");

	return retval;
}


static int cm_close(struct inode *inode, struct file *file)
{
    int retval = 0;
    printk("cm_close\n");

	return retval;
}

static const struct file_operations cm_fops = {
	.owner	= THIS_MODULE,
	.read  = cm_read,
	.open	= cm_open,
	.release = cm_close,

};

static struct miscdevice cm_miscdev = {
	.minor = CM_MINOR,
	.name = "copymemory",
	.nodename = "copymemory",
	.fops = &cm_fops,
};

static int __init cm_init(void)
{
    int ret = 0;

    printk("cm_init\n");

    ret = misc_register(&cm_miscdev);
	if (ret) {
		pr_err("Can't register misc device %d\n", CM_MINOR);
		goto err_cm;
	}
    return 0;

err_cm:
    return ret;
}

static void cm_cleanup(void)
{
    printk("cm_cleanup\n");
	misc_deregister(&cm_miscdev);
}

module_init(cm_init);
module_exit(cm_cleanup);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("copy memory driver");
MODULE_ALIAS_MISCDEV(CM_MINOR);

下面是用户空间,发送指令的示例代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    if (argc < 3)
    {
        printf("invalid param,need: pid addr\n");
        return -1;
    }

    int pid = atoi(argv[1]); // 进程id
    long long addr = atoll(argv[2]); // 数据内存地址

    int fd = open("/dev/copymemory", O_RDONLY);
    if (fd < 0)
    {
        printf("open failed, ret: %d\n", fd);
        return -1;
    }

    char buf[100] = {0};
    memcpy(buf, &pid, sizeof(int));
    memcpy(buf+4, &addr, sizeof(addr));
    read(fd, buf, 100);

    printf("content: %s\n", buf);

    close(fd);
    return 0;
}

 a.out为用户空间代码编译的程序,获取进程17750,内存0x4006b7处的数据,执行方法和获取的内容如下:


http://www.kler.cn/a/226828.html

相关文章:

  • Vue3学习记录(二)--- 组合式API之计算属性和侦听器
  • 学习数据结构的第一天
  • 代码随想录算法训练营第四十一天|122. 买卖股票的最佳时机 II
  • 专业139总分400+南昌大学811信号与系统考研经验电子信息与通信工程集成电路
  • Redis核心技术与实战【学习笔记】 - 16.Redis 缓存异常:缓存和数据库不一致
  • 红日三打靶!!!
  • 力扣hot100 编辑距离 多维DP
  • 力扣刷题之旅:启程篇(二)
  • Mac M1使用PD虚拟机运行win10弹出“内部版本已过期立即安装新的windows内部版本”
  • 短剧小程序开发:打造高效、便捷的娱乐体验
  • 好的问卷设计标准:确保数据质量与准确性的关键要素
  • 【Spring实战】33 Spring Boot3 集成 Nacos 配置中心
  • Flink容错机制
  • 2024/1/28CSS学习:基础认知;选择器;文本样式
  • Android ViewPager2 同屏显示左右item
  • Qt实现类似ToDesk顶层窗口 不规则按钮
  • 【Java程序设计】【C00207】基于(JavaWeb+SSM)的宠物领养管理系统(论文+PPT)
  • 前端面试题-JavaScriptl原型,原型链?有什么特点?(2024.2.2)
  • 题目: 有1234个数字, 组成多个互不相同且无重复数字的三位数? 都是多少?
  • 【大数据技术攻关专题】「Apache-Flink零基础入门」手把手+零基础带你玩转大数据流式处理引擎Flink(基础加强+运行原理)