1

What I want to do

What I want to do is inject an existing ELF binary with additional code that runs before the original .text section and then transfers control back to it.

What I can already do

Now, I have the following sorted:

  • Insert new ELF section and section header
  • Insert new ELF program header that loads the section
  • Modify entrypoint in the ELF header to point to my new section's VA entrypoint
  • Be able to write POC assembly code, compile with NASM into headerless raw cpu instructions format
  • Return control back to original entrypoint
  • All the above works and runs well

What I can't do

What I haven't been able to do is use GCC instead of NASM and use the standard library. Take the following example code:

#include <stdio.h>

void foo() {
    printf("hello world");
    // ignore the fact that this does not return control to the original ELF entry point
}

If I were to compile this with gcc -fPIC -c -o hello.o and then yank the .text section from the generated object file with objcopy -O binary -j .text hello.o hello.bin and try to use that as a new section, it simply won't work. hello.bin will contain the following instructions when inspected with objdump:

Disassembly of section .data:

00000000 <.data>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # 0xb
   b:   b8 00 00 00 00          mov    $0x0,%eax
  10:   e8 00 00 00 00          callq  0x15
  15:   90                      nop
  16:   5d                      pop    %rbp
  17:   c3                      retq

The above code has a couple of issues. It was yanked from an object file that expects to be linked and relocated into an executable binary that will have .plt and .got sections. Through these PLT stubs it will be able to call printf that will be located in the standard shared library loaded by ld somewhere in memory.

What I suppose it boils down to

I want GCC to produce an entirely self-contained object file that has a .text section that does not expect to be relocated, already contains libc statically and is position independent. So that it can just be put anywhere and do its thing.

3
  • This is not a real answer, but you're going to want to split up the way you think about it a bit. GCC will produce an object file, but it's not going to be self-contained. This is because certain symbol types it can emit literally requre knowing the address of a segment. Your linker (ld), however, is directly responsible for performing these calculations, determining the layout, and putting segments together. You can use a linker script to get most of the way there (applying relos and an elf), but some crt's require rt linking and you'll want a static crt/libc that's more compartmentalized. Commented Apr 5 at 14:30
  • In summary, use the rt linker with its abilities to resolve symbols and apply relocations as suggested in the other answer. It'll likely be far easier for your needs and for your libc (depending on which one you're using). If you really want to do it the other way, you'll need to be aware of the segment address and stripping the relocations when copying out your segments. Commented Apr 5 at 14:35
  • Actually...wrote a blogpost that contains an ld-script you can probably use as a base that is referenced at reddit.com/r/ReverseEngineering/comments/1bnljpl/… Commented May 11 at 20:41

1 Answer 1

0

Using LD_PRELOAD

I suggest to use the ELF constructor instead:

  • mark your entry point function with __attribute__((constructor))
  • compile your code as -shared
  • inject it using the LD_PRELOAD environment variable

Your function will be executed before the main function of the targeted executable. The ELF loader will take care of everything for you.

The manual approach

All your steps in "What I can already do" seems correct, but you probably don't have to add a new section, most (if not all) ELF loaders work with segments, not sections.

The problem with this line objcopy -O binary -j .text hello.o hello.bin is you only keep the program code: in your disassembly listing, you can see lea 0x0(%rip),%rdi is PIC but the actual data ("hello world" should in in .rodata) will be missing because it's not stored into the .text section.

You can use __attribute__((section(".text"))) to move data inside the .text section, but keep in mind that .text is R-X by default, you will have to patch the segment to be RWX if you need non-const data.

The last part is "relocations" (which on ELF include resolving external symbols), assuming you just need external symbols: you will have find or rewrite dlopen and dlfunc to resolve symbols at runtime and it's OS dependent.

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.