Linux 进程隐藏:初级隐藏篇

文摘   2024-11-11 13:52   上海  

/ Linux 进程隐藏:初级隐藏篇 /

   

前言

Linux 下查看进程信息的途径通常有以下几种方式

途径说明
top、ps 等命令通过 ps 及 top 命令查看进程信息时,只能查到相对路径,查不到的进程的详细信息,如绝对路径等。常用命令如下 ps -A 查看所有进程名称;ps -ef 接显示进程绝对路径及参数;ps -aux 显示所有用户进程状态,最后一列显示进程绝对路径及参数;top 命令 参考 http://c.biancheng.net/view/1065.html
/proc/pid/文件夹Linux 在启动一个进程时,系统会在/proc 下创建一个以 pid 命名的文件夹,在该文件夹下会有我们的进程的信息,其中包括一个名为 exe 的文件即记录了绝对路径,通过 ll 或 ls –l 命令即可查看。exe 实际运行程序的符号链接;cmdline 一个只读文件,包含进程的完整命令 ( https://www.linuxcool.com/ )行信息;comm 包含进程的命令名;cwd 进程当前工作目录的符号链接;status 进程状态信息,包含的信息多于 stat;stat 进程状态信息;cwd 进程当前工作目录的符号链接;latency 显示哪些代码造成的延时比较大;environ 记录了进程运行时的环境变量;fd 目录下是进程打开或使用的文件的符号连接。

初级隐藏篇介绍以下两种方式修改隐藏进程名

1. 通过修改进程argv[0]修改进程名
2. 通过Linux prctl修改进程名




   

一、通过修改进程 argv[0]修改进程名

优缺点:

优点是 ps -ef 、ps -aux 看不到进程名及参数了

缺点是这种方法仅仅是修改了/prco/pid/cmdline 的值,使用 ps -A 或者 top 命令还是可以看到进程名称

我们知道在一个程序中,参数的个数保存在 int 型 argc 中,参数保存在数组 argv[]中,数组的第一个元素 argv[0]保存的就是进程名,第二个元素 argv[1]保存的是第一个参数,依次类推。通过修改进程 argv[0]修改进程名,这一方法实现比较简单,我们只要在进程启动 mian 函数中修改掉 argv 数组所指向的内存空间的内容即可,这里需要注意的是 linux 中 main()还有一个隐藏参数就是环境变量信息,存放了运行时所需要的环境变量,

  1. 如果新名称比 argv[0]的长度小,我们可以直接修改,并把多余的部分请 0

  2. 如果新名称比 argv[0]长我们需要两步


  1. 申请新内存保存环境变量信息和 argv[1...argc-1]参数信息



  2. 修改 argv[0],将新名称往后到 environ 的最后一项清 0


以下示例代码仅仅是将 argv[]清空


Copy#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>int main(int argc, char **argv) {

printf("========== Before the modification ============\n"); printf("ProcessName: %s\n", argv[0]); for(int i = 1; i < argc; i ++){ printf("Argv%d: %s\n", i, argv[i]); }

/* Start the modification */ int new_argc = argc; char ** new_argv = malloc((argc+1) * sizeof(*new_argv)); for(int j = 0; j < argc; j++) { size_t length = strlen(argv[j]) + 1; new_argv[j] = malloc(length); memcpy(new_argv[j], argv[j], length); memset(argv[j], '\0', length); }

printf("========== After the modification ============\n"); printf("ProcessName: %s\n", argv[0]); for(int i = 1; i < argc; i ++){ printf("Argv%d: %s\n", i, argv[i]); }

printf("========== Copy data ============\n"); printf("ProcessName: %s\n", new_argv[0]); for(int k = 1; k < new_argc; k ++){ printf("Argv%d: %s\n", k, new_argv[k]); }

sleep(1000); return 0;}




   

二、通过 Linux prctl 修改进程名

优缺点:

优点是修改了/prco/pid/stat 及/prco/pid/status 中的进程名称,使用 ps -A 或者 top 命令看不到原来的进程名称

缺点是未修改/prco/pid/cmdline 的值,使用 ps -ef 、ps -aux 可以看到进程名称及参数

使用 prctl 修改进程名实现也比较简单,

看下面代码


Copy/*gcc changetitle.c -o changetitle*/#include <stdio.h>#include <sys/prctl.h>
int main(int argc, char *argv[], char *envp[]){ char *new_name = "1234567890abcdefg"; getchar(); prctl(PR_SET_NAME, new_name); getchar();



return 0;}


