目录
(代码:linux 6.3.1,架构:arm64)
One look is worth a thousand words. —— Tess Flanders
相关链接:
linux ptrace 图文详解(二) PTRACE_TRACEME 跟踪程序
linux ptrace 图文详解(三) PTRACE_ATTACH 跟踪程序
linux ptrace 图文详解(四) gdb设置软断点-优快云博客
linux ptrace 图文详解(五) gdb设置硬断点、观察点
引言
在现代操作系统中,对于开发者来说,能够深入理解和控制进程的行为是解决复杂问题的关键。Linux提供了多种机制来实现这一目标,而 ptrace 系统调用无疑是其中最为强大和灵活的工具之一。尽管 ptrace 的功能强大,它的使用和实现原理却相对复杂,需要对操作系统内核机制有深入的理解。许多开发者在使用 ptrace 时,往往只停留在表面,而对于其底层实现知之甚少。
为了帮助开发者更好理解和应用ptrace,笔者将推出一系列文章,深入探讨 ptrace 的各个功能及其详细实现原理。本系列文章将从基础概念入手,逐步深入到每个功能的具体实现,包括:进程控制、寄存器操作、内存读写、系统调用跟踪、断点设置、单步调试等。
在本系列的第一篇文章中,笔者将对 ptrace 进行基本介绍,包括其定义、功能、应用场景等。通过这篇文章,读者将对 ptrace 有一个全面的了解,为后续深入学习ptrace实现原理打下坚实的基础。
让我们一起踏上探索 ptrace 的旅程,解锁其强大功能。
一、ptrace 基础介绍
ptrace 是 linux内核 提供的一个系统调用,并非一个标准的posix接口,ptrace 主要用于进程跟踪和调试。它运行一个用户态进程(通常称为跟踪器, Tracer)控制和监视另一个进程(称为被调试进程, Tracee)的执行。ptrace是许多调试跟踪工具(如:GDB、strace 等)的 “基座”,其函数原型如下:
参数:
request:用于标识一个需要执行的操作;
pid:标识目标线程ID
addr、data:一个内存地址和附加信息,其语义因选择的操作而不同;
这里详细介绍下ptrace系统调用中的参数request,通过该参数,ptrace为用户态提供了丰富的进程调试跟踪功能。
1)PTRACE_TRACEME
允许当前进程被其父进程跟踪,通常用于GDB加载运行一个被调试程序;
2)PTRACE_PEEKTEXT
读取目标进程的代码段内容,通常用于GDB查看目标进程的指令代码;
3)PTRACE_PEEKDATA
读取目标进程的数据段内容,通常用于GDB查看目标进程的全局变量、堆栈内容等;
4)PTRACE_PEEKUSER
读取目标进程的用户态寄存器和状态信息,通常用于GDB查看目标进程的PC、SP等;
5)PTRACE_POKETEXT
修改目标进程的代码段内容,用于GDB修改目标进程的指令代码,例如设置软断点;
6)PTRACE_POKEDATA
修改目标进程的数据段内容,用于GDB修改目标进程的全局变量、堆栈内容等数据;
7)PTRACE_POKEUSER
修改目标进程的用户态寄存器和状态信息;
8)PTRACE_CONT
唤醒目标进程继续执行,通常用于GDB的continue功能;
9)PTRACE_KILL
终止目标进程,用于GDB杀死被调试进程;
10)PTRACE_SINGLESTEP
单步执行目标进程,通常用于GDB的step单步调试目标进程的功能;
11)PTRACE_GETREGS
获取目标进程的寄存器状态,如当前的程序计数器(PC)、栈指针(SP)等;
12)PTRACE_SETREGS
设置目标进程的寄存器状态;
13)PTRACE_ATTACH
用于attach到一个正在运行的目标进程,通常用于GDB attach调试功能;
14)PTRACE_DETACH
从一个目标进程上detach,通常用于GDB解除对目标进程的调试功能;
15)PTRACE_SYSCALL
在目标进程的系统调用入口处、返回处暂停,通常用于strace工具捕获目标进程的系统调用;
16)PTRACE_SETOPTIONS
设置目标进程的跟踪选项,通常用于GDB设置是否对目标进程的一些操作(如:fork、pthread_create、exec、所有系统调用等)进行跟踪;
17)PTRACE_GETSIGINFO
获取目标进程的信号信息,通常用于GDB获取目标进程的异常地址、exit_code、pending信号等信息;
18)PTRACE_GETEVENTMSG
获取目标进程与特定 ptrace事件 相关联的消息,例如GDB获取目标进程fork创建的子进程/子线程pid信息、位于系统调用入口处/出口处 等信息;
19)PTRACE_GETREGSET
获取目标进程的寄存器集合;
20)PTRACE_SETREGSET
设置目标进程的寄存器集合,通常用于GDB设置目标进程的硬断点、观察点;
二、ptrace 常见应用场景
1、gdb进程调试
gdb对目标进程进行跟踪调试,其底下依赖的主要是linux内核中的 ptrace功能、以及 signal + wait 这两个用于同步的系统调用。通过ptrace接口,gdb可以对被调试进程进行一系列的调试跟踪操作。
2、strace 系统调用跟踪
strace是一个用户态的工具,其主要用途是跟踪目标进程执行期间的所有系统调用操作,获取对应系统调用的参数、返回值等信息。strace底层依赖的就是ptrace(PTRACE_SYSCALL)这一功能,做到对目标进程的所有系统调用操作进行监控。
3、动态注入
通过ptrace系统调用,可以用于向目标进程注入代码或数据,在某些情况下用于功能扩展或漏洞利用。
三、gdb 与 ptrace
这里简单介绍下GDB调试,GDB调试主要分为以下两种方法:
1)本地调试
该方式下,调试程序(GDB) 和 被调试程序(Tracee)运行在同一台电脑中。可以使用 “gdb加载运行被调试程序” 或 “gdb attach到正在运行的被调试程序” 这两个模式进行调试。
2)远程调试
GDB远程调试的方式,主要用于嵌入式的场景,由于GDB这个程序本身体积比较大,在某些容量比较下的嵌入式目标机中,没有充足的资源用于运行庞大的GDB。因此,GDB也提供远程调试的方式:gdb server程序 运行在目标机上,gdb client运行在调试机上。由于gdb server程序的体积比较小,所以可以在大部分嵌入式目标机上运行,gdb client运行在调试机上,通过网络/串口与目标机上运行的gdb server进行通知,并通过gdb server调试控制目标程序。
以下总结了gdb中常用的一些操作,以及其底层对应的ptrace操作。本系列后续文章将围绕以下功能进行深入探讨。