7 ms·
If anyone's looking for an example, I used this trick a few months ago to embed a tiny helper binary[0] directly into my application[1] so I wouldn't have to sh
by impl 4y ago
If anyone's looking for an example, I used this trick a few months ago to embed a tiny helper binary[0] directly into my application[1] so I wouldn't have to ship two executables or add "hidden" behavior to the main program. It works really well (on Linux)!
[0]: https://github.com/impl/systemd-user-sleep/blob/666cf29871b1eb50859caad23188d9867c255c7b/helper/src/main.rs https://github.com/impl/systemd-user-sleep/blob/666cf29871b1...
[1]: https://github.com/impl/systemd-user-sleep/blob/666cf29871b1eb50859caad23188d9867c255c7b/src/user/helper.rs https://github.com/impl/systemd-user-sleep/blob/666cf29871b1...
- jart 4y agoHere's a simple concrete example for folks who don't know Rust: int main(int argc, char *argv[]) { #define TINY_ELF_PROGRAM "\ \177\105\114\106\002\001\001\000\000\000\000\000\000\000\000\000\ \002\000\076\000\001\000\000\000\170\000\100\000\000\000\000\000\ \100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ \000\000\000\000\100\000\070\000\001\000\000\000\000\000\000\000\ \001\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000\ \000\000\100\000\000\000\000\000\000\000\100\000\000\000\000\000\ \200\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\ \000\020\000\000\000\000\000\000\152\052\137\152\074\130\017\005" int fd = memfd_create("foo", MFD_CLOEXEC); write(fd, TINY_ELF_PROGRAM, sizeof(TINY_ELF_PROGRAM)-1); fexecve(fd, argv, environ); } Who here is brave enough to run my C string?
- anshargal 4y agoI had to add #define _GNU_SOURCE #include <sys/mman.h> #include <unistd.h> I've tested in Fabrice Bellard JSLinux with tcc (x86 arch) and on https://replit.com/languages/c https://replit.com/languages/c (x64). I failed to see any side effect at all. gdb "catch syscall" doesn't show anything interesting too. Looks like TINY_ELF_PROGRAM is not doing anything.
- enriquto 4y agoyou can disassemble the code portion, they are single-byte instructions push 0x2a pop edi push 0x3c pop eax db 0x0f, 0x05 ; invalid?
- qguv 4y ago; set the first syscall argument to 42 push 0x2a pop edi ; select syscall 60 (sys_exit) push 0x3c pop eax ; sys_exit(42) syscall
- enriquto 4y agoLOL my asm is rusty, didn't even know about the syscall instruction (I'd have used int 0x80 here)
- mFixman 4y agoWhat's the point of `push`ing constants to the stack and `pop`ing them to registers instead of `mov`ing them directly?
- saagarjha 4y agoI think they encode smaller?
- anshargal 4y agoThat's cool - I wonder why exit code is not set to 42 in practice? binary still returns 0, must be a bug somewhere.
- saagarjha 4y agoA successful run not exiting with EXIT_SUCCESS usually requires a good reason to justify it.
- tralarpa 4y agoIt returns the answer to an important question :) Edit: Wouldn't mov be shorter than push/pop? (I am not very familar with x86)
- kubanczyk 4y agoNo, mov is longer. Push stores the constant as just one byte and omits the three zero bytes. https://stackoverflow.com/questions/56618815/why-use-push-pop-instead-of-mov-to-put-a-number-in-a-register-in-shellcode https://stackoverflow.com/questions/56618815/why-use-push-po...