Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149807
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 145
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-12 15:27
个人简介

文章分类

全部博文(14)

文章存档

2014年(14)

分类: LINUX

2014-02-25 11:05:59

    在编写网络服务器程序时,为了响应客户端的请求,我们经常需要新建进程来处理业务流程;而且又是为了关闭某个非法请求或者关闭长连接的客户端,这时就需要杀死进程 killall  proc_name。 但是在新建进程时,子进程名与父进程名相同。因此需要由进程名及参数来区分客户端连接。
   在linux中prctl可以满足这个要求,下满是man手册:
      PR_SET_NAME (since Linux 2.6.9)
              Set the process name for the calling process, using the value in
              the location pointed to by (char *) arg2.  The name can be up to
              16  bytes  long,  and  should  be null terminated if it contains
              fewer bytes.
    但是prctl修改的进程名,只能是16个字节(包括'\0')。下面是修改的代码(changetitle.c):

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/prctl.h>

  3. int main(int argc, char *argv[], char *envp[])
  4. {
  5.     char *new_name = "abcdefghijklmnopqrstuvwxyz";
  6.     
  7.     getchar();
  8.     prctl(PR_SET_NAME, new_name);
  9.     getchar();

  10.     return 0;
  11. }
    当新名称长度大于16时就会截断,上面的新名字截断后是abcdefghijklmno。这对于我们来说是有缺陷的。而且通过ps -aux 查看,进程名称并没有改变,改变的只是/prco/$(PID)/stat和
/prco/$(PID)/status的值,而/prco/$(PID)/cmdline并没有改变。这种方式使用起来也是不方便的。
   下面介绍另一种方式,可以与上面的方式互补。
    首先看一下main函数的原型:int main(int argc, char *argv[]);
        argv[0]存放的是终端执行的程序名称也就是进程名。argv[1...argc-1]存放的是命令行参数。
        linux中main()还有一个隐藏参数就是环境变量信息,存放了运行时所需要的环境变量。
        我们可以通过以下来访问这个变量

点击(此处)折叠或打开

  1. extern char **environ;
      argv与environ是连续存放在栈区的。下面代码可以查看参数信息:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>

  3. extern char **environ;
  4. int main(int argc , char *argv[])
  5. {
  6.     int i;

  7.     printf("argc:%d\n" , argc);

  8.     for (i = 0; i < argc; ++i)
  9.     {
  10.         printf("argv[%d](0x%x):%s\n" , i , (unsigned int)argv[i], argv[i]);
  11.     }

  12.     printf("evriron=0x%x\n" , (unsigned int)environ[0]);

  13.     return 0;
  14. }
        通过上面可以看出,我们只需要修改argv[0]所指向的内存空间的内容,就可以修改进程名。但是如果新名称比argv[0]的长度小,我们可以直接修改,并把多余的部分请0,如果新名称
比argv[0]长我们需要两步:
            1、申请新内存保存环境变量信息和argv[1...argc-1]参数信息
            2、修改argv[0],将新名称往后到environ的最后一项清0
        以下是参考代码:

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sys/prctl.h>

  7. # define MAXLINE 2048

  8. extern char **environ;

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

  11. void setproctitle_init(int argc, char **argv, char **envp)
  12. {
  13.     int i;

  14.     for (i = 0; envp[i] != NULL; i++) // calc envp num
  15.         continue;
  16.     environ = (char **) malloc(sizeof (char *) * (i + 1)); // malloc envp pointer
  17.     
  18.     for (i = 0; envp[i] != NULL; i++)
  19.     {
  20.         environ[i] = malloc(sizeof(char) * strlen(envp[i]));
  21.         strcpy(environ[i], envp[i]);
  22.     }
  23.     environ[i] = NULL;

  24.     g_main_Argv = argv;
  25.     if (i > 0)
  26.       g_main_LastArgv = envp[i - 1] + strlen(envp[i - 1]);
  27.     else
  28.       g_main_LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
  29. }

  30. void setproctitle(const char *fmt, ...)
  31. {
  32.     char *p;
  33.     int i;
  34.     char buf[MAXLINE];

  35.     extern char **g_main_Argv;
  36.     extern char *g_main_LastArgv;
  37.     va_list ap;
  38.     p = buf;

  39.     va_start(ap, fmt);
  40.     vsprintf(p, fmt, ap);
  41.     va_end(ap);

  42.     i = strlen(buf);

  43.     if (i > g_main_LastArgv - g_main_Argv[0] - 2)
  44.     {
  45.         i = g_main_LastArgv - g_main_Argv[0] - 2;
  46.         buf[i] = '\0';
  47.     }
  48.     (void) strcpy(g_main_Argv[0], buf);

  49.     p = &g_main_Argv[0][i];
  50.     while (p < g_main_LastArgv)
  51.         *p++ = '\0';
  52.     g_main_Argv[1] = NULL;

  53.     prctl(PR_SET_NAME,buf);
  54. }

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

  58.     for(int i = 1; i < argc; i++)
  59.     {
  60.         strcat(argv_buf, argv[i]);
  61.         strcat(argv_buf, " ");
  62.     }

  63.     setproctitle_init(argc, argv, environ);

  64.     setproctitle("%s@%s %s", "new_name", "ip", argv_buf);

  65.     for (int i = 0; environ[i] != NULL; i++)
  66.         free(environ[i]);
  67.     getchar();

  68.     return 0;
  69. }
      上面的代码使用了prctl和修改argv[0]两种修改方法的结合,通过ps -a 、 ps -ef  、ps -aux、 top 等等命令都只能查询到新进程名,/proc/$PID/ 下的文件也显示了新进程名的信息。
      应用场景:
         1、标识父子进程名称,防止被误杀
         2、构造假的进程名及参数,引导非法进入人员到蜜罐系统,取证


阅读(21017) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~