【问题标题】:Execute shellcode by casting to function pointer in Visual C++通过强制转换为 Visual C++ 中的函数指针来执行 shellcode
【发布时间】:2012-03-06 22:57:41
【问题描述】:

在 gcc 中这很好用。代码类似于:

unsigned char b[50] = "\xda\xd1 ... \x0"; //some shellcode with terminating \x0
( (void(*)())b )(); //cast b to function pointer from void to void, then run it

但是当它被放到 Visual C++ 中时,它会吐出这个错误信息:

1>..\test.cpp(132): error C2440: 'type cast' : cannot convert from 'unsigned char [50]' to 'void (__cdecl *)(void)'
1>          There is no context in which this conversion is possible

有人知道为什么会这样吗?

【问题讨论】:

  • 即使你让它以某种方式工作,这也是一个非常糟糕的主意。
  • 或:reinterpret_cast<void(*)()>(static_cast<char*>(b))()
  • @NiklasB。 (*(void(*)())&b[0])() 在运行时崩溃。首先,&b[0] 与 b 相同。其次,开头多余的 * 解引用了函数指针;我假设它会尝试将 shellcode 解释为地址。
  • 奇迹不是它在 Visual C++ 中崩溃,奇迹是它在 gcc 中工作。你所说的“shellcode”到底是什么意思?
  • @user49164 取消引用函数指针是无害的。它很快衰减回函数指针。这就是经典的***********************************fun_ptr 示例的来源。

标签: c++ casting shellcode


【解决方案1】:

适当的调试器会告诉您出了什么问题。我只能猜测您的代码导致访问冲突,因为您要跳转到的缓冲区不可执行。

可能您使用的是默认启用DEP 的系统,例如 Vista 或 7,因此您必须确保您的 shellcode 是可执行的。为此,首先使用VirtualAlloc 分配一个新的可执行缓冲区并将您的shellcode 复制到其中,然后执行它:

void *exec = VirtualAlloc(0, sizeof b, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, b, sizeof b);
((void(*)())exec)();

顺便说一句,您不需要以空值终止 shellcode(C++ 会自动为您终止字符串文字,但这不是必需的)。您也不需要指定尺寸:

unsigned char b[] = "\xcc";

【讨论】:

  • 谢谢 - 这工作正常。不知道执行东西有一个特殊的分配函数。
  • @user49164:为了增加利用基于堆栈和堆的缓冲区溢出的难度,DEP 强制服从内存页面上的执行权限。这可以防止立即执行堆栈或堆上的数据。 VirtualAlloc 不是用于执行内容的特殊分配函数,它是通用分配函数(恰好将分配内存的所需访问权限作为参数)。
【解决方案2】:

将数据重新解释为不同类型的典型方法是复制二进制表示:

void (*fp)();
unsigned char buf[50];
char const * p = reinterpret_cast<char const *>(&buf);

std::copy(p, p + sizeof(char const *), reinterpret_cast<char*>(&fp));

// now fp contains the same value as &buf

fp();  // call

这避免了由别名和对齐违规引起的未定义行为。

【讨论】:

  • OP 正在尝试将指向缓冲区的指针重新解释为函数指针,以便将内容作为代码执行。你的版本用一些缓冲区内容覆盖了函数指针——结果肯定不是一个有效的指针。您需要定义一个指向buf 的指针,然后复制它的值。
  • 已确认。这会在运行时崩溃。
  • 这似乎应该可以工作,但它崩溃了——也许是同一个 DEP 问题?
  • 即使在编辑后的表单中,也只会复制sizeof(void*)字节。
  • @NiklasB.:嗯,不,它会复制sizeof(char*) 字节,这正是&amp;buf 的字节数。没有人说这保证是有意义的,并且由您来确保在您的平台上 char 指针、void 指针和函数指针具有相同的大小。如果您想省略第一次检查(即添加 void const * q = static_cast&lt;void const *&gt;(p); 并复制该检查),可以向 void-pointer 添加一个(标准)转换。
猜你喜欢
  • 2012-01-19
  • 2021-02-26
  • 2012-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多