可以用这种方式使用函数指针吗

is it possible to use function pointers this way?

本文关键字:函数 指针 方式使      更新时间:2023-10-16

最近我突然想到了这件事,引用了维基百科上的话:"要初始化函数指针,必须给它程序中函数的地址。"

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

理论上可能吗?

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

如果你正在编写像JIT这样的东西,它可以动态生成本地代码,那么是的,你可以完成所有这些事情。

然而,为了生成本机代码,您显然需要了解所使用系统的一些实现细节,包括其函数指针是如何工作的,以及对可执行代码需要采取哪些特殊措施。例如,在某些系统上,在修改包含代码的内存后,需要先刷新指令缓存,然后才能安全地执行新代码。你不能用标准的C或C++来实现这些便携功能。

当您覆盖函数时,您可能会发现,您只能对程序在运行时生成的函数进行覆盖。作为正在运行的可执行文件一部分的函数可能会被标记为受操作系统写保护。

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

虽然标准没有提供任何保证,如果你制作了一个不引用函数的函数指针,会发生什么,但在现实生活中,在你的特定实现中,在知道平台的情况下,你可能可以用原始数据来做这件事。

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

这是可能的,但在其他答案中给出了注意事项。不过,您肯定不想用自定义代码覆盖某个现有函数地址的内存。典型的可执行内存不仅是不可写的,而且不能保证编译器是如何使用这些代码的。据您所知,代码可能由许多您认为没有修改的函数共享。

所以,你需要做的是:

  1. 从系统中分配一个或多个内存页。

  2. 将您的自定义机器代码写入其中。

  3. 将页面标记为不可写和可执行。

  4. 运行代码,有两种方法:

    1. 将您在#1中获得的页面地址强制转换为函数指针,然后调用该指针。

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

你的问题措辞混乱。

您可以重新分配函数指针,也可以将它们分配为null。与成员指针相同。除非您将它们声明为const,否则您可以重新分配它们,是的,新函数将被调用。您也可以将它们指定为null。签名必须完全匹配。请改用std::function

您不能"覆盖函数地址处的内存"。你可能确实可以通过某种方式做到这一点,但就是不要这样做。你正在编写程序代码,很可能会把它搞砸。