c -两个shellcode在一个程序中导致段错误,我如何将shellcode作为参数传递给函数? &



下面我有两个关于C编程和shellcoding(汇编)的问题。

问题1:谁能提供一个答案,为什么把两个shellcode在一个程序不会工作?我知道这与记忆区域有关,但我需要知道确切的原因。程序是用gcc编译的,带有-zexecstack-fno-stack-protector选项。

#include <stdio.h>
#include <string.h>
main(int argc, char *argv[])
{
unsigned char shellcode[] = "x01x02<SHELLCODE>";
/* if the below line is uncommmented it will result in segault */ 
/* unsigned char shellcode_[] = "x01x02<SHELLCODE>"; */
int (*ret)() = (int(*)())shellcode;
return 0;
}

那么如何将多个shellcode划分到不同的内存区域并调用它们而不中断彼此之间的执行流,并决定调用哪一个呢?(我的意思是只是存储两个shell代码,而不是同时运行它们,如果这是可能的) .

问题2:如果shellcode必须作为参数传递给函数,正确的方法是什么?

伪代码:

unsigned char shellcode[]  = "x01x02...";
void call_shellcode(unsigned char shellcode[200]);
main()
{
call_shellcode(shellcode);
}
void call_shellcode(unsigned char shellcode[200])
{
... print/call shellcode
}

更新:因为似乎有一些误解的问题,这不是实际的shellcode。我知道shellcode是什么以及它是如何产生的,以及它是如何运作的。我没有在C存根中提供实际的shellcode以使其处于可读状态。值"x01x01"是一个伪代码指问题的想法,而不是任何实际内容。

你的shellcode不可能工作的原因很简单:它开始于x01x02:

unsigned char shellcode[] = "x01x02<SHELLCODE>";

我不知道为什么你认为你的shellcode必须以这两个字节开始:它真的没有!

这两个字节解码为add DWORD PTR [rdx],eax(或edx如果运行在32位模式下)。由于在调用shellcode时,您无法控制RDX/EDX的值,因此很可能会立即导致分段错误,因为RDX/EDX不包含有效的(可写的)内存地址。

改变字面上的任何周围的shellcode,在函数或外部,可能会导致编译器选择一个不同的寄存器分配,这将导致RDX/EDX有一个好的值在运行时,不会导致崩溃,但这只是一个幸运的巧合。像这样编写和使用shellcode本质上是未定义的行为,或者至少是实现定义的(固定操作系统和编译器),所以必须格外小心。

那么如何将多个shellcode划分到不同的内存区域并调用它们而不中断彼此之间的执行流,并决定调用哪一个呢?

嗯,你并没有把任何东西划分到"不同的记忆区域"……无论你使用的是一个数组、两个数组还是十个数组,它们都是在堆栈上声明的,而且它们在堆栈上是紧挨着的。

如果你想从一个跳转到另一个,这将是一个复杂的任务,因为通常你不知道一个变量在堆栈上的位置,所以你必须做一些数学计算你的当前位置,然后从一个shellcode块到另一个的偏移量,最终执行一个相对的调用/跳转。

如果shellcode必须作为一个参数传递给一个函数,什么是正确的方法来做到这一点?

正确的方法是mmap一个RWX内存区域,将shellcode写入其中(memcpy,从stdin读取等),然后将指向该内存区域的指针传递给您想要的函数。您不能保证编译器将全局数据的一部分放在可执行内存区域中。事实上,没有现代的编译器会这样做,而且,没有现代的内核会把这样一个区域映射为可执行的,即使ELF是用-z execstack编译的。

在最近的内核中,-z execstack只适用于堆栈本身,所以通过变量传递shellcode作为函数参数只有当变量在堆栈上定义时才有效。

在同一个作用域中不能有两个同名的变量(这部分与变量是什么或如何使用它们无关)。只需给第二个shellcode一个不同的名字。

注意,我不打算评论你正在尝试做什么,除了我不会认为手工创建的机器代码作为"shell代码";(我通常认为这是为bash之类的命令shell编写的代码)。