Problem
I wish to inject an object file into an existing binary. As a concrete example, consider a source Hello.c
:
#include <stdlib.h>
int main(void)
{
return EXIT_SUCCESS;
}
It can be compiled to an executable named Hello
through gcc -std=gnu99 -Wall Hello.c -o Hello
. Furthermore, now consider Embed.c
:
func1(void)
{
}
An object file Embed.o
can be created from this through gcc -c Embed.c
. My question is how to generically insert Embed.o
into Hello
in such a way that the necessary relocations are performed, and the appropriate ELF internal tables (e.g. symbol table, PLT, etc.) are patched properly?
Assumptions
It can be assumed that the object file to be embedded has its dependencies statically linked already. Any dynamic dependencies, such as the C runtime can be assumed to be present also in the target executable.
Current Attempts/Ideas
libbfd
to copy sections from the object file into the binary. The progress I have made with this is that I can create a new object with the sections from the original binary and the sections from the object file. The problem is that since the object file is relocatable, its sections can not be copied properly to the output without performing the relocations first.ld
. So far I tried using objcopy
to perform the conversion objcopy --input elf64-x86-64 --output elf64-x86-64 Hello Hello.o
. Evidently this does not work as I intend since ld -o Hello2 Embed.o Hello.o
will then result in ld: error: Hello.o: unsupported ELF file type 2
. I guess this should be expected though since Hello
is not an object file.Rationale (Optional Read)
I am making a static executable editor, where the vision is to allow the instrumentation of arbitrary user-defined routines into an existing binary. This will work in two steps:
I have, for the most part, already completed the work necessary for step 2, but I am having trouble with the injection of the object file. The problem is definitely solvable given that other tools use the same method of object injection (e.g. EEL).
Use the ld command. "ld file.o -o executable. This will give executable.
A shared object file holds code and data suitable to be linked in two contexts. First, the link-editor can process it with other relocatable and shared object files to create other object files. Second, the runtime linker combines it with a dynamic executable file and other shared objects to create a process image.
In computing, a linker or link editor is a computer system program that takes one or more object files (generated by a compiler or an assembler) and combines them into a single executable file, library file, or another "object" file.
Definition. An object file is a file that contains an object code that has relocatable format machine code which is not directly executable. An executable file is a file that can be directly executed by the computer and is capable of performing the indicated tasks according to the encoded instructions.
If it were me, I'd look to create Embed.c
into a shared object, libembed.so
, like so:
gcc -Wall -shared -fPIC -o libembed.so Embed.c
That should created a relocatable shared object from Embed.c
. With that, you can force your target binary to load this shared object by setting the environment variable LD_PRELOAD
when running it (see more information here):
LD_PRELOAD=/path/to/libembed.so Hello
The "trick" here will be to figure out how to do your instrumentation, especially considering it's a static executable. There, I can't help you, but this is one way to have code present in a process' memory space. You'll probably want to do some sort of initialization in a constructor, which you can do with an attribute (if you're using gcc
, at least):
void __attribute__ ((constructor)) my_init()
{
// put code here!
}
The problem is that .o's are not fully linked yet, and most references are still symbolic. Binaries (shared libraries and executables) are one step closer to finally linked code.
Doing the linking step to a shared lib, doesn't mean you must load it via the dynamic lib loader. The suggestion is more that an own loader for a binary or shared lib might be simpler than for .o.
Another possibility would be to customize that linking process yourself and call the linker and link it to be loaded on some fixed address. You might also look at the preparation of e.g. bootloaders, which also involve a basic linking step to do exactly this (fixate a piece of code to a known loading address).
If you don't link to a fixed address, and want to relocate runtime you will have to write a basic linker that takes the object file, relocates it to the destination address by doing the appropriate fixups.
I assume you already have it, seeing it is your master thesis, but this book: http://www.iecc.com/linker/ is the standard introduction about this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With