I believe that scripts without a shebang line cannot be executed by execve. They will only run if the shell sees them before the kernel does. It's an annoying limitation of this approach and it wasn't clear to me whether this technique includes a workaround for this. Also the push for code signing everywhere is going to make this harder in the future as well. (I heard a rumor that the workaround to run unsigned executables on macOS no longer works when running on Apple Silicon.) Otherwise, I love it!
My approach was slightly different; I created a polyglot script header you can paste at the beginning of a C source file to make it essentially a C script which is just-in-time compiled when it is executed. Works on Windows, Linux, and Mac as long as a C compiler is installed. https://gist.github.com/jdarpinian/6860ddfd92b5b458a20ab6055...
Author here. I considered doing that. Then I learned about things like how MSVC 2017 would wrap the main() function of C programs with telemetry. The push for code signing, retpoline, aslr, etc. worries me too, from a software freedom standpoint, and the same goes for how difficult it's become to build native software from scratch, thanks to the shift from autotools to a whole new set of competitors like bazel, cmake, ninja, gin, etc. Secure boot is another red flag. By 2018 it almost felt like we were entering a world in which, for all practical purposes, we couldn't share native software easily in either source or binary forms. If PC platforms ever do manage to get consumers to accept the iPhone App Store restriction model, it'll likely stay that way. Best way to prevent that from happening is to use Actually Portable Executable. The more people who continue to depend directly on canonical long-standing stock platform abis, the more impossible it becomes for platforms to re-imagine them every few years. I'll take UNIX+WIN32 over things like XUL any day, since I don't want to fall into the JS dev trap of having to rewrite my app with each passing moon.
Also note that the execve() shebang thing is a one-time cost. The printf statement in the header will overwrite the first 64-bytes of the executable, the first time it's invoked, so it becomes a canonical ELF or Mach-O executable for subsequent invocations. The one-time cost is also cheap. The shell script only needs three system calls (open, write, and execve) to patch the binary appropriately. The generation of this header is also abstracted by the GNU ld script, which made it easy for me to encode the ELF header relocations as octal printf codes!
> from a software freedom standpoint, and the same goes for how difficult it's become to build native software from scratch, thanks to the shift from autotools to a whole new set of competitors like bazel, cmake, ninja, gin, etc.
Every single one of those programs you listed is FOSS licensed.
Autotools was originally developed as a compatibility layer to compile code on proprietary UNIXes.
> The printf statement in the header will overwrite the first 64-bytes of the executable
This is cool but also a problem for subsequent sharing of the executable. I thought about doing this as well but decided against having the file mutate into a version that wouldn't work on other systems.
Again, super cool project! I love this kind of thing.
> the same goes for how difficult it's become to build native software from scratch, thanks to the shift from autotools to a whole new set of competitors like bazel, cmake, ninja, gin, etc.
What's the issue specifically? I've never had a good Autotools experience (granted, I wouldn't reach for Bazel or CMake either--the whole build tool ecosystem is in desperate need of innovation IMO and probably the nicest things are Nix or Guix).
> The printf statement in the header will overwrite the first 64-bytes of the executable, the first time it's invoked
Is this a problem for anti-virus/other security measures? My understanding is, executables that manipulate themselves is something any security software will look for.
Though perhaps the answer is "don't rely upon security software to police your system; do it yourself"
If that's true, it's just further proof that once people learn something, they never think to check if it's still true later. This entire industry churns over and over so quickly. To me, it's borderline negligence in public forums like this one to make statements which could no longer be true without a quick verification that they are still true, especially for particularly egregious statements, because of the scaling factor.
The 1000 people reading the comments can do the checking, or the one person making the statement can do the checking. To me, it's a moral failure to get one person's jimmies in a rustle over something that isn't true anymore, nevermind 1000 people.
On Windows, though, there's C# compiler out of the box on every OS since Vista. And C# has a bunch of rarely-used syntax for things like raw pointers, that can work on more or less the same level as C, and even look pretty similar. It might be possible to do something with that.
Huh, I never knew this. For anyone else who didn't know, it's in the C:\Windows\Microsoft.NET\Framework64\ folders, it's the CSC.exe file included with each version of the .NET framework.
Edit: Good grief, there's even vbc.exe, which is a command line Visual Basic 2012 compiler. Also JSC.exe for Jscript, aspnet_compiler.exe for ASP and MSBuild. Kinda embarrassed that I didn't know this.
If you look at the functionality provided there, it includes ability to compile generated code. This is implemented using those command-line compilers.
It’s been my go to toolset for ages. It’s the #1 reason to learn c# as it’s everywhere.
Also if we are talking exploit vectors, uuencode is great for people that let you have a clipboard. Get uudecode in c#, and paste in your arbitrary binaries and you’ll be in business In no time!
It is actually pretty useful. If you’re given a locked down machine (for example in your company), you can write code in notepad, compile it with csc.exe and run it. As it is generated on the local machine, you may get to be able to execute it. (I tried this once when I was super bored at an intership, and a hello world program compiled and ran.)
Downloaded unsigned executables will not run by default on macOS and the error dialog provides no affordance to override this. You just have to know that if you option-click and select "Open", which is always identical to double-clicking except in this special case, you get a different dialog that allows you to override the block.
I think that counts as a workaround and no longer works on Apple Silicon. But I haven't verified this myself. Would be interesting to hear from someone who knows.
> I believe that scripts without a shebang line cannot be executed by execve.
This was once true on old systems, but current ones (including Linux) have native support for scripts starting with #!. See fs/binfmt_script.c in Linux, which has existed for several decades.
My approach was slightly different; I created a polyglot script header you can paste at the beginning of a C source file to make it essentially a C script which is just-in-time compiled when it is executed. Works on Windows, Linux, and Mac as long as a C compiler is installed. https://gist.github.com/jdarpinian/6860ddfd92b5b458a20ab6055...