ptrace 中 PEEKUSER 和 POKEUSER 用法
1. ptrace 函数的声明:
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
- ptrace有四个参数:
1). enum __ptrace_request request:指示了ptrace要执行的命令。
2). pid_t pid: 指示ptrace要跟踪的进程。
3). void *addr: 指示要监控的内存地址。
4). void *data: 存放读取出的或者要写入的数据。
- PTRACE_PEEKUSER 和 PTRACE_POKEUSER 官方手册介绍
PTRACE_PEEKUSER
Read a word at offset addr in the tracee's USER area,
which holds the registers and other information about the
process (see <sys/user.h>). The word is returned as the
result of the ptrace() call. Typically, the offset must
be word-aligned, though this might vary by architecture.
See NOTES. (data is ignored; but see NOTES.)
PTRACE_POKEUSER
Copy the word data to offset addr in the tracee's USER
area. As for PTRACE_PEEKUSER, the offset must typically
be word-aligned. In order to maintain the integrity of
the kernel, some modifications to the USER area are
disallowed.
2. PTRACE_PEEKUSER 如何读取 user 区域地址偏移 offset
常见用法为:
ptrace(PTRACE_PEEKUSER, pid, sizeof(long)*ORIG_EAX, 0);
或者把sizeof(long)
换成8
或4
,那这里参数选取的依据是什么呢?
打开内核头文件/usr/include/x86_64-linux-gnu/sys/reg.h
,
...
#ifdef __x86_64__
/* Index into an array of 8 byte longs returned from ptrace for
location of the users' stored general purpose registers. */
// ptrace 根据索引从用户存储的通用寄存器的位置读取并返回 8 字节的数据。
# define R15 0
# define R14 1
# define R13 2
# define R12 3
# define RBP 4
# define RBX 5
# define R11 6
# define R10 7
# define R9 8
# define R8 9
# define RAX 10
...
所有这些宏 ( RAX, RCX, ...) 定义特定寄存器的索引。并且因为每个都是 8 字节长(x86_64),所以偏移量是8 * $index. 在rax寄存器的情况下,偏移量计算为8 * RAX = 8 * 10 = 80。80是你应该在函数调用中使用的addr参数。ptrace这就是它的工作原理。请注意,它与其他架构等不同。
3. PEEKUSER/DATA/TEXT 功能对比
-
PTRACE_PEEKUSER - 用于读取寄存器和一些调试信息,如读取硬件调试寄存器.
-
PTRACE_PEEKDATA - 用于读取程序的数据段和代码段.
-
PTRACE_PEEKTEXT - 复制一个字长的数据到地址 addr 处. 对于 PTRACE_PEEKTEXT 和 PTRACE_PEEKDATA, 这两个几乎等价,因为 Linux 并不为 text 和 data 区分地址空间.