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