但是 prctl 修改的进程名,只能是 16 个字节(包括'\0’),当新名称长度大于 16 时就会截断,上面的新名字截断后是 1234567890abcde


ubuntu18@ubuntu:~/Desktop/change_processname$ ps -A | grep chang
ubuntu18@ubuntu:~/Desktop/change_processname$ ps -A | grep 1234
10764 pts/8 00:00:00 1234567890abcde
ubuntu18@ubuntu:~/Desktop/change_processname$ cat /proc/10764/stat
10764 (1234567890abcde) S 10709 10764 10709 34824 10764 4194304 69 0 0 0 0 0 0 0 20 0 1 0 14090125 4612096 197 18446744073709551615 94579895803904 94579895806128 140721599190352 0 0 0 0 0 0 1 0 0 17 0 0 0 0 0 0 94579897904560 94579897905168 94579902476288 140721599193924 140721599193938 140721599193938 140721599197162 0




   

三、两者方法相结合

我们可以发现,使用以上两种方法相结合,可以使得 ps -ef 、ps -aux 、ps -A 、top、/proc/pid/status、/proc/pid/cmdline 均看不到真实的进程信息;

看下面代码:


/*gcc changetitle.c -o changetitle*/#include <unistd.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <stdlib.h>#include <sys/prctl.h>

# define MAXLINE 2048

extern char **environ;

static char **g_main_Argv = NULL; /* pointer to argument vector */static char *g_main_LastArgv = NULL; /* end of argv */

void setproctitle_init(int argc, char **argv, char **envp){ int i;

for (i = 0; envp[i] != NULL; i++) // calc envp num continue; environ = (char **) malloc(sizeof (char *) * (i + 1)); // malloc envp pointer

for (i = 0; envp[i] != NULL; i++) { environ[i] = malloc(sizeof(char) * strlen(envp[i])); strcpy(environ[i], envp[i]); } environ[i] = NULL;

g_main_Argv = argv; if (i > 0) g_main_LastArgv = envp[i - 1] + strlen(envp[i - 1]); else g_main_LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);}

void setproctitle(const char *fmt, ...){ char *p; int i; char buf[MAXLINE];

extern char **g_main_Argv; extern char *g_main_LastArgv; va_list ap; p = buf;

va_start(ap, fmt); vsprintf(p, fmt, ap); va_end(ap);

i = strlen(buf);

if (i > g_main_LastArgv - g_main_Argv[0] - 2) { i = g_main_LastArgv - g_main_Argv[0] - 2; buf[i] = '\0'; } //修改argv[0] (void) strcpy(g_main_Argv[0], buf);

p = &g_main_Argv[0][i]; while (p < g_main_LastArgv) *p++ = '\0'; g_main_Argv[1] = NULL; //调用prctl prctl(PR_SET_NAME,buf);}

int main(int argc, char *argv[]){ char argv_buf[MAXLINE] = {0}; // save argv paramters int i;

for( i = 1; i < argc; i++) { strcat(argv_buf, argv[i]); strcat(argv_buf, " "); } //修改argv[0]所指向的内存空间的内容 setproctitle_init(argc, argv, environ); //调用prctl修改进程名 setproctitle("%s@%s %s", "12345678", "ip", argv_buf);

for (i = 0; environ[i] != NULL; i++) free(environ[i]); getchar();

return 0;}


但是这样还是有一定的局限性,比如说,ps、top 等命令还是能看见真实的 pid 信息,proc 文件夹下还是会生成相应的 pid 文件夹;最理想的情况应该是让我们的进程信息彻底消失,Linux 进程隐藏-中级隐藏篇将会进一步介绍更加高级的进程隐藏技术。



   

Relevant Link:

https://www.linuxprobe.com/linux-proc-pid.html

https://www.cnblogs.com/LittleHann/p/4991600.html

http://blog.chinaunix.net/uid-29482215-id-4120748.html

https://www.cnblogs.com/reuodut/articles/13711963.html

4

   

帮会双十一活动来啦,活动仅剩4

帮会领域:专注于 APT 框架、渗透测试、红蓝对抗等领


   

帮会内容覆盖

  1. 挖洞技巧和小 tips

  2. 挖洞实战项目案例内部分享

  3. 应急响应案例内部分享

  4. 不定时分享高质量小工具

  5. 可加入内部群进行攻防技术交流

  6. 团队内部师傅开发的小工具,优先体验新版本,还可和师傅提出 bug 获得奖励哦

  7. 有机会进入团队,成为正式成员,获得更多好处

  8. 私域信息安全图书馆

活动价格:15/月卡、39.9/季卡

9.9/月 20/季 79/永久

活动结束后将恢复原价


   

帮会私域信安图书馆

建立信息安全图书馆也有一段时间了,为大家准备了大量的资料,想学的时候,翻开那些你感兴趣的领域的资料看一看只要你需要,我们会尽可能的帮你寻找你感兴趣或者需要的资料。

Eonian Sharp
Eonian Sharp | 永恒之锋,专注APT框架、渗透测试攻击与防御的研究与开发,没有永恒的安全,但有永恒的正义之锋击破黑暗的不速之客。
 最新文章