haste
haste

Reputation: 1461

Loading and executing ELF-64 object code--unsure about the last steps

I'm writing a small tool for experimenting with ELF-64 object code which is intended to parse and load ELF-64 object code for execution in the parent process. I believe I'm on the right track for now, but I need some pointers for the last steps.

Step 1: I parse the object file and extract all necessary information. I've verified this to be correct using the readelf tool.

Step 2: I loop through all section headers with the SHF_ALLOC-bit set and mmap memory.

Step 3: This seemingly simple and useless object consisting of only a main-routine and a return statement, requires no symbol relocating as far as I know (I've double-checked with readelf). I've compiled with TinyCC to avoid .eh_frame and its relocation entries from being emitted.

But at this point I need to load the sections with SHF_ALLOC-bit set into memory, and this is where I suspect I'm doing wrong.

offset = 0

foreach section in sections
    if section.flags & SHF_ALLOC
        memcpy(memory_address + offset, object_code + section.offset, section.size)
        offset += section_size

Step 4: The last step which I'm unsure of also. I need to call into the allocated memory which I've marked as executable.

typedef int (main_t)(int argc, char* argv[]);

((main_t)object->address)(0, NULL);

I'd very much appreciate some input on this. I believe it boils down to lack of understanding what exactly .text-segment contains and how they are intended to be stored in memory.

Some thoughts:

Anything to point me in the right direction will help immensely! Thanks!

PS. I intend to learn about relocating symbols shortly. One step at a time. :-)

Upvotes: 4

Views: 1154

Answers (2)

haste
haste

Reputation: 1461

I managed to pull this off after a good night's sleep.

I first disassembled the object file using objdump which produced:

/tmp/test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 10 00 00 00    sub    $0x10,%rsp
   b:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   f:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  13:   b8 c8 00 00 00          mov    $0xc8,%eax
  18:   e9 00 00 00 00          jmpq   1d <main+0x1d>
  1d:   c9                      leaveq 
  1e:   c3                      retq 

This output ensured me the location of main to be at 0x0, meaning if I copy the .text-segment correctly into memory at the address returned by mmap, I should be able to call it with the snippet found in the question (which I was unsure about). It'll use the stack of the calling thread.

I then found a small error when copying the sections to memory where section.offset was the offset from the beginning of the file, which I mistakenly assumed was the offset from the beginning of the section header entry.

It'll be much simpler to experiment when I know the basics work. :-)

Upvotes: 0

ninjalj
ninjalj

Reputation: 43748

You should use program headers for that, not section headers. Section headers are for the linker, program headers are for the loader.

Allocated segments are intended to go to their preferred VirtAddr, if they have one (non-prelinked libraries may have a base virtual address of 0, which means the loader will assign them random addresses).

The ELF header has an entry point field. This is not main, it's typically some libc initialization code that ... does initialization ... and then calls main. You should have setup everything conforming to the ELF ABI prior to passing control to the entry point (put argc, argv, envp, auxv on the stack, clear some registers, I think that's it).

Upvotes: 2

Related Questions