c - 加载原始二进制文件

时间:2015-05-22 19:10:04

标签: c operating-system elf

是否可以执行存储在char数组中的原始二进制文件?我尝试这样做:

#include "stdio.h"
int main(int argc, char **argv)
{
    FILE *f = fopen(argv[1],"r");
    if(!f)
        return 1;
    fseek(f,0,SEEK_END);
    long l=ftell(f);
    rewind(f);
    char *buf = malloc(l+1);
    fread(buf,1,l,f);
    fclose(f);
    void (*func)() = (void(*))buf;
    func();
}

但它只给出了我的段错误。我在自己的操作系统上工作(从头开始),所以我摆脱了它们。

2 个答案:

答案 0 :(得分:5)

道歉,这不是一个完全答案,但它太长,不适合作为评论......

我将假设将原始二进制文件读取到缓冲区中的文件的意图是将代码字节写入RAM,并且您希望执行这些字节。让我们假设你已经修复了文件I / O,所以现在你有一个带代码字节的缓冲区。还有一些原因可以解释为什么你仍然可以进行段落错误。

首先,您的O / S是否实现了具有读取,写入和执行等页面属性的虚拟内存?大多数现代操作系统都不允许您在未标记为代码的页面上执行代码。 (以这种方式标记页面对于了解可以交换的内容以及防止恶意编码非常重要。)

其次,您完全可重定位的二进制代码是否已加载?换句话说,如果代码中有任何JUMP,它们都是相对的吗?如果它们中存在任何绝对的JUMP操作,那么你需要通过补丁运行它们,直到缓冲区在内存中的位置。

第三,二进制代码是100%自包含的吗?如果它调用任何外部函数,那么你也需要修补它们。

最后,二进制代码是否需要访问数据?如果是这样,所有数据也都在二进制文件中,也是相对地址与绝对数据。

答案 1 :(得分:1)

您可以这样做但是:

  1. 您不能(通常)将您的可执行文件存储在堆中,因为您在此处使用malloc(由于相同的原因也不在堆栈中),因为如果您的硬件支持它,您的操作系统可能会标记这些区域是可读的,可写的但没有可执行文件(或者至少它应该这样做)。

  2. 您不仅可以获取已编译程序的代码,将其解压缩到文件中并期望运行它,因为它通常需要重定位,导入动态库,为变量设置另一个虚拟内存区域。

  3. 你可以通过一个简单的手工程序来做到这一点,该程序可以调用exit(0)打印" Hello World"。

    您可以使用已编译的代码。为此,您需要(至少):

    • 编译一个自包含的程序(没有导入的动态库,静态链接库并重新编译这些静态链接的库);

    • 与位置无关的代码(-fpic的{​​{1}});

    • 没有任何重新定位(也许-fpie可能有帮助吗?)。

    如果您设法执行此操作,则可以从ELF文件的-fvisibility=hidden部分生成原始文件。它可能需要可执行,可读和可写(因为您将拥有代码和数据)。您可能必须在前面添加一条指令,以跳转到可能位于文件中间的入口点。

    你可能会看看PT_LOAD是如何编译的:它应该被加载到虚拟地址空间的任何地方,并且有一个自身的子集,它应该在重定位之前起作用(因为ld.so重新定位本身就像我所理解的那样。)

    但你可能只是尝试实现一个基本的ELF加载器(并正确处理重定位)。