您包含的代码有些不合常规,所以我将解释它的作用,然后展示一种不同的方法。
unsigned short int ret;
ret = ptrace(PTRACE_PEEKDATA, pid, regs.rip, 0);
Linux 上的 ptrace 返回一个 long,而不是 unsigned short。代码的作者只是在看 ptrace 返回的 4 或 8 个字节的低位 2 个字节。由于 x86 是 little-endian,因此可以完成工作,但稍后我将展示另一种方法。
if (ret == 0xFFFF) {
perror("failed")
exit(1); }
ptrace 在失败时返回 -1。由于代码只存储了返回值的低位 2 字节,并且将该值视为无符号,因此 -1 的测试使用 0xFFFF 代替。
由于ptrace(PTRACE_PEEKDATA, ...)即使成功也可以返回-1,所以最好也看看errno(我稍后会展示)。
if (ret == 0x80CD || ret == 0x50F)
return (true);
return (false);
您可以在 http://ref.x86asm.net/coder64.html 等网站找到操作码列表。 CD 是 int 和 CD80 是 int 80 和 0F05 是 syscall。这是 x86 Linux 中用于执行系统调用的两个操作码。更多信息请访问What is better “int 0x80” or “syscall”?。
这是检查系统调用指令的另一种方法(未经测试):
int is_a_syscall(regs)
struct user_reg_struct regs;
{
long ret;
unsigned char primary, secondary;
extern int errno;
errno = 0;
ret = ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
if (ret == -1 && errno != 0) {
perror("failed")
exit(1);
}
primary = (unsigned)0xFF & ret;
secondary = ((unsigned)0xFF00 & ret) >> 8;
if (primary == 0xCD && secondary == 0x80 || primary == 0x0F && secondary == 0x05)
return true;
return false;
}
我使用 ptrace 的返回值的全宽。如果它是 -1 并且如果 errno 已设置,则表示错误。我也使用PTRACE_PEEKTEXT 而不是PTRACE_PEEKDATA,尽管在x86 上没关系。位掩码用于获取主要和次要操作码字节。
如何使用它们来获取我的系统调用及其参数。
对此,请看这个详细回答:What are the calling conventions for UNIX & Linux system calls on x86-64。