Would like to have an executable save its state by modifying its own global constants. Just for the kicks of having a totally self-contained executable.
A few solutions/hacks that come to mind:
- Use libelf and have the program parse itself to find the offset.
- Add a specific marker and just search for it in the executable file. I guess this might even be somewhat cross-platform?
- Use object dumping utils to determine the address in the executable file. This probably needs to be always done as a post-process to project build..
It would be neat to have the linker provide this info.
Is it possible to have the linker provide the offset of a read-only section in the executable file?
Thanks
You are essentially talking about binary rewriting. One method to achieve this without fiddling with the compile process is to map a virtual address to a physical one and then patch it. Interestingly, this is something I covered in my master’s thesis. The following images and text are pulled from that document:
Note that the concept behind my original project was to rewrite code in other binaries assuming that the compile process could not be modified. If your requirements and assumptions are different, this may well not be the easiest and best approach.
The most important idea here is that a section in the disk representation is preserved (not split) when it is mapped into memory. This means data that is at a certain offset into the section in the disk representation will be offset by the same amount after loaded into memory.
In
libelf, similarly tolibbfd, an executable contains a set of sections in which both code and data can reside. When the operating system loads the executable into memory, each section is based at some base address. We can reverse this to map a virtual memory address to a physical file offset. If a physical file offset can be found, the bytes can be patched as a regular file.libelf.This allows us to obtain a set of sections and most importantly, for
each section
libelfcan tell us three things:(virtual_memory_address - section_base_address).(section_disk_offset + (virtual_memory_address - section_base_address)).This process allows an arbitrary virtual memory address to be mapped to its corresponding disk file offset. This offset can then be patched with regular C file IO functions such as
fopen/fseek/fwrite/fclose.This is my code for mapping a virtual address to a physical file offset using the above steps:
This is the code to patch an ELF executable given an offset:
More detailed information can be found in the report itself which is publicly available here.