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.
(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.