我一直在使用迷你 strace 程序进行重新编码,而不使用PTRACE_SYSCALL来熟悉寄存器。
因此在使用ptrace(PTRACE_GETREGS,...)设置user_reg_struct字段后的代码中,我使用ptrace(PTRACE_PEEKDATA,...)来读取它。
不知道如何处理该功能的使用以使用它的数据(系统调用等...),我开始查看一些代码,我遇到了类似的事情:
int is_a_syscall() {
struct user_reg_struct regs;
unsigned short int ret;
ret = ptrace(PTRACE_PEEKDATA, pid, regs.rip, 0);
if (ret == 0xFFFF) {
perror("failed")
exit(1); }
if (ret == 0x80CD || ret == 0x50F)
return (true);
return (false);
}
现在有人可以向我解释if()语句中的数字是什么,a.k.a:
我想知道它们是什么,我在哪里可以找到它们,我能解释它们吗?如何使用它们来获取我的系统调用及其参数。
答案 0 :(得分:2)
你所包含的代码有些不同寻常,所以我会解释它的作用,然后以不同的方式来做。
unsigned short int ret;
ret = ptrace(PTRACE_PEEKDATA, pid, regs.rip, 0);
Linux上的ptrace返回一个很长的,而不是一个未签名的短片。代码的作者只是查看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)xFF00 & ret) >> 8;
if (primary == 0xCD && secondary == 0x80 || primary == 0x0F && secondary == 0x05)
return true;
return false;
}
我使用ptrace的全宽返回值。如果它是-1并且如果已设置errno
,则表示错误。我也使用PTRACE_PEEKTEXT
代替PTRACE_PEEKDATA
,尽管在x86上它并不重要。 Bitmasks用于获取主要和次要操作码字节。
如何使用它们来获取系统调用及其参数。
为此,请参阅此详细答案:What are the calling conventions for UNIX & Linux system calls on x86-64。
答案 1 :(得分:0)
你的意思是这些与十进制有什么关系(例如0x80CD = 32973),或者它们与ptrace()
的语义是什么(例如0xFFFF可能意味着函数遇到错误)?
如果是前者,这些是以十六进制表示的数字。也就是说,数字范围包括的数字系统:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F。
如果是后者,请查看man page for ptrace
中的返回值部分