文章目录
一、ptrace 函数族
1、进程附着
2、进程脱离
3、进程数据读写权限
4、进程对应的主线程寄存器读写
5、单步调试
6、继续向后执行
二、ptrace 函数族状态转换
一、ptrace 函数族
ptrace 函数原型 : ptrace 函数实际上是由一系列的函数组成 , 具体调用哪个函数 , 要根据第一个参数确定 ;
#include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
ptrace 函数参考文档 : https://man7.org/linux/man-pages/man2/ptrace.2.html
下面是 enum __ptrace_request request 参数的可能的取值 : 在上述文档中有详细的说明 ;
1、进程附着
PTRACE_ATTACH : 指明要附着的进程 ;
进程 A 要 调试进程 B , 在进程 A 中 先通过 ptrace 函数 附着进程 B , 传入 PTRACE_ATTACH 作为第一参数 ;
( 注意 : 进程 A 必须有 root 权限 )
调用 ptrace 函数时 , 会调用系统内核层 , 给进程 A 一个权限 , 将被调试进程 B 的控制权限交给 进程 A ;
进程 A 调试 进程 B 时 , 进程 B 被挂起 , 进程 B 的 CPU 和 内存信息 , 都会被保存到内存中 , 进程 B 处于休眠状态 , CPU 不会运行 进程 B 的任何指令 ;
2、进程脱离
PTRACE_DETACH : 要脱离的进程 ;
进程 A 如果调用 ptrace 函数 , 传入 PTRACE_DETACH , 就会释放权限 , 发出信号 , 进程 B 恢复运行 ;
3、进程数据读写权限
读取进程数据权限 : PTRACE_PEEKTEXT、PTRACE_PEEKDATA、PTRACE_PEEKUSER
写入进程数据权限 : PTRACE_POKETEXT、PTRACE_POKEDATA、PTRACE_POKEUSER
注意 : 读写内存时 , 尽量在进程挂起后读写 , 否则内存数据不可靠 ;
4、进程对应的主线程寄存器读写
读取寄存器 : PTRACE_GETREGS
写出寄存器 : PTRACE_SETREGS
同一个进程 , 可能有多个线程 , 不同线程可能会被分配到不同的 CPU , 进程读写的寄存器可能有多套 ;
上面的 PTRACE_GETREGS , PTRACE_SETREGS , 读写的寄存器 是 执行 主线程 的 CPU 的 寄存器 ;
5、单步调试
PTRACE_SYSCALL : 每当发生系统调用时, 被调试进程暂停 , 将控制权交还给调试进程 ;
PTRACE_SINGLESTEP : 每当执行一条指令时 , 被调试进程暂停 , 将控制权交还给调试进程 ; 单步调试 ;
6、继续向后执行
PTRACE_CONT : ptrace 调试进程 , 完毕之后 , 退出调试 , 程序继续向后执行 , 使用该 PTRACE_CONT 作为 ptrace 函数的 第一参数即可 ;
CONTINUE 继续执行 ;
二、ptrace 函数族状态转换
进程 A 调试 进程 B , 进程 A 先 调用 ptrace 函数 Attach 进程 B , 可以进行 数据读写 , 单步执行 , 等待系统调用 , 读写寄存器 等操作 , 执行完毕后 可以继续执行 ;
调试完毕后 , 进程 B 脱离 Detach 进程 A 的调试 ;