【发布时间】:2020-03-11 21:10:05
【问题描述】:
我正在尝试做一件简单的事情(只是为了学习), 我希望在 64 位 linux 上截取 clock_gettime,读取输出并修改它,以便将一个 flase 日期/时间返回给被跟踪者(/bin/date)。
我做的是:
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
if(regs.orig_rax==228){ // this is the clock_gettime syscall number in 64 bit linux
unsigned long p1=ptrace(PTRACE_PEEKDATA, pid, regs.rcx, NULL); // rcx is ARG1
printf("ARG1: 0x%lx\n",p1);
}
现在,如果我理解正确(显然不是) regs.rcx 应该指向 timespec 结构,所以 我应该阅读该结构的第一个 long int,它是以秒为单位的时间(unixtime)。 但我读的是 0。
另外,printf 被调用两次,一次进入系统调用,第二次退出。 所以好的,进入时正常为0,但退出时不应该是。 事实上 strace 显示正确:
strace 2>&1 date|grep CLOCK
clock_gettime(CLOCK_REALTIME, {tv_sec=1583960872, tv_nsec=403163000}) = 0
我该怎么做?
【问题讨论】:
-
请注意,clock_gettime 是特殊的,纯粹在用户空间中运行(VDSO 页面中的代码和比例因子),通常不使用
syscall指令进入内核。在我的系统(Arch Linux)上,strace date不包含任何 clock_gettime 系统调用,但显然你的包含。无论如何,你如何决定什么时候做PTRACE_GETREGS?为什么你认为 RCX 是第一个参数? x86-64 System V 使用 RDI 作为函数和系统调用的调用约定中的第一个参数。syscall本身使用 RCX 来保存 RIP,而不是系统调用 arg。 (这是第 4 个函数 arg) -
我在这里和那里阅读..我正在试图弄清楚这个......我的程序是错误的,否则它会起作用:D
-
看看blog.packagecloud.io/eng/2016/04/05/…,也可以使用 GDB 单步进入
clock_gettime。有关 Linux 上的函数和系统调用约定,请参阅 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64。 (不是 Windows,其中 RCX 是函数调用的第一个参数传递寄存器;也许这就是你读到的?) -
找到了.. reg 是 rsi
-
好的,所以你在调用 glibc 的 clock_gettime 或其他东西的断点处执行此操作。是的,这是第二个参数,而不是第一个:
int clock_gettime(clockid_t clk_id, struct timespec *tp);