您的code
变量是一个数组,它是程序的初始化数据 ( .data
) 段的一部分。当你的程序被操作系统加载时,加载器从你的可执行文件中读取并执行加载命令。其中一个命令是“将以下数据(名为 的段.data
)加载到内存中”。
通常,该.data
段被加载为不可执行的段,这意味着那里的内存无法执行。因此,如果您尝试通过跳转到那里执行代码,就像您所做的那样,那么它将因分段错误而崩溃。
有几种方法可以解决这个问题。您可以告诉链接器使.data
段可执行(不是一个好主意)。您可以告诉编译器将code
变量放入.text
段中(用于所有程序常规代码的段)。您可以告诉编译器和链接器创建一个新的可执行段并将code
其放入其中。所有这些都很棘手。
最好的解决方案是在运行时专门分配您自己的可执行内存并将 shellcode 复制到其中。这完全避免了任何潜在的编译器/链接器问题,尽管它确实增加了一点运行时损失。但是有些操作系统不允许内存同时可写和可执行;所以你首先必须让它可写,复制shellcode,然后让它可执行。
在运行时控制内存权限的方式是mprotect(2)
调用. 所以这是一个很好的方法:
#include <string.h>
#include <sys/mman.h>
char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f";
// Error checking omitted for expository purposes
int main(int argc, char **argv)
{
// Allocate some read-write memory
void *mem = mmap(0, sizeof(shellcode), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
// Copy the shellcode into the new memory
memcpy(mem, shellcode, sizeof(shellcode));
// Make the memory read-execute
mprotect(mem, sizeof(shellcode), PROT_READ|PROT_EXEC);
// Call the shellcode
int (*func)();
func = (int (*)())mem;
(int)(*func)();
// Now, if we managed to return here, it would be prudent to clean up the memory:
munmap(mem, sizeof(shellcode));
return 0;
}