LINUX 3.5.4 PTRACE(系列三)

来源:互联网 发布:nginx 算是中间件吗 编辑:程序博客网 时间:2024/05/30 02:52

 

本系列文章将对ptrace系统调用的强大功能进行详细分析和验证,通过本系列文章,可以深入理解ptrace的实现原理和使用方法,之后编写自己的编译器就不在话下了。

我们首先以一个简单的例子作为入门。‘CTRL+C’这个快捷键我们再熟悉不过了。在正常情况下,我们向一个正常的进行发送‘CTRL+C’ 即SIGINT信号,程序就会停止运行。但是,如果我们在程序中加入ptrace系统调用之后,‘CTRL+C’这个信号就不能让进程终止(terminated),而是让进程暂停(stopped)。

程序一:

child1:

#include "ptrace.h"void main(){    ptrace(PTRACE_TRACEME,NULL,0,0);    while (1);}

本系列所有的头文件我们都在“ptrace.h”中定义

#include <sys/ptrace.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <sys/user.h>     /* For struct user_regs_sturct */#include <sys/syscall.h>    /* For SYS_write etc */#include <sys/reg.h> /* For constants ORI_EAX etc */
编译程序并运行

#gcc list1.c -o list1.o

#./list1.o

从上面的程序中我们可以看到,这个程序其实啥也没做,就是一个死循环,此时我们输入'CTRL+C'。然后查看进程的状态

#ps -ax

在linux中,进程的常用状态包括:

D 无法中断的休眠状态(通常 IO 的进程); 
R 正在运行,在可中断队列中; 
S 处于休眠状态,静止状态; 
T 停止或被追踪,暂停执行; 
W 进入内存交换(从内核2.6开始无效); 
X 死掉的进程; 
Z 僵尸进程不存在但暂时无法消除

如果程序中没有ptrace系统调用,则进程的状态为彻底结束,从而使用ps命令也看不出来。

我们都知道SIGINT信号的含义:程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

那么为什么同样是‘SIGINT’,进程的处理方式却不同了呢?

为了清除的了解究竟发生了什么,我们可以对进程停止的状态进行扑捉

list1.c

#include "ptrace.h"void main(){    pid_t child;    int status;    child=fork();    if(child==0){//child       // ptrace(PTRACE_TRACEME,0,NULL,NULL);         usleep(50);        //while(1) printf("hello!\n");     }   else{    //int status;    //printf("parent!,%d\n\n\n\n",child);    usleep(10);    kill(child,SIGINT);//send SIGINT to child    wait(&status);    if(WIFSTOPPED(status)){        printf("%d",WSTOPSIG(status));       fprintf(stderr,"%s",strsignal(WSTOPSIG(status)));       printf("\nstopped!\n");    }     else if(WIFEXITED(status)){        printf("%d",WEXITSTATUS(status));        fprintf(stderr,"%s",strsignal(WEXITSTATUS(status)));        printf("\eixted!\n");     }     else if(WIFSIGNALED(status)){         printf("%d",status);        fprintf(stderr,"%s",strsignal(WTERMSIG(status)));        printf("\nterminated!\n");      }      else         printf("error!\n");    ptrace(PTRACE_CONT,child,0,0);   }}
编译并运行结果如下所示:


而interrupt后面紧跟的数字“2”正好对应的是SIGINT信号。而WIFSIPPED我们以前也解释过了,只有当进程被ptrace调用监控的时候被信号停止/暂停才会为真。

通过上面的分析我们可以看到:由于子进程使用了ptrace调用使得子进程对SIGINT信号的处理不同了。

为了充分验证这一点,我们接下来再分析一下没有ptrace调用的效果。此时,只要child1中的ptrace系统调用注释掉就行了,在运行list1,看看结果:

从这里我们可以看到子进程同样是收到了SIGINT信号,然而子进程的处理方式却不同。显然此时是WIFSIGNALED(status)判断条件为真。说明子进程是因为收到SIGINT信号而退出了。

未完待续!




0 0