Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Myths about Microsoft® Windows NT

Purpose
Myth № 0
Demonstration (Variant 1)
Demonstration (Variant 2)

Purpose

Bust some myths about Microsoft Windows NT.

Myth № 0

Loaded portable executable image files, i.e. applications and DLLs, can’t be replaced or updated.

Demonstration (Variant 1)

Perform the following 4 simple steps to bust this myth on Windows NT 4.0 and later versions.
  1. Create the text file myth.c with the following content in an arbitrary, preferable empty directory:

    // Copyright © 2004-2025, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>
    
    #define STRICT
    #define UNICODE
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    #ifdef _DLL
    __declspec(safebuffers)
    BOOL	WINAPI	_DllMainCRTStartup(HMODULE hModule, DWORD dwReason, CONTEXT *lpContext)
    {
    	WCHAR	szBuffer[MAX_PATH];
    	WCHAR	szModule[MAX_PATH];
    	WCHAR	szProcess[MAX_PATH];
    
    	if ((dwReason != DLL_PROCESS_ATTACH)
    	 || (GetModuleFileName((HMODULE) NULL, szProcess, sizeof(szProcess) / sizeof(*szProcess)) == 0)
    	 || (GetModuleFileName(hModule, szModule, sizeof(szModule) / sizeof(*szModule)) == 0)
    	 || (GetTempPath(sizeof(szBuffer) / sizeof(*szBuffer), szBuffer) == 0)
    	 || (GetTempFileName(szBuffer, L"dll", 0, szBuffer) == 0)
    #ifdef MYTHS
    	 || !DeleteFile(szBuffer)
    	 || !MoveFile(szModule, szBuffer)
    	 || !CopyFile(szProcess, szModule, FALSE))
    #else
    	 || !MoveFileEx(szModule, szBuffer, MOVEFILE_REPLACE_EXISTING)
    	 || !MoveFileEx(szProcess, szModule, MOVEFILE_CREATE_HARDLINK))
    #endif
    		return FALSE;
    
    	return TRUE;
    }
    
    __declspec(dllexport)
    const	WCHAR	szConsole[] = L"com";
    
    __declspec(dllexport)
    const	WCHAR	szWindows[] = L"exe";
    #else // _DLL
    #ifndef CONSOLE
    __declspec(dllimport)
    extern	WCHAR	szWindows[];
    
    __declspec(noreturn)
    VOID	CDECL	wWinMainCRTStartup(VOID)
    {
    	WCHAR	szBuffer[MAX_PATH];
    	WCHAR	szProcess[MAX_PATH];
    
    	if ((GetModuleFileName((HMODULE) NULL, szProcess, sizeof(szProcess) / sizeof(*szProcess)) == 0)
    	 || (GetTempPath(sizeof(szBuffer) / sizeof(*szBuffer), szBuffer) == 0)
    	 || (GetTempFileName(szBuffer, szWindows, 0, szBuffer) == 0)
    	 || !DeleteFile(szBuffer)
    	 || !MoveFile(szProcess, szBuffer))
    		ExitProcess(GetLastError());
    
    	ExitProcess(ERROR_SUCCESS);
    }
    #else // CONSOLE
    __declspec(dllimport)
    extern	WCHAR	szConsole[];
    
    __declspec(safebuffers)
    BOOL	CDECL	PrintConsole(HANDLE hConsole, [SA_FormatString(Style="printf")] LPCWSTR lpFormat, ...)
    {
    	WCHAR	szOutput[1024];
    	DWORD	dwOutput;
    	DWORD	dwConsole;
    
    	va_list	vaInput;
    	va_start(vaInput, lpFormat);
    
    	dwOutput = wvsprintf(szOutput, lpFormat, vaInput);
    
    	va_end(vaInput);
    
    	if (dwOutput == 0)
    		return FALSE;
    
    	if (!WriteConsole(hConsole, szOutput, dwOutput, &dwConsole, NULL))
    		return FALSE;
    
    	return dwConsole == dwOutput;
    }
    
    __declspec(noreturn)
    VOID	CDECL	wmainCRTStartup(VOID)
    {
    	WCHAR	szProcess[MAX_PATH];
    	DWORD	dwProcess;
    	WCHAR	szBuffer[MAX_PATH];
    	DWORD	dwBuffer;
    	DWORD	dwError = ERROR_SUCCESS;
    	HANDLE	hConsole = GetStdHandle(STD_ERROR_HANDLE);
    
    	if (hConsole == INVALID_HANDLE_VALUE)
    		dwError = GetLastError();
    	else
    	{
    		dwProcess = GetModuleFileName((HMODULE) NULL,
    		                              szProcess,
    		                              sizeof(szProcess) / sizeof(*szProcess));
    		if (dwProcess == 0)
    			PrintConsole(hConsole,
    			             L"GetModuleFileName() returned error %lu\n",
    			             dwError = GetLastError());
    		else
    		{
    			dwBuffer = GetTempPath(sizeof(szBuffer) / sizeof(*szBuffer),
    			                       szBuffer);
    			if (dwBuffer == 0)
    				PrintConsole(hConsole,
    				             L"GetTempPath() returned error %lu\n",
    				             dwError = GetLastError());
    			else
    				if (GetTempFileName(szBuffer, szConsole, 0, szBuffer) == 0)
    					PrintConsole(hConsole,
    					             L"GetTempFileName() returned error %lu\n",
    					             dwError = GetLastError());
    				else
    					if (!DeleteFile(szBuffer))
    						PrintConsole(hConsole,
    						             L"DeleteFile() returned error %lu\n",
    						             dwError = GetLastError());
    					else
    						if (!MoveFile(szProcess, szBuffer))
    							PrintConsole(hConsole,
    							             L"MoveFile() returned error %lu\n",
    							             dwError = GetLastError());
    		}
    
    		if (!CloseHandle(hConsole))
    			PrintConsole(hConsole,
    			             L"CloseHandle() returned error %lu\n",
    			             GetLastError());
    	}
    
    	ExitProcess(dwError);
    }
    #endif // CONSOLE
    #endif // _DLL
  2. Build the DLL myth.dll and its import library myth.lib from the source file myth.c created in step 1., then build the Windows application myth.exe and the console application myth.com, linking both with the import library myth.lib:

    SET CL=/GAFy /Osy /W4 /Zl
    SET LINK=/NODEFAULTLIB
    CL.EXE /LD /MD myth.c kernel32.lib
    SET LINK=/ENTRY:wWinMainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Windows
    CL.EXE myth.c myth.lib kernel32.lib
    SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Console
    CL.EXE /DCONSOLE /Femyth.com myth.c myth.lib kernel32.lib user32.lib
    For details and reference see the MSDN articles Compiler Options and Linker Options.

    Note: if necessary, see the MSDN article Use the Microsoft C++ toolset from the command line for an introduction.

    Note: myth.dll, myth.exe and myth.com are pure Win32 executables and build without the MSVCRT libraries.

    Note: the command lines can be copied and pasted as block into a Command Processor window.

    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    myth.c
    myth.c(11) : warning C4100: 'lpContext' : unreferenced formal parameter
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /NODEFAULTLIB
    /out:myth.dll
    /dll
    /implib:myth.lib
    myth.obj
    kernel32.lib
       Creating library myth.lib and object myth.exp
    
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    myth.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:wWinMainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Windows
    /out:myth.exe
    myth.obj
    myth.lib
    kernel32.lib
    
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    myth.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Console
    /out:myth.com
    myth.obj
    myth.lib
    kernel32.lib
    user32.lib
  3. Execute the console application myth.com together with its statically linked myth.dll built in step 2. and display its exit code:

    .\myth.com
    ECHO %ERRORLEVEL%
    0
  4. Verify that the console application myth.com has moved itself as com‹4 random characters›.tmp into your TMP directory, that the DLL myth.dll has also moved itself as dll‹4 random characters›.tmp there and replaced itself with its caller myth.com, then restore them both:

    DIR myth.*
    DIR "%TMP%\com????.tmp" "%TMP%\dll????.tmp"
    FC.EXE /B "%TMP%\com????.tmp" myth.dll
    MOVE /Y "%TMP%\dll????.tmp" myth.dll
    MOVE "%TMP%\com????.tmp" myth.com
     Volume in drive C has no label.
     Volume Serial Number is 1957-0427
    
     Directory of C:\Users\Stefan\Desktop
    
    04/27/2010  08:15 PM             3.962 myth.c
    04/27/2010  08:15 PM             3.584 myth.dll
    04/27/2010  08:15 PM             2.560 myth.exe
    04/27/2010  08:15 PM               691 myth.exp
    04/27/2010  08:15 PM             1.784 myth.lib
    04/27/2010  08:15 PM             4.004 myth.obj
                   6 File(s)         16.585 bytes
                   0 Dir(s)    9,876,543,210 bytes free
    
     Volume in drive C has no label.
     Volume Serial Number is 1957-0427
    
     Directory of C:\Users\Stefan\AppData\Local\Temp
    
    04/27/2010  08:15 PM             2.560 dll4707.tmp
    
     Directory of C:\Users\Stefan\AppData\Local\Temp
    
    04/27/2010  08:15 PM             3.584 com4711.tmp
                   2 File(s)          6.144 bytes
                   0 Dir(s)    9,876,543,210 bytes free
    
    Compare the files C:\USERS\STEFAN\APPDATA\LOCAL\TEMP\com4711.tmp and MYTH.DLL
    FC: no differences found
    
            1 file(s) moved.
            1 file(s) moved.

