【发布时间】:2022-01-25 12:55:56
【问题描述】:
我正在使用下面的代码玩弄ptrace。我发现 execve 的系统调用号是 59,即使我使用 -m32 选项编译也是如此。由于我是在 64 位机器上使用 Ubuntu,所以可以理解。
很快,问题出现了:“libc32 在 32 位机器和 64 位机器上的行为是否不同?它们不同吗?”所以我检查了 libc32 在 64 位中的内容。但是,libc 的 execve 系统调用号是 11,这与 32 位系统的 execv 系统调用号相同。那么魔法发生在哪里呢?提前谢谢你。
这是代码。源自https://www.linuxjournal.com/article/6100
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <stdio.h>
int main()
{
pid_t child;
long orig_eax;
child = fork();
if (child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/bin/ls", "ls", NULL);
} else {
wait(NULL);
orig_eax = ptrace(PTRACE_PEEKUSER,
#ifdef __x86_64__
child, &((struct user_regs_struct *)0)->orig_rax,
#else
child, &((struct user_regs_struct *)0)->orig_eax,
#endif
NULL);
printf("The child made a "
"system call %ld\n", orig_eax);
ptrace (PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
这是代码的结果
~/my-sandbox/ptrace$ file s1 && ./s1
s1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f84894c2f5373051682858937bf54a66f21cbeb4, for GNU/Linux 3.2.0, not stripped
The child made a system call 59
~/my-sandbox/ptrace$ file s2 && ./s2
s2: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=cac6a2bbeee164e27c11764c1b68f4ddd06405cf, for GNU/Linux 3.2.0, with debug_info, not stripped
The child made a system call 59
这是我使用 gdb 从 32 位可执行文件中得到的。可以看到它使用的是/lib/i386-linux-gnu/libc.so.6,execve的系统调用号是11。
>>> bt
#0 0xf7e875a0 in execve () from /lib/i386-linux-gnu/libc.so.6
#1 0xf7e8799f in execl () from /lib/i386-linux-gnu/libc.so.6
#2 0x565562a4 in main () at simple1.c:15
>>> disassemble
Dump of assembler code for function execve:
=> 0xf7e875a0 <+0>: endbr32
0xf7e875a4 <+4>: push %ebx
0xf7e875a5 <+5>: mov 0x10(%esp),%edx
0xf7e875a9 <+9>: mov 0xc(%esp),%ecx
0xf7e875ad <+13>: mov 0x8(%esp),%ebx
0xf7e875b1 <+17>: mov $0xb,%eax
0xf7e875b6 <+22>: call *%gs:0x10
0xf7e875bd <+29>: pop %ebx
0xf7e875be <+30>: cmp $0xfffff001,%eax
0xf7e875c3 <+35>: jae 0xf7dd9000
0xf7e875c9 <+41>: ret
End of assembler dump.
【问题讨论】:
-
libc 使用了内核导出的 VDSO 包装器,因此它可以在支持它的机器上受益于
sysenter,而不是较慢的int $0x80。请参阅blog.packagecloud.io/eng/2016/04/05/… 了解相关概述。 -
(我之前的评论仅基于标题)。如您所见,32 位 libc execve 包装器通过
mov $0xb,%eax传递 EAX=11。 IDK 为什么您的程序在这种情况下会发现 EAX=59。我肯定也希望那里有 11 个,__NR_execve来自unistd_32.h,特别是因为我们可以看到 libc 包装器通过它。与 Windows WOW64 不同,Linux 上的 32 位用户空间直接调用内核,而不是为syscall跳转到 64 位模式。所以是的,32 位用户空间库在 64 位系统上并不特殊。 64 位内核只是为 32 位进程提供 32 位 ABI。 -
是的。我检查了 32 位机器上的 libc32 与 64 位机器上的 libc32 没有什么不同。我的问题是 libc hand 11 (on 64-bit machine with 32-bit elf) for execve 为什么内核(即 64 位)将其视为 59 以及如何处理。
-
是的,我可以看到内核可以/应该只保留 59 用于执行。那么在哪里 11,在 32 位精灵上执行,转换为 59?
-
也许在内核内部,作为 32 位系统调用包装器的实现细节,在执行检查
PTRACE_TRACEME的 execve 代码的过程中,实际上在 execve 上引发了 SIGTRAP?
标签: linux x86-64 system-calls 32bit-64bit ptrace