[转载]playing with ptrace(Part I) 之一 --- 初识ptrace

本文转载自: http://blog.csdn.net/ixidof/article/details/7673568

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) PTRACE_TRACEME

形式:ptrace(PTRACE_TRACEME,0 ,0 ,0)

描述:本进程被其父进程所跟踪。其父进程应该希望跟踪子进程。

2) PTRACE_PEEKTEXT, PTRACE_PEEKDATA

形式:ptrace(PTRACE_PEEKTEXT, pid, addr, data)

ptrace(PTRACE_PEEKDATA, pid, addr, data)

描述:从内存地址中读取一个字节,pid表示被跟踪的子进程,内存地址由addr给出,data为用户变量地址用于返回读到的数据。在Linux(i386)中用户代码段与用户数据段重合所以读取代码段和数据段数据处理是一样的。

3) PTRACE_POKETEXT, PTRACE_POKEDATA

形式:ptrace(PTRACE_POKETEXT, pid, addr, data)

ptrace(PTRACE_POKEDATA, pid, addr, data)

描述:往内存地址中写入一个字节。pid表示被跟踪的子进程,内存地址由addr给出,data为所要写入的数据。

4) PTRACE_PEEKUSR

形式:ptrace(PTRACE_PEEKUSR, pid, addr, data)

描述:从 USER区域中读取一个字节,pid表示被跟踪的子进程,USER区域地址由addr给出,data为用户变量地址用于返回读到的数据。USER结构为 core文件的前面一部分,它描述了进程中止时的一些状态,如:寄存器值,代码、数据段大小,代码、数据段开始地址等。在Linux(i386)中通过 PTRACE_PEEKUSER和PTRACE_POKEUSR可以访问USER结构的数据有寄存器和调试寄存器。

5) PTRACE_POKEUSR

形式:ptrace(PTRACE_POKEUSR, pid, addr, data)

描述:往USER区域中写入一个字节,pid表示被跟踪的子进程,USER区域地址由addr给出,data为需写入的数据。

6) PTRACE_CONT

形式:ptrace(PTRACE_CONT, pid, 0, signal)

描述:继续执行。pid表示被跟踪的子进程,signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。

7) PTRACE_SYSCALL

形式:ptrace(PTRACE_SYS, pid, 0, signal)

描述:继续执行。pid表示被跟踪的子进程,signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。与PTRACE_CONT不同的是进行系统调用跟踪。在被跟踪进程继续运行直到调用系统调用开始或结束时,被跟踪进程被中止,并通知父进程。

8) PTRACE_KILL

形式:ptrace(PTRACE_KILL,pid)

描述:杀掉子进程,使它退出。pid表示被跟踪的子进程。

9) PTRACE_SINGLESTEP

形式:ptrace(PTRACE_KILL, pid, 0, signle)

描述:设置单步执行标志,单步执行一条指令。pid表示被跟踪的子进程。signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。当被跟踪进程单步执行完一个指令后,被跟踪进程被中止,并通知父进程。

10) PTRACE_ATTACH

形式:ptrace(PTRACE_ATTACH,pid)

描述:跟踪指定pid 进程。pid表示被跟踪进程。被跟踪进程将成为当前进程的子进程,并进入中止状态。

11) PTRACE_DETACH

形式:ptrace(PTRACE_DETACH,pid)

描述:结束跟踪。 pid表示被跟踪的子进程。结束跟踪后被跟踪进程将继续执行。

12) PTRACE_GETREGS

形式:ptrace(PTRACE_GETREGS, pid, 0, data)

描述:读取寄存器值,pid表示被跟踪的子进程,data为用户变量地址用于返回读到的数据。此功能将读取所有17个基本寄存器的值。

13) PTRACE_SETREGS

形式:ptrace(PTRACE_SETREGS, pid, 0, data)

描述:设置寄存器值,pid表示被跟踪的子进程,data为用户数据地址。此功能将设置所有17个基本寄存器的值。

14) PTRACE_GETFPREGS

形式:ptrace(PTRACE_GETFPREGS, pid, 0, data)

