- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
监视嵌入式系统内进程间通信的技术原理
traced_process = atoi(argv[1]); /* 从命令行得到监视进程的PID */
ptrace(PTRACE_ATTACH, traced_process, NULL, NULL);
wait(&status); /* 等待被监视进程状态变化 */
ptrace(PTRACE_SYSCALL, traced_process, NULL, NULL);
参数为 PTRACE_ATTACH 的 ptrace 对被监视进程在内核中的进程结构进行修改。使被监视进程成为当前程序的子进程。一旦被监视进程的状态发生变化, wait() 将返回。程序再次调用 ptrace 。这次的参数为 PTRACE_SYSCALL 。被监视进程的进程结构再次被修改,其 trace 标志被激活。内核将在被监视进程的每一次系统调用时,触发当前程序的运行。
While (1) {
/* 等待被监视程序调用系统调用或是发生其它状态变化 */
wait(&status);
/* 如果被监视进程退出,函数返回真。程序退出 */
if ( WIFEXITED(status) )
break;
ptrace(PTRACE_GETREGS, traced_process, 0, &u_in);
if (u_in.orig_eax == 102 && u_in.ebx == SYS_SENDTO) {
if (syscall_entry == 0) { /* syscall entry */
insyscall = 1;
printf("call sendto()n");
}
else { /* Syscall exit */
Syscall_entry = 0;
}
}
ptrace(PTRACE_SYSCALL, traced_process, NULL, NULL);
} /* while */
return 0;
} /* main */
被监视进程的 trace 标志被激活后,它的每一次系统调用都会被内核检查。我们程序也随之被内核用信号通知。使用参数 PTRACE_GETREGS 的 ptrace() 将获得截获的系统调用的参数。最重要的参数是系统调用号。它保存在了 u_in.orig_eax 中。通过系统调用号,我们可以确定发生的是那一个系统调用。系统调用号可以在 Linux 的源代码中查找。它的定义在 Linux-source-2.6.xx/arch/x86/kernel/syscall_table_32.S 中。它的部分代码如下所示:
.long sys_fstatfs /* 100 */
.long sys_ioperm
.long sys_socketcall
.long sys_syslog
在这里,我们最关心的是 sendto 系统调用。在 Linux 的内核中, sendto 的真实入口是 socketcall 系统调用。它是 bind , sendto 等socket相关系统调用的入口。在这个系统调用中,通过一个 call number 来区分出 bind , sendto 等不同的子系统调用。在我们的程序中,这个 call number 保存在 u_in.ebx 中。 从上面的 syscall_table_32.S 示例代码就可以看出, socketcall 的系统调用号是102(从100向下数两行)。而 call number 则在 net.h 有定义,我们关心的 sendto 的 call number 被定义为 SYS_SENDTO ,其绝对值为11。有了这两个重要的数据,我们的程序据此判断当前发生的系统调用是否为 sendto 。这一点表现为代码:
if (u_in.orig_eax == 102 && u_in.ebx == SYS_SENDTO)
被监视进程进入系统调用和退出系统调用时,都会触发 wait() 返回,使我们的程序有机会运行。因此,我们需要使用 syscall_entry 来记录当前时刻是被监视进程进入系统调用,还是退出系统调用。这是一个开关量,非常容易理解。 最后,每次处理完,都需要再次调用参数为 PTRACE_SYSCALL 的 ptrace ,准备监视下一次的系统调用。
上面的程序虽然很简单,但已经可以完整的表现出利用 ptrace 截获被监视进程的 sendto 系统调用的过程。值得补充一点的是,利用 ptrace 也可以获得 sendto 向外发送的数据。
来源:21IC电子网
上一篇:基于功率分配的H.264空时编码方案
下一篇:多路独立供电的半桥变换器的设计