![](/img/trans.png)
[英]Can ptrace tell if an x86 system call used the 64-bit or 32-bit ABI?
[英]Why does ptrace show a 32-bit execve system call having EAX = 59, the 64-bit call number? How do 32-bit system calls work on x86-64?
我正在用下面的代碼玩弄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.
execve
是特殊的; 它是唯一一個與PTRACE_TRACEME
有特殊交互的。 strace
的工作方式,其他系統調用確實顯示 32 位調用號。 (現代 strace 需要特殊幫助才能知道這是int 0x80
/ sysenter
的 32 位調用號還是 64 位調用號,因為 64 位進程仍然可以調用int 0x80
,盡管它們通常不應該調用。這個僅在 2019 年通過PTRACE_GET_SYSCALL_INFO
添加了支持)
沒錯,當實際調用 kernel 時,EAX 持有11
,來自__NR_execve
的unistd_32.h
。 它由mov $0xb,%eax
在 glibc 的 execve 包裝器跳轉到 VDSO 頁面以通過此硬件支持的任何有效方法(通常為sysenter
)進入 kernel 之前設置。
但是執行實際上並沒有停止,直到它到達主execve
實現中檢查PTRACE_TRACEME
並引發SIGTRAP
的一些代碼。
顯然在此之前的某個時間,它在 arch/x86/kernel/process_64.c 中調用void set_personality_64bit(void)
,其中包括
/* Pretend that this comes from a 64bit execve */
task_pt_regs(current)->orig_ax = __NR_execve;
我發現通過在 kernel 源瀏覽器中搜索__NR_execve
並查看 arch/x86 中最可能的文件。 我沒有繼續交叉引用來查找調用的位置; 它存在的事實(以及理智的非混淆設計的假設)非常強烈地表明這是您的謎團的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.