Open Source Linux Process Memory Kernel Management Module Source Code

Open Source Linux Process Memory Kernel Management Module Source Code

This article is an excellent piece from the Kanxue Forum.
Author from Kanxue ForumID: abcz316

Linux is an open-source kernel system. I am also very fond of embedded Linux systems, especially its kernel source code, which is written in a style that I really appreciate.

This driver was previously written during my spare time for an embedded development board, left over when lighting up an LED. The ioremap has been removed from the code now. However, for beginners, it still has learning value.

Open Source Linux Process Memory Kernel Management Module Source Code

The source code is for communication and learning purposes only and must not be used for illegal purposes.

To prevent malicious individuals from using this driver for illegal purposes, I will also provide detection suggestions later. If you are a game developer, you might consider my detection advice.

Next, I will analyze this driver with you to see how it is written.
Open Process Interface

In the Linux kernel, there is no distinction between processes and threads. They are uniformly treated as threads. Each thread has a corresponding pid_t, pid, and task_struct.

The relationship between them is as follows:

pid_t <–> struct pidnr is the process pid value
#include <linux/pid.h> pid_t pid_vnr(struct pid *pid){    return pid_nr_ns(pid, current->nsproxy->pid_ns);}EXPORT_SYMBOL_GPL(pid_vnr); struct pid *find_pid_ns(int nr, struct pid_namespace *ns);EXPORT_SYMBOL_GPL(find_pid_ns); struct pid *find_vpid(int nr){    return find_pid_ns(nr, current->nsproxy->pid_ns);}EXPORT_SYMBOL_GPL(find_vpid); struct pid *find_get_pid(int nr){    struct pid *pid;     rcu_read_lock();    pid = get_pid(find_vpid(nr));    rcu_read_unlock();     return pid;}EXPORT_SYMBOL_GPL(find_get_pid); void put_pid(struct pid *pid);EXPORT_SYMBOL_GPL(put_pid);  struct pid * –> struct task_struct *  #include <linux/pid.h> struct pid *get_task_pid(struct task_struct *task, enum pid_type);EXPORT_SYMBOL_GPL(get_task_pid); struct task_struct *pid_task(struct pid *pid, enum pid_type);EXPORT_SYMBOL(pid_task); struct task_struct *get_pid_task(struct pid *pid, enum pid_type){    struct task_struct *result;    rcu_read_lock();    result = pid_task(pid, type);    if (result)        get_task_struct(result);    rcu_read_unlock();    return result;}EXPORT_SYMBOL(get_pid_task); #include <linux/sched.h>#define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while (0)static inline void put_task_struct(struct task_struct *t){    if (atomic_dec_and_test(&t->usage))        __put_task_struct(t);} void __put_task_struct(struct task_struct *t);EXPORT_SYMBOL_GPL(__put_task_struct);

After reviewing the above logic, isn’t it a breath of fresh air? It’s clear that they can be converted into each other.

By using the process pid_t, you can obtain the pid, and from the pid, you can get the task_struct. Conversely, you can also obtain the process pid through task_struct.

Close Process Interface

The driver source code uses put_pid to decrease the usage count of the process pid* by 1.

You can see this in the Linux kernel source code under /kernel/pid.c:

void put_pid(struct pid *pid){    struct pid_namespace *ns;     if (!pid)        return;     ns = pid->numbers[pid->level].ns;    if ((atomic_read(&pid->count) == 1) ||         atomic_dec_and_test(&pid->count)) {        kmem_cache_free(ns->pid_cachep, pid);        put_pid_ns(ns);    }}EXPORT_SYMBOL_GPL(put_pid);
Read and Write Process Memory Interface

First, use get_pid_task to retrieve task_struct based on pid*. Then use get_task_mm to retrieve the mm_struct structure, which contains the memory information of the process. First, check if the memory is readable if (vma->vm_flags & VM_READ).

If it is readable, then start calculating the physical memory address. Since the Linux kernel has the MMU mechanism enabled by default, physical memory addresses can only be calculated in pages. There are many methods to calculate physical memory addresses.

For example, pagemap, pgd pud pmd pte, get_user_pages. The driver demonstrates pagemap.

Other methods can be referenced in the Linux kernel source code /fs/proc/task_mmu.c.

Once the physical memory address is known, reading and writing to the physical memory address is also demonstrated in the Linux kernel: drivers/char/mem.c. It is written in great detail. Finally, attention must be paid to the discrete memory of the MMU mechanism, i.e., the non-continuous buffer issue.

