Userspace ELF loader that uses unmodified binaries without execve() by reimplementing the kernel's ELF loading path in userspace
poppy opens the target ELF and sanity checks the header against the subset of the ABI it supports. It walks the program header table then enumerates the loadable segments and then resolves the interpreter path if a PT_INTERP exists
For dynamically linked binaries the interpreter is treated as a first class ELF image and staged before control transfer. A contiguous virtual address reservation is established and then each loadable segment is materialised into that region at its load bias with last protection bits applied
Anonymous tail regions are synthesised for .bss where the file image terminates before the in memory extent. The interpreters entry becomes the initial instruction pointer while the programs original entry is preserved in the auxv so the loader can complete relocation as well as bootstrap userspace state and tail into the target image
make release
poppy [options] <executable> [args...]
Loads the target image then resolves and stages the dynamic linker if one exists and writes an ABI compatible initial process stack and transfers execution to the resolved entry point
./poppy /usr/bin/true
./poppy /bin/echo hello world
./poppy ./busybox sh
./poppy /bin/sh -c 'uptime'
$ ./poppy -d /bin/date -u
[.] ELF header:
[.] type: DYN
[.] machine: EM_X86_64
[.] entry: 0x2fe0
[.] phoff: 0x40
[.] phnum: 14
[.] phentsize: 56
[.] [ 0] PHDR off=0x000040 va=0x000000040 filesz=0x000310 memsz=0x000310 R-- align=0x8
[.] [ 1] INTERP off=0x000374 va=0x000000374 filesz=0x00001c memsz=0x00001c R-- align=0x1
[.] [ 2] LOAD off=0x000000 va=0x000000000 filesz=0x001b70 memsz=0x001b70 R-- align=0x1000
[.] [ 3] LOAD off=0x002000 va=0x000002000 filesz=0x00f7d1 memsz=0x00f7d1 R-X align=0x1000
[.] [ 4] LOAD off=0x012000 va=0x000012000 filesz=0x0058a0 memsz=0x0058a0 R-- align=0x1000
[.] [ 5] LOAD off=0x017c70 va=0x000018c70 filesz=0x001434 memsz=0x001650 RW- align=0x1000
[.] [ 6] DYNAMIC off=0x018b78 va=0x000019b78 filesz=0x0001e0 memsz=0x0001e0 RW- align=0x8
[.] [12] GNU_STACK off=0x000000 va=0x000000000 filesz=0x000000 memsz=0x000000 RW- align=0x10
[.] [13] GNU_RELRO off=0x017c70 va=0x000018c70 filesz=0x001390 memsz=0x001390 R-- align=0x1
[*] interpreter: /lib64/ld-linux-x86-64.so.2
[*] loading PIE at base 0x7b285f4c3000
[.] PT_LOAD: va=0x7b285f4c3000 off=0x0 filesz=0x1b70 memsz=0x1b70 aligned=0x7b285f4c3000+0x2000 R--
[.] PT_LOAD: va=0x7b285f4c5000 off=0x2000 filesz=0xf7d1 memsz=0xf7d1 aligned=0x7b285f4c5000+0x10000 R-X
[.] PT_LOAD: va=0x7b285f55000 off=0x12000 filesz=0x58a0 memsz=0x58a0 aligned=0x7b285f55000+0x6000 R--
[.] PT_LOAD: va=0x7b285f5bc70 off=0x17c70 filesz=0x1434 memsz=0x1650 aligned=0x7b285f5bb000+0x3000 RW-
[*] all segments loaded
[*] child jumping to 0x7f285ff53300, stack at 0x7b285d3ff730