C++ 可以这样使用函数指针吗?

C++ 可以这样使用函数指针吗?,c++,c,function,pointers,C++,C,Function,Pointers,这是我最近想到的一件事,引用维基百科的一句话:“要初始化函数指针,必须给它程序中函数的地址。” 所以,我不能让它指向一个任意的内存地址,但是如果我用一段与以前相同大小的数据覆盖函数地址处的内存,然后通过指针调用它呢?如果此类数据对应于实际函数,且两个函数具有匹配的签名,则应调用后者而不是第一个签名 理论上可能吗 如果由于我应该知道的一些非常明显的原因而无法做到这一点,我深表歉意。您的问题措辞混乱 您可以重新分配函数指针,也可以将它们分配给null。成员指针也是如此。除非声明它们为const,否则

这是我最近想到的一件事,引用维基百科的一句话:“要初始化函数指针,必须给它程序中函数的地址。”

所以,我不能让它指向一个任意的内存地址,但是如果我用一段与以前相同大小的数据覆盖函数地址处的内存,然后通过指针调用它呢?如果此类数据对应于实际函数,且两个函数具有匹配的签名,则应调用后者而不是第一个签名

理论上可能吗


如果由于我应该知道的一些非常明显的原因而无法做到这一点,我深表歉意。

您的问题措辞混乱

您可以重新分配函数指针,也可以将它们分配给null。成员指针也是如此。除非声明它们为const,否则可以重新分配它们,并且会调用新函数。您还可以将它们分配给null。签名必须完全匹配。改用
std::function


不能“覆盖函数地址处的内存”。你可能确实可以用某种方式来做,但就是不可以。您正在编写程序代码,很可能会把它搞得一团糟。

如果您正在编写JIT之类的东西,它会动态生成本机代码,那么是的,您可以完成所有这些事情

然而,为了生成本机代码,您显然需要了解所使用系统的一些实现细节,包括其函数指针如何工作以及需要对可执行代码采取哪些特殊措施。例如,在某些系统上,在修改包含代码的内存后,需要先刷新指令缓存,然后才能安全地执行新代码。你不能用标准C或C++来做任何一个。
您可能会发现,当您要覆盖函数时,您只能对程序在运行时生成的函数进行覆盖。作为正在运行的可执行文件的一部分的函数可能会被操作系统标记为写保护。

您可能遇到的问题是。它试图阻止您以代码的形式执行数据或允许将代码写入类似的数据。你可以在Windows上关闭它。一些编译器/操作系统还可能将代码放入操作系统/硬件保护的内存中类似常量的部分。当您将字节数组写入一个内存位置,然后调用一个包含jmping的函数到该位置时,该标准没有说明什么应该或不应该起作用。这一切都取决于您的硬件和操作系统。

虽然标准没有提供任何保证,但如果您在现实生活中以及在您的特定实现中创建了一个不引用函数的函数指针,并且了解了平台,您可能能够使用原始数据执行该操作


我见过一些示例程序,这些程序使用适当的二进制代码创建了一个char数组,并通过仔细转换指针来执行它。因此,在实践中,以一种不可移植的方式,您可以实现这种行为。

这是可能的,其他答案中给出了警告。不过,您肯定不想用自定义代码覆盖某些现有函数地址的内存。不仅通常可执行内存是不可写的,而且对于编译器可能如何使用该代码,您也没有任何保证。据您所知,代码可能由许多您认为没有修改的函数共享

因此,您需要做的是:

  • 从系统中分配一个或多个内存页

  • 将自定义机器代码写入其中

  • 将页面标记为不可写和可执行

  • 运行代码,有两种方法:

  • 将#1中的页面地址强制转换为函数指针,并调用该指针

  • 在另一个线程中执行代码。您将代码指针直接传递给启动线程的系统API或框架函数


  • 我想这就是恶意软件的工作原理,像这样:这个问题是如何被投票的?因为这是一个关于有用技术的真正问题。@AndersLindén可能是因为答案很简单。@AndersLindén通过点击“^”按钮。我想我的问题可以被改写成两个子问题1)是否可以覆盖函数地址处的内存?2) 如果签名匹配,是否可以通过指针调用与刚编写的数据对应的函数?@user1909612:取决于“可能”的含义。某些系统不会阻止您这样做,但结果可能未定义。同样,堆的大多数可写部分都标记为“执行保护”。不过,大多数操作系统都有一个API来改变这一点。@Dan:区别在于,为了支持JIT,操作系统允许您标记一个堆区域的可执行文件,但它仍然可能不允许您标记自己的可写可执行文件。到目前为止,这个答案是最详细的,为了公平起见,我会再等待一段时间,然后再将其标记为可接受。