为什么execve系统调用run“/bin/sh“;没有任何argv参数,但不是/垃圾箱/垃圾箱;?
我对为什么execve系统调用run“/bin/sh“;没有任何argv参数,但不是/垃圾箱/垃圾箱;?,c,linux,system-calls,glibc,shellcode,C,Linux,System Calls,Glibc,Shellcode,我对的系统调用感到困惑。当我学习linux系统调用时。我知道使用execve的正确方法如下: char *sc[2]; sc[0]="/bin/sh"; sc[1]= NULL; execve(sc[0],sc,NULL); 然后函数execve将调用syscall()进入系统内核,将参数放在寄存器EAX、EBX、ECX和EDX上。但是,如果我使用 execve("/bin/sh",NULL,NULL); 但是,如果我将“/bin/sh”替换为“/bin/ls”,它将失败: A NU
的系统调用感到困惑。当我学习linux系统调用时。我知道使用execve
的正确方法如下:
char *sc[2];
sc[0]="/bin/sh";
sc[1]= NULL;
execve(sc[0],sc,NULL);
然后函数execve
将调用syscall()
进入系统内核,将参数放在寄存器EAX
、EBX
、ECX
和EDX
上。但是,如果我使用
execve("/bin/sh",NULL,NULL);
但是,如果我将“/bin/sh”
替换为“/bin/ls”
,它将失败:
A NULL argv[0] was passed through an exec system call.
我想知道为什么“/bin/sh”
可以在没有足够参数的情况下成功执行,而“/bin/ls”
失败?这不是内核问题,内核将运行execve的filename
arg,而不管argv
和envp
是否为NULL
,这只是unix约定的argv[0]
指向程序名
你所看到的一切都很正常,没有什么不对劲。由于ls
是GNU的coreutils的一部分,coreutils包中的所有程序都调用set\u program\u name
来执行一些设置工作,您可以在源代码中看到,如果为空,它将检查argv[0]
,如果为空,它将调用abort
。
另一方面,/bin/sh
显然是一个不属于coreutils的程序,并且不检查argv[0]
,这就是为什么它运行时没有问题
请参阅源代码:
我根本不指望NULL
在那里工作;execve
手册页说明argv
是一个参数字符串数组;NULL
指针不是指向数组的有效指针。(对env
使用NULL
也不好看;相反,使用execv
或execvp
,或传递指向char*p=NULL
的指针)数组在作为函数参数传递时是指向其第一个元素的指针,因此NULL在这里肯定有效。@AnttiHaapala:,并将其视为指向空列表的指针。这是不鼓励的,而且不可移植,但在Linux上是未来的证明。我看到的主要用例是利用外壳代码,在系统调用(x86int0x80
或syscall
)之前将两个寄存器归零,而不是将0
推到两个寄存器中。i、 e.它节省了几个字节的漏洞利用负载大小,并且如果负载中已经存在“/bin/sh”
字符串,则不需要写入内存。@petercordes认为hellcodez保持兼容性很好,但是是的,手册页确实提到了这个例外,下面是一个没有任何argv的最小示例: