多进程保护实现

下面代码已经详细的注释了双进程下如何父进程和子进程双向保护(代码仅阐述了原理实现过程),多进程原理相同,需处理多个进程信号

void AttachAllThread(int pid)
{
	DIR* dir;
	struct dirent *direntp;
	char szTaskDir[0xFF] = { 0, };
	
    sprintf(szTaskDir, "/proc/%d/task", pid);
    
    //获取父进程的所有线程
	dir = opendir(szTaskDir);

	if (dir != NULL)
	{
		int nTmpIndex = 0;
		while ((direntp = readdir(dir)) != NULL)
		{
			if (direntp->d_name[0] != '.' && strlen(direntp->d_name) > 1)
			{
				int tid = atoi(direntp->d_name);
       
                //附加
				int attachret = ptrace(PTRACE_ATTACH, tid, 0, 0);

				if (attachret == 0)
				{
					int status = 0;
					int waitval = waitpid(tid, &status, __WALL);

					if (WIFSTOPPED(status) && ((status + 1) & 0x7F) <= 1 && waitval == tid)
					{
                        //这里设置选项,接受父进程创建线程的信号
						ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)(PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK));

						int contret = ptrace(PTRACE_CONT, tid, 0, 0);
						if (contret != 0)
						{
							LOGE("[*]ERROR: Continue Error:(TID:%d,ERR:%s)", tid, strerror(errno));
						}
					}
					else
					{
						LOGE("[*]ERROR: Waitpid Error:(%s)", strerror(errno));
					}
				}
				else
				{
					LOGE("[*]ERROR: Attach Process Error:(%s)", strerror(errno));
				}
			}
		}
		closedir(dir);
	}
}


int main()
{
    int nProtectPid = fork();
    if (nProtectPid >= 0)
    {
        //子进程
        if (nProtectPid == 0)
        {
            //附加父进程的所有线程
            AttachAllThread(getppid());
            
            while (1)
            {
                int status = 0;
                
                //等待父进程产生的信号
                int pid = waitpid(-1, &status, __WALL | WUNTRACED);
                int signo =  WSTOPSIG(status);

                if (pid < 0)//收到错误信号时 
                {
                    exit(0);
                }

                //收到父进程退出信号,子进程也退出
                if ((WIFSIGNALED(status) || WIFEXITED(status)) && (pid == nProtectPid ))
                {
                    kill(nProtectPid, SIGKILL);
                    exit(0);
                }
                //收到暂停信号时,线程继续执行,阻止其暂停
                else if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP)
                {
                    LOGD("[*]INFO: SIG Stop Thread:(TID=%d)", pid);
                    ptrace(PTRACE_CONT, pid, NULL, NULL);
                }
                //收到创建线程返的信号
                /*
                    这里有一点问题是,在某保护中实现对这段信号处理有判断,猜测是创建线程是会收到两次信号,某保护会对其只处理一次。
                    (维护了一个数组,若数组中存在PID,则从数组中删除,若不存在,则处理并添加到数组中)
                    下面参考链接中也是同样判断逻辑(通过hlist维护),目前实际实现中没有遇到这个问题
                    ref:https://github.com/majek/dump/blob/master/ptrace/trace.c
                */
                else if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
                { 			
                    int lastStatus = (status >> 16) & 0xffff;
                    
                    //通过exec创建的线程,解除附加并暂停
                    if (lastStatus == PTRACE_EVENT_EXEC)
                    {
                        ptrace(PTRACE_DETACH, pid, NULL, NULL);
                        kill(pid, SIGSTOP);
                    }
                    
                    //通过fork/vfork/clone创建的线程
                    else
                    {
                        //获取创建的线程PID
                        pid_t new_pid;
                        if (ptrace(PTRACE_GETEVENTMSG, pid, 0, &new_pid) >= 0)
                        {
                            //这里可以对新创建的线程进行操作
                            
                            //恢复主线程
                            ptrace(PTRACE_CONT, pid, 0, 0);
                            continue;
                        }
                    }
                    ptrace(PTRACE_CONT, pid, 0, signo);
                }
                else
                {
                    //不被处理的信号,信号交还给父进程进行处理
                    ptrace(PTRACE_CONT, pid, NULL, signo);
                }		
            }
        }
        else
        {
            //父进程
            while (nProtectPid >= 0)
            {
                int status = 0;
                //等待子进程产生的信号
                if (waitpid(nProtectPid, &status, __WALL | WUNTRACED) >= 0)
                {
                    //收到子进程退出的信号,父进程也退出
                    if (WIFSIGNALED(status) || WIFEXITED(status))
                    {
                        kill(nProtectPid, SIGKILL);
                        exit(0);
                    }
                    //子进程被暂停时,继续其运行,阻止其暂停
                    if (WIFSTOPPED(status))
                    {
                        kill(nProtectPid, SIGCONT);
                    }
                }
            }
        }
    }
}

posted on 2018-10-30 19:10  GeT1t  阅读(475)  评论(0编辑  收藏  举报

导航