0

I was wondering if it was possible to excecute code that isn't in the main program at all, and if possible, how would you go about doing it? If it can't be done in c, can it be done in c++?

I'm thinking that this might be possible if you import a binary file onto the heap, move the pointer to a register int, and then try to predict the register and call the pointer, but I don't really have a spare pc to attempt this, in case something goes wrong.

trincot
  • 317,000
  • 35
  • 244
  • 286
Draden Merenox
  • 305
  • 2
  • 10
  • Yes, it is possible. All you need to do is call a function where the pointer points to arbitrary code instead of the actual function's instructions. – Dillon Davis Jul 29 '18 at 21:57
  • So you'd do something like make a template function, and then equate the function pointer to another location? – Draden Merenox Jul 29 '18 at 21:58
  • Copy your code into an array `testFun`, and then call it with `((unsigned int (*)())testfun)();` – Dillon Davis Jul 29 '18 at 22:02
  • 1
    Note that whatever code you execute will need to be fairly "simple", since most code expects to be loaded in at a specific memory address rather than an arbitrarily positioned array. You can compile your code to be position independent (-PIC), but there's still going to be other issues involving patching the GOT and PLT. – Dillon Davis Jul 29 '18 at 22:05
  • 2
    One of the easiest ways might be for the program to compile the desired code (by invoking the C compiler), link it into a dynamic library, and then call the routine in the dynamic library. This has the advantage of using existing tools for creating dynamically linked code rather than trying to implement your own. It will, of course, be implementation-system-version-everything dependent. – Eric Postpischil Jul 29 '18 at 22:13
  • @EricPostpischil this is by far the easiest approach. The only justification I've ever encountered for writing one's own dynamic loader is when the resource to be loaded cannot be written to disk. – Dillon Davis Jul 29 '18 at 22:18
  • 1
    Re “I don't really have a spare pc to attempt this, in case something goes wrong”: You are not going to break your hardware with software. You are not going to break your operating system installation by running software in an unprivileged account. (If you do not regularly log into an unprivileged account on your system, create one. [Does current retail Microsoft Windows support that? I have not used it in a while.]) – Eric Postpischil Jul 29 '18 at 22:20
  • @Eric Postpischil : Windows (since Vista) has used a split administrative token, even if you log in as Administrator most actions are performed with a normal user set of permissions, you have to use an elevated process in order to run with full admin powers, And the elevation sequence is such that it is supposed to _always_ require user interaction to perform. It is also possible to run as a true regular user and do the windows equivalent of sudo to run programs that actually require admin privileges. – SoronelHaetir Jul 29 '18 at 23:21

1 Answers1

0

(Update: I may have missed the forest for the trees, so I will cover the more sensible dynamic linking approach first. Note that the answer was accepted before this edit, so see below the divider for the original.)

If you want to use code outside of the main program, the operating system will usually provide the tools for this as part of its dynamic linker. You can usually get it to load .so or .dll files at runtime.

On Linux, you can achieve this with dlopen (loads the .so file) and dlsym (gets a function from it). Here is an example for a fictitious plugin system, where you pass load_plugin a path to a .so file and it attempts to run foo_plugin_init from that file:

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

On Windows, you can do something similar with LoadLibrary (loads the .dll file) and GetProcAddress (gets a function from it). The usage is about the same, except the error reporting dance is a little more complex with GetLastError and FormatMessage to retrieve the resulting string. My Windows programming is quite rusty so I cannot demonstrate this easily.


So long as you have an executable region of memory, you can simply cast it to a function pointer:

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

You might need to first make the memory executable, though the method for doing this is platform-specific. Most operating systems use mprotect for this, though Windows uses VirtualProtect.

Bear in mind that while this technique is often used in JIT compilers, it is very easy to accidentally write software with serious security flaws, so I would avoid it if at all possible. It also violates various security policies that might be in place (e.g. DEP, or grsecurity's W^X policy). Because of this, if you plan to use this in practice, you should provide a fallback which does not rely on executing runtime-generated code.

Score_Under
  • 1,189
  • 10
  • 20
  • 2
    The address of code in memory is not necessarily the value of a function pointer for it. For example, the Digital Alpha referred to functions using a function descriptor, which provided some argument/register information as well as the address of the code. Nobody should expect things like this to work without having a good understanding of C semantics, the C implementation they are using, the operating system they are using, and the hardware they are using. – Eric Postpischil Jul 29 '18 at 22:12
  • Would it be possible to change the program's location variable in order to make the process safer, and then change it back; kind of like a function call, but using program location instead of stack base location? – Draden Merenox Jul 29 '18 at 22:34
  • If you want to make the function use a different area of memory for its stack, that is possible but not in C. You will need to write a platform-specific assembly shim for the specific function you want to call in this way. However, doing this will not improve the security of the execution if that's what you're looking for. For that, you would need something like seccomp or just plain old emulation. – Score_Under Jul 29 '18 at 22:37