While debugging a console application on Windows 8, I noticed the console application is trying to create a process in the very beginning:
windbg.exe -xe ld:ntdll.dll -c "bm ntdll!*CreateProcess*; g; k" cmd.exe
CommandLine: cmd.exeModLoad: 000007ff`01d60000 000007ff`01f1e000 ntdll.dllntdll!RtlUserThreadStart:000007ff`01d7c3d0 4883ec48 sub rsp,48hProcessing initial command 'bm ntdll!*CreateProcess*; g; k'0:000> bm ntdll!*CreateProcess*; g; k 1: 000007ff`01d90f60 @!"ntdll!RtlCreateProcessParametersEx" 2: 000007ff`01d63070 @!"ntdll!NtCreateProcessEx"breakpoint 2 redefined 2: 000007ff`01d63070 @!"ntdll!ZwCreateProcessEx" 3: 000007ff`01e1bf74 @!"ntdll!RtlCreateProcessReflection" 4: 000007ff`01da8bb4 @!"ntdll!RtlpCreateProcessRegistryInfo" 5: 000007ff`01e1ceac @!"ntdll!RtlCreateProcessParameters" 6: 000007ff`01d63651 @!"ntdll!ZwCreateProcess"breakpoint 6 redefined 6: 000007ff`01d63651 @!"ntdll!NtCreateProcess"Breakpoint 1 hitChild-SP RetAddr Call Site000000bf`8268e558 000007fe`feea02a4 ntdll!RtlCreateProcessParametersEx000000bf`8268e560 000007fe`feea00be KERNELBASE!ConsoleLaunchServerProcess+0x60000000bf`8268e5f0 000007fe`fee95d40 KERNELBASE!ConsoleAllocate+0xf6000000bf`8268e8c0 000007fe`fee7f6db KERNELBASE!ConsoleInitialize+0x1d1000000bf`8268e950 000007fe`fee7230d KERNELBASE!KernelBaseBaseDllInitialize+0x4dd000000bf`8268ec20 000007ff`01d6b9be KERNELBASE!KernelBaseDllInitialize+0xd000000bf`8268ec50 000007ff`01d8b3fc ntdll!LdrpCallInitRoutine+0x3e000000bf`8268eca0 000007ff`01d8a88b ntdll!LdrpInitializeNode+0x192000000bf`8268eda0 000007ff`01d8e74e ntdll!LdrpInitializeGraph+0x6f000000bf`8268ede0 000007ff`01d8c322 ntdll!LdrpInitializeGraph+0x8d000000bf`8268ee20 000007ff`01d8cc02 ntdll!LdrpPrepareModuleForExecution+0x1a5000000bf`8268ee70 000007ff`01d8337b ntdll!LdrpLoadDll+0x344000000bf`8268f0a0 000007ff`01d9264f ntdll!LdrLoadDll+0xa7000000bf`8268f120 000007ff`01d91826 ntdll!LdrpInitializeProcess+0x1664000000bf`8268f420 000007ff`01d7c1ae ntdll!_LdrpInitialize+0x1565e000000bf`8268f490 00000000`00000000 ntdll!LdrInitializeThunk+0xe
0:000> dc rbx000000bf`8268e660 00000000 00000000 00000000 00000000 ................000000bf`8268e670 003f005c 005c003f 003a0043 0057005c \.?.?.\.C.:.\.W.000000bf`8268e680 004e0049 004f0044 00530057 0073005c I.N.D.O.W.S.\.s.000000bf`8268e690 00730079 00650074 0033006d 005c0032 y.s.t.e.m.3.2.\.000000bf`8268e6a0 006f0063 0068006e 0073006f 002e0074 c.o.n.h.o.s.t...000000bf`8268e6b0 00780065 00200065 00780030 00660066 e.x.e. .0.x.f.f.000000bf`8268e6c0 00660066 00660066 00660066 00000000 f.f.f.f.f.f.....000000bf`8268e6d0 8268e960 000000bf 00000008 00000000 `.h.............
This means conhost.exe process on Windows 8 will be created by the console application itself, instead of the CSRSS. And conhost.exe would always have the native bitness (on Windows 8 64bit version, only 64bit version of conhost.exe is available).
Now debug into conhost.exe using .childdbg, it's pretty clear that conhost.exe is in charge of drawing the console window, handling user inputs and communicate with the console application:
0 Id: 124c.d34 Suspend: 1 Teb: 000007f6`3311b000 UnfrozenChild-SP RetAddr Call Site00000094`85aefb38 000007f6`33b91146 ntdll!NtWaitForSingleObject+0xa00000094`85aefb40 000007ff`00c9167e conhost!ConsoleIoThread+0xda00000094`85aefd80 000007ff`01d7c3f1 KERNEL32!BaseThreadInitThunk+0x1a00000094`85aefdb0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
# 1 Id: 124c.1428 Suspend: 1 Teb: 000007f6`3311e000 UnfrozenChild-SP RetAddr Call Site00000094`85b6fd28 000007ff`0140171e conhost!ConsoleWindowProc00000094`85b6fd30 000007ff`014014d7 USER32!UserCallWinProcCheckWow+0x13a00000094`85b6fdf0 000007f6`33b92fcc USER32!DispatchMessageWorker+0x1a700000094`85b6fe70 000007ff`00c9167e conhost!ConsoleInputThread+0xd200000094`85b6fed0 000007ff`01d7c3f1 KERNEL32!BaseThreadInitThunk+0x1a00000094`85b6ff00 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
And cmd.exe itself doesn't draw the console window at all:
0 Id: 1aec.5ec Suspend: 1 Teb: 000007f7`b280d000 UnfrozenChild-SP RetAddr Call Site00000008`50fff5b8 000007fe`fee8f17c ntdll!NtDeviceIoControlFile+0xa00000008`50fff5c0 000007fe`fef0bb29 KERNELBASE!ConsoleCallServerGeneric+0x11800000008`50fff710 000007fe`fef0b986 KERNELBASE!ReadConsoleInternal+0x13100000008`50fff850 000007f7`b3621025 KERNELBASE!ReadConsoleW+0x1a00000008`50fff890 000007f7`b362bd3e cmd!ReadBufFromConsole+0x11100000008`50fff960 000007f7`b3604aae cmd!_chkstk+0x382000000008`50fffae0 000007f7`b36042e4 cmd!Lex+0x4be00000008`50fffb50 000007f7`b362d560 cmd!Parser+0x12800000008`50fffba0 000007f7`b361b721 cmd!_chkstk+0x503200000008`50fffc00 000007ff`00c9167e cmd!mystrchr+0x27d00000008`50fffc40 000007ff`01d7c3f1 KERNEL32!BaseThreadInitThunk+0x1a00000008`50fffc70 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
The interesting thing is that if we use Spy++, it would report that the console window is associated with the main thread of cmd.exe process! I believe this is a hack in the underlying implementation of GetWindowThreadProcessId for backward compatibility. Also, Spy++ cannot be used to inspect conhost.exe message loop.
Due to the side effects of IFEO Debugger, console application would fail to start if IFEO Debugger is enabled for conhost.exe.
The following call stack showed conhost.exe just created a normal window from Console Input Thread:
USER32!CreateWindowExWconhost!CreateWindowsWindow+0x105conhost!InitWindowsSubsystem+0x69conhost!ConsoleInputThread+0x22KERNEL32!BaseThreadInitThunk+0x1antdll!RtlUserThreadStart+0x1d
0:001> du @rdx000007f6`33b9d460 "ConsoleWindowClass"
0:001> du @r800000025`f7dc37c0 "C:\WINDOWS\SYSTEM32\cmd.exe"
When cmd.exe exits, the Console I/O Thread would be notified:
ntdll!NtTerminateProcess+0xantdll!RtlExitUserProcess+0xb6conhost!ConsoleIoThread+0xac4KERNEL32!BaseThreadInitThunk+0x1antdll!RtlUserThreadStart+0x1d
(to be continued...)