You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在内核模块中获取用户态程序SO库的基地址?

内核模块中获取用户态进程指定.so基地址的最优方式

一、内核原生遍历内存映射的高效方法

不需要依赖/proc文件系统,直接遍历目标进程的内存映射结构vm_area_struct——这是最直接高效的方式,毕竟/proc/[pid]/maps的内容本质就是从这些内核结构生成的。

实现步骤

  • 通过PID定位目标进程的task_struct,需用RCU锁避免进程退出导致的野指针问题。
  • 获取进程的内存管理结构mm_struct,并通过读锁保护内存映射链表的遍历。
  • 遍历mm->mmap链表中的每个vm_area_struct:
    1. 检查vm_file是否非空(说明该内存区域对应一个文件映射)。
    2. 通过file_path()获取映射文件的路径,与目标.so文件名精确匹配。
    3. 匹配成功后,vma->vm_start即为该.so在用户态的基地址。

代码示例

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/rculist.h>
#include <linux/string.h>

unsigned long get_target_so_base(pid_t target_pid, const char *target_so) {
    struct task_struct *task;
    struct mm_struct *mm;
    struct vm_area_struct *vma;
    char file_path[256];
    unsigned long so_base = 0;
    const char *filename;

    rcu_read_lock();
    // 通过PID查找进程task_struct
    task = pid_task(find_vpid(target_pid), PIDTYPE_PID);
    if (!task) {
        rcu_read_unlock();
        return 0;
    }

    // 获取进程的mm_struct,需调用mmput释放
    mm = get_task_mm(task);
    if (!mm) {
        rcu_read_unlock();
        return 0;
    }

    // 加读锁保护vma链表,防止并发修改
    down_read(&mm->mmap_sem);
    for (vma = mm->mmap; vma; vma = vma->vm_next) {
        if (vma->vm_file) {
            if (file_path(vma->vm_file, file_path, sizeof(file_path)) >= 0) {
                // 提取文件名(路径最后一个/之后的部分),避免子串匹配错误
                filename = strrchr(file_path, '/');
                if (filename && strcmp(filename + 1, target_so) == 0) {
                    so_base = vma->vm_start;
                    break;
                }
            }
        }
    }
    up_read(&mm->mmap_sem);
    mmput(mm);
    rcu_read_unlock();

    return so_base;
}

注意事项

  • 必须严格持有锁:RCU锁保护task_struct的访问,mmap_sem读锁保护内存映射链表的遍历,避免并发场景下的竞态问题。
  • 文件名匹配用strrchr提取路径末尾的文件名,比strstr更精确,防止误匹配包含目标so名的其他文件。

二、访问/proc/[pid]/maps的更优方式

如果一定要通过/proc路径实现,不要直接手动用kernel_read读取文件内容后解析,内核提供了更规范的接口:

  1. 使用filp_open打开/proc/[pid]/maps文件(权限设为O_RDONLY)。
  2. 通过kernel_read读取文件内容到内核缓冲区。
  3. 解析缓冲区内容,按照/proc/maps的格式(每行以地址区间开头,包含路径)提取目标so的基地址。

但这种方式本质是绕回了内核生成/proc/maps的逻辑,效率远低于直接遍历vm_area_struct,仅适合必须依赖/proc的特殊场景。

内容的提问来源于stack exchange,提问作者Parvo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:40:45