ptrace可以告诉x86系统调用使用的是64位还是32位ABI?

时间:2018-11-24 07:54:04

标签: linux x86 x86-64 system-calls ptrace

我正在尝试使用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一样)寄存器结构的大小,但没有可靠的结果。

这使64位进程可以switch out of long mode直接执行32位代码的事实变得复杂。他们还可以make 32-bit int $0x80 syscalls,当然,它们使用32位系统调用号。我不“信任”我跟踪的过程以不使用这些技巧,因此我想正确地检测它们。而且我已经独立验证,至少在后一种情况下,ptrace会看到32位系统调用号和参数寄存器分配,而不是64位。

我在内核源代码中打听,并遇到了arch/x86/include/asm/processor.h中的TS_COMPAT标志,每当64位进程进行32位系统调用时,该标志似乎就是set 。唯一的问题是我不知道如何从用户区访问此标志,或者甚至不知道。

我还考虑过阅读%cs并将其与$0x23$0x33进行比较,受this method启发,在运行过程中切换了位。但这只能检测64位进程中的32位进程,而不一定检测到32位 syscalls (由int $0x80进行的调用)。它也很脆弱,因为它依赖于未记录的内核行为。

最后,我注意到x86体系结构在扩展功能使能寄存器MSR中具有长模式的含义。但是ptrace无法从跟踪中读取MSR,我觉得从跟踪器中读取MSR是不够的,因为跟踪器始终以长模式运行。

我很茫然。也许我可以尝试使用其中一种黑客手段(此时,我倾向于使用%cs/proc/<pid>/exec方法),但是我想要一种可以区分32位和64位的持久性产品系统调用。 在x86-64下使用ptrace的进程如何检测到它的踪迹进行了系统调用,如何可靠地确定该系统调用是使用32位(int $0x80)还是64位({{ 1}})ABI?,用户进程是否还有其他方法可以获取有关已授权ptrace的另一个进程的信息?

1 个答案:

答案 0 :(得分:2)

有趣的是,我还没有意识到strace并没有明显的更聪明的方法可以用来正确解码来自64位进程的int 0x80。 (此问题正在处理中,请参见this answer 以获取指向拟议的内核补丁的链接,以将PTRACE_GET_SYSCALL_INFO添加到ptrace API。strace 4.26已在补丁中支持它内核。)


作为一种解决方法,我认为您可以在RIP上反汇编代码并检查它是否是syscall指令(0F 05),因为ptrace确实可以让您读取目标进程的内存。

但是对于像disallowing some system calls这样的安全用例,这很容易出现竞争状况:syscall进程中的另一个线程可以在执行后将syscall个字节重写为int 0x80 ,但是在您可以使用ptrace来窥视它们之前。


仅在进程以64位模式运行时才需要这样做,否则仅32位ABI可用。如果不是,则无需检查。 (vdso页面可以在支持它的AMD CPU上使用32位模式syscall,但不支持sysenter。不首先检查32位进程可以避免这种情况。)我想您是就是说,您至少有一种可靠的方法来检测

(我没有直接使用ptrace API,只是像strace这样的工具使用了它,所以我希望这个答案有意义。)