linux下修改进程名称

在编写网络服务器程序时,为了响应客户端的请求,我们经常需要新建进程来处理业务流程;而且又是为了关闭某个非法请求或者关闭长连接的客户端,这时就需要杀死进程 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 (= 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 (= 0; envp[i] != NULL; i++) // calc envp num
  15.         continue;
  16.     environ = (char **) malloc(sizeof (char *) * (+ 1)); // malloc envp pointer
  17.     
  18.     for (= 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 (> 0)
  26.       g_main_LastArgv = envp[- 1] + strlen(envp[- 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 (> 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 (< 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、构造假的进程名及参数,引导非法进入人员到蜜罐系统,取证
第二种办法:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/prctl.h>
#ifndef PR_SET_NAME
#define PR_SET_NAME 15
#endif
#ifndef PR_GET_NAME
#define PR_GET_NAME 16
#endif
static char *arg_start;
static char *arg_end;
static char *env_start;
void init_proc_title(int argc, char **argv) {
	int i;
	arg_start = argv[0];
	arg_end = argv[argc-1] + strlen(argv[argc-1])+1;
	env_start = environ[0];
	for(i=0; i<argc; i++)
		argv[i] = strdup(argv[i]);
}
void set_proc_title(const char *title) {
		int tlen = strlen(title)+1;
	int i;
	char *p;
	if(arg_end-arg_start < tlen && env_start==arg_end) {
		char *env_end = env_start;
		for(i=0; environ[i]; i++) {
		if(env_end == environ[i]) {
			env_end = environ[i] + strlen(environ[i]) + 1;
			environ[i] = strdup(environ[i]);
		} else
			break;
		}
		arg_end = env_end;
		env_start = NULL;
	}
	i = arg_end - arg_start;
	if(tlen==i) {
		strcpy(arg_start, title);
	} else if(tlen < i) {
		strcpy(arg_start, title);
		memset(arg_start+tlen, 0, i-tlen);
			// 1、当要更改的进程名称串比原始进程名称串短时,填充argv[0]字段时,改为填充argv[0]区的后段,前段填充0
			memset(arg_start,0,i);
			strcpy(arg_start + (i - tlen),title);
	} else {
		*(char *)mempcpy(arg_start, title, i-1) = '\0';
	}
	if(env_start) {
		p = strchr(arg_start, ' ');
		if(p) *p = '\0';
	}
}
void set_proc_name(const char *name) {
	prctl(PR_SET_NAME, name);
}
void get_proc_name(char *name) {
	prctl(PR_GET_NAME, name);
}
int main(int argc,char* argv[])
{
	char buf[1024]="stamhe";
	init_proc_title(argc,argv);
	set_proc_title(buf);
	set_proc_name(buf);
	while(1)
		;
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值