我正在尝试使用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的另一个进程的信息?
答案 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
这样的工具使用了它,所以我希望这个答案有意义。)