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

时间:2013-12-03 16:42:40

标签: c++ c function pointers

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

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

理论上可行吗?

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

5 个答案:

答案 0 :(得分:4)

如果您正在编写类似JIT的东西,它可以动态生成本机代码,那么您可以完成所有这些操作。

但是,为了生成本机代码,您显然需要了解系统的一些实现细节,包括其函数指针的工作方式以及可执行代码需要采取的特殊措施。例如,在修改包含代码的内存之后的某些系统上,您需要先刷新指令缓存,然后才能安全地执行新代码。您无法使用标准C或C ++进行任何此类操作。

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

虽然标准没有提供任何保证,如果你创建一个不引用函数的函数指针会发生什么,在现实生活中和你的特定实现中并且知道平台你可能能够做到这一点原始数据。

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

答案 3 :(得分:1)

有可能,其他答案中给出了警告。但是你肯定想用自定义代码覆盖某个现有函数地址的内存。通常可执行内存不仅不可写,但您无法保证编译器如何使用该代码。如您所知,代码可能会被您认为未修改的许多函数共享。

所以,你需要做的是:

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

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

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

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

    1. 将#1中的页面地址转换为函数指针,并调用指针。

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

答案 4 :(得分:0)

你的问题令人困惑。

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

您不能“覆盖函数地址的内存”。你可能确实可以用某种方式做到这一点,但事实并非如此。你正在写你的程序代码,可能会把它弄得很糟糕。