I hate these stupid popups! They’re ruining my life! Every time I think I’m doing alright, out of nowhere comes another popup. Then the user reports it to IT, one thing leads to another, and I’ve been detected. No, I don’t mean annoying advertisement popups. I mean when you compile an otherwise-good executable payload for post-exploitation, and it pops up (even briefly!) a CMD window for the users to see in all its glory, prompting thoughts of profound wonder (I wonder if I’m being hacked!?!).

When Windows loads an executable to run, it first has to figure out what kind it is. Microsoft has a long and storied history of different hardware architectures and OS revisions, and backwards compatibility makes this a complicated thing. In the PE header, which describes every executable in modern Windows, there is a field indicating the “subsystem” used by the binary for its user interface. Here you can see hex dumps from two executables – one uses the WINDOWS_GUI subsystem (02 00) and the other uses the WINDOWS_CUI subsystem (03 00):

Hex Dumps

If you compile your EXE for the console (WINDOWS_CUI) subsystem, then the operating system will make sure you get a console. And that’s where the popup comes from. On the other hand, if you compile for the GUI subsystem (WINDOWS_GUI), then no console window is necessary, and your program will only become visible if it creates windows. So, for stealth purposes, it’ll be better to make GUI EXEs, in general.

But there are more differences between GUI and CUI binaries than just an extra bit in a PE header field. Windows will load and execute your program differently for the two UIs. For example, we’re quite used to the main entry point for a C program as follows:

int main(int argc, char **argv) {
    ...
    return 0;
}

To accommodate the design goals of the Windows GUI, however, Microsoft decided this wasn’t a good way to start a GUI program. The entry point for a GUI executable should instead look like this:

int CALLBACK WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
		     LPSTR     lpCmdLine,
		     int       nCmdShow) {
  ...
  return 0;
}

If you want to convert a console application to a GUI executable, it should be quickly obvious that there’s at least a little work to be done. Since you don’t get argc and argv the same way (the lpCmdLine parameter is the actual, complete command line, without the command at the beginning), you have to change up your argument parsing, etc.

Nevertheless, this isn’t too hard to do. If you just throw in some \0 bytes at the separators and build an array of char *s, you can make your own argc and argv well enough.

But that’s not all you have to do – a console app gets its in- and output streams, and proceeds just like a standard C program. But a GUI application is expected to interact with the GUI by handling messages. If it doesn’t do this, then Windows might do bad things to the program during execution. Somewhere in your WinMain() function, you need to enter an event loop, handling these. It looks something like this:

...
while(GetMessage(&message, NULL, 0, 0) > 0) {
    TranslateMessage(&message);
    DispatchMessage(&message);
  }
...

Actually, it should be more complicated than that, but this will just get you by. Of course, this means that you will need to create a separate thread for what used to go in your main() function. This is pretty easy to accomplish – just create a function that will start your main() function that can be used with CreateThread():

DWORD threadmain(LPVOID params) {
  ...
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR lpCmdLine, int show) {
  ...
  DWORD threadID;
  CreateThread(NULL, 0, threadmain, NULL, 0, &threadID);
  ...
}

Et voila, you will now have a happy program that can be set up for the GUI subsystem, and Windows won’t need to create a console. And your victims users will be less likely to notice when you persuade them to run something without their prior knowledge.

Well, and one more thing – you need to tell your compiler how to compile it for the GUI subsystem (and get that value set in the PE header I talked about above!). In Visual Studio, you just make your project a GUI application from the wizard. But if you’re using MinGW (GCC in Windows), you can specify the -mwindows flag to indicate to the linker how it should set that field:

$(CC) -o program.exe program.c $(CFLAGS) -mwindows

As an example of how to put this all together, I have put up a fork of Raphael Mudge’s metasploit-loader on Github: