我正在尝试使用ptrace跟踪由单独进程生成的所有系统调用,无论是32位(IA-32)还是64位(x86-64).我的跟踪器将在启用了IA-32仿真的64位x86安装上运行,但理想情况下可以跟踪64位和32位应用程序,包括64位应用程序是否分叉并执行32位进程.
问题在于,由于32位和64位系统调用号不同,我需要知道进程是32位还是64位来确定它使用哪个系统调用,即使我有系统调用号.似乎有imperfect methods,比如检查/ proc /< pid> / exec或(作为strace)寄存器struct的大小,但没什么可靠的.
使这一点复杂化的事实是,64位进程可以直接执行32位代码.它们也可以是make 32-bit int $0x80
syscalls,当然,它使用32位系统调用号码.我不“信任”我追踪的过程不使用这些技巧,所以我想要正确地检测它们.我已经独立验证,至少在后一种情况下,ptrace会看到32位系统调用号和参数寄存器分配,而不是64位.
我在内核源代码中搜索过,并在arch/x86/include/asm/processor.h
中遇到了TS_COMPAT标志,只要64位进程发出32位系统调用,就会显示为set.唯一的问题是我不知道如何从userland访问这个标志,或者甚至可能.
我还考虑过读取%cs并将其与$0x23或$0x33进行比较,灵感来自this method,用于在运行过程中切换位数.但这只能检测32位进程,不一定是64位进程的32位系统调用(使用int $0x80进行调用).它也很脆弱,因为它依赖于未记录的内核行为.
最后,我注意到x86架构在扩展特征启用寄存器MSR中有一点长模式.但是ptrace无法从tracee中读取MSR,我觉得从我的跟踪器中读取它将是不充分的,因为我的跟踪器总是在长模式下运行.
我不知所措.也许我可以尝试使用其中一个黑客 – 此时我倾向于%cs或/ proc /< pid> / exec方法 – 但我想要一些能够实际区分32位和64位的东西位系统调用.如何在x86-64下使用ptrace检测到其tracee进行了系统调用,如何可靠地确定该系统调用是使用32位(int $0x80)还是64位(系统调用)ABI进行的?用户进程是否有其他方式来获取有关其被授权进行ptrace的另一个进程的信息?
解决方法:
有趣的是,我没有意识到没有一种明显更聪明的方式,strace可以用来从64位进程正确解码int 0x80. (这是正在进行的,请参阅this answer以获取建议的内核补丁的链接,以便将PTRACE_GET_SYSCALL_INFO添加到ptrace API.过滤4.26已经在补丁内核上支持它.)
作为一种解决方法,我认为您可以在RIP处反汇编代码并检查它是否是syscall指令(0F 05
),因为ptrace确实允许您读取目标进程的内存.
但对于像disallowing some system calls这样的安全用例,这将容易受到竞争条件的影响:系统调用进程中的另一个线程可能会在执行后将syscall字节重写为int 0x80,但在您可以使用ptrace查看它们之前.
如果进程在64位模式下运行,则只需执行此操作,否则只有32位ABI可用.如果不是,您不需要检查. (vdso页面可能会在支持它但不支持sysenter的AMD CPU上使用32位模式系统调用.首先不检查32位进程可以避免这种情况.)我想你说你有一个可靠的方法至少检测到.
(我没有直接使用ptrace API,只是像strace那样使用它的工具.所以我希望这个答案有意义.)