如何修复“ SYSCALL execve”:ls抱怨NULL argv [0]

时间:2019-08-27 21:29:08

标签: linux debugging assembly x86 system-calls

我创建了系统调用,但未找到。 这是我在asm中的代码

section .text
global _start
_start:
xor eax,eax

push eax
push dword '//ls'
push dword '/bin'
mov ebx,esp
mov al,0xb
int 0x80
;/bin//ls

从中构建一个静态的32位可执行文件并运行它时,我得到:

A NULL argv[0] was passed through an exec system call.
Aborted (core dumped)

这里发生了什么以及如何解决?

1 个答案:

答案 0 :(得分:0)

您的代码将按预期工作,并成功进行execve("/bin//ls", NULL, NULL)系统调用。

问题在于,与ls或某些其他程序不同,GNU sh在使用空argv[] 运行时会选择abort()。通常的惯例是将程序名称作为第一个参数(argv[0])。

您的程序在/bin//sh而不是ls上正常工作


您的execve的argv和envp args来自ECX和EDX = 0,因为Linux选择在进入用户空间之前设置它们。 (这避免了内核信息泄漏,而无需进行初始化)。显然,这在shellcode中不起作用,它将与包含未知值的寄存器一起运行。

顺便说一句,Linux execve() does document支持传递envp和/或argv=NULL而不是argv = (char*[]){NULL};(指向NULL的指针)。不会返回-EFAULT来返回指向有效内存的argv,而是将NULL作为空数组进行特殊处理。


我可以使用ls (GNU coreutils) 8.31

在Arch Linux上重现您的结果
$ nasm -felf32 exec.asm
$ ld -melf_i386 -o exec exec.o

$ ./exec 
A NULL argv[0] was passed through an exec system call.
Aborted (core dumped)

您可以使用strace来确定消息不是来自您的进程。

$ strace ./exec 
execve("./exec", ["./exec"], 0x7ffd7090ed90 /* 54 vars */) = 0  <=== starting your program
strace: [ Process PID=21152 runs in 32 bit mode. ]

execve("/bin//ls", NULL, NULL)          = 0         <==== This is your system call
  # then ls starts up normally
strace: [ Process PID=21152 runs in 64 bit mode. ]
brk(NULL)                               = 0x55b5fbaff000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe1d74c5b0) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3

 ... normal dynamically-linked executable startup stuff ...

 ... until it writes a message to stderr and raises SIGABRT ...
write(2, "A NULL argv[0] was passed throug"..., 55A NULL argv[0] was passed through an exec system call.
) = 55
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [], 8) = 0
getpid()                                = 21152
gettid()                                = 21152
tgkill(21152, 21152, SIGABRT)           = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=21152, si_uid=1000} ---
+++ killed by SIGABRT (core dumped) +++
Aborted (core dumped)

如果您查看了ls的源代码,则可能会看到abort()函数调用,尤其是在搜索打印的字符串时。

正如我所说,bash和其他大多数shell都不这样做。


如果确实要修复它,则可能要创建一个指针数组{"/bin//ls", NULL},并将指向该指针的指针作为第二个arg传递。

    ...
    mov  ebx, esp     ; path

    push eax          ; 0
    push ebx          ; pointer to the filename
    mov  ecx, esp     ; argv = pointer to that array

    cdq               ; envp = EDX = 0 (broadcast high bit of EAX into EDX)

    mov  al, 0xb
    int  0x80

我添加了EDX的归零以达到很好的效果。

对我有用:ls成功运行。