您的位置:首页 > 运维架构 > Linux

linux下修改进程名称

2014-09-15 21:10 495 查看
在编写网络服务器程序时,为了响应客户端的请求,我们经常需要新建进程来处理业务流程;而且又是为了关闭某个非法请求或者关闭长连接的客户端,这时就需要杀死进程 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):

点击(此处)折叠或打开

#include <stdio.h>

#include <sys/prctl.h>

int main(int argc, char *argv[], char *envp[])

{

char *new_name = "abcdefghijklmnopqrstuvwxyz";

getchar();

prctl(PR_SET_NAME, new_name);

getchar();

return 0;

}

当新名称长度大于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()还有一个隐藏参数就是环境变量信息,存放了运行时所需要的环境变量。

我们可以通过以下来访问这个变量

点击(此处)折叠或打开

extern char **environ;

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

点击(此处)折叠或打开

#include <stdio.h>

#include <string.h>

extern char **environ;

int main(int argc , char *argv[])

{

int i;

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

for (i = 0; i < argc; ++i)

{

printf("argv[%d](0x%x):%s\n" , i , (unsigned int)argv[i], argv[i]);

}

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

return 0;

}

通过上面可以看出,我们只需要修改argv[0]所指向的内存空间的内容,就可以修改进程名。但是如果新名称比argv[0]的长度小,我们可以直接修改,并把多余的部分请0,如果新名称

比argv[0]长我们需要两步:

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

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

以下是参考代码:

点击(此处)折叠或打开

#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';

}

(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(PR_SET_NAME,buf);

}

int main(int argc, char *argv[])

{

char argv_buf[MAXLINE] = {0}; // save
argv paramters

for(int i = 1; i < argc; i++)

{

strcat(argv_buf, argv[i]);

strcat(argv_buf, " ");

}

setproctitle_init(argc, argv, environ);

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

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

free(environ[i]);

getchar();

return 0;

}

上面的代码使用了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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: