7

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.

3
  • 1
    There are well-known techniques that can be used to add code to an ELF binary. What is your goal? Is the binary statically linked? Is the section header table present in the binary?
    – julian
    Aug 17, 2019 at 11:30
  • 1
    Hi and welcome to RE.SE. Adding to what @julian wrote: what has python to do with it?
    – 0xC0000022L
    Aug 17, 2019 at 21:56
  • it does have the standard dynamically linked libraries but I want to add a user defined function to the ELF. The section header table is present
    – stayge
    Aug 19, 2019 at 13:50

3 Answers 3

7

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.

  1. 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".
  2. 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.
  3. Having the knowledge obtained in 1., you can now interpret the output of readelf -S executableToPatch command. It will list the sections present in the executable along with the information such as their offset in the file.
  4. 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 nameOfExePatched and you are done.
  5. 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 objcopy has 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.
  6. 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.
  7. 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 .rodata has been moved forward by 4096 bytes, you will have to change all references to .rodata by adding 4096 to 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.
1
  • Thank you! I've recently tried the obj copy - I now see that I have .rodata references in the .text section which explains quite a bit. Now going through and updating those will definitely be the next challenge. I appreciate it!
    – stayge
    Aug 19, 2019 at 23:08
3

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:

  1. adding code to the file itself (static modification, occurs prior to program runtime)
  2. 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:

  1. Increase p_shoff by PAGE_SIZE in the ELF header
  2. Patch the insertion code (parasite) to jump to the entry point (original)
  3. Locate the text segment program header
    • Modify the entry point of the ELF header to point to the new code (p_vaddr + p_filesz)
    • Increase p_filesz by account for the new code (parasite)
    • Increase p_memsz to account for the new code (parasite)
  4. For each phdr who's segment is after the insertion (text segment)
    • increase p_offset by PAGE_SIZE
  5. For the last shdr in the text segment
    • increase sh_len by the parasite length
  6. For each shdr who's section resides after the insertion
    • Increase sh_offset by PAGE_SIZE
  7. Physically insert the new code (parasite) and pad to PAGE_SIZE, into the file - text segment p_offset + p_filesz (original) 1

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 [1], 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.


PLT/GOT Infection

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_PRELOAD is 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 ptrace()

Some methods are more obscure, such as the DT_NEEDED infection detailed in The Cerberus ELF Interface and "subversive dynamic linking" described in Cheating the ELF


References

  1. Unix Viruses. Silvio Cesare

  2. SHARED LIBRARY CALL REDIRECTION VIA ELF PLT INFECTION, Silvio Cesare

4
  • While I was thinking about that route - I don't want my code to be executed first. I want to modify an original function call in main to call my code. While I change the entry point to my code would that not execute my code immediately?
    – stayge
    Aug 21, 2019 at 15:08
  • @stayge You have been presented with many routes. I want to modify an original function call in main to call my code. <- Is a shared library function being called? Is patching the CALL address to jump to your inserted code sufficient? Why are you operating under this constraint? Please clearly describe the problem.
    – julian
    Aug 21, 2019 at 15:23
  • A user-defined function is being called. I have tried putting my code into a .so and using LD_PRELOAD but it only overrides library functions. I would like to patch the call so it can jump to my function and then return back to main and continue executing. It's just a matter of where to put the code without having to rework the whole ELF
    – stayge
    Aug 21, 2019 at 17:10
  • @stayge Yes, this approach to using DLL injection will not work, since you want to interpose code resident within the binary itself rather than code in a DLL. As far as I know, you can use the text segment infection method without patching the entry point; the CALL address of the function can be patched instead to point to your code in the text segment. If you are calling a function via this kind of detour (same with the objcopy route), stack alignment may be an issue.
    – julian
    Aug 22, 2019 at 6:32
0

I wrote a small utility back in high school to do something similar: https://github.com/jdefrancesco/elfy

You inject the .note section with the payload and it will modify the ELF entry pointing to the .note section. Afterwards it will jump back to the original entry point.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.