Get Process Memory Block List

This interface has no technical content; it simply copies the code from the Linux kernel source code, fs/proc/task_mmu.c.

The core idea is to retrieve mm_struct through task_struct, and then iterate through mm_struct to retrieve vma.

struct mm_struct {    struct vm_area_struct * mmap;        /* list of VMAs */    struct rb_root mm_rb;    struct vm_area_struct * mmap_cache;    /* last find_vma result */#ifdef CONFIG_MMU    unsigned long (*get_unmapped_area) (struct file *filp,                unsigned long addr, unsigned long len,                unsigned long pgoff, unsigned long flags);    void (*unmap_area) (struct mm_struct *mm, unsigned long addr);#endif    unsigned long mmap_base;        /* base of mmap area */    unsigned long mmap_legacy_base;         /* base of mmap area in bottom-up allocations */    unsigned long task_size;        /* size of task vm space */    unsigned long cached_hole_size;     /* if non-zero, the largest hole below free_area_cache */    unsigned long free_area_cache;        /* first hole of size cached_hole_size or larger */    unsigned long highest_vm_end;        /* highest vma end address */    pgd_t * pgd;    atomic_t mm_users;            /* How many users with user space? */    atomic_t mm_count;            /* How many references to "struct mm_struct" (users count as 1) */    int map_count;                /* number of VMAs */     spinlock_t page_table_lock;        /* Protects page tables and some counters */    struct rw_semaphore mmap_sem;     struct list_head mmlist;        /* List of maybe swapped mm's.    These are globally strung                         * together off init_mm.mmlist, and are protected                         * by mmlist_lock                         */      unsigned long hiwater_rss;    /* High-watermark of RSS usage */    unsigned long hiwater_vm;    /* High-water virtual memory usage */     unsigned long total_vm;        /* Total pages mapped */    unsigned long locked_vm;    /* Pages that have PG_mlocked set */    unsigned long pinned_vm;    /* Refcount permanently increased */    unsigned long shared_vm;    /* Shared pages (files) */    unsigned long exec_vm;        /* VM_EXEC & ~VM_WRITE */    unsigned long stack_vm;        /* VM_GROWSUP/DOWN */    unsigned long def_flags;    unsigned long nr_ptes;        /* Page table pages */    unsigned long start_code, end_code, start_data, end_data;    unsigned long start_brk, brk, start_stack;    unsigned long arg_start, arg_end, env_start, env_end;     unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
Get Process Command Line

The mm_struct structure contains a variable arg_start, which stores the address value of the process command line.

To prevent malicious individuals from using this driver for illegal purposes, here are detection suggestions:

1. Check if the file /dev/rwProcMem33 exists.
2. Check if SELinux is disabled. Since SELinux was enabled in Android 5.0, apps must disable SELinux to communicate with the driver. If SELinux is found to be disabled and it is a high version of Android, then this Android user must have issues.
There are many methods to detect SELinux, such as opening a certain file, ioctl, etc. If SELinux is enabled, these will directly return EACCES (Permission denied), indicating access is denied.
Additionally, in high versions of Android, such as Android 10, if SELinux is enabled, lsmod will also directly return Permission denied when checking the driver list. If lsmod can directly display the driver list, then the SELinux of this user is also problematic, possibly disabled.

Finally, here is the open-source address (including demo)

Github link: https://github.com/abcz316/rwProcMem33

Summary

First, compiling this source code requires some skills. Moreover, the phone itself has multiple barriers set during factory settings to prevent the loading of third-party drivers (even if you have root permissions, you cannot load), this source code is for communication and learning purposes only regarding the Linux system.

Open Source Linux Process Memory Kernel Management Module Source Code
– End –
Open Source Linux Process Memory Kernel Management Module Source Code

Kanxue ID:abcz316

https://bbs.pediy.com/user-892833.htm

* This is an original piece by Kanxue Forum abcz316, please indicate the source when reprinting from the Kanxue community.

Recommended Articles++++

Open Source Linux Process Memory Kernel Management Module Source Code

* glibc character encoding research

* TP-Link Archer router LAN RCE

* In-depth understanding of static variables

* KERNEL PWN state switching principle and KPTI bypass

* Building and breaking a brute-force target and experimental attack

Good Book RecommendationsOpen Source Linux Process Memory Kernel Management Module Source Code

Open Source Linux Process Memory Kernel Management Module Source Code
Official Account ID: ikanxue
Official Weibo: Kanxue Security
Business Cooperation: [email protected]

Leave a Comment