Hacker News new | past | comments | ask | show | jobs | submit login
Windows Command-Line Obfuscation (wietzebeukema.nl)
49 points by sam345 on July 25, 2021 | hide | past | favorite | 11 comments



Windows has the additional complication that the arguments of a program are actually handled as a single string, instead of a string array as in Unix, so the programs parse the command line into arguments. This is done by the libc for most programs, but not all programs use that, so there are sometimes differences how the same command line is split into arguments depending on the receiving program. This also means that there are bugs in applications supplying command line flags to other applications due to missing or incorrect quoting, since CreateProcess and .NET Process expect a single string as the command line.


Indeed. Splitting, quotes and globs are all handled by the application rather than the shell.

Furthermore, you don't just have the two categories of "programs that use libc" and "programs that wing it", but also the third category of "programs that use shell32". Windows ships with two cmdline->argv implementations - one in MSVCRT and the other in shell32. Both are first-party but don't split args the same in all cases.


There is a great example of "start" command that has a very uncool feature when using double quotes.


That's a shell built-in, though. So how command-line arguments are handled by processes and the OS doesn't really apply here.


What is an example of a command line string that is split differently by Shell32 and MSVCRT? In D, we use CommandLineToArgvW. I'm guessing it's related to Unicode?


https://github.com/rust-lang/rust/issues/44650

(Nothing to do with unicode. I haven't got a Windows machine to test, but I assume WinMain will behave the same as main wrt quotes and spaces.)

(Note that Rust doesn't use CLTAW any more; it switched to "winging it" ie its own implementation. Among other things, this allowed it to drop the dependency on shell32, which is useful for running compiled binaries in nanoserver containers.)


MSDN has this blurb with sounds rather... weird to me:

> CommandLineToArgvW has a special interpretation of backslash characters when they are followed by a quotation mark character ("). This interpretation assumes that any preceding argument is a valid file system path, or else it may behave unpredictably.


This also of course leads to inconsistencies in quoting and escaping and makes secure scripting practically impossible. But hey! It certainly was a little easier 30 years ago!


There is an API to get an argc/argv-style list of arguments:

https://docs.microsoft.com/en-us/windows/win32/api/shellapi/...

I suppose that is what the C++ runtime uses to feed main/WinMain/_tmain entry points in Win32 programs.


Also, as far as I know, there's no "ArgvToCommandLine", at least officially. There is a fairly common one floating around the Internet.

That means there are always subtle little gotchas with programs that build up command lines to call other programs.


Be sure to check out the related blog article at the bottom concerning DLL injection, too -- it is some severe faceplam that "c:\windows \system32\" is considered a trusted directory for auto escalation (after what I presume was `inputdir.ReplaceAll(" ", "").Equals(...)`)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: