是否可以在 C 中执行任意代码?

Is it possible to excecute arbitrary code in C?

我想知道是否可以执行根本不在主程序中的代码,如果可能的话,您将如何执行?如果不能在c中完成,是否可以在c++中完成?

我认为如果将二进制文件导入堆,将指针移动到寄存器 int,然后尝试预测寄存器并调用指针,这可能是可能的,但我真的不知道有一台备用电脑来尝试这个,以防出现问题。

(更新:我可能只见树木不见森林,所以我将首先介绍更明智的动态链接方法。请注意,在本次编辑之前答案已被接受,因此请参阅下面的分隔符以获取原始内容。)

如果您想在主程序之外使用代码,操作系统通常会为此提供工具,作为其动态链接器的一部分。您通常可以让它在 运行 时间加载 .so.dll 文件。

在 Linux 上,您可以使用 dlopen(加载 .so 文件)和 dlsym(从中获取函数)来实现此目的。这是一个虚构插件系统的示例,您将 load_plugin 传递给 .so 文件的路径,它会尝试从该文件 运行 foo_plugin_init

#include <stdio.h>
#include <dlfcn.h>

int load_plugin(const char* filename) {
    void *handle = dlopen(filename, RTLD_LAZY);  // Try to load the .so file

    dlerror();  // Clear any error a previous dlsym might have reported
    void (*plugin_init)() = dlsym(handle, "foo_plugin_init");  // Load the "foo_plugin_init" function
    const char* error = dlerror();  // Check for errors reported by dlsym
    if (error) {
        fprintf(stderr, "Could not load plugin %s: %s\n", filename, error);
        return 0;
    }

    plugin_init();  // Call the newly loaded function
    return 1;
}

在 Windows 上,您可以使用 LoadLibrary(加载 .dll 文件)和 GetProcAddress(从中获取函数)执行类似的操作。用法大致相同,除了错误报告舞蹈有点复杂,使用 GetLastErrorFormatMessage 来检索结果字符串。我的 Windows 程序很生疏,所以我不能轻易演示。


只要你有一个可执行的内存区域,你就可以简单地将它转换为一个函数指针:

void execute_memory(const void* mem) {
    void (*func)() = mem;
    func();
}

您可能需要先使内存可执行,但执行此操作的方法因平台而异。大多数操作系统为此使用 mprotect,尽管 Windows 使用 VirtualProtect.

请记住,尽管 JIT 编译器中经常使用这种技术,但 非常 很容易意外编写出具有严重安全漏洞的软件,因此我会尽量避免使用它可能的。它还违反了可能存在的各种安全策略(例如 DEP 或 grsecurity 的 W^X 策略)。因此,如果你打算在实践中使用它,你应该提供一个不依赖于执行 运行time-generated 代码的回退。