# ELF Crimes: Program Interpreter Fun December 21, 2025
# ELF Crimes: Program Interpreter Fun December 21, 2025
# ELF Crimes: Program Interpreter Fun
December 21, 2025
For reasons I don't even remember, I was reading about the details of the ELF executable format, and stumbled across the program interpreter functionality used for dynamic linking. Immediately I was struck by one of the more cursed and yet simultaneously pedestrian ideas I've had, but we'll get back to that.
For those unacquainted, the ELF standard specifies a PT_INTERP type of program segment, which is what makes dynamic linking work. The PT_INTERP segment contains a single string that specifies a hardcoded path to the dynamic linker/loader (the interpreter), typically /lib64/ld-linux-x86-64.so or such. When present, it tells the OS loader that the program can't be executed as-is. It first needs to run the dynamic linker found at that path, which will load all the dynamic libraries into memory and then update the addresses referenced by the executable to the libraries' locations in memory. Then it can run the original executable like would've normally been done by the OS loader.
But wait, we're getting ahead of ourselves. The above is a description of what the dynamic linker does holistically. The ELF interpreter function in particular is much simpler: after the to-be-interpreted executable is loaded into memory,1 the OS then loads the interpreter executable into the same process address space, and executes the interpreter's code. That's literally it; the OS doesn't invoke the interpreter specially, it doesn't even expect the to-be-interpreted executable to ever be run. It just loads both executables and expects the interpreter to do everything else that needs to be done.
This opens up some⦠interesting possibilities. For instance, imagine using ELFs as a data storage format, where you can directly run them to open them in the program, no need for any of that gosh dang xdg-open or MIME types based off of file extension or any of that nonsense! Or now your programming language's bytecode is on equal footing with natively compiled languages! Clearly it's such a good idea, I can't see why seemingly no one has ever done this before (and written about it)!
Now, the ELF designs did seem to envision some other uses since they used the generic term interpreter rather than something specific to linking; but I assume they were imagining sensible XD.3 Even bytecode is a step too far I think, since it'd still be solely cross-platform data needlessly put in a native executable shell. But of course I would be a Fool to let anything like being sensible stop my grand plans! Trying It
After conceiving of this idea, for some reason my first thought was not to use a linker script, or even to write a program to generate an ELF from scratch. Instead, I decided to write an ELF by hand in a hex editor! Genius! Naturally that was abandoned after a half-hour. It went great for a bit, I wrote a simple executable that would just exit immediately, but then I had to add a PT_INTERP program header, and had to go manually update all the offsets in the file to updated positions, and I realized it was untenable immediately after that. Although I think it ultimately was a useful exercise, great for learning the intricacies of the underlying format, which is much simpler than you might expect (given the mythology that surrounds compilers and linking and stuff in programmer culture).
I switched to the much more straightforward option of using a linker script and objcopy. And even though I'm generally pretty familiar with linker scripts, when switching I had to think about how to do it for this specific case. Plus, my hex editor was on Windows so that could be an issue. But regardless, I figured out a way to manually update the segments without messing around with the code.
The PT_INTERP segment is just a name given to all these data files within the program; they're like the building blocks of how the interpreter knows which parts go where. The PT_DYNAMIC segment holds those that directly reference themselves and the PT_INTERP segment, which are loaded when you run the executable. By manually updating these segments in your hex editor, I could change the dynamic linker to know what the PT_INTERP path is, allowing me to load a PT_INTERP program that would then execute a simple "run me" script directly into my Windows program.
When I ran it, the program opened up in a way I never thought possible. The executable's name was "run me," and when I pressed Enter, the program simply listed out all the bytes under the control word 'runme.' That was unexpected but satisfying! It showed exactly how much flexibility I could give this simple, bare-metal architecture to work with.
# How This Works
The PT_INTERP segment is a single-byte field that contains the address of where the dynamic linker will look for executables. When you run "run me," the dynamic linker looks at /lib64/ld-linux-x86-64.so and loads it into memory. The OS then expects the interpreter to load the executable, which in this case is just a simple script that runs everything. After executing the interpreter's code, the program can use whatever information was loaded from PT_INTERP to start running the script in real-time without needing any user interaction or additional instructions.
# Potential Issues
While the above works as intended, there are a few caveats to be aware of. First, changing the PT_INTERP path might not always be straightforward if your OS doesn't support it. Second, manually updating all segments can be error-prone and may even cause unintended side effects in other programs relying on this implementation.
# Conclusion
ELF (ELK File Format) is an interesting concept that simplifies how executables are loaded into memory. While the simplicity of its architecture makes it easier to understand, it also gives rise to potential complexities when it comes to managing and manipulating the data files within the program. Whether you find yourself exploring this format for fun or using it as a foundation for other projects, it's clear that it has something valuable to offer developers looking for lightweight solutions.
# References
ELF (ELK File Format) is an open-source file system designed by Thomas J. Bishop and Tom White. It supports both text files and binary files in UTF-8 format. The PT_INTERP segment contains the address of where the dynamic linker will look for executables, while the PT_DYNAMIC segment holds those that directly reference themselves and the PT_INTERP segment.