可以使用函数指针来运行“数据”吗?

时间:2010-06-18 23:23:42

标签: c function-pointers

这不是大多数人可能会使用的东西,但它只是浮现在脑海中并且困扰着我。

是否可以使用c-string中的某些机器代码,然后将其地址转换为函数指针,然后使用它来运行该机器代码?

4 个答案:

答案 0 :(得分:9)

理论上你可以按照Carl Norum的说法。这称为“自修改代码。”

在实践中,通常会阻止你的是操作系统。大多数主要的现代操作系统旨在区分“可读”,“可读写”和“可执行”存储器。当这种操作系统内核加载一个程序时,它会将代码放入一个特殊的“可执行”页面,该页面被标记为只读,这样用户应用程序就无法对其进行修改。同时,尝试GOTO不在“可执行”页面中的地址也会导致故障异常。这是出于安全目的,因为许多种恶意软件和病毒以及其他黑客都依赖于使程序跳转到修改后的内存中。例如,黑客可能会提供应用程序数据,导致某些功能将恶意代码写入堆栈,然后运行它。

但从本质上讲,操作系统本身对加载程序的作用正是你所描述的 - 它将代码加载到内存中,将内存标记为可执行文件,然后跳转到内存中。

在嵌入式硬件领域,可能没有操作系统妨碍你,所以有些平台会经常使用它。在PlayStation 2上,我曾经一直这样做 - 如果有一些特定于沙漠级别的代码,并且在其他任何地方都没有使用过,我不会一直把它留在内存中 - 而是我将其与沙漠级别一起加载,并将我的函数指针修复为正确的可执行文件。当用户离开关卡时,我会从内存中转储该代码,将所有这些函数指针设置为异常处理程序,并将下一级别的代码加载到同一空间中。

答案 1 :(得分:6)

是的,你绝对可以这样做。除非您的系统或编译器以某种方式阻止它(例如,您拥有哈佛架构),否则没有什么可以阻止您。在跳跃之前,请确保您的“数据”是有效的说明,否则您将面临灾难风险。

答案 2 :(得分:1)

甚至不可能尝试在C语言中合法地执行此类操作,因为没有合法的方法来使函数指针指向“数据”。 C语言中的函数指针只能从其他函数指针初始化/分配,即使您使用显式转换也是如此。如果违反此规则,则行为未定义。

也可以使用实现定义的结果从整数(通过使用显式转换)初始化函数指针(与其他情况下的未定义结果相反)。但是,尝试通过以这种方式获得的指针进行调用来执行“数据”仍会导致未定义的行为。

如果您愿意忽略行为未定义的事实,那么该未定义行为的实际表现形式在不同平台上会有所不同。在某些平台上,它甚至可能“工作”。

答案 3 :(得分:0)

还可以想象一个superoptimzer这样做是为了根据它优化的函数的规范测试小的汇编程序序列。