playing with ptrace(Part I) 之一 --- 初识ptrace

文章出处:http://www.linuxjournal.com/article/6100


ptrace --- 允许在用户层进行系统调用的拦截与修改


你是否想知道系统调用是如何被拦截的?

你是否尝试过通过修改系统调用的参数来愚弄内核?

你是否考虑过调试器是如何暂停运行中的进程并将控制权交给你的?


无需复杂的内核编程,ptrace( Process trace )系统调用就可以帮你实现上面的功能。

ptrace提供了一种机制,使得父进程能够观察并控制其他的进程,它可以检查和修改其他进程的内核映像,因此被优先用于实现断点调试和系统调用跟踪。

本文中将主要学习如何拦截系统调用并修改它的参数。在Part II中,将会学习到一些高级技巧 ---设置断点并向运行中的程序中注入代码。我们将会窥探子进程的寄存器及数据段,并修改其中的内容。我们也将讲述一种代码注入方法,使得进程可以停止并执行任意指令。


基础知识


系统调用( system call ) --- 系统调用是沟通应用层与内核之间的桥梁,应用程序通过系统调用可以访问底层硬件和下层服务(如:文件系统等)。当应用程序进行系统调用时,会将参数放入寄存器中并调用0x80软中断。该软中断就像是进入内核模式的一扇门,内核完成参数检查后就开始执行具体的操作了。

在i386体系架构上(本文中的代码都是基于i386架构),系统调用号被放在%eax寄存器中,而系统调用的参数则依次放在%ebx, %ecx, %edx, %esi%edi 寄存器中。

例如:

write( 2, "Hello", 5 );

翻译为汇编语言后大致为如下形式:

movl $4,%eax
movl $2,%ebx
movl $hello,%ecx
movl $5,%edx
int $0x80

其中,$hello指向字符串常量“Hello”.

那么,ptrace应该出现在什么位置呢?

在执行系统调用之前,内核会检查进程是否被跟踪( being traced ),若是,内核将暂停被跟踪进程,并将控制权交到跟踪进程,让跟踪进程可以修改被跟踪进程的寄存器。

下面让我们通过一个例子来看看进程是如何工作的:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>   /* For constants
                                   ORIG_EAX etc */
int main()
{   pid_t child;
    long orig_eax;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
        wait(NULL);
        orig_eax = ptrace(PTRACE_PEEKUSER,
                          child, 4 * ORIG_EAX,
                          NULL);
        printf("The child made a "
               "system call %ld\n", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}

:需要包含的头文件与具体的系统有关,比如在本人的机器上还需要包含<sys/reg.h>)

运行该程序,会打印出:

The child made a system call 11

一并输出的还有ls命令的执行结果。(系统调用号可以参考/usr/include/asm/unistd.h)

正如你所看到的,父进程fork出一个子进程,并在子进程中执行我们想要跟踪的过程( ls )。在运行exec之前,子进程先调用ptrace且其第一个参数为PTRACE_TRACEME.  这就告诉了内核该进程是一个被跟踪的进程,当它执行execve系统调用时,就会将控制权交到其父进程手中(父进程中通过wait()调用等待来自内核的通知),之后,父进程就可以检查系统调用的参数或者做些其他事情,如查看寄存器等。

系统调用发生时,内核将保存eax寄存器中的原始值(即系统调用号),将ptrace的第一个参数设为PTRACE_PEEKUSER,可以读到用户数据段的数值。

将ptrace的第一个参数设为PTRACE_CONT,可以让子进程中的系统调用继续执行。

ptrace 的参数

long ptrace( enum __ptrace_request request, 

pid_t pid,

void *addr,

void *data );

其中,第一个参数决定了ptrace的行为以及其他参数的使用方式,request的值可能是下列中的某一个:

PTRACE_TRACEME, 

PTRACE_PEEKTEXT, 

PTRACE_PEEKDATA, 

PTRACE_PEEKUSER, 

PTRACE_POKETEXT, 

PTRACE_POKEDATA, 

PTRACE_POKEUSER, 

PTRACE_GETREGS, 

PTRACE_GETFPREGS, 

PTRACE_SETREGS, 

PTRACE_SETFPREGS, 

PTRACE_CONT, 

PTRACE_SYSCALL, 

PTRACE_SINGLESTEP,

PTRACE_DETACH.

每个值的意义将在本文的余下部分中介绍。




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值