I'm trying to see if I can append function code in the .text section of an ELF while still maintaining the execution flow of the original ELF. Ideally, I want to call the new function but that's it's own mountain to climb. I'm more concerned with just adding the code. Is this realistic? Or am I way over my head? I've been able to add the code by simply overwriting bytes. However, I would like to extend the .text section and insert it. If there's a better method of inserting new functionality into an ELF I'm all ears. But any guidance is helpful.
It is possible to do what you want. There are some difficulties you may encounter though. I'll show you a short instruction how it can be done in several different cases.
- Have a look at ELF specification to know how every file in that format looks like, which sections it consists of and how they are located in the process image at the runtime. Even when there exist tools that can perform the job automatically for you, it's good to know what has to be done "underneath".
- Write and compile the code you want to add. You can do it later of course, but this way you will know how much space you need to add.
- Having the knowledge obtained in
1., you can now interpret the output of
readelf -S executableToPatchcommand. It will list the sections present in the executable along with the information such as their offset in the file.
- If you are lucky, the offset of the section you want to update + its basic size + size of the code you want to add is less than the offset of the next section. In such a case, you simply want to create a file containing the new content of this section (that is, entire content before your modification and the extra code appended by you). Then you can simply run:
objcopy --update-section .text=fileWithTheNewContent nameOfExe nameOfExePatchedand you are done.
- If you are not so lucky, you can still run the command from the previous point, but you will get messages similar to this:
objcopy: nameOfExe: section .text offset adjusted to newOffset, which simply means that
objcopyhas moved some subsequent sections forward in such a way that they don't overlap with each other (which, from
1., is one of the requirements of the ELF specification). However, contrary to the previous point, you cannot simply finish here, because it could be the case that some section with data has changed its offset as well.
- Check which sections have been relocated. If none of them contains data, you can now test the program whether it behaves the same as before your modification. If it does, your job is done - your code has been successfully updated.
- If it behaves differently or some of your sections with data has changed its offset, it is necessary to fix the data references to this section, that is to patch the code, so that it references offsets in the new data section location. For example, when
.rodatahas been moved forward by
4096bytes, you will have to change all references to
4096to each address, i.e. if you have
mov rax, [rip+0x20]you want to change it to
mov rax, [rip+0x1020], but it isn't straightforward to do, although it's still possible.
I would like to extend the .text section and insert [code]. If there's a better method of inserting new functionality into an ELF I'm all ears.
Techniques for adding arbitrary code to ELF files were pioneered by Linux virus writers beginning all the way back in the 1990s. In comparison with the methods they developed, as well as with more modern techniques, taking the
objcopy route seems rather crude. There is no need to re-invent the wheel.
More modern approaches to manipulating ELF binary runtime behavior have emerged since then, including a variety of injection techniques and instrumentation frameworks.
For the purposes of this question we can divide approaches to modifying binary functionality into 2 approaches:
- adding code to the file itself (static modification, occurs prior to program runtime)
- inducing new behavior via injection (runtime modification).
Static Modification Techniques
Text Segment Padding Infection
The classic ELF
text segment (not section) padding infection method seems to be the most closely related to what you are currently attempting.
Page padding at segment borders however provides a practical location for parasite code given that its size is able. This space will not interfere with the original segments, requiring no relocation. Following the guideline just given of preferencing the text segment, we can see that the padding at the end of the text segment is a viable solution. 1
The algorithm to accomplish this is as follows:
PAGE_SIZEin the ELF header
- Patch the insertion code (parasite) to jump to the entry point (original)
- Locate the text segment program header
- Modify the entry point of the ELF header to point to the new code (
p_fileszby account for the new code (parasite)
p_memszto account for the new code (parasite)
- For each
phdrwho's segment is after the insertion (text segment)
- For the last
shdrin the text segment
sh_lenby the parasite length
- For each
shdrwho's section resides after the insertion
- Physically insert the new code (parasite) and pad to
PAGE_SIZE, into the file - text segment
In addition to an explanation of the technique as well as the source code for a virus that implements this technique included with the 1998 article , there is a 2016 (it still works, after all these years) tutorial on ELF segment padding infection available at 0x00sec called ELFun File Injector.
Besides the text segment infection approach, there is also data segment infection, which is quite similar. One can also add an additional segment if they so choose.
First detailed in a Phrack article back in 2000 2, this method involves patching the PLT/GOT to point to code inside the binary, which has been inserted via an infection method rather than pointing at code in a shared library dynamically linked to the binary:
It can be noted that we can change [function name in GOT] to point to our own code, thus replacing library calls. If we save the state of the GOT before replacing, we can call the old library routine and thus redirect any library call. 2
The easiest way to implement this method seems to be using the LIEF instrumentation framework. A tutorial for doing this is provided in the LIEF documentation under the title Infecting the plt/got. Note that in the tutorial the GOT is patched instead of the PLT, and code is added to the file by creating a new segment (one of the aforementioned infection techniques).
There are additional techiniques besides this for modifying the file directly, but segment padding infection and PLT/GOT infection seem to be the most straightforward.
Runtime Modification Techniques
Since DLL injection and runtime process manipulation are less directly related to your current task, I won't go into much detail.
- DLL injection via
LD_PRELOADis incredibly powerful and useful. 2 tutorials I have found to be useful are
- DLL hooking can be accomplished with LIEF as well: see ELF Hooking
- process code injection using
Unix Viruses. Silvio Cesare
SHARED LIBRARY CALL REDIRECTION VIA ELF PLT INFECTION, Silvio Cesare