描述:读取浮点寄存器值,pid表示被跟踪的子进程,data为用户变量地址用于返回读到的数据。此功能将读取所有浮点协处理器387的所有寄存器的值。

15) PTRACE_SETFPREGS

形式:ptrace(PTRACE_SETREGS, pid, 0, data)

描述:设置浮点寄存器值,pid表示被跟踪的子进程,data为用户数据地址。此功能将设置所有浮点协处理器387的所有寄存器的值。

时间: 2024-09-28 22:59:19

[转载]playing with ptrace(Part I) 之一 --- 初识ptrace的相关文章

[转载] 《Hadoop基础教程》之初识Hadoop

转载自http://blessht.iteye.com/blog/2095675 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. <Hadoop基础教程>是我读的第一本Hadoop书籍,当然在线只能试读第一章,不过对Hadoop历史.核心技术和应用场景有了初步了解. Hadoop历史 雏形开始于2002年的Apache的Nutch,Nutch是一个开源Java 实现的搜索引擎.

ptrace运行原理及使用详解

X86_64 的 Redhat / Centos / Scientific 下面,若要编译.运行32位程序,需要安装以下包: yum install libgcc.i686 yum install glibc-static.i686 yum install glibc-devel.i686 #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h&

linux ptrace II

第一篇 linux ptrace I 在之前的文章中我们用ptrace函数实现了查看系统调用参数的功能.在这篇文章中,我们会用ptrace函数实现设置断点,跟代码注入功能. 参考资料 Playing with ptrace, Part I Playing with ptrace, Part II 英文好的推荐直接看老外的文章.但是其代码是运行在x86系统上的,本文中将其移植到了x86_64系统. 进程附加 在之前的文章中,我们都是trace自己程序fork出来的子进程,现在我们来看一下如何tra

玩转ptrace(转)

下面是转帖的内容,写的很详细.但是不同的linux发行版中头文件的路径和名称并不相同.如在某些发行版中<linux/user.h>就不存在,其中定义的变量出现在<asm/ptrace-abi.h>和<sys/user.h>中. ================================================================================================== by Pradeep Padala Create

ptrace can&#39;t work in kernel 2.6.32 mips

最近需要在mips上做监控,最底层的话就是调用kernel中的监控了,也就是ptrace了,gdb也是基于此的. 遇到一个问题,无论是使用attach还是fork一个新的进程,都无法唤醒被监控进程(子进程),发现在kernel3.4上是ok的. 后面发现是kernel2.6.32中,mips架构的ptrace存在一个bug,而2.6.34中被修复了. 具体可见: https://sourceforge.net/p/strace/mailman/message/31856938/ 然后patch在

玩转ptrace (一)

转自http://www.cnblogs.com/catch/p/3476280.html [本文翻译自这里: http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia] 你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一下系统调用的参数来耍一把内核?你是否想过调试器是怎样把一个进程停下来,然后把控制权转移给你的?如果你以为这些都是通过复杂的内核编程来实现的,那你就错了,事实上,Linux 提供了一种很优雅的

ptrace x64 转

#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <sys/reg.h> //#include <linux/user.h> #include <sys/syscall.h> const int long_size = sizeof(long); void reverse(cha

Linux内核调试方法总结之ptrace

ptrace [用途] 进程跟踪器,类似于gdb watch的调试方法 [原理][详细说明参考man ptrace帮助文档] ptrace系统调用主要是父进程用来观察和控制子进程的执行过程.检查并替换子进程执行序列或者寄存器值的一种手段.主要用于实现断点调试和跟踪系统调用. [接口说明] #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); 序

Linux Ptrace 详解

转 https://blog.csdn.net/u012417380/article/details/60470075 Linux Ptrace 详解 2017年03月05日 18:59:58 阅读数:6331 一.系统调用 操作系统提供一系列系统调用函数来为应用程序提供服务.关于系统调用的详细相关知识,可以查看<<程序员的自我修养>第十二章. 对于x86操作系统来说,用中断命令"int 0x80"来进行系统调用,系统调用前,需要将系统调用号放入到%EAX寄存器中,将