In this article, without modifying any code of the PS or top command and setting the process number to 0, we can hide the process. This program is implemented on crux 2.2.
1. Principle
In Linux, you can access the internal information of many kernels through the/proc file system. The/proc file system was originally designed to easily access process-related information. Therefore, it is named Proc. Now, this file system is used to reflect all aspects of the system. For example,/proc/modules is the list of modules, And/proc/meminfo is the memory usage statistics. The directory in the/proc file system is not the persistent storage information, that is, its directory does not exist in the disk, but is dynamically generated during access.
In this project, we are interested in the process information in the/proc file system. Each process has a directory (/proc/<pid>) in the/proc file system, and the directory name is the process number. The self directory is a link pointing to the current process.
The ps command and the top command read and display process information from the/proc file system. Therefore, if the process number of a process is not reflected in the/proc file system, the process is "hidden, hidden processes are not output in PS or top commands.
2. Implementation
2.1 Add the variable hide for task_struct as follows: (include/Linux/sched. h)
Struct task_struct {<br/> unsigned did_exec: 1; <br/> pid_t PID; <br/> pid_t tgid; <br/>... (Omitted) <br/> char hide; (add this sentence in the last line) <br/>}
2.2 Where to modify proc code
In the Linux code tree, all file system code is stored in the Linux/fs/directory, where the original proc file system code is in Linux/fs/proc, the following describes the source files in the proc directory.
There are a total of 11 related files in the directory:
Procfs_syms.c inode. c generic. C base. c
Array. c root. c proc_tty.c proc_misc.c
Kmsg. c kcore. c proc_devtree.c
How can we find so many files? Learn from the information on the Internet and find the files:
Among them, procfs_syms.c, generic. C and inode. C are related to the management of proc file systems, including proc file system registration and routines provided to other subsystems in the kernel.
The management of the root nodes of the source file root. C and proc file systems is related.
Base. C and array. C are used to process the process information in the/proc directory, including the command line, Process status, memory status, and other process-related content. Proc_tty.c is used to process/proc/tty information, and proc_misc.c is used to manage most files in the/proc directory.
In addition, there are two very important header files proc_fs.h and proc_fs_ I .h, which can be found in the/Linux/include/Linux/directory.
At the same time, the most important thing is that we have determined the information we need in the base. in the c file, it is mainly between the two functions: proc_pid_readdir, proc_task_readdir. But which function is it? Because there is very little information on the Internet, you cannot try it one by one. View the source code of the two books:
NT proc_pid_readdir (struct file * filp, void * dirent, filldir_t filldir) <br/>{< br/> unsigned int tgid_array [proc_maxpids]; <br/> char Buf [proc_numbuf]; <br/> unsigned int Nr = filp-> f_pos-first_process_entry; <br/> unsigned int nr_tgids, I; <br/> int next_tgid; <br/> If (! NR) {<br/> ino_t ino = fake_ino (0, proc_tgid_ino); <br/> If (filldir (dirent, "self", 4, filp-> f_pos, Ino, dt_lnk) <0) <br/> return 0; <br/> filp-> f_pos ++; <br/> Nr ++; <br/>}< br/>/* f_version caches the tgid value that the last readdir call couldn't <br/> * return. lseek aka telldir automagically resets f_version to 0. <br/> */<br/> next_tgid = filp-> f_version; <br/> filp-> f_version = 0; <br/> (;;){ <Br/> nr_tgids = get_tgid_list (NR, next_tgid, tgid_array); <br/> If (! Nr_tgids) {<br/>/* No more entries! */<Br/> break; <br/>}< br/> next_tgid = 0; <br/>/* do not use the last found PID, reserve it for next_tgid */<br/> If (nr_tgids = proc_maxpids) {<br/> nr_tgids --; <br/> next_tgid = tgid_array [nr_tgids]; <br/>}< br/> for (I = 0; I <nr_tgids; I ++) {<br/> int tgid = tgid_array [I]; <br/> ino_t ino = fake_ino (tgid, proc_tgid_ino); <br/> unsigned long J = proc_numbuf; <br/> DO <br/> Buf [-- J] = '0' + (tgid % 10); <br /> While (tgid/= 10 )! = 0); <br/> If (filldir (dirent, BUF + J, PROC_NUMBUF-j, filp-> f_pos, Ino, dt_dir) <0) {<br/>/* returning this tgid failed, save it as the first <br/> * pid for the next readir call */<br/> filp-> f_version = tgid_array [I]; <br/> goto out; <br/>}< br/> filp-> f_pos ++; <br/> Nr ++; <br/>}< br/> out: <br/> return 0; <br/>}< br/>
/* For the/proc/tgid/task/directories */<br/> static int proc_task_readdir (struct file * filp, void * dirent, filldir_t filldir) <br/>{< br/> unsigned int tid_array [proc_maxpids]; <br/> char Buf [proc_numbuf]; <br/> unsigned int nr_tids, I; <br/> struct dentry * dentry = filp-> f_dentry; <br/> struct inode * inode = dentry-> d_inode; <br/> int retval =-enoent; <br/> ino_t ino; <br/> unsigned long Pos = filp-> F_pos;/* avoiding "long" filp-> f_pos */<br/> If (! Pid_alive (proc_task (inode) <br/> goto out; <br/> retval = 0; <br/> switch (POS) {<br/> case 0: <br/> ino = inode-> I _ino; <br/> If (filldir (dirent ,". ", 1, POs, Ino, dt_dir) <0) <br/> goto out; <br/> POS ++; <br/>/* fall through */<br/> case 1: <br/> ino = parent_ino (dentry); <br/> If (filldir (dirent, ".. ", 2, POs, Ino, dt_dir) <0) <br/> goto out; <br/> POS ++; <br/>/* fall through */<br/>}< br/> nr_tids = G Et_tid_list (Pos, tid_array, inode); <br/> inode-> I _nlink = POS + nr_tids; <br/> for (I = 0; I <nr_tids; I ++) {<br/> unsigned long J = proc_numbuf; <br/> int tid = tid_array [I]; <br/> ino = fake_ino (TID, proc_tid_ino ); <br/> DO <br/> Buf [-- J] = '0' + (TID % 10); <br/> while (TID/= 10 )! = 0); <br/> If (filldir (dirent, BUF + J, PROC_NUMBUF-j, POs, Ino, dt_dir) <0) <br/> break; <br/> POS ++; <br/>}< br/> out: <br/> filp-> f_pos = Pos; <br/> return retval; <br/>
Through observation, we can boldly guess that the filldir () function is to add the <pid> directory function to/proc. We can make an experiment, that is, in filldir () next, add a filldir () function. In this way, a process has two directories under the/proc directory. At the same time, PS-Ax displays two for the same process.
Compile the kernel after modification:
CD/usr/src/Linux-<version number>
Make bzimage
Cp arch/i386/boot/bzimage/boot/vmlinuz-0.1
CP system. MAP/boot/system. Map-0.1
Modify grub and add corresponding startup items for the modified kernel.
Vim/boot/GRUB/menu. lst
Reboot restarts. After the restart, select the crux_test option and use the modified kernel,
Input PS-ax or view the/proc file will show the result we guessed in advance. At the same time, after verification, we can see that PS, top command calls proc_pid_readdir function, rather than proc_task_readdir function. Hey, here we will find the New World!
2.3 How to modify proc
From 2.2, we need to modify the function in proc_pid_readdir, read the relevant code carefully, we only need to in if (filldir (dirent, BUF + J, PROC_NUMBUF-j, filp-> f_pos, Ino, dt_dir) <0) determine whether a process is set to hidden. Before that, obtain the task_struct of the process. The specific code is as follows (the added code is included in the comment):
Int proc_pid_readdir (struct file * filp, void * dirent, filldir_t filldir) <br/>{< br/> unsigned int tgid_array [proc_maxpids]; <br/> char Buf [proc_numbuf]; <br/> unsigned int Nr = filp-> f_pos-first_process_entry; <br/> unsigned int nr_tgids, I; <br/> int next_tgid; <br/> task_t * task; // declare a task_struct. <br/> If (! NR) {<br/> ino_t ino = fake_ino (0, proc_tgid_ino); <br/> If (filldir (dirent, "self", 4, filp-> f_pos, Ino, dt_lnk) <0) <br/> return 0; <br/> filp-> f_pos ++; <br/> Nr ++; <br/>}< br/>/* f_version caches the tgid value that the last readdir call couldn't <br/> * return. lseek aka telldir automagically resets f_version to 0. <br/> */<br/> next_tgid = filp-> f_version; <br/> filp-> f_version = 0; <br/> (;;){ <Br/> nr_tgids = get_tgid_list (NR, next_tgid, tgid_array); <br/> If (! Nr_tgids) {<br/>/* No more entries! */<Br/> break; <br/>}< br/> next_tgid = 0; <br/>/* do not use the last found PID, reserve it for next_tgid */<br/> If (nr_tgids = proc_maxpids) {<br/> nr_tgids --; <br/> next_tgid = tgid_array [nr_tgids]; <br/>}< br/> for (I = 0; I <nr_tgids; I ++) {<br/> int tgid = tgid_array [I]; <br/> ino_t ino = fake_ino (tgid, proc_tgid_ino); <br/> unsigned long J = proc_numbuf; <br/> // obtain the PID of the Process <br/> task = find_task_by_pid (Tgid); <br/> DO <br/> Buf [-- J] = '0' + (tgid % 10 ); <br/> while (tgid/= 10 )! = 0); </P> <p> printk (kern_debug "PID: % d, hide: % d/N", task-> PID, task-> hide ); <br/> // determine whether the process is hidden <br/> If (task! = NULL & task-> hide = 0) <br/>{< br/> printk (kern_debug "task: % d No hide/N ", task-> PID); <br/> If (filldir (dirent, BUF + J, PROC_NUMBUF-j, filp-> f_pos, Ino, dt_dir) <0) {<br/>/* returning this tgid failed, save it as the first <br/> * pid for the next readir call */<br/> filp-> f_version = tgid_array [I]; <br/> goto out; <br/>}< br/> filp-> f_pos ++; <br/> Nr ++; </P> <p >}< br/> out: <br/> return 0; <br/>}
In addition, you need to add the initialization hide code in the copy_process () function of kernel/fork. C (although not necessary, add it to ensure the logic)
... Omitted... <br/> If (p-> binfmt &&! Try_module_get (p-> binfmt-> module) <br/> goto bad_fork_cleanup_put_domain; <br/> P-> did_exec = 0; <br/> copy_flags (clone_flags, P ); <br/> P-> pid = PID; <br/> P-> hide = 0; <br/> retval =-efault; <br/>... omitted...
Recompile the kernel
2.4 Add a system call
In order to verify the kernel code modified by 2.3, we need to add the corresponding system call and set the hide of task_struct. Therefore, we add two system calls and modify them as follows:
2.4.1 Add source code to kernel/sys. c
Asmlinkage long sys_hide () <br/>{< br/> If (current-> hide = 1) <br/> return-efault; <br/> else <br/> current-> hide = 1; <br/> return 0; <br/>}< br/> asmlinkage long sys_unhide () <br/>{< br/> If (current-> hide = 0) <br/> return-efault; <br/> else <br/> current-> hide = 0; <br/> return 0; <br/>}
2.4.2 include/asm-i386/unistd. h add system call number and total number of system calls
# DEFINE _ nr_inotify_add_watch292 <br/> # DEFINE _ detail <br/> # DEFINE _ nr_hide 294 <br/> # DEFINE _ nr_unhide 295 <br/> # define nr_syscils 296 // total number of system calls
2.4.3 ARCH/i386/kernel/syscall_table.s
. Long sys_hide <br/>. Long sys_unhide
2.4.4 add function declaration in include/Linux/syscils. H (it seems this is dispensable)
Asmlinkage long hide (); <br/> asmlinkage long unhide ();
Now, the system call is added and the kernel is re-compiled.
3 Test
We have compiled a test function to check whether the modified kernel is successful. The Code hide. C is as follows:
<Br/> # include <stdio. h> <br/> # include <sys/types. h> <br/> # include <Linux/unistd. h> <br/> # DEFINE _ nr_hide 294 <br/> # DEFINE _ nr_unhide 295 <br/> int main (INT argc, char ** argv) <br/>{< br/> int I = 0; <br/> printf ("original/N"); <br/> system ("Ps "); <br/> int I = syscall (_ nr_hide); // call a system call whose system number is 294 <br/> printf ("Hide:/N "); <br/> system ("Ps"); <br/> I = syscall (_ nr_unhide); <br/> printf ("unhide:/N "); <br/> system ("Ps"); <br/> return 0; <br/>}< br/>
Run./hide after GCC hide. C-o hide and check the result.
The test is successful. The process is hidden!
4. Conclusion
This is just a way to implement hiding. One thing I can see on the Internet is to intercept system calls. What I previously thought was to intercept interruptions and directly modify the interruptions. This is to be verified, if you have the opportunity to implement it in the future, we will post it to share it with you.
It took me 6 to 7 hours to complete the program from the beginning, but it was not difficult to say. The number of modifications to the kernel code was very small. The key to the problem was to find out where to modify the code, this problem was found only when I checked the information and made an experiment.
[] Has been implemented by intercepting the system call hidden process way, share with you: http://blog.csdn.net/billpig/archive/2011/02/20/6196163.aspx
All rights reserved. For more information, see the source!