Execve系统调用未设置errno且未返回-1的问题排查
问题原因及解决方法
1. 系统调用参数完全错误
你对execve系统调用的参数传递存在两处关键错误:
- execve的第一个参数(
%ebx)需要是指向路径字符串的指针(即command[0],也就是"/bin/sh"的地址),但你传递的是command数组本身的地址(char**类型),内核无法识别这个错误路径,返回错误码ENOENT(数值2),对应系统调用返回值-2(即0xfffffffe)。 - execve的第二个参数(
%ecx)需要是指向argv数组的指针(即command的地址),但你错误地将其设为0,不符合系统调用的参数要求。
2. 直接调用int $0x80不会自动设置errno
C标准库的errno是由libc封装系统调用时负责设置的。当你直接用汇编指令int $0x80调用系统调用时,libc不会介入处理,errno会保持初始值0,这就是perror输出"Success"的原因。系统调用的错误码会直接通过%eax返回(失败时返回-errnum,比如-2对应错误码2)。
修复后的代码
#include <stdio.h> #include <errno.h> int main() { char *command[] = { "/bin/sh", NULL }; asm volatile( "movl $11, %%eax\n" // 32位execve系统调用号为11 "movl %0, %%ebx\n" // ebx: 路径字符串指针(command[0]) "movl %1, %%ecx\n" // ecx: argv数组指针(command) "xorl %%edx, %%edx\n" // edx: 空环境变量数组 "int $0x80\n" // 触发系统调用 "movl %%eax, %2\n" // 将返回值存入临时变量 : "=r"(command[0]), "=r"(command), "=m"(errno) : : "%eax", "%ebx", "%ecx", "%edx" ); // 转换系统调用返回值为正确的errno格式 if (errno < 0) { errno = -errno; } perror("execve failed"); return 1; }
额外说明
- 如果只是为了获取shell,直接调用libc的
execve函数更简单可靠:execve("/bin/sh", command, NULL);,无需手动编写汇编。 - 32位Linux系统调用的参数传递规则:
%eax存系统调用号,%ebx、%ecx、%edx依次存放第1到第3个参数。 - 若execve调用成功,会直接替换当前进程的代码段,不会执行到后续的
perror代码;一旦执行到perror,说明系统调用必然失败。
内容的提问来源于stack exchange,提问作者nadav levin
相关产品推荐
相关产品推荐

