4 ms·
I'm surprised to see this little article of mine on the front page! If anyone has any questions about it, feel free to ask. Also, if you're interested in more
by LegionMammal978 3y ago
I'm surprised to see this little article of mine on the front page! If anyone has any questions about it, feel free to ask.
Also, if you're interested in more ELF shenanegans, check out the rest of tmp.0ut #3 [0]; the other authors have been working on some really neat stuff!
[0] https://tmpout.sh/3/ https://tmpout.sh/3/
- upon_drumhead 3y agoAmazing work and a very entertaining read. Thank you for sharing!
- tomcam 3y agoGreat article. What is the meaning of code like this? The jmp instruction seems necessary. jmp 0x14 0x14:
- LegionMammal978 3y agoIn the instruction listings, I've omitted all the data between the basic blocks, and reordered/repeated the blocks to emphasize the control flow. In that particular case, there are actually four bytes, 03 00 3e 00, between the jump and the label. In fact, it's not actually necessary to use a 2-byte 'jmp' to skip past that data, but golfing it further doesn't matter, since it's already at the minimum size for the 80-byte pattern with an undivided string.
- o11c 3y agoDid you consider doing multiple calls to `write` instead reassembling the string? I wonder if that's enough bytes that implementing a tiny interpreter would work; certainly it would win for slightly larger sizes (say, 4KiB).
- LegionMammal978 3y agoI did consider that (as well as using writev), but the problem is that every syscall overwrites the number in eax with the return value, so we'd need more logic to reset it to __NR_write twice before setting it to __NR_exit_group. Also, the two parts have two different lengths that we'd have to store in rdx. (Unless we split it into 7+7 bytes, I suppose, but that would waste a perfectly good byte at offset 0xb.) Ultimately, more than 1-2 small instructions of extra logic simply aren't worth it at this scale, unless we can balance it out with fewer bytes of control flow. Meanwhile, you're right that an ad-hoc interpreter will always be the answer for larger sizes. (It's very common in regular sizecoding to use a compressed executable with some code to unpack itself.) But since there simply isn't enough space here for complex logic, our only remaining avenue is to make the bytes work double and triple duty, whether through "Ouroboros Programming" or through regular subroutines. And of course, these kinds of techniques remain important when golfing the interpreter/decompressor itself, which has to be rooted in bare machine code.