Krzysztof Witkowski
Krzysztof Witkowski

Reputation: 13

c - loading raw binaries

Is it possible to execute a raw binary stored in a char array? I tried doing it like so:

#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();
}

but it only gives my segfaults. I'm working on my own OS (from scratch), so I'm getting rid of them.

Upvotes: 1

Views: 127

Answers (2)

ysdx
ysdx

Reputation: 9315

You might be able to do that but:

  1. You cannot (in general) store your executable in the heap as your doing it here with malloc (nor in the stack for the same reason) because if your hardware supports it, your OS probably marks those areas as readable, writable but no executable (or at least it should do it).

  2. You cannot just take the code of a compiled program, extract it to a file and expect to run it because it usually needs relocation, importing dynamic libraries, setting up another virtual memory area for the variables.

You could be able to do this with a simple handcrafted program which makes a system call to exit(0) ot prints "Hello World".

You might be able to use compiled code. For this, you would need to (at least):

  • compile a self-contained program (no imported dynamic libraries, link the libraries statically and recompile those statically linked library);

  • with position-independant code (-fpic of -fpie);

  • without any relocation (maybe -fvisibility=hidden might help?).

If you manage to do this, you might be able to generate a raw file from the PT_LOAD sections of the ELF file. It would probably need to be executable, readable and writable (because you'll have code and data). And you will probably have to prepend an instruction to jump to the entry point which might be in the middle of the file.

You might look at how ld.so is compiled: it is expected to be loaded anywhere in the virtual address space and has a subset of itself which is supposed to be functional before relocations (because ld.so relocates itself as fare as I understand).

But you should probably just try to implement a basic ELF loader instead (and properly handle relocations).

Upvotes: 1

Ron Kuper
Ron Kuper

Reputation: 847

Apologies that this isn't exactly an answer but it's too long to fit as a comment...

I'm going to assume the intent of the file read with raw binary into a buffer is get code bytes into RAM, and you want to execute these bytes. Let's assume you've got the file I/O fixed, so now you have a buffer with code bytes. There's a few reasons why you could still segfault.

First, does your O/S implement virtual memory with page attributes such as read, write and execute? Most modern O/S's won't let you execute code on a page that isn't marked as code. (Marking pages this way is important to know what can be swapped and also to prevent malicious coding.)

Second, is the binary code you've loaded in fully relocatable? In other words, if the code has any JUMPs in it are they all relative? If there's any absolute JUMP ops in their then you need to run through a patch them up to line up where your buffer is in memory.

Third, is the binary code 100% self contained? If it calls out to any external functions then you need to patch those up, too.

Finally, does the binary code need to access data? If so, is all the data also in the binary and also relative addressed vs. absolute.

Upvotes: 5

Related Questions