前言
运行时修改进程名以及命令行的方式以及检测手段,希望有所帮助。本文较长,建议先收藏,细细阅读。正文
mount -o bind /proc/pid这种方式能够实现进程隐藏。那么进程名&&命令行可以从/proc/pid的哪些文件字段中获取呢?用户态获取进程名&&命令行
strace追踪常用的查看进程信息的命令
open调用,发现涉及到进程名&&命令行的文件有三个:
stat、status、cmdline
/proc/[pid]/comm也是-
-
进程名:comm文件、stat文件的第二个字段、status文件的Name字段 -
命令行:cmdline文件
-
内核相关的数据结构
comm[TASK_COMM_LEN]变量。从源码来看,进程名是长度为16的不包含路径的可执行文件名,且最后一个字符为空字符,也就是说进程名的有效长度为15。当可执行文件名长度超过15后,进程名会进行截断处理。
comm[TASK_COMM_LEN]变量:
task_struct->mm_struct中的arg_start和arg_end,前者表示命令行参数的开始地址,后者表示结束地址,各参数之间以空字符分割,结尾也为空字符。修改进程名
PR_SET_NAME选项,可以用来设置进程的名称。例如如下代码:
int main() {
if (prctl(PR_SET_NAME, "shorter") != 0) {
perror("prctl(PR_SET_NAME)");
return 1;
}
sleep(120);
return 0;
}
修改命令行
int main(int argc, char *argv[]) {
char *new = "sshd -D";
// 设置进程名称
if (prctl(PR_SET_NAME, "shorter") != 0) {
perror("prctl(PR_SET_NAME)");
return 1;
}
int i;
size_t rsize=0;
for(i=0;i<argc;i++){
rsize+=strlen(argv[i])+1;
}
printf("rsize:%zu",rsize);
size_t nsize=strlen(new)+1;
if (nsize>rsize){
// 设置命令行
strncpy(argv[0],new,nsize+1);
}else{
strncpy(argv[0],new,rsize);
}
sleep(120);
return 0;
}
environ[i]指向新地址,确保通过
environ[i]还能访问到正确的环境变量;然后将之前命令行参数和环境变量的内存空间清空,写入修改后的命令行,最后再使用prctl来修改进程名。这种方式确实可以既能一定程度上随意修改命令行,也可以保证能够获取到正确的环境变量。但是也有一个弊端,就是这种方式并未修改mm_struct中的env_start以及env_end,所以/proc/pid/environ文件输出的内容可能会出现大批量的空字符。
PR_SET_MM选项的
PR_SET_MM_ARG_START以及
PR_SET_MM_ARG_END,来重新设置mm_struct命令参数的地址空间,但是只有特权用户才可以调用成功:
int main(int argc, char **argv) {
char * nm;
char cmd[] = "new_program --first-argv first --second-argv second";
size_t cmd_size=strlen(cmd);
nm = mmap(NULL, cmd_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
strncpy(nm, cmd, cmd_size);
prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nm, 0, 0);
prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nm + cmd_size + 1, 0, 0);
prctl(PR_SET_NAME,"NewProcName");
sleep(120);
return 0;
}
如何检测
select pid,name,path,cmdline from processes where path <>'' and not (path like concat('%/',name) and (cmdline like concat(name,'%') or cmdline like concat('%/',name,'%'))) and (cmdline not like concat('%',name,'%') or path <> replace(split(cmdline,' ',0),'./',concat(cwd,'/')));
总结
comm[TASK_COMM_LEN],通过prctl系统调用可进行修改。命令行也可以通过prctl调用修改,但是需要特权用户。也可以通过覆盖原始命令行的形式进行修改,但是如果长度超过原始命令行,会覆盖环境变量,导致应用环境变量获取错误。在最后笔者也分享了对应的osquery检测规则,但是由于很多正常进程都会存在一些相似行为,所以检测结果中存在一定的误报,需要人工二次确认。原文始发于微信公众号(风奕安全):Linux进程伪装(二):进程名&&命令行
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论