Demonstration (Variant 2)

Perform the following 4 simple steps to bust this myth on Windows Vista and later versions.
  1. Create the text file myth.c with the following content in an arbitrary, preferable empty directory:

    // Copyright © 2004-2025, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>
    
    #define STRICT
    #define UNICODE
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    __declspec(safebuffers)
    BOOL	CDECL	PrintConsole(HANDLE hConsole, [SA_FormatString(Style="printf")] LPCWSTR lpFormat, ...)
    {
    	WCHAR	szOutput[1024];
    	DWORD	dwOutput;
    	DWORD	dwConsole;
    
    	va_list	vaInput;
    	va_start(vaInput, lpFormat);
    
    	dwOutput = wvsprintf(szOutput, lpFormat, vaInput);
    
    	va_end(vaInput);
    
    	if (dwOutput == 0)
    		return FALSE;
    
    	if (!WriteConsole(hConsole, szOutput, dwOutput, &dwConsole, NULL))
    		return FALSE;
    
    	return dwConsole == dwOutput;
    }
    
    const	FILE_DISPOSITION_INFO	fdi = {TRUE};
    const	FILE_RENAME_INFO	fri = {TRUE, (HANDLE) NULL, sizeof(L'€'), L'€'};
    
    __declspec(noreturn)
    VOID	CDECL	wmainCRTStartup(VOID)
    {
    	DWORD	dwError = ERROR_SUCCESS;
    	DWORD	dwModule;
    	WCHAR	szModule[MAX_PATH];
    	HANDLE	hModule;
    	HANDLE	hConsole = GetStdHandle(STD_ERROR_HANDLE);
    
    	if (hConsole == INVALID_HANDLE_VALUE)
    		dwError = GetLastError();
    	else
    	{
    		dwModule = GetModuleFileName((HMODULE) NULL,
    		                             szModule,
    		                             sizeof(szModule) / sizeof(*szModule));
    		if (dwModule == 0)
    			PrintConsole(hConsole,
    			             L"GetModuleFileName() returned error %lu\n",
    			             dwError = GetLastError());
    		else
    		{
    			hModule = CreateFile(szModule,
    			                     DELETE,
    			                     FILE_SHARE_DELETE,
    			                     (LPSECURITY_ATTRIBUTES) NULL,
    			                     OPEN_EXISTING,
    			                     FILE_ATTRIBUTE_NORMAL,
    			                     (HANDLE) NULL);
    
    			if (hModule == INVALID_HANDLE_VALUE)
    				PrintConsole(hConsole,
    				             L"CreateFile() returned error %lu\n",
    				             dwError = GetLastError());
    			else
    			{
    				if (!SetFileInformationByHandle(hModule,
    #ifdef MYTHS
    				                                FileDispositionInfo,
    				                                &fdi,
    				                                sizeof(fdi)))
    #else
    				                                FileRenameInfo,
    				                                &fri,
    				                                sizeof(fri)))
    #endif
    					PrintConsole(hConsole,
    					             L"SetFileInformationByHandle() returned error %lu\n",
    					             dwError = GetLastError());
    
    				if (!CloseHandle(hModule))
    					PrintConsole(hConsole,
    					             L"CloseHandle() returned error %lu\n",
    					             GetLastError());
    			}
    		}
    
    		if (!CloseHandle(hConsole))
    			PrintConsole(hConsole,
    			             L"CloseHandle() returned error %lu\n",
    			             GetLastError());
    	}
    
    	ExitProcess(dwError);
    }
  2. Build the console application myth.exe from the source file myth.c created in step 1.:

    SET CL=/GAFy /Osy /W4 /Zl
    SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Console
    CL.EXE myth.c kernel32.lib user32.lib
    For details and reference see the MSDN articles Compiler Options and Linker Options.

    Note: if necessary, see the MSDN article Use the Microsoft C++ toolset from the command line for an introduction.

    Note: the console application myth.exe is a pure Win32 executable and builds without the MSVCRT libraries.

    Note: the command lines can be copied and pasted as block into a Command Processor window.

    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    myth.c
    myth.c(78) : warning C4090: 'function' : different 'const' qualifiers
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:Console
    /out:myth.exe
    myth.obj
    kernel32.lib
    user32.lib
  3. Execute the console application myth.exe built in step 2. and display its exit code:

    .\myth.exe
    ECHO %ERRORLEVEL%
    0
  4. Verify that the console application myth.exe has renamed itself to by restoring its original name:

    RENAME € myth.exe

Contact and Feedback

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, deficiencies, errors, inaccuracies, misrepresentations, omissions, shortcomings, vulnerabilities or weaknesses, …: don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Note: email in weird format and without a proper sender name is likely to be discarded!

I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see your full (real) name as sender, not your nickname.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!

Data Protection Declaration

This web page records no (personal) data and stores no cookies in the web browser.

The web service is operated and provided by

Telekom Deutschland GmbH
Business Center
D-64306 Darmstadt
Germany
<‍hosting‍@‍telekom‍.‍de‍>
+49 800 5252033

The web service provider stores a session cookie in the web browser and records every visit of this web site with the following data in an access log on their server(s):


Copyright © 1995–2025 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>