Artof Computer Programming
Note: some cases of disinformation presented below were published 25 (in words: twenty-five) years ago and never corrected!
45 years ago I participated in the research project
Entwicklung von Entwurfstechnologien für Familien von Programmsystemen
(Development of Design Technologies for Families of Program Systems
)
initiated and led by David Parnas (who coined the term information
hiding) to design and implement the prototype of a modular operating
system built from formally specified independent components where
both concepts played the crucial role.
Was für Plunder!
(What rubbish!)
NetAddServiceAccount()
,
NetEnumerateServiceAccounts()
,
NetIsServiceAccount()
,
NetQueryServiceAccount()
and
NetRemoveServiceAccount()
states since 2009:
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Logoncli.dll.Note: while the[…]
Requirement Value … … Header lmaccess.h DLL Netapi32.dll
Requirementssections name
Netapi32.dll
, all texts but
specify Logoncli.dll
!
Managed Service Accounts
Managed Service Accounts
Managed Service Accounts Frequently Asked Questions (FAQ)
Service Accounts Step-by-Step Guide
Managed Service Accounts: Understanding, Implementing, Best Practices, and Troubleshooting
Determine which of the 2
DLLs
Logoncli.dll
and
Netapi32.dll
provides the 5
functions:
FOR %? IN (Logoncli.dll) DO SET LOGONCLI=%~$PATH:? LINK.EXE /DUMP /EXPORTS /OUT:logoncli.txt "%LOGONCLI%" FOR %? IN (Netapi32.dll) DO SET NETAPI32=%~$PATH:? LINK.EXE /DUMP /EXPORTS /OUT:netapi32.txt "%NETAPI32%" FIND.EXE "ServiceAccount" logoncli.txt netapi32.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET LOGONCLI=C:\Windows\System32\logoncli.dll Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. SET NETAPI32=C:\Windows\System32\netapi32.dll Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- LOGONCLI.TXT 61 3C 0000F520 NetAddServiceAccount 62 3D 0000F5AC NetEnumerateServiceAccounts 66 41 0000F64C NetIsServiceAccount 69 44 0000F6AC NetQueryServiceAccount 70 45 0000F568 NetRemoveServiceAccount ---------- NETAPI32.TXT 98 61 NetAddServiceAccount (forwarded to LOGONCLI.NetAddServiceAccount) 142 8D NetEnumerateServiceAccounts (forwarded to LOGONCLI.NetEnumerateServiceAccounts) 164 A3 NetIsServiceAccount (forwarded to LOGONCLI.NetIsServiceAccount) 186 B9 NetQueryServiceAccount (forwarded to LOGONCLI.NetQueryServiceAccount) 191 BE NetRemoveServiceAccount (forwarded to LOGONCLI.NetRemoveServiceAccount)
Logoncli.dll
exports the 5
functions; Netapi32.dll
exports them too, but as forwardersto the functions implemented in
Logoncli.dll
, i.e. either
DLL
can be linked!
Determine whether the highlighted claim
This function has no associated import library.
is true
– or false:
FOR %? IN (Logoncli.lib) DO SET LOGONCLI=%~$LIB:? FOR %? IN (Netapi32.lib) DO SET NETAPI32=%~$LIB:? LINK.EXE /DUMP /EXPORTS /OUT:netapi32.txt "%NETAPI32%" FIND.EXE "ServiceAccount" netapi32.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET LOGONCLI= SET NETAPI32=C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\NetAPI32.Lib Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- NETAPI32.TXT _NetAddServiceAccount@16 _NetEnumerateServiceAccounts@16 _NetIsServiceAccount@12 _NetQueryServiceAccount@16 _NetRemoveServiceAccount@12OUCH¹: contrary to the statements in all 5 MSDN articles cited above, not just the Windows Software Development Kit for Windows 7 but ships with an
associated import library
NetAPI32.lib
!
Create the text file lmaccess.c
with the following
content in an arbitrary, preferably empty directory:
// Copyleft © 2009-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <lmaccess.h>
#define STATUS_SUCCESS 0L
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
#ifndef BLUNDER
DWORD dwCount;
LPWSTR *lpArray;
LONG ntStatus = NetEnumerateServiceAccounts((LPWSTR) NULL,
0UL,
&dwCount,
&lpArray);
#elif BLUNDER == 1
BOOL blunder;
LPBYTE lpBuffer;
LONG ntStatus = -NetIsServiceAccount((LPWSTR) NULL,
(LPWSTR) NULL,
&blunder);
if (ntStatus == -STATUS_SUCCESS)
ntStatus = NetQueryServiceAccount((LPWSTR) NULL,
(LPWSTR) NULL,
0UL,
&lpBuffer);
#else
LONG ntStatus = NetAddServiceAccount((LPWSTR) NULL,
L"",
(LPWSTR) NULL,
SERVICE_ACCOUNT_FLAG_LINK_TO_HOST_ONLY);
if (ntStatus == STATUS_SUCCESS)
ntStatus = -NetRemoveServiceAccount((LPWSTR) NULL,
L"",
SERVICE_ACCOUNT_FLAG_UNLINK_FROM_HOST_ONLY);
#endif
ExitProcess(ntStatus);
}
Compile and link the source file lmaccess.c
created in
step 3. to test whether the associated import library
Netapi32.lib
can be linked statically – or not:
SET CL=/W4 /Zl SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE lmaccess.c kernel32.lib netapi32.libNote: 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.
lmaccess.c
Microsoft (R) Incremental Linker Version 10.00.40219.386
Copyright (C) Microsoft Corporation. All rights reserved.
/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE
/out:lmaccess.exe
lmaccess.obj
kernel32.lib
netapi32.lib
lmaccess.obj : error LNK2019: unresolved external symbol _NetEnumerateServiceAccounts referenced in function _mainCRTStartup
lmaccess.exe : fatal error LNK1120: 1 unresolved externals
OUCH²: the undecorated symbol
name _NetEnumerateServiceAccounts
in the error message
indicates 2 NetEnumerateServiceAccounts()
in the header file lmaccess.h
– the
mandatory calling convention
__stdcall
and the (optional) storage class attribute
__declspec
(dllimport)
are missing!
Note: most obviously nobody
at Microsoft tests or uses their own
products crap with the default settings of
their own development tools – and their quality
miserability assurance is sound asleep!
Note: without the optional
__declspec(dllimport)
the Visual C
compiler generates a
CALL ‹function name›
that the linker needs to resolve with a stub function, an indirect
JMP
through the
Import Address Table; with
__declspec(dllimport)
it just generates an indirect
CALL
through the
Import Address Table.
Note: properly declared, the symbol name would be
__imp__NetEnumerateServiceAccounts@16
– see the
MSDN article
Decorated Names
for details.
Repeat the previous step 4., now with the
/Gz
compiler option:
CL.EXE /Gz lmaccess.c kernel32.lib netapi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lmaccess.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj kernel32.lib netapi32.lib
Execute the console application lmaccess.exe
built in
step 5. and evaluate its exit code:
.\lmaccess.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%Note: the command lines can be copied and pasted as block into a Command Processor window.
0xc0020012 (NT: 0xc0020012 RPC_NT_UNKNOWN_IF) -- 3221356562 (-1073610734) Error message text: The interface is unknown. CertUtil: -error command completed successfully.OUCH³: WTF?
Repeat step 4., but with the preprocessor macro
BLUNDER
defined:
CL.EXE /DBLUNDER lmaccess.c kernel32.lib netapi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lmaccess.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj kernel32.lib netapi32.lib lmaccess.obj : error LNK2019: unresolved external symbol _NetIsServiceAccount referenced in function _mainCRTStartup lmaccess.obj : error LNK2019: unresolved external symbol _NetQueryServiceAccount referenced in function _mainCRTStartup lmaccess.exe : fatal error LNK1120: 2 unresolved externalsOUCH⁴: the declarations of the function prototypes for
NetIsServiceAccount()
and
NetQueryServiceAccount()
are as faulty as that for
NetEnumerateServiceAccounts()
!
Repeat the previous step 7., now with the
/Gz
compiler option
too:
CL.EXE /DBLUNDER /Gz lmaccess.c kernel32.lib netapi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lmaccess.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj kernel32.lib netapi32.lib
Execute the console application lmaccess.exe
built in
step 8. and evaluate its exit code:
.\lmaccess.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%Note: the command lines can be copied and pasted as block into a Command Processor window.
0xc0030009 (NT: 0xc0030009 RPC_NT_NULL_REF_POINTER) -- 3221422089 (-1073545207) Error message text: A null reference pointer was passed to the stub. CertUtil: -error command completed successfully.OUCH⁵: while the
NetIsServiceAccount()
function accepts a NULL
pointer for the
AccountName
parameter, the
NetQueryServiceAccount()
function rejects it with
NTSTATUS
0xC0030009
alias RPC_NT_NULL_REF_POINTER
!
Repeat step 7., now with the preprocessor macro
BLUNDER
defined as 0:
CL.EXE /DBLUNDER=0 lmaccess.c kernel32.lib netapi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lmaccess.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj kernel32.lib netapi32.lib lmaccess.obj : error LNK2019: unresolved external symbol _NetAddServiceAccount referenced in function _mainCRTStartup lmaccess.obj : error LNK2019: unresolved external symbol _NetRemoveServiceAccount referenced in function _mainCRTStartup lmaccess.exe : fatal error LNK1120: 2 unresolved externalsOUCH⁶: the declarations of the function prototypes for
NetAddServiceAccount()
and
NetRemoveServiceAccount()
are as faulty as those for
NetEnumerateServiceAccounts()
,
NetIsServiceAccount()
and
NetQueryServiceAccount()
!
Repeat the previous step 10., now with the
/Gz
compiler option
too:
CL.EXE /DBLUNDER=0 /Gz lmaccess.c kernel32.lib netapi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lmaccess.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj kernel32.lib netapi32.lib
Finally execute the console application lmaccess.exe
built in step 11. and evaluate its exit code:
.\lmaccess.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%Note: the command lines can be copied and pasted as block into a Command Processor window.
0xc0020012 (NT: 0xc0020012 RPC_NT_UNKNOWN_IF) -- 3221356562 (-1073610734) Error message text: The interface is unknown. CertUtil: -error command completed successfully.OUCH⁷: WTF?
RtlDecryptMemory()
states since 2001:
Ouch¹: a function is not a (named) resource – see the MSDN article Menus and Other Resources for their definition!Note This function has no associated import library. This function is available as a resource named SystemFunction041 in Advapi32.dll. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Advapi32.dll.[…]NTSTATUS RtlDecryptMemory( PVOID Memory, ULONG MemorySize, ULONG OptionFlags );
[…]
Requirement Value … … Header ntsecapi.h DLL Advapi32.dll
The documentation for the Win32 function
RtlEncryptMemory()
states since 2001:
Ouch²: a function is not a (named) resource – see the MSDN article Menus and Other Resources for their definition!Note This function has no associated import library. This function is available as a resource named SystemFunction040 in Advapi32.dll. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Advapi32.dll.[…]NTSTATUS RtlEncryptMemory( PVOID Memory, ULONG MemorySize, ULONG OptionFlags );
[…]
Requirement Value … … Header ntsecapi.h DLL Advapi32.dll
The documentation for the Win32 function
RtlGenRandom()
states since 2001:
Ouch³: a function is not a (named) resource – see the MSDN article Menus and Other Resources for their definition!Note This function has no associated import library. This function is available as a resource named SystemFunction036 in Advapi32.dll. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Advapi32.dll.[…]BOOLEAN RtlGenRandom( PVOID RandomBuffer, ULONG RandomBufferLength );
[…]
Requirement Value … … Header ntsecapi.h DLL Advapi32.dll
Determine whether the highlighted claim
This function has no associated import library.
is true
– or false:
FOR %? IN (Advapi32.lib) DO SET ADVAPI32=%~$LIB:? LINK.EXE /DUMP /EXPORTS /OUT:advapi32.txt "%ADVAPI32%" FIND.EXE "SystemFunction0" advapi32.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET ADVAPI32=C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\Advapi32.Lib Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- ADVAPI32.TXT _SystemFunction001@12 _SystemFunction002@12 _SystemFunction003@8 _SystemFunction004@12 _SystemFunction005@12 _SystemFunction006@8 _SystemFunction007@8 _SystemFunction008@12 _SystemFunction009@12 _SystemFunction010@12 _SystemFunction011@12 _SystemFunction012@12 _SystemFunction013@12 _SystemFunction014@12 _SystemFunction015@12 _SystemFunction016@12 _SystemFunction017@12 _SystemFunction018@12 _SystemFunction019@12 _SystemFunction020@12 _SystemFunction021@12 _SystemFunction022@12 _SystemFunction023@12 _SystemFunction024@12 _SystemFunction025@12 _SystemFunction026@12 _SystemFunction027@12 _SystemFunction028@8 _SystemFunction029@8 _SystemFunction030@8 _SystemFunction031@8 _SystemFunction032@8 _SystemFunction033@8 _SystemFunction034@12 _SystemFunction036@8 _SystemFunction040@12 _SystemFunction041@12OUCH¹: contrary to the statements in all 3 MSDN articles cited above, not just the Windows Software Development Kit for Windows 7 but ships with an
associated import library
Advapi32.lib
!
Create the text file ntsecapi.c
with the following
content in an arbitrary, preferably empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ntsecapi.h>
#define STATUS_SUCCESS 0L
#define STATUS_UNSUCCESSFUL 0xC0000001L
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
BYTE cbMemory[RTL_ENCRYPT_MEMORY_SIZE];
LONG ntStatus;
if (RtlGenRandom(cbMemory, sizeof(cbMemory)))
{
ntStatus = RtlEncryptMemory(cbMemory, sizeof(cbMemory), 0UL);
if (ntStatus == STATUS_SUCCESS)
ntStatus = RtlDecryptMemory(cbMemory, sizeof(cbMemory), 0UL);
}
else
ntStatus = STATUS_UNSUCCESSFUL;
ExitProcess(ntStatus);
}
Compile and link the source file ntsecapi.c
created in
step 2. to test whether the associated import library
Advapi32.lib
can be linked statically – or not:
SET CL=/W4 /Zl SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE ntsecapi.c advapi32.lib kernel32.libNote: 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. ntsecapi.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:ntsecapi.exe ntsecapi.obj advapi32.lib kernel32.lib ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction041 referenced in function _mainCRTStartup ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction040 referenced in function _mainCRTStartup ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction036 referenced in function _mainCRTStartup ntsecapi.exe : fatal error LNK1120: 3 unresolved externalsOUCH²: the undecorated symbol names
_SystemFunction036
,
_SystemFunction040
and _SystemFunction041
in the error messages indicate 2 RtlDecryptMemory()
,
RtlEncryptMemory()
and
RtlGenRandom()
in the header file ntsecapi.h
– the
mandatory calling convention
__stdcall
and the (optional) storage class attribute
__declspec
(dllimport)
are missing!
Note: properly declared, the symbol names were but
__imp__SystemFunction036@8
,
__imp__SystemFunction040@12
and
__imp__SystemFunction041@12
– see the
MSDN article
Decorated Names
for details.
Repeat the previous step 3., now with the
/Gz
compiler option:
CL.EXE /Gz ntsecapi.c advapi32.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. ntsecapi.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:ntsecapi.exe ntsecapi.obj advapi32.lib kernel32.lib
Finally execute the console application ntsecapi.exe
built in step 4. and evaluate its exit code:
.\ntsecapi.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%Note: the command lines can be copied and pasted as block into a Command Processor window.
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0) Error message text: The operation completed successfully. CertUtil: -error command completed successfully.
InstallPerfDllA()
and
InstallPerfDllW()
states since 1999:
This function has no associated import library; you must call it using the LoadLibrary and GetProcAddress functions.[…]
Requirement Value … … Header Loadperf.h DLL Loadperf.dll
Determine whether the highlighted claim
This function has no associated import library.
is true
– or false:
FOR %? IN (Loadperf.lib) DO SET LOADPERF=%~$LIB:? LINK.EXE /DUMP /EXPORTS /OUT:loadperf.txt "%LOADPERF%" FIND.EXE "InstallPerfDll" loadperf.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET LOADPERF=C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\LoadPerf.Lib Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- LOADPERF.TXT _InstallPerfDllA@12 _InstallPerfDllW@12
Create the text file loadperf.c
with the following
content in an arbitrary, preferably empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <loadperf.h>
FARPROC loadperf[] = {InstallPerfDllA,
InstallPerfDllW};
Compile and link the source file loadperf.c
created in
step 2. to show that the associated import library
Loadperf.lib
can be linked statically:
SET CL=/W4 /Zl SET LINK=/DLL /NODEFAULTLIB /NOENTRY CL.EXE loadperf.c loadperf.libNote: 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. loadperf.c loadperf.c(9) : warning C4232: nonstandard extension used : 'loadperf' : address of dllimport 'InstallPerfDllA' is not static, identity not guaranteed C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\loadperf.h(49) : see declaration of 'InstallPerfDllA' loadperf.c(9) : warning C4057: 'initializing' : 'FARPROC' differs in indirection to slightly different base types from 'DWORD (__stdcall *)(LPCSTR,LPCSTR,ULONG_PTR)' loadperf.c(10) : warning C4232: nonstandard extension used : 'loadperf' : address of dllimport 'InstallPerfDllW' is not static, identity not guaranteed C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\loadperf.h(42) : see declaration of 'InstallPerfDllW' loadperf.c(10) : warning C4057: 'initializing' : 'FARPROC' differs in indirection to slightly different base types from 'DWORD (__stdcall *)(LPCWSTR,LPCWSTR,ULONG_PTR)' Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DLL /NODEFAULTLIB /NOENTRY /out:loadperf.exe loadperf.obj loadperf.libOOPS: contrary to their documentation all functions can be linked statically with their import library
loadperf.lib
!
CryptCATAdminAcquireContext()
,
CryptCATAdminAcquireContext2()
,
CryptCATAdminAddCatalog()
,
CryptCATAdminCalcHashFromFileHandle()
,
CryptCATAdminCalcHashFromFileHandle2()
,
CryptCATAdminReleaseCatalogContext()
,
CryptCATAdminReleaseContext()
,
CryptCATAdminRemoveCatalog()
,
CryptCATCatalogInfoFromContext()
,
CryptCATClose()
,
CryptCATEnumerateAttr()
,
CryptCATEnumerateCatAttr()
and
CryptCATGetMemberInfo()
states since 2001:
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.Ouch: the highlighted reference to the import library[…]
Requirement Value … … Header mscat.h Library Wintrust.lib DLL Wintrust.dll
Wintrust.lib
in the Requirementssection but contradicts the highlighted claim
This function has no associated import library.given in the text!
The documentation for both of the Win32 functions
CryptCATAdminResolveCatalogPath()
and
IsCatalogFile()
states since 2001:
The documentation for the Win32 functionNote This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.[…]
Requirement Value … … Header mscat.h DLL Wintrust.dll
CryptCATOpen()
states since 2001:
Note Some older versions of Wintrust.lib do not contain the export information for this function. In this case, you must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.[…]
Requirement Value … … Header mscat.h Library Wintrust.lib DLL Wintrust.dll
CryptCATCDFClose()
CryptCATCDFEnumCatAttributes()
CryptCATCDFOpen()
The documentation for both of the Win32 functions
CryptCATCDFEnumAttributesWithCDFTag()
and
CryptCATCDFEnumMembersByCDFTagEx()
states since 2001:
Ouch: the highlighted reference toNote This function has no associated header file or import library. To call this function, you must create a user-defined header file and use the LoadLibrary and GetProcAddress functions to dynamically link to Mssign32.dll.[…]
Requirement Value … … DLL Wintrust.dll
Wintrust.dll
in the Requirementssection but contradicts the highlighted claim
dynamically link to Mssign32.dll.given in the text!
Determine whether the highlighted claim
This function has no associated import library.
is true
– or false:
FOR %? IN (Wintrust.lib) DO SET WINTRUST=%~$LIB:? LINK.EXE /DUMP /EXPORTS /OUT:wintrust.txt "%WINTRUST%" FIND.EXE "CryptCAT" wintrust.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET WINTRUST=C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\Wintrust.Lib Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- WINTRUST.TXT ?CryptCATVerifyMember@@YGHPAXPAUCRYPTCATMEMBER_@@0@Z (int __stdcall CryptCATVerifyMember(void *,struct CRYPTCATMEMBER_ *,void *)) _CryptCATAdminAcquireContext@12 _CryptCATAdminAddCatalog@16 _CryptCATAdminCalcHashFromFileHandle@16 _CryptCATAdminEnumCatalogFromHash@20 _CryptCATAdminPauseServiceForBackup@8 _CryptCATAdminReleaseCatalogContext@12 _CryptCATAdminReleaseContext@8 _CryptCATAdminRemoveCatalog@12 _CryptCATAdminResolveCatalogPath@16 _CryptCATAllocSortedMemberInfo@8 _CryptCATCDFClose@4 _CryptCATCDFEnumAttributes@16 _CryptCATCDFEnumAttributesWithCDFTag@20 _CryptCATCDFEnumCatAttributes@12 _CryptCATCDFEnumMembers@12 _CryptCATCDFEnumMembersByCDFTag@16 _CryptCATCDFEnumMembersByCDFTagEx@24 _CryptCATCDFOpen@8 _CryptCATCatalogInfoFromContext@12 _CryptCATClose@4 _CryptCATEnumerateAttr@12 _CryptCATEnumerateCatAttr@8 _CryptCATEnumerateMember@8 _CryptCATFreeSortedMemberInfo@8 _CryptCATGetAttrInfo@12 _CryptCATGetCatAttrInfo@8 _CryptCATGetMemberInfo@8 _CryptCATHandleFromStore@4 _CryptCATOpen@20 _CryptCATPersistStore@4 _CryptCATPutAttrInfo@24 _CryptCATPutCatAttrInfo@20 _CryptCATPutMemberInfo@28 _CryptCATStoreFromHandle@4OUCH: contrary to the statements in all 16 MSDN articles cited above, not just the Windows Software Development Kit for Windows 7 but ships with an
associated import library
Wintrust.lib
!
Create the text file mscat.c
with the following content
in an arbitrary, preferably empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wintrust.h>
#include <mscat.h>
CRYPTCATATTRIBUTE* WINAPI CryptCATCDFEnumAttributesWithCDFTag(
_In_ CRYPTCATCDF *pCDF,
_In_ LPWSTR pwszMemberTag,
_In_ CRYPTCATMEMBER *pMember,
_In_ CRYPTCATATTRIBUTE *pPrevAttr,
_In_ PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError
);
LPWSTR WINAPI CryptCATCDFEnumMembersByCDFTagEx(
_In_ CRYPTCATCDF *pCDF,
_Inout_ LPWSTR pwszPrevCDFTag,
_In_ PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError,
_In_ CRYPTCATMEMBER **ppMember,
_In_ BOOL fContinueOnError,
_In_ LPVOID pvReserved
);
FARPROC mscat[] = {CryptCATAdminAcquireContext,
#if _WIN32_WINNT >= 0x0602
CryptCATAdminAcquireContext2,
#endif
CryptCATAdminAddCatalog,
CryptCATAdminCalcHashFromFileHandle,
#if _WIN32_WINNT >= 0x0602
CryptCATAdminCalcHashFromFileHandle2,
#endif
CryptCATAdminReleaseCatalogContext,
CryptCATAdminReleaseContext,
CryptCATAdminRemoveCatalog,
CryptCATAdminResolveCatalogPath,
CryptCATCatalogInfoFromContext,
CryptCATCDFEnumAttributesWithCDFTag,
CryptCATCDFEnumMembersByCDFTagEx,
CryptCATClose,
CryptCATEnumerateAttr,
CryptCATEnumerateCatAttr,
CryptCATGetMemberInfo,
CryptCATOpen,
IsCatalogFile};
Compile and link the source file mscat.c
created in
step 2. to show that the associated import library
Wintrust.lib
can be linked statically:
SET CL=/W4 /Zl SET LINK=/DLL /NODEFAULTLIB /NOENTRY CL.EXE mscat.c wintrust.libNote: 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. mscat.c c:\program files\microsoft sdks\windows\v7.1\include\mssip.h(92) : warning C4201 : nonstandard extension used : nameless struct/union mscat.c(31) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'HCATINFO (__stdcall *)(HCATADMIN,PWSTR,PWSTR,DWORD)' mscat.c(44) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPTCATATTRIBUTE *(__stdcall *)(HANDLE,CRYPTCATMEMBER *,CRYPTCATATTRIBUTE *)' mscat.c(45) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPTCATATTRIBUTE *(__stdcall *)(HANDLE,CRYPTCATATTRIBUTE *)' mscat.c(46) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPTCATMEMBER *(__stdcall *)(HANDLE,LPWSTR)' mscat.c(47) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'HANDLE (__stdcall *)(LPWSTR,DWORD,HCRYPTPROV,DWORD,DWORD)' Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DLL /NODEFAULTLIB /NOENTRY /out:mscat.exe mscat.obj wintrust.libOOPS: contrary to their documentation all functions can be linked statically with their import library
wintrust.lib
!
OpenPersonalTrustDBDialog()
and
OpenPersonalTrustDBDialogEx()
states since 2003:
Ouch¹: the highlighted reference to the header fileNote This function has no associated header file or import library. You must define the function yourself and use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.[…]
Requirement Value … … Header wintrust.h DLL Wintrust.dll
wintrust.h
in the Requirementssection but contradicts the highlighted claim
This function has no associated header file or import library.given in the text!
The documentation for both of the Win32 functions
WintrustGetRegPolicyFlags()
and
WintrustSetRegPolicyFlags()
states since 2001:
The documentation for the Win32 functionNote This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.[…]
Requirement Value … … Header wintrust.h DLL Wintrust.dll
WTHelperCertFindIssuerCertificate()
states since 2001:
Ouch²: no header file is specified in theNote
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.
[…]
Requirement Value … … DLL Wintrust.dll
Requirementssection!
The documentation for each of the Win32 functions
WintrustAddActionID()
,
WintrustLoadFunctionPointers()
,
WintrustRemoveActionID()
,
WintrustSetDefaultIncludePEPageHashes()
WTHelperCertIsSelfSigned()
,
WTHelperGetProvCertFromChain()
,
WTHelperGetProvPrivateDataFromChain()
,
WTHelperGetProvSignerFromChain()
and
WTHelperProvDataFromStateData()
states since 2001:
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.Ouch³: the highlighted reference to the import library[…]
Requirement Value … … Header wintrust.h Library Wintrust.lib DLL Wintrust.dll
Wintrust.lib
in the Requirementssection but contradicts the highlighted claim
This function has no associated import library.given in the text!
Determine whether the highlighted claim
This function has no associated import library.
is true
– or false:
FOR %? IN (Wintrust.lib) DO SET WINTRUST=%~$LIB:? LINK.EXE /DUMP /EXPORTS /OUT:wintrust.txt "%WINTRUST%" FIND.EXE "OpenPersonalTrustDBDialog" wintrust.txt FIND.EXE "Wintrust" wintrust.txt FIND.EXE "WTHelper" wintrust.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
SET WINTRUST=C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\Wintrust.Lib Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. ---------- WINTRUST.TXT _OpenPersonalTrustDBDialog@4 _OpenPersonalTrustDBDialogEx@12 ---------- WINTRUST.TXT _WintrustAddActionID@12 _WintrustAddDefaultForUsage@8 _WintrustCertificateTrust@4 _WintrustGetDefaultForUsage@12 _WintrustGetRegPolicyFlags@4 _WintrustLoadFunctionPointers@8 _WintrustRemoveActionID@4 _WintrustSetDefaultIncludePEPageHashes@4 _WintrustSetRegPolicyFlags@4 ---------- WINTRUST.TXT _WTHelperCertCheckValidSignature@4 _WTHelperCertIsSelfSigned@8 _WTHelperCheckCertUsage@8 _WTHelperGetAgencyInfo@12 _WTHelperGetFileHandle@4 _WTHelperGetFileHash@24 _WTHelperGetFileName@4 _WTHelperGetKnownUsages@8 _WTHelperGetProvCertFromChain@8 _WTHelperGetProvPrivateDataFromChain@8 _WTHelperGetProvSignerFromChain@16 _WTHelperIsInRootStore@8 _WTHelperOpenKnownStores@4 _WTHelperProvDataFromStateData@4OUCH: contrary to the statements in all 13 MSDN articles cited above, not just the Windows Software Development Kit for Windows 7 but ships with an
associated import library
Wintrust.lib
!
Create the text file wintrust.c
with the following
content in an arbitrary, preferably empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wintrust.h>
FARPROC wintrust[] = {OpenPersonalTrustDBDialog,
OpenPersonalTrustDBDialogEx,
WintrustAddActionID,
WintrustGetRegPolicyFlags,
WintrustLoadFunctionPointers,
WintrustRemoveActionID,
WintrustSetDefaultIncludePEPageHashes,
WintrustSetRegPolicyFlags,
WTHelperCertIsSelfSigned,
WTHelperGetProvCertFromChain,
WTHelperGetProvPrivateDataFromChain,
WTHelperGetProvSignerFromChain,
WTHelperProvDataFromStateData};
Compile and link the source file wintrust.c
created in
step 2. to show that the associated import library
Wintrust.lib
can be linked statically:
SET CL=/W4 /Zl SET LINK=/DLL /NODEFAULTLIB /NOENTRY CL.EXE wintrust.c wintrust.libNote: 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. wintrust.c wintrust.c(12) : warning C4133: 'initializing' : incompatible types - from 'void (__stdcall *)(DWORD *)' to 'FARPROC' wintrust.c(15) : warning C4133: 'initializing' : incompatible types - from 'void (__stdcall *)(BOOL)' to 'FARPROC' wintrust.c(18) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPT_PROVIDER_CERT *(__stdcall *)(CRYPT_PROVIDER_SGNR *,DWORD)' wintrust.c(19) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPT_PROVIDER_PRIVDATA *(__stdcall *)(CRYPT_PROVIDER_DATA *,GUID *)' wintrust.c(20) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPT_PROVIDER_SGNR *(__stdcall *)(CRYPT_PROVIDER_DATA *,DWORD,BOOL,DWORD)' wintrust.c(21) : warning C4047: 'initializing' : 'FARPROC' differs in levels of indirection from 'CRYPT_PROVIDER_DATA *(__stdcall *)(HANDLE)' Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DLL /NODEFAULTLIB /NOENTRY /out:wintrust.exe wintrust.obj wintrust.libOOPS: contrary to their documentation all functions can be linked statically with their import library
wintrust.lib
!
SetEnvironmentStrings()
states:
Sets the environment strings of the calling process (both the system and the user environment variables) for the current process.OUCH: the[…]BOOL SetEnvironmentStrings( LPWCH NewEnvironment );
The environment variable string using the following format:
Var1 Value1 Var2 Value2 Var3 Value3 VarN ValueN
[…]
Requirement Value Minimum supported client Windows 10 Build 20348 Minimum supported server Windows 10 Build 20348 Header processenv.h Library kernel32.lib DLL kernel32.dll
SetEnvironmentStrings()
function was but introduced with Windows Server 2003;
its
A and W variants
were declared in the header file winbase.h
shipped with
the corresponding
Platform SDK!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
LPSTR lpBlock;
LPSTR lpString;
DWORD dwString;
DWORD dwError = ERROR_SUCCESS;
HANDLE hError = GetStdHandle(STD_ERROR_HANDLE);
#ifndef BLUNDER
if (!SetEnvironmentStrings("NAME value BLUNDER blunder"))
#else
if (!SetEnvironmentStrings("NAME=value\0EMPTY=\0BLUNDER=blunder\0"))
#endif
dwError = GetLastError();
else
{
lpBlock = GetEnvironmentStrings();
if (lpBlock == NULL)
dwError = GetLastError();
else
{
for (lpString = lpBlock;
lpString[0] != '\0';
lpString[dwString = strlen(lpString)] = '\n', lpString += dwString + 1)
continue;
if (!WriteConsole(hError, lpBlock, lpString - lpBlock, &dwString, NULL))
dwError = GetLastError();
else
if (dwString != lpString - lpBlock)
dwError = ERROR_WRITE_FAULT;
if (!FreeEnvironmentStrings(lpBlock))
dwError = GetLastError();
}
}
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/Oi /W4 /Zl SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c blunder.c(38) : warning C4389: '!=' : signed/unsigned mismatch Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. and evaluate its exit code to prove the highlighted
statement of the documentation cited above wrong:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x57 (WIN32: 87 ERROR_INVALID_PARAMETER) -- 87 (87) Error message text: The parameter is incorrect. CertUtil: -error command completed successfully.
Compile and link the source file blunder.c
created in
step 1. a second time, now with the preprocessor macro
BLUNDER
defined:
CL.EXE /DBLUNDER blunder.c kernel32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c blunder.c(38) : warning C4389: '!=' : signed/unsigned mismatch Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 4. and evaluate its exit code to demonstrate the true
behaviour:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
NAME=value EMPTY= BLUNDER=blunder 0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0) Error message text: The operation completed successfully. CertUtil: -error command completed successfully.
ExpandEnvironmentStrings()
states:
Expands environment-variable strings and replaces them with the values defined for the current user.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
WCHAR szExpand[1234];
DWORD dwExpand = ExpandEnvironmentStrings(L"%COMPUTERNAME%\n%PATH%\n", szExpand, sizeof(szExpand) / sizeof(*szExpand));
DWORD dwError = ERROR_SUCCESS;
HANDLE hError = GetStdHandle(STD_ERROR_HANDLE);
if (dwExpand == 0UL)
dwError = GetLastError();
else
if (!WriteConsole(hError, szExpand, dwExpand - 1UL, (LPDWORD) NULL, NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. to prove the highlighted statement of the documentation
cited above wrong:
REG.EXE QUERY "HKEY_CURRENT_USER\Environment" /V COMPUTERNAME REG.EXE QUERY "HKEY_CURRENT_USER\Environment" /V PATH REG.EXE QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V COMPUTERNAME REG.EXE QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V PATH ECHO %COMPUTERNAME% ECHO %PATH% .\blunder.exe ECHO %ERRORLEVEL%
ERROR: The specified registry key or value was not found. HKEY_CURRENT_USER\Environment Path REG_EXPAND_SZ %USERPROFILE%\AppData\Local\Microsoft\WindowsApps; ERROR: The specified registry key or value was not found. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment Path REG_EXPAND_SZ %SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;%SystemRoot%\System32\OpenSSH\ AMNESIAC C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Users\Stefan\AppData\Local\Microsoft\WindowsApps; AMNESIAC C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Users\Stefan\AppData\Local\Microsoft\WindowsApps; 0OOPS: contrary to the highlighted statement of the documentation cited above, the Win32 function
ExpandEnvironmentStrings()
but replaces environment variable strings with values defined for
the current process!
ExpandEnvironmentStringsForUser()
states:
Expands the source string by using the environment block established for the specified user.[…]
[…]BOOL ExpandEnvironmentStringsForUser( [in, optional] HANDLE hToken, [in] LPCTSTR lpSrc, [out] LPTSTR lpDest, [in] DWORD dwSize );
If hToken is NULL, the environment block contains system variables only.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <userenv.h>
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
WCHAR szExpand[1234];
DWORD dwError = ERROR_SUCCESS;
HANDLE hError = GetStdHandle(STD_ERROR_HANDLE);
if (!ExpandEnvironmentStringsForUser((HANDLE) NULL, L"%USERNAME%\n%USERPROFILE%\n",
szExpand, sizeof(szExpand) / sizeof(*szExpand)))
dwError = GetLastError();
else
if (!WriteConsole(hError, szExpand, wcslen(szExpand), (LPDWORD) NULL, NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/Oi /W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.lib userenv.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib userenv.lib
Execute the console application blunder.exe
built in
step 2. to prove the highlighted statement of the documentation
cited above wrong:
REG.EXE QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V USERPROFILE .\blunder.exe ECHO %ERRORLEVEL%
ERROR: The specified registry key or value was not found. SYSTEM C:\Users\Default 0OOPS: contrary to the highlighted statement of the documentation cited above, the Win32 function
ExpandEnvironmentStringsForUser()
but expands (some) user environment variables when its first
argument is NULL
!
GetModuleHandle()
and
GetModuleHandleEx()
states:
Retrieves a module handle for the specified module. The module must have been loaded by the calling process.[…]
HMODULE GetModuleHandle( [in, optional] LPCTSTR lpModuleName );
[…]
[in, optional] lpModuleName
[…]
If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).
Retrieves a module handle for the specified module and increments the module's reference count unless GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT is specified. The module must have been loaded by the calling process.OUCH: both functions don’t return a handle to the[…]
BOOL GetModuleHandleEx( [in] DWORD dwFlags, [in, optional] LPCTSTR lpModuleName, [out] HMODULE *phModule );
[…]
[in, optional] lpModuleName
[…]
If this parameter is NULL, the function returns a handle to the file used to create the calling process (.exe file).
.exe filefrom which a process was loaded, but the handle alias load address of the process, equal to the address of the symbol
__ImageBase
supplied by the
linker!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2009-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
extern const IMAGE_DOS_HEADER __ImageBase;
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
#ifndef BLUNDER
HMODULE hProcess = GetModuleHandle((LPCWSTR) NULL);
DWORD dwError = (DWORD_PTR) hProcess ^ (DWORD_PTR) &__ImageBase;
#else
HMODULE hProcess;
DWORD dwError = ERROR_SUCCESS;
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCWSTR) NULL,
&hProcess)
|| !CloseHandle(hProcess))
dwError = GetLastError();
#endif
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. and evaluate its exit code:
.\blunder.exe ECHO %ERRORLEVEL%
0
Compile and link the source file blunder.c
created in
step 1. a second time, now with the preprocessor macro
BLUNDER
defined:
CL.EXE /DBLUNDER blunder.c kernel32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 4. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ErrorLevel%
0x6 (WIN32: 6 ERROR_INVALID_HANDLE) -- 6 (6)
Error message text: The handle is invalid.
CertUtil: -error command completed successfully.
GetWindowModuleFileName()
states:
Retrieves the full path and file name of the module associated with the specified window handle.Note: this documentation fails to specify error conditions and restrictions!
The MSKB article 228469 but states:
GetWindowModuleFileName and GetModuleFileName correctly retrieve information about windows and modules in the calling process. In Windows 95 and 98, they return information about windows and modules in other processes. However, in Windows NT 4.0 and Windows 2000, since module handles are no longer shared by all processes as they were on Windows 95 and 98, these APIs do not return information about windows and modules in other processes.OUCH: Windows NT 4.0 and Windows 2000 were released in the last millennium, but nobody at Microsoft was able to add the information provided in the MSKB article 228469 to the documentation for the Win32 function
GetWindowModuleFileName()
for more than 24 (in words: twenty-four) years
– it's a real shame!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
WCHAR szBuffer[MAX_PATH];
DWORD dwBuffer;
DWORD dwError = ERROR_SUCCESS;
DWORD dwConsole;
HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
HWND hWindow = HWND_DESKTOP;
if (hConsole == INVALID_HANDLE_VALUE)
dwError = GetLastError();
else
{
#ifdef BLUNDER
SetLastError(123456789);
#if BLUNDER == 1
hWindow = GetActiveWindow();
#elif BLUNDER == 2
hWindow = GetConsoleWindow();
#elif BLUNDER == 3
hWindow = GetDesktopWindow();
#elif BLUNDER == 4
hWindow = GetForegroundWindow();
#elif BLUNDER == 5
hWindow = GetOpenClipboardWindow();
#elif BLUNDER == 6
hWindow = GetShellWindow();
#elif BLUNDER == 7
hWindow = GetTopWindow(HWND_DESKTOP);
#else
#error
#endif
if (hWindow == NULL)
dwError = GetLastError();
else
#endif // BLUNDER
{
dwBuffer = GetWindowModuleFileName(hWindow,
szBuffer,
sizeof(szBuffer) / sizeof(*szBuffer));
if (dwBuffer == 0UL)
dwError = GetLastError();
else
{
szBuffer[dwBuffer++] = L'\n';
if (!WriteConsole(hConsole, szBuffer, dwBuffer, &dwConsole, NULL))
dwError = GetLastError();
else
if (dwConsole != dwBuffer)
dwError = ERROR_WRITE_FAULT;
}
}
}
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x578 (WIN32: 1400 ERROR_INVALID_WINDOW_HANDLE) -- 1400 (1400) Error message text: Invalid window handle. CertUtil: -error command completed successfully.Note: this exit code is expected – the preprocessor macro
HWND_DESKTOP
is defined as
((HWND) 0)
alias NULL
!
MapWindowPoints()
Compile and link the source file blunder.c
created in
step 1. seven more times, now with the preprocessor macro
BLUNDER
defined as 1 to 7 in turn, execute the seven
console applications blunder.exe
and evaluate their
exit code:
FOR /L %? IN (1,1,7) DO @( CL.EXE /DBLUNDER=%? /nologo blunder.c kernel32.lib .\blunder.exe ECHO !ERRORLEVEL!)
blunder.c 123456789 blunder.c C:\Users\Stefan\Desktop\blunder.exe 0 blunder.c 123456789 blunder.c C:\Users\Stefan\Desktop\blunder.exe 0 blunder.c 123456789 blunder.c 123456789 blunder.c C:\Users\Stefan\Desktop\blunder.exe 0OUCH: upon error the Win32 functions
GetActiveWindow()
,
GetOpenClipboardWindow()
and
GetWindowModuleFileName()
don’t call the
SetLastError()
function!
OOPS: upon success the Win32 function
GetWindowModuleFileName()
returns the pathname of the calling (console) application!
WriteFile()
states:
Writes data to the specified file or input/output (I/O) device.Ouch: 232−2 nonzero[…]
[…]BOOL WriteFile( [in] HANDLE hFile, [in] LPCVOID lpBuffer, [in] DWORD nNumberOfBytesToWrite, [out, optional] LPDWORD lpNumberOfBytesWritten, [in, out, optional] LPOVERLAPPED lpOverlapped );
[out, optional] lpNumberOfBytesWritten
A pointer to the variable that receives the number of bytes written when using a synchronous hFile parameter. WriteFile sets this value to zero before doing any work or error checking. Use NULL for this parameter if this is an asynchronous operation to avoid potentially erroneous results.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
Windows 7: This parameter can not be NULL.
[…]
If the function succeeds, the return value is nonzero (TRUE).
If the function fails, or is completing asynchronously, the return value is zero (FALSE). To get extended error information, call the GetLastError function.
BOOL
values differ from the value of the preprocessor
macro TRUE
!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2009-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
DWORD dwError = ERROR_SUCCESS;
HANDLE hError = GetStdHandle(STD_ERROR_HANDLE);
if (!WriteFile(hError, "BLUNDER!\r\n", 10UL, (LPDWORD) NULL, (LPOVERLAPPED) NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. on Windows 7 and evaluate its exit code to
prove the highlighted statement of the documentation cited above
wrong:
VER .\blunder.exe ECHO %ERRORLEVEL%
Microsoft Windows [Version 6.1.7601] BLUNDER! 0OOPS: contrary to the highlighted statement of the documentation cited above, lpNumberOfBytesWritten can be
NULL
on Windows 7!
CreateProcess()
,
CreateProcessAsUser()
,
CreateProcessWithLogonW()
and
CreateProcessWithTokenW()
specifies:
[…] the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:OUCH¹: the second position is the current directory of the
- The directory from which the application loaded.
- The current directory for the parent process.
- The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
- The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.
- The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
- The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.
OOPS: in the 64-bit execution environment, the
GetSystemDirectory()
function yields but the path of the 64-bit system directory!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
const STARTUPINFO si = {sizeof(si)};
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
PROCESS_INFORMATION pi;
DWORD dwError = ERROR_SUCCESS;
WCHAR szBlunder[] = L"blunder.bat";
#ifdef BLUNDER
if (!SetEnvironmentVariable(L"COMSPEC",
#if BLUNDER == 1
L"blunder.com"))
#elif BLUNDER == 2
L"blunder.exe"))
#elif BLUNDER == 3
L"blunder.bat"))
#elif BLUNDER == 4
L"blunder.cmd"))
#elif BLUNDER == 5
L"blunder"))
#else
(LPCWSTR) NULL))
#endif
dwError = GetLastError();
else
#endif
if (!CreateProcess((LPCWSTR) NULL,
szBlunder,
(LPSECURITY_ATTRIBUTES) NULL,
(LPSECURITY_ATTRIBUTES) NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE | CREATE_UNICODE_ENVIRONMENT,
(LPWSTR) NULL,
(LPCWSTR) NULL,
&si,
&pi))
dwError = GetLastError();
else
{
if (WaitForSingleObject(pi.hThread, INFINITE) == WAIT_FAILED)
dwError = GetLastError();
if (!CloseHandle(pi.hThread))
dwError = GetLastError();
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
dwError = GetLastError();
if (!CloseHandle(pi.hProcess))
dwError = GetLastError();
}
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c blunder.c(44) : 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:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x2 (WIN32: 2 ERROR_FILE_NOT_FOUND) -- 2 (2) Error message text: The system cannot find the file specified. CertUtil: -error command completed successfully.Note: the Win32 error code 2 alias
ERROR_FILE_NOT_FOUND
is expected here – the file blunder.bat
does not
exist yet.
Create the text file blunder.bat
with the following
content next to the console application blunder.exe
built in step 2.:
@REM Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
@ECHO %CMDCMDLINE%
@ECHO %~f0
@EXIT
Execute the console application blunder.exe
built in
step 2. a second time and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
C:\Windows\system32\cmd.exe /c blunder.bat
C:\Users\Stefan\Desktop\blunder.bat
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
Error message text: The operation completed successfully.
CertUtil: -error command completed successfully.
Note: since the current directory is also the
application directory here this doesn’t tell whether the batch
script blunder.bat
is executed from the first or the
second position of the documented search sequence.
Move the console application blunder.exe
built in
step 2. into another directory, for example the parent
directory, then execute it there and evaluate its exit code:
MOVE blunder.exe .. ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
C:\Windows\system32\cmd.exe /c blunder.bat
C:\Users\Stefan\Desktop\blunder.bat
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
Error message text: The operation completed successfully.
CertUtil: -error command completed successfully.
Note: the batch script blunder.bat
is
executed from the current directory.
Move the batch script blunder.bat
created in
step 4. into the same directory as the console application
blunder.exe
built in step 1., then execute the
latter there again and evaluate its exit code to prove the
documentation cited above wrong:
MOVE blunder.bat .. ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
'blunder.bat' is not recognized as an internal or external command,
operable program or batch file.
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
Error message text: The operation completed successfully.
CertUtil: -error command completed successfully.
OUCH²: contrary to its documentation cited
above, the
CreateProcess()
function fails to execute the batch script blunder.bat
from the application directory – the cause for this
Compile and link the source file blunder.c
created in
step 1. a second time, now with the preprocessor macro
BLUNDER
defined:
CL.EXE /DBLUNDER blunder.c kernel32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c blunder.c(44) : 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:blunder.exe blunder.obj kernel32.lib
Move the batch script blunder.bat
back into the
current directory, then execute the console application
blunder.exe
built in step 8. and evaluate its
exit code to prove the documentation cite above incomplete:
MOVE ..\blunder.bat . .\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x2 (WIN32: 2 ERROR_FILE_NOT_FOUND) -- 2 (2) Error message text: The system cannot find the file specified. CertUtil: -error command completed successfully.OUCH³: the
CreateProcess()
function exhibits undocumented behaviour – in
order to execute a batch script it evaluates the environment
variable COMSPEC
to locate the
Command Processor, indicated here with
the Win32 error code 2 alias
ERROR_FILE_NOT_FOUND
!
Create the empty file blunder.com
in the current
directory, then execute the console application
blunder.exe
built in step 8. a second time and
evaluate its exit code:
COPY NUL: blunder.com .\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.OUCH⁴: in order to execute a batch script the
CreateProcess()
function executes an arbitrary executable whose
file name is set in the environment variable COMSPEC
from the application directory or the current directory, indicated
here with the Win32 error code 193 alias
ERROR_BAD_EXE_FORMAT
due to the empty file blunder.com
!
Move the console application blunder.exe
built in
step 8. into another directory, for example the parent
directory, then execute it there and evaluate its exit code:
MOVE /Y blunder.exe .. ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.OUCH⁵: in order to execute a batch script the
CreateProcess()
function executes an arbitrary executable whose
file name is set in the environment variable COMSPEC
from the current directory!
Move the empty file blunder.com
created in
step 10. into the same directory as the console application
blunder.exe
created in step 8., then execute the
latter a third time and evaluate its exit code:
MOVE blunder.com .. ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.OUCH⁶: in order to execute a batch script the
CreateProcess()
function executes an arbitrary executable whose
file name is set in the environment variable COMSPEC
from the application directory too!
Optionally move the empty file blunder.com
from the
parent directory into an arbitrary directory listed in the
environment variable PATH
, for example the
user-writable directory
%USERPROFILE%\AppData\Local\Microsoft\WindowsApps\
present since Windows 8, then execute the console
application blunder.exe
created in step 8. a
fourth time and evaluate its exit code:
MOVE ..\blunder.com "%USERPROFILE%\AppData\Local\Microsoft\WindowsApps" ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.OUCH⁷: in order to execute a batch script the
CreateProcess()
function executes an arbitrary executable whose
file name is set in the environment variable COMSPEC
from any directory in the search path!
Compile and link the source file blunder.c
created in
step 1. a third time, now with the preprocessor macro
BLUNDER
defined as 0:
CL.EXE /DBLUNDER=0 blunder.c kernel32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c blunder.c(44) : 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:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 14. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
C:\Windows\system32\cmd.exe /c blunder.bat
C:\Users\Stefan\Desktop\blunder.bat
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
Error message text: The operation completed successfully.
CertUtil: -error command completed successfully.
Note: with the environment variable
COMSPEC
unset, the Win32 function
CreateProcess()
executes %SystemRoot%\System32\cmd.exe
as the
Command Processor for batch scripts!
Finally erase all files which were moved outside the current directory:
ERASE ..\blunder.exe ..\blunder.com "%USERPROFILE%\AppData\Local\Microsoft\WindowsApps\blunder.com"
Note: an evaluation of the (mis)behaviour with a
batch script Windows NT.bat
or %OS%.bat
is
left as an exercise to the reader.
Note: an evaluation of the (mis)behaviour with the
environment variable COMSPEC
set to
blunder.bat
, blunder.exe
or just
blunder
is left as an exercise to the reader.
Note: a repetition of this falsification for the
CreateProcessAsUser()
,
CreateProcessWithLogonW()
and
CreateProcessWithTokenW()
functions is also left as an exercise to the reader.
NeedCurrentDirectoryForExePath()
specifies in section Remarks:
IfNOTE: the use of a (user-controlled) environment variable to remove the current directory from (its prominent second position in) the search path for applications is not safe – properly implemented, theCreateProcess()
is called with a relative executable name, it will automatically search for the executable, calling this function to determine the search path.[…]
The value of the NoDefaultCurrentDirectoryInExePath environment variable determines the value this function returns. […] the existence of the NoDefaultCurrentDirectoryInExePath environment variable is checked, and not its value.
An example of an instance when this function should be called instead of relying on the default search path resolution algorithm in
CreateProcess()
is the "cmd.exe" executable. It calls this function to determine the command search path because it does its own path resolution before calling CreateProcess. If this function returns TRUE, cmd.exe uses the path ".;%PATH%" for the executable search. If it returns FALSE, cmd.exe uses the path "%PATH%" for the search.
NeedCurrentDirectoryForExePath()
function would query a registry entry writable only by privileged
users, similar to CWDIllegalInDllSearch
documented in
the MSKB
article
2264107!
Note: properly implemented in the first place, the
Process Creation Flags
of the four CreateProcess*()
functions would support
some CREATE_PROCESS_SEARCH_*
flags, similar to the
LOAD_LIBRARY_SEARCH_*
flags of the
LoadLibraryEx()
function.
Note: properly implemented in the second place,
functions similar to
AddDllDirectory()
,
RemoveDllDirectory()
and
SetDefaultDllDirectories()
or
SetDllDirectory()
would have been added.
2533623
OUCH⁰: the documentation for all four
CreateProcess*()
functions fails to specify that the
environment variable NoDefaultCurrentDirectoryInExePath
alters their search sequence!
OUCH¹: the first highlighted statement of
the documentation cited above contradicts the documentation for the
CreateProcess*()
functions cited earlier – the
latter search the executable file only if its name contains no
(directory) path at all, i.e. neither an absolute nor a relative
path!
OUCH²: the last highlighted statements of the documentation cited above even contradict each other – the second statement specifies the true behaviour!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
const STARTUPINFO si = {sizeof(si)};
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
PROCESS_INFORMATION pi;
DWORD dwError = ERROR_SUCCESS;
WCHAR szBlunder[] = L"blunder.com";
if (!SetEnvironmentVariable(L"NoDefaultCurrentDirectoryInExePath",
#ifdef BLUNDER
L""))
#else
(LPCWSTR) NULL))
#endif
dwError = GetLastError();
else
if (!CreateProcess((LPCWSTR) NULL,
szBlunder,
(LPSECURITY_ATTRIBUTES) NULL,
(LPSECURITY_ATTRIBUTES) NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE | CREATE_UNICODE_ENVIRONMENT,
(LPWSTR) NULL,
(LPCWSTR) NULL,
&si,
&pi))
dwError = GetLastError();
else
{
if (WaitForSingleObject(pi.hThread, INFINITE) == WAIT_FAILED)
dwError = GetLastError();
if (!CloseHandle(pi.hThread))
dwError = GetLastError();
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
dwError = GetLastError();
if (!CloseHandle(pi.hProcess))
dwError = GetLastError();
}
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c blunder.c(35) : 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:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 2. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x2 (WIN32: 2 ERROR_FILE_NOT_FOUND) -- 2 (2) Error message text: The system cannot find the file specified. CertUtil: -error command completed successfully.Note: the Win32 error code 2 alias
ERROR_FILE_NOT_FOUND
is expected here – the file blunder.com
does not
exist yet.
Create the empty file blunder.com
in the current
directory, then execute the console application
blunder.exe
built in step 2. a second time and
evaluate its exit code:
COPY NUL: blunder.com .\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.Note: the Win32 error code 193 alias
ERROR_BAD_EXE_FORMAT
is expected here – the empty file blunder.com
can’t be mapped into memory, i.e. the
CreateProcess()
function handles batch scripts like (portable executable) application files.
Compile and link the source file blunder.c
created in
step 1. a second time, now with the preprocessor macro
BLUNDER
defined:
CL.EXE /DBLUNDER blunder.c kernel32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c blunder.c(35) : 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:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 5. and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.Note: the Win32 error code 193 alias
ERROR_BAD_EXE_FORMAT
is expected here – the empty file blunder.com
is
now found in the application directory!
Move the console application blunder.exe
built in
step 5. into another directory, for example the parent
directory, then execute it there and evaluate its exit code:
MOVE blunder.exe .. ..\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0x2 (WIN32: 2 ERROR_FILE_NOT_FOUND) -- 2 (2) Error message text: The system cannot find the file specified. CertUtil: -error command completed successfully.Note: with the environment variable
NoDefaultCurrentDirectoryInExePath
set, the
CreateProcess()
function fails to execute the file blunder.com
–
it doesn’t search the current directory any more!
Finally erase the file blunder.exe
which was moved
outside the current directory:
ERASE ..\blunder.exe
shell
Explorer.exe
looks up the
file type
alias
Programmatic Identifier
associated with its extension, retrieves the command line template
registered with the default verb of that associated file type,
replaces the various tokens %‹digit›
,
%‹letter›
and %*
in this
command line template with file or path names and arguments, then
feeds the completed command line to one of the
CreateProcess()
,
CreateProcessAsUser()
,
CreateProcessWithLogonW()
or
CreateProcessWithTokenW()
functions.
The MSDN articles File Types and File Associations and Launching Applications (ShellExecute, ShellExecuteEx, SHELLEXECUTEINFO) provide details.
shellcan’t distinguish batch scripts from applications.
Create the empty file blunder.bat
in
an arbitrary, preferable empty directory, then open
it via
double-click.
OOPS: according to the error message text,
Windows treats batch scripts as applications, i.e.
portable executable
files!
Note: as already shown with
Blunder № 12,
the Win32 error code is 193 alias
ERROR_BAD_EXE_FORMAT
!
Create the text file blunder.c
with the following
content in the same directory as the empty file
blunder.bat
:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
SHELLEXECUTEINFO sei = {sizeof(sei),
SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE,
HWND_DESKTOP,
(LPCWSTR) NULL,
L".\\blunder.bat",
L"/?",
L".",
SW_SHOWNORMAL,
(HINSTANCE) NULL,
NULL,
(LPCWSTR) NULL,
HKEY_CLASSES_ROOT,
0UL,
(HANDLE) NULL,
(HANDLE) NULL};
DWORD dwError = ERROR_SUCCESS;
if (!ShellExecuteEx(&sei))
dwError = GetLastError();
ExitProcess(dwError);
}
Note: this program performs the equivalent of a
double-click on the file blunder.bat
in the current
directory.
Compile and link the source file blunder.c
created in
step 2.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.lib shell32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib shell32.lib
Execute the console application blunder.exe
built in
step 3. and evaluate its exit code to verify the
Win32 error code 193:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc1 (WIN32: 193 ERROR_BAD_EXE_FORMAT) -- 193 (193) Error message text: %1 is not a valid Win32 application. CertUtil: -error command completed successfully.
Display the
file types
associated with the extensions .bat
, .cmd
,
.com
and .exe
plus their command line
templates to show the cause for this undocumented
behaviour:
ASSOC .bat FTYPE batfile ASSOC .cmd FTYPE cmdfile ASSOC .com FTYPE comfile ASSOC .exe FTYPE exefile
.bat=batfile batfile="%1" %* .cmd=cmdfile cmdfile="%1" %* .com=comfile cpmfile="%1" %* .exe=exefile exefile="%1" %*
Overwrite the empty file blunder.bat
created in
step 1. with the following content:
@REM Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
@ECHO %CMDCMDLINE%
@ECHO %~f0
@EXIT
Execute the console application blunder.exe
built in
step 3. a second time and evaluate its exit code:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
C:\Windows\system32\cmd.exe /c ""C:\Users\Stefan\Desktop\blunder.bat" /?"
C:\Users\Stefan\Desktop\blunder.bat
0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
Error message text: The operation completed successfully.
CertUtil: -error command completed successfully.
OUCH: the
ShellExecuteEx()
function (which Explorer.exe
calls internally) expands the token "%1"
in
the command line template to the fully qualified quoted path name of
the batch script blunder.bat
, but fails to double the
inner double quotes!
Rename the console application blunder.exe
built in
step 3 as blunder.cmd
and execute it via
double-click:
RENAME blunder.exe *.cmd
Note: an evaluation of the (mis)behaviour with a
batch script Windows NT.bat
or %OS%.bat
is
left as an exercise to the reader.
AdjustTokenPrivileges()
,
CheckTokenMembership()
,
CompareFileTime()
,
CreateDirectory()
,
ConvertSecurityDescriptorToStringSecurityDescriptor()
,
ConvertSidToStringSid()
,
ConvertStringSecurityDescriptorToSecurityDescriptor()
,
ConvertStringSidToSid()
,
CreateEnvironmentBlock()
,
CreateFile()
,
CreateProcess()
,
DestroyEnvironmentBlock()
,
FreeEnvironmentStrings()
,
GetUserObjectSecurity()
,
IsValidAcl()
,
IsValidSecurityDescriptor()
,
IsValidSid()
,
LocalFree()
,
RegisterClass()
,
RegisterClassEx()
,
SetSecurityInfo()
and
SetUserObjectSecurity()
(just to pick a few examples, in alphabetical order) as follows:
BOOL AdjustTokenPrivileges( [in] HANDLE TokenHandle, [in] BOOL DisableAllPrivileges, [in, optional] PTOKEN_PRIVILEGES NewState, [in] DWORD BufferLength, [out, optional] PTOKEN_PRIVILEGES PreviousState, [out, optional] PDWORD ReturnLength );
BOOL CheckTokenMembership( [in, optional] HANDLE TokenHandle, [in] PSID SidToCheck, [out] PBOOL IsMember );
LONG CompareFileTime( [in] const FILETIME *lpFileTime1, [in] const FILETIME *lpFileTime2 );
BOOL ConvertSecurityDescriptorToStringSecurityDescriptor( [in] PSECURITY_DESCRIPTOR SecurityDescriptor, [in] DWORD RequestedStringSDRevision, [in] SECURITY_INFORMATION SecurityInformation, [out] LPTSTR *StringSecurityDescriptor, [out] PULONG StringSecurityDescriptorLen );
BOOL ConvertSidToStringSid( [in] PSID Sid, [out] LPTSTR *StringSid );
BOOL ConvertStringSecurityDescriptorToSecurityDescriptor( [in] LPCTSTR StringSecurityDescriptor, [in] DWORD StringSDRevision, [out] PSECURITY_DESCRIPTOR *SecurityDescriptor, [out] PULONG SecurityDescriptorSize );
BOOL ConvertStringSidToSid( [in] LPCTSTR StringSid, [out] PSID *Sid );
BOOL CreateDirectory( [in] LPCTSTR lpPathName, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes );
BOOL CreateEnvironmentBlock( [out] LPVOID *lpEnvironment, [in, optional] HANDLE hToken, [in] BOOL bInherit );
HANDLE CreateFile( [in] LPCTSTR lpFileName, [in] DWORD dwDesiredAccess, [in] DWORD dwShareMode, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, [in] DWORD dwCreationDisposition, [in] DWORD dwFlagsAndAttributes, [in, optional] HANDLE hTemplateFile );
BOOL CreateProcess( [in, optional] LPCTSTR lpApplicationName, [in, out, optional] LPTSTR lpCommandLine, [in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes, [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes, [in] BOOL bInheritHandles, [in] DWORD dwCreationFlags, [in, optional] LPVOID lpEnvironment, [in, optional] LPCTSTR lpCurrentDirectory, [in] LPSTARTUPINFO lpStartupInfo, [out] LPPROCESS_INFORMATION lpProcessInformation );
BOOL DestroyEnvironmentBlock( [in] LPVOID lpEnvironment );
BOOL FreeEnvironmentStrings( [in] LPTCH penv );
BOOL GetUserObjectSecurity( [in] HANDLE hObj, [in] PSECURITY_INFORMATION pSIRequested, [in, out, optional] PSECURITY_DESCRIPTOR pSID, [in] DWORD nLength, [out] LPDWORD lpnLengthNeeded );
BOOL IsValidAcl( [in] PACL pAcl );
BOOL IsValidSecurityDescriptor( [in] PSECURITY_DESCRIPTOR pSecurityDescriptor );
BOOL IsValidSid( [in] PSID pSid );
HLOCAL LocalFree( [in] HLOCAL hMem );
ATOM RegisterClass( [in] const WNDCLASS *lpWndClass );
ATOM RegisterClassEx( [in] const WNDCLASSEX *unnamedParam1 );
DWORD SetSecurityInfo( [in] HANDLE handle, [in] SE_OBJECT_TYPE ObjectType, [in] SECURITY_INFORMATION SecurityInfo, [in, optional] PSID psidOwner, [in, optional] PSID psidGroup, [in, optional] PACL pDacl, [in, optional] PACL pSacl );
OUCH: except for the properly declared prototypes of the Win32 functionsBOOL SetUserObjectSecurity( [in] HANDLE hObj, [in] PSECURITY_INFORMATION pSIRequested, [in] PSECURITY_DESCRIPTOR pSID );
CompareFileTime()
,
RegisterClass()
and
RegisterClassEx()
shown above, they all fail to specify their
read-only input parameters as const
or
const *
, due to which the Visual C
compiler throws the superfluous warning
C4090
for arguments of type pointer to constant!
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <userenv.h>
#include <shellapi.h>
#include <sddl.h>
#include <aclapi.h>
#define SE_CHANGE_NOTIFY_PRIVILEGE 23 // "SeChangeNotifyPrivilege"
const TOKEN_PRIVILEGES tp = {1, {SE_CHANGE_NOTIFY_PRIVILEGE, 0, SE_PRIVILEGE_ENABLED}};
const SID group = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID},
owner = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID};
typedef struct _ace
{
ACE_HEADER Header;
ACCESS_MASK Mask;
SID Trustee;
} ACE;
const struct _acl
{
ACL acl;
ACE ace;
} dacl = {{ACL_REVISION, 0, sizeof(dacl), 1, 0},
// (A;NP;FA;;;AU)
{{ACCESS_ALLOWED_ACE_TYPE, NO_PROPAGATE_INHERIT_ACE, sizeof(ACE)},
FILE_ALL_ACCESS,
{SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_AUTHENTICATED_USER_RID}}},
sacl = {{ACL_REVISION, 0, sizeof(sacl), 1, 0},
// (ML;;NRNWNX;;;ME)
{{SYSTEM_MANDATORY_LABEL_ACE_TYPE, 0, sizeof(ACE)},
SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP | SYSTEM_MANDATORY_LABEL_NO_READ_UP | SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
{SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, SECURITY_MANDATORY_MEDIUM_RID}}};
const SECURITY_DESCRIPTOR sd = {SECURITY_DESCRIPTOR_REVISION,
0,
SE_DACL_PRESENT | SE_SACL_PRESENT,
&owner,
&group,
&sacl,
&dacl};
const SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE};
const SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
| LABEL_SECURITY_INFORMATION
| OWNER_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION;
const STARTUPINFO st = {sizeof(st)};
const WNDCLASS wc = {0};
const WNDCLASSEX wce = {sizeof(wce)};
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
SECURITY_DESCRIPTOR const *lpSD;
SID const *lpSID;
PROCESS_INFORMATION pi;
FILETIME ft = {0UL, 0UL};
INT nArguments;
BOOL b;
WCHAR sz[] = L".";
DWORD dwSD;
HANDLE h;
LPCWSTR lpBlock;
LPCWSTR lpStrings = GetEnvironmentStrings();
LPCWSTR lpCmdLine = GetCommandLine();
LPCWSTR *lpArguments = CommandLineToArgvW(lpCmdLine, &nArguments);
if (lpArguments != NULL)
LocalFree(lpArguments);
if (lpStrings != NULL)
FreeEnvironmentStrings(lpStrings);
AdjustTokenPrivileges(INVALID_HANDLE_VALUE,
FALSE,
&tp,
sizeof(tp),
(TOKEN_PRIVILEGES *) NULL,
(LPDWORD) NULL);
CheckTokenMembership(NULL,
&owner,
&b);
CompareFileTime(&ft, &ft); // no warning C4090 here!
if (ConvertSecurityDescriptorToStringSecurityDescriptor(&sd,
SDDL_REVISION_1,
si,
&lpStrings,
(LPDWORD) NULL))
LocalFree(lpStrings);
if (ConvertSidToStringSid(&owner,
&lpStrings))
LocalFree(lpStrings);
if (ConvertStringSidToSid(sz, // no warning C4090 here!
&lpSID))
LocalFree(lpSID);
if (ConvertStringSecurityDescriptorToSecurityDescriptor(sz,
SDDL_REVISION_1,
&lpSD,
&dwSD))
LocalFree(lpSD);
if (CreateDirectory(sz, // no warning C4090 here!
&sa))
RemoveDirectory(sz);
if (CreateEnvironmentBlock(&lpBlock,
NULL,
FALSE))
DestroyEnvironmentBlock(lpBlock);
h = CreateFile(sz, // no warning C4090 here!
MAXIMUM_ALLOWED,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
(HANDLE) NULL);
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
CreateProcess((LPCWSTR) NULL,
(LPWSTR) NULL,
&sa,
&sa,
FALSE,
CREATE_UNICODE_ENVIRONMENT,
lpStrings,
sz, // no warning C4090 here!
&st,
&pi);
GetUserObjectSecurity(INVALID_HANDLE_VALUE,
&si,
(SECURITY_DESCRIPTOR *) NULL,
0,
&dwSD);
IsValidAcl(&dacl);
IsValidAcl(&sacl);
IsValidSecurityDescriptor(&sd);
IsValidSid(&owner);
IsValidSid(&group);
if (RegisterClass(&wc) != 0U) // no warning C4090 here!
UnregisterClass(wc.lpszClassName,
wc.hInstance);
if (RegisterClassEx(&wce) != 0U)// no warning C4090 here!
UnregisterClass(wce.lpszClassName,
wce.hInstance);
SetSecurityInfo(INVALID_HANDLE_VALUE,
SE_FILE_OBJECT,
si,
&owner,
&group,
&dacl,
&sacl);
SetUserObjectSecurity(INVALID_HANDLE_VALUE,
&si,
&sd);
ExitProcess(nArguments);
}
Note: in order to exercise defensive programming,
all pointers are intentionally defined as const *
– their targets are not (to be) written here!
Run a syntax check on the source file blunder.c
created
in step 1.:
CL.EXE /Zs blunder.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
blunder.c
blunder.c(45) : warning C4090: 'initializing' : different 'const' qualifiers
blunder.c(46) : warning C4090: 'initializing' : different 'const' qualifiers
blunder.c(47) : warning C4090: 'initializing' : different 'const' qualifiers
blunder.c(48) : warning C4090: 'initializing' : different 'const' qualifiers
blunder.c(50) : warning C4090: 'initializing' : different 'const' qualifiers
blunder.c(85) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(88) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(92) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(98) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(103) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(106) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(108) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(110) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(111) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(112) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(115) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(116) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(120) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(122) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(125) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(128) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(131) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(136) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(146) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(147) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(150) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(152) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(156) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(160) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(161) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(162) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(163) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(164) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(177) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(178) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(179) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(180) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(183) : warning C4090: 'function' : different 'const' qualifiers
blunder.c(184) : warning C4090: 'function' : different 'const' qualifiers
OOPS: Was für Plunder!
Run a syntax check on the source file blunder.c
created
in step 1. a second time, now as C++ source:
CL.EXE /TP /Zs blunder.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
blunder.c
blunder.c(45) : error C2440: 'initializing' : cannot convert from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(46) : error C2440: 'initializing' : cannot convert from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(47) : error C2440: 'initializing' : cannot convert from 'const _acl *' to 'PACL'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(48) : error C2440: 'initializing' : cannot convert from 'const _acl *' to 'PACL'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(50) : error C2440: 'initializing' : cannot convert from 'const SECURITY_DESCRIPTOR *' to 'LPVOID'
Conversion loses qualifiers
blunder.c(82) : error C2440: 'initializing' : cannot convert from 'LPWSTR *' to 'LPCWSTR *'
Conversion loses qualifiers
blunder.c(88) : error C2664: 'FreeEnvironmentStringsW' : cannot convert parameter 1 from 'LPCWSTR' to 'LPWCH'
Conversion loses qualifiers
blunder.c(95) : error C2664: 'AdjustTokenPrivileges' : cannot convert parameter 3 from 'const TOKEN_PRIVILEGES *' to 'PTOKEN_PRIVILEGES'
Conversion loses qualifiers
blunder.c(99) : error C2664: 'CheckTokenMembership' : cannot convert parameter 2 from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(107) : error C2664: 'ConvertSecurityDescriptorToStringSecurityDescriptorW' : cannot convert parameter 1 from 'const SECURITY_DESCRIPTOR *' to 'PSECURITY_DESCRIPTOR'
Conversion loses qualifiers
blunder.c(108) : error C2664: 'LocalFree' : cannot convert parameter 1 from 'LPCWSTR' to 'HLOCAL'
Conversion loses qualifiers
blunder.c(111) : error C2664: 'ConvertSidToStringSidW' : cannot convert parameter 1 from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(112) : error C2664: 'LocalFree' : cannot convert parameter 1 from 'LPCWSTR' to 'HLOCAL'
Conversion loses qualifiers
blunder.c(115) : error C2664: 'ConvertStringSidToSidW' : cannot convert parameter 2 from 'const SID **' to 'PSID *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(116) : error C2664: 'LocalFree' : cannot convert parameter 1 from 'const SID *' to 'HLOCAL'
Conversion loses qualifiers
blunder.c(121) : error C2664: 'ConvertStringSecurityDescriptorToSecurityDescriptorW' : cannot convert parameter 3 from 'const SECURITY_DESCRIPTOR **' to 'PSECURITY_DESCRIPTOR *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(122) : error C2664: 'LocalFree' : cannot convert parameter 1 from 'const SECURITY_DESCRIPTOR *' to 'HLOCAL'
Conversion loses qualifiers
blunder.c(125) : error C2664: 'CreateDirectoryW' : cannot convert parameter 2 from 'const SECURITY_ATTRIBUTES *' to 'LPSECURITY_ATTRIBUTES'
Conversion loses qualifiers
blunder.c(130) : error C2664: 'CreateEnvironmentBlock' : cannot convert parameter 1 from 'LPCWSTR *' to 'LPVOID *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(131) : error C2664: 'DestroyEnvironmentBlock' : cannot convert parameter 1 from 'LPCWSTR' to 'LPVOID'
Conversion loses qualifiers
blunder.c(139) : error C2664: 'CreateFileW' : cannot convert parameter 4 from 'const SECURITY_ATTRIBUTES *' to 'LPSECURITY_ATTRIBUTES'
Conversion loses qualifiers
blunder.c(153) : error C2664: 'CreateProcessW' : cannot convert parameter 3 from 'const SECURITY_ATTRIBUTES *' to 'LPSECURITY_ATTRIBUTES'
Conversion loses qualifiers
blunder.c(159) : error C2664: 'GetUserObjectSecurity' : cannot convert parameter 2 from 'const SECURITY_INFORMATION *' to 'PSECURITY_INFORMATION'
Conversion loses qualifiers
blunder.c(160) : error C2664: 'IsValidAcl' : cannot convert parameter 1 from 'const _acl *' to 'PACL'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(161) : error C2664: 'IsValidAcl' : cannot convert parameter 1 from 'const _acl *' to 'PACL'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
blunder.c(162) : error C2664: 'IsValidSecurityDescriptor' : cannot convert parameter 1 from 'const SECURITY_DESCRIPTOR *' to 'PSECURITY_DESCRIPTOR'
Conversion loses qualifiers
blunder.c(163) : error C2664: 'IsValidSid' : cannot convert parameter 1 from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(164) : error C2664: 'IsValidSid' : cannot convert parameter 1 from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(180) : error C2664: 'SetSecurityInfo' : cannot convert parameter 4 from 'const SID *' to 'PSID'
Conversion loses qualifiers
blunder.c(184) : error C2664: 'SetUserObjectSecurity' : cannot convert parameter 2 from 'const SECURITY_INFORMATION *' to 'PSECURITY_INFORMATION'
Conversion loses qualifiers
OUCH: Was für Plunder!
CertRDNValueToStr()
and
GetVolumePathNamesForVolumeNameW()
(just to pick some examples) as well as the window message
LVM_GETISEARCHSTRING
(just to pick another example) exhibit an unfortunately
very common Size, in characters, allocated for the returned string. The size must include the terminating NULL character.[…]
Returns the number of characters converted, including the terminating NULL character. If psz is NULL or csz is zero, returns the required size of the destination string.
The list is a array of null-terminated strings terminated by an additional NULL character. […][…] including all NULL characters.
Supplies the maximum number of bytes that are allowed in the buffer that psz points to, including the terminating NULL character.
StrChrNIW searches for wMatch from pszStart to pszStart + cchMax, or until a NULL character is encountered.
StrChrNW searches for wMatch from pszStart to pszStart + cchMax, or until a NULL character is encountered.
Searches a string for the first occurrence of any of a group of characters. The search method is case-sensitive, and the terminating NULL character is included within the search pattern match.
Searches a string for the first occurrence of any of a group of characters. The search method is not case-sensitive, and the terminating NULL character is included within the search pattern match.
Returns the number of characters in the incremental search string, not including the terminating NULL character, or zero if the list-view control is not in incremental search mode.[…]
Make sure that the buffer is large enough to hold the string and the terminating NULL character.
Specifies the length, in bytes, of the string pointed to by the Buffer member, not including the terminating NULL character, if any.
Specifies the length, in bytes, of the string pointed to by the Buffer member, not including the terminating NULL character, if any.
These routines operate on null-terminated single-byte character,
wide-character, and multibyte-character strings. Use the
buffer-manipulation routines, described in
Buffer manipulation,
to work with character arrays that don't end with a
NULL
character.
OUCH: there is no NULL character–
NULL
is a preprocessor macro defined as ((void *) 0)
–
and the highlighted text parts should be replaced with
null character,
NUL
,
'\0'
or L'\0'
!
winnt.h
shipped with the
Oops¹: the definition of the#define ANYSIZE_ARRAY 1 […] //////////////////////////////////////////////////////////////////////// // // // Security Id (SID) // // // //////////////////////////////////////////////////////////////////////// // // // Pictorially the structure of an SID is as follows: // // 1 1 1 1 1 1 // 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---------------------------------------------------------------+ // | SubAuthorityCount |Reserved1 (SBZ)| Revision | // +---------------------------------------------------------------+ // | IdentifierAuthority[0] | // +---------------------------------------------------------------+ // | IdentifierAuthority[1] | // +---------------------------------------------------------------+ // | IdentifierAuthority[2] | // +---------------------------------------------------------------+ // | | // +- - - - - - - - SubAuthority[] - - - - - - - - -+ // | | // +---------------------------------------------------------------+ // // #ifndef SID_IDENTIFIER_AUTHORITY_DEFINED #define SID_IDENTIFIER_AUTHORITY_DEFINED typedef struct _SID_IDENTIFIER_AUTHORITY { BYTE Value[6]; } SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; #endif #ifndef SID_DEFINED #define SID_DEFINED typedef struct _SID { BYTE Revision; BYTE SubAuthorityCount; SID_IDENTIFIER_AUTHORITY IdentifierAuthority; DWORD SubAuthority[ANYSIZE_ARRAY]; } SID, *PISID; #endif #define SID_REVISION (1) // Current revision level #define SID_MAX_SUB_AUTHORITIES (15) #define SID_RECOMMENDED_SUB_AUTHORITIES (1) // Will change to around 6 // in a future release. #define SECURITY_MAX_SID_SIZE \ (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD))) // 2 (S-) // 4 (Rev(max: 255)-) // 15 ( // If (Auth < 2^32): Auth(max:4294967295)- // Else: 0xAuth(max:FFFFFFFFFFFF)- // ) // (11 * SID_MAX_SUB_AUTHORITIES) (SubN(max:4294967295)-) // 1 (NULL character) // = 187 (assuming SID_MAX_SUB_AUTHORITIES = 15) #define SECURITY_MAX_SID_STRING_CHARACTERS \ (2 + 4 + 15 + (11 * SID_MAX_SUB_AUTHORITIES) + 1) […] ///////////////////////////////////////////////////////////////////////////// // // // Universal well-known SIDs // // // // Null SID S-1-0-0 // // World S-1-1-0 // // Local S-1-2-0 // // Creator Owner ID S-1-3-0 // // Creator Group ID S-1-3-1 // // Creator Owner Server ID S-1-3-2 // // Creator Group Server ID S-1-3-3 // // // // (Non-unique IDs) S-1-4 // // // ///////////////////////////////////////////////////////////////////////////// #define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} #define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} #define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} #define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} #define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} #define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} […] /////////////////////////////////////////////////////////////////////////////// // // // NT well-known SIDs // // // // NT Authority S-1-5 // // Dialup S-1-5-1 // // // // Network S-1-5-2 // // Batch S-1-5-3 // // Interactive S-1-5-4 // // (Logon IDs) S-1-5-5-X-Y // // Service S-1-5-6 // // AnonymousLogon S-1-5-7 (aka null logon session) // // Proxy S-1-5-8 // // Enterprise DC (EDC) S-1-5-9 (aka domain controller account) // // Self S-1-5-10 (self RID) // // Authenticated User S-1-5-11 (Authenticated user somewhere) // // Restricted Code S-1-5-12 (Running restricted code) // // Terminal Server S-1-5-13 (Running on Terminal Server) // // Remote Logon S-1-5-14 (Remote Interactive Logon) // // This Organization S-1-5-15 // // // // IUser S-1-5-17 // // Local System S-1-5-18 // // Local Service S-1-5-19 // // Network Service S-1-5-20 // // // // (NT non-unique IDs) S-1-5-0x15-... (NT Domain Sids) // // // // (Built-in domain) S-1-5-0x20 // // // // (Security Package IDs) S-1-5-0x40 // // NTLM Authentication S-1-5-0x40-10 // // SChannel Authentication S-1-5-0x40-14 // // Digest Authentication S-1-5-0x40-21 // // // // Other Organization S-1-5-1000 (>=1000 can not be filtered) // // // // // // NOTE: the relative identifier values (RIDs) determine which security // // boundaries the SID is allowed to cross. Before adding new RIDs, // // a determination needs to be made regarding which range they should // // be added to in order to ensure proper "SID filtering" // // // /////////////////////////////////////////////////////////////////////////////// #define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} // ntifs […] #define SECURITY_APP_PACKAGE_AUTHORITY {0,0,0,0,0,15} […] #define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} […] #define SECURITY_SCOPED_POLICY_ID_AUTHORITY {0,0,0,0,0,17} […] #define SECURITY_AUTHENTICATION_AUTHORITY {0,0,0,0,0,18} […] #define SECURITY_PROCESS_TRUST_AUTHORITY {0,0,0,0,0,19}
SID_IDENTIFIER_AUTHORITY
structure fails to match the
ASCII
art – according to the latter it should be
WORD Value[3]
instead of BYTE Value[6]
!
Oops²: the value of the preprocessor macro
SECURITY_MAX_SID_SIZE
fails to match the definition of
the SID
structure –
according to the latter it should be
(sizeof(SID) + sizeof(DWORD) * (SID_MAX_SUB_AUTHORITIES - ANYSIZE_ARRAY))
!
Oops³: the value of the preprocessor macro
SECURITY_MAX_SID_STRING_CHARACTERS
(introduced with
Windows 10 1703 alias Creators Update,
codenamed Redstone 2) counts one minus sign to many and
matches neither the
ASCII
art nor (the use of) the SID_IDENTIFIER_AUTHORITY
structure – it should be
(sizeof("S-15-65535") + sizeof("4294967295") * SID_MAX_SUB_AUTHORITIES)
to match the former or
(sizeof("S-15-255") + sizeof("4294967295") * SID_MAX_SUB_AUTHORITIES)
to match the latter!
Well-known SIDs
SID Strings
You can specify any number of options, filenames, and library names, as long as the number of characters on the command line does not exceed 1024, the limit dictated by the operating system.OUCH: Windows NT supports but up to 32767 characters on the command line!
Note: according to the
MSKB
article
830473,
the command interpreter
Cmd.exe
supports up to 8191 characters on the command line.
/GS
compiler option
states:
The /GS compiler option requires that the security cookie be initialized before any function that uses the cookie is run. The security cookie must be initialized immediately on entry to an EXE or DLL. This is done automatically if you use the default VCRuntime entry points: mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup, or _DllMainCRTStartup. If you use an alternate entry point, you must manually initialize the security cookie by calling __security_init_cookie.OOPS¹: contrary to the first highlighted statement, the code generated by the Visual C compiler requires only that the (arbitrary) value of the security cookie does not change between entry and exit of any function which uses it!
OOPS²: contrary to the second highlighted
statement there is absolutely no need to call the
__security_init_cookie()
function to (re)initialise the security cookie!
OOPS³: the documentation cited above fails to provide the following (implementation) details:
_load_config_used
structure matches the size of the
IMAGE_LOAD_CONFIG_DIRECTORY
structure in the eleventh entry of the
IMAGE_DATA_DIRECTORY
array in the
IMAGE_OPTIONAL_HEADER
structure;
__security_init_cookie()
function provided in the
MSVCRT
libraries (re)initialises the security cookie only if it has this
default value or is 0;
mainCRTStartup
,
wmainCRTStartup
, WinMainCRTStartup
,
wWinMainCRTStartup
and _DllMainCRTStartup
!
/Gs
compiler option
states in section Remarks:
A stack probe is a sequence of code that the compiler inserts at the beginning of a function call. When initiated, a stack probe reaches benignly into memory by the amount of space required to store the function's local variables. This probe causes the operating system to transparently page in more stack memory if necessary, before the rest of the function runs.The documentation for the Visual C compiler helper routineBy default, the compiler generates code that initiates a stack probe when a function requires more than one page of stack space. This default is equivalent to a compiler option of
/Gs4096
for x86, x64, ARM, and ARM64 platforms. This value allows an application and the Windows memory manager to increase the amount of memory committed to the program stack dynamically at run time.
_chkstk()
states since more than 20 years in section Remarks:
_chkstk Routine is a helper routine for the C compiler. For x86 compilers, _chkstk Routine is called when the local variables exceed 4K bytes; for x64 compilers it is 8K.OUCH: the correct value for x64 alias AMD64
_alloca()
states since more than 20 years in section Remarks:
Allocates memory on the stack. […]The
_alloca
routine returns avoid
pointer to the allocated space, which is guaranteed to be suitably aligned for storage of any type of object. […]
Create the text file alloca.c
with the following
content in an arbitrary, preferably empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
void *mainCRTStartup(void)
{
return _alloca(42);
}
Compile and link the source file alloca.c
created in
step 1.:
SET CL=/GAFS- /Oxy /W4 /X SET LINK=/ENTRY:mainCRTStartup /MACHINE:I386 /SUBSYSTEM:CONSOLE CL.EXE alloca.cNote: 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. alloca.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /MACHINE:I386 /SUBSYSTEM:CONSOLE /out:alloca.exe alloca.obj
Execute the console application alloca.exe
built in
step 2. and evaluate its exit code to prove the highlighted
claim of the documentation cited above wrong:
.\alloca.exe ECHO %ERRORLEVEL% SET /A %ERRORLEVEL% % 16
3733996 12OUCH¹: memory objects referenced by SSE instructions require but a 16 byte alignment!
OUCH²: for constant arguments less than 64
the Visual C compiler generates calls to the
_alloca_probe
routine which returns but an unaligned
pointer!
#pragma comment
states:
Places a comment record into an object file or executable file.OUCH: the highlighted statement is misleading and wrong – the Visual C compiler accepts arbitrary strings as linker options and writes them into theSyntax
#pragma comment(
comment-type [,
"comment-string" ])
Remarks
The comment-type is one of the predefined identifiers, described below, that specifies the type of comment record. The optional comment-string is a string literal that provides additional information for some comment types. Because comment-string is a string literal, it obeys all the rules for string literals on use of escape characters, embedded quotation marks (
"
), and concatenation.[…]
linker
Places a linker option in the object file. You can use this comment-type to specify a linker option instead of passing it to the command line or specifying it in the development environment. For example, you can specify the /include option to force the inclusion of a symbol:
Only the following (comment-type) linker options are available to be passed to the linker identifier:#pragma comment(linker, "/include:__mySymbol")
.drectve
section of the
object file;
the linker but rejects all options except the 6 options cited above
plus the 15 options enumerated below with error
LNK1276
or warning
LNK4229
!
/ALIGN
/ALTERNATENAME
/ASSEMBLYMODULE
/BASE
/CLRTHREADATTRIBUTE
/DLL
/DISALLOWLIB
/ENTRY
/HEAP
/INCREMENTAL
/NODEFAULTLIB
/OUT
/STACK
/SUBSYSTEM
/VERSION
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2001-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
int blunder(void *module, int reason, void *context)
{
return module != context, reason == 1;
#pragma comment(linker, "/ALIGN:4096")
#pragma comment(linker, "/ALTERNATENAME:@=" __FUNCDNAME__)
#pragma comment(linker, "/ASSEMBLYMODULE:@")
#pragma comment(linker, "/BASE:0")
#pragma comment(linker, "/CLRTHREADATTRIBUTE:NONE")
#pragma comment(linker, "/DEFAULTLIB:libcmt.lib")
#pragma comment(linker, "/DISALLOWLIB:msvcrt.lib")
#pragma comment(linker, "/DISALLOWLIB:oldnames.lib")
#pragma comment(linker, "/DLL")
#pragma comment(linker, "/ENTRY:" __FUNCTION__)
#pragma comment(linker, "/EXPORT:@")
#pragma comment(linker, "/HEAP:0,0")
#pragma comment(linker, "/INCLUDE:@")
#pragma comment(linker, "/INCREMENTAL")
#pragma comment(linker, "/MANIFESTDEPENDENCY:name='@'")
#pragma comment(linker, "/MERGE:.rdata=.const")
#pragma comment(linker, "/MERGE:.text=.code")
#pragma comment(linker, "/NODEFAULTLIB")
#pragma comment(linker, "/OUT:blunder.dll")
#pragma comment(linker, "/SECTION:.bss,d")
#pragma comment(linker, "/STACK:0,0")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#pragma comment(linker, "/VERBOSE")
#pragma comment(linker, "/VERSION:0.815")
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/Gz /W4 /X /Zl SET LINK= CL.EXE blunder.cNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:blunder.exe blunder.obj blunder.obj : warning LNK4070: /OUT:blunder.dll directive in .EXP differs from output filename 'blunder.exe'; ignoring directive blunder.obj : warning LNK4229: invalid directive '/VERBOSE' encountered; ignored Creating library blunder.lib and object blunder.exp
/ENTRY:‹symbol›
linker option
states under the heading Remarks:
RemarksOuch: no prototypes are provided for the entry point functions!The /ENTRY option specifies an entry point function as the starting address for an .exe file or DLL.
The function must be defined to use the
__stdcall
calling convention. The parameters and return value depend on if the program is a console application, a windows application or a DLL. It is recommended that you let the linker set the entry point so that the C run-time library is initialized correctly, and C++ constructors for static objects are executed.By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.
Function name Default for mainCRTStartup
(or wmainCRTStartup)An application that uses /SUBSYSTEM:CONSOLE; calls main
(orwmain
)WinMainCRTStartup
(or wWinMainCRTStartup)An application that uses /SUBSYSTEM:WINDOWS; calls WinMain
(orwWinMain
), which must be defined to use__stdcall
_DllMainCRTStartup A DLL; calls DllMain
if it exists, which must be defined to use__stdcall
If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether
main
orWinMain
is defined.The functions
main
,WinMain
, andDllMain
are the three forms of the user-defined entry point.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2001-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define NULL (void *) 0
extern struct _IMAGE_DOS_HEADER __ImageBase;
typedef unsigned short wchar_t;
#ifndef BLUNDER
#error
#elif BLUNDER == 0 // DLL
int DllMain(void *module, int reason, void *context)
{
return module != context, reason == 1;
}
#elif BLUNDER == 1 // DLL entry point function
int DllMain(void *module, int reason, void *context);
int _DllMainCRTStartup(void *module, int reason, void *context)
{
return DllMain(module, reason, context);
}
#elif BLUNDER == 2 // ANSI console program
int main(int argc, char *argv[], char *envp[])
{
return *envp != argv[argc];
}
#elif BLUNDER == 3 // ANSI console program entry point function
int __cdecl main(int argc, char *argv[], char *envp[]);
static char *argv[] = {"main.exe", "/?", NULL};
static char *envp[] = {"name=value", NULL};
int mainCRTStartup(void)
{
return main(sizeof(argv) / sizeof(*argv) - 1, argv, envp);
}
#elif BLUNDER == 4 // UNICODE console program
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
return *envp != argv[argc];
}
#elif BLUNDER == 5 // UNICODE console program entry point function
int __cdecl wmain(int argc, wchar_t *argv[], wchar_t *envp[]);
static wchar_t *argv[] = {L"wmain.exe", L"/?", NULL};
static wchar_t *envp[] = {L"name=value", NULL};
int wmainCRTStartup(void)
{
return wmain(sizeof(argv) / sizeof(*argv) - 1, argv, envp);
}
#elif BLUNDER == 6 // ANSI Windows program
int WinMain(void *current, void *previous, char cmdline[], int show)
{
return current != previous, *cmdline != show;
}
#elif BLUNDER == 7 // ANSI Windows program entry point function
int WinMain(void *current, void *previous, char cmdline[], int show);
int WinMainCRTStartup(void)
{
return WinMain(&__ImageBase, NULL, "/?", 0);
}
#elif BLUNDER == 8 // UNICODE Windows program
int wWinMain(void *current, void *previous, wchar_t cmdline[], int show)
{
return current != previous, *cmdline != show;
}
#elif BLUNDER == 9 // UNICODE Windows program entry point function
int wWinMain(void *current, void *previous, wchar_t cmdline[], int show);
int wWinMainCRTStartup(void)
{
return wWinMain(&__ImageBase, NULL, L"/?", 0);
}
#else
#error
#endif // BLUNDER
WinMain function
Start the command prompt of the Visual C
development environment for the i386 platform, then
execute the following 7 command lines to compile the source file
blunder.c
created in step 1. to generate the 5
object files dllmain.obj
, main.obj
,
wmain.obj
, winmain.obj
plus
wwinmain.obj
with the entry point functions and put
them into the new object library libcmt.lib
:
SET CL=/c /Gyz /Oxy /W4 /X /Zl CL.EXE /DBLUNDER=1 /Fodllmain.obj blunder.c CL.EXE /DBLUNDER=3 /Fomain.obj blunder.c CL.EXE /DBLUNDER=5 /Fowmain.obj blunder.c CL.EXE /DBLUNDER=7 /Fowinmain.obj blunder.c CL.EXE /DBLUNDER=9 /Fowwinmain.obj blunder.c LINK.EXE /LIB /MACHINE:I386 /NODEFAULTLIB /OUT:libcmt.lib dllmain.obj main.obj wmain.obj winmain.obj wwinmain.objNote: 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. blunder.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Library Manager Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
Execute the following 7 command lines to compile the source file
blunder.c
created in step 1. 5 times and (try to)
link each generated object file blunder.obj
with the
entry point functions from the object library
libcmt.lib
generated in step 2.:
SET CL=/Gy /MT /Oxy /W4 /X SET LINK=/MACHINE:I386 CL.EXE /DBLUNDER=0 /Gz /LD blunder.c CL.EXE /DBLUNDER=2 /Gd blunder.c CL.EXE /DBLUNDER=4 /Gd blunder.c CL.EXE /DBLUNDER=6 /Gz blunder.c CL.EXE /DBLUNDER=8 /Gz blunder.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /MACHINE:I386 /out:blunder.dll /dll /implib:blunder.lib blunder.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /MACHINE:I386 /out:blunder.exe blunder.obj LINK : error LNK2001: unresolved external symbol _mainCRTStartup blunder.exe : fatal error LNK1120: 1 unresolved externals Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /MACHINE:I386 /out:blunder.exe blunder.obj LINK : error LNK2001: unresolved external symbol _wmainCRTStartup blunder.exe : fatal error LNK1120: 1 unresolved externals Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /MACHINE:I386 /out:blunder.exe blunder.obj LINK : error LNK2001: unresolved external symbol _WinMainCRTStartup blunder.exe : fatal error LNK1120: 1 unresolved externals Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /MACHINE:I386 /out:blunder.exe blunder.obj LINK : error LNK2001: unresolved external symbol _wWinMainCRTStartup blunder.exe : fatal error LNK1120: 1 unresolved externalsOUCH: contrary to the documentation cited above, the linker expects the entry point functions for console as well as Windows applications to be defined using the
__cdecl
calling and naming convention!
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef VOID (NTAPI PS_POST_PROCESS_INIT_ROUTINE) (VOID);
typedef struct _UNICODE_STRING
{
WORD Length;
WORD MaximumLength;
LPWSTR Buffer;
} UNICODE_STRING;
typedef struct _RTL_USER_PROCESS_PARAMETERS
{
BYTE Reserved1[16];
LPVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_LDR_DATA
{
BYTE Reserved1[8];
LPVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA;
typedef struct _PEB // Process Environment Block
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
LPVOID Reserved3[2];
PEB_LDR_DATA *Ldr;
RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
LPVOID Reserved4[3];
LPVOID AtlThunkSListPtr;
LPVOID Reserved5;
DWORD Reserved6;
LPVOID Reserved7;
DWORD Reserved8;
DWORD AtlThunkSListPtr32;
LPVOID Reserved9[45];
BYTE Reserved10[96];
PS_POST_PROCESS_INIT_ROUTINE *PostProcessInitRoutine;
BYTE Reserved11[128];
LPVOID Reserved12[1];
DWORD SessionId;
} PEB;
LONG CDECL mainCRTStartup(PEB *peb);
LONG CDECL wmainCRTStartup(PEB *peb);
LONG CDECL WinMainCRTStartup(PEB *peb);
LONG CDECL wWinMainCRTStartup(PEB *peb);
BOOL WINAPI _DllMainCRTStartup(HMODULE module, DWORD reason, CONTEXT *context);
LIST_ENTRY structure
PEB structure
PEB_LDR_DATA structure
RTL_USER_PROCESS_PARAMETERS structure
UNICODE_STRING structure
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
static long bss;
static long data = 'DATA';
const long rdata = 'VOID';
long mainCRTStartup(void)
{
return bss = data = rdata;
}
Compile the source file blunder.c
created in
step 1. to generate the object file blunder.obj
,
then enumerate the names and sizes of its
COFF sections:
CL.EXE /c /W4 /X /Zl blunder.c LINK.EXE /DUMP blunder.obj
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.obj File Type: COFF OBJECT Summary 4 .bss 4 .data 74 .debug$S 3 .drectve 4 .rdata 20 .textNote: the Visual C compiler puts uninitialised static variables in the
.bss
section, initialised
static variables in the .data
section, and constants in
the .rdata
section.
Link the object file blunder.obj
created in
step 1. to generate the executable image file
blunder.exe
, using the undocumented
/TEST
linker option,
then enumerate its sections:
LINK.EXE /LINK /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /TEST blunder.obj LINK.EXE /DUMP blunder.exe
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. LINK : file alignment: 512, section alignment: 4096 LINK : section '.sdata' (C0000040) merged into '.data' (C0000040) LINK : section '.xdata' (40000040) merged into '.rdata' (40000040) Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.exe File Type: EXECUTABLE IMAGE Summary 1000 .data 1000 .rdata 1000 .reloc 1000 .textOops: the linker merges the
.bss
section into the
.data
section, but fails to print the corresponding
message although their characteristics differ – 0xC0000080
alias uninitialised data, readable, writablevs. 0xC0000040 alias
initialised data, readable, writable!
Link the object file blunder.obj
created in
step 1. a second time to generate the executable image file
blunder.exe
, now merging the
.bss
section into the
.blunder
section, the .sdata
section into
the .static
section and the .xdata
section
into the .xcept
section, again using the
undocumented /TEST
linker option,
then enumerate its headers and give the 3 sections their original
names back:
LINK.EXE /LINK /BREPRO /ENTRY:mainCRTStartup /MERGE:.bss=.blunder /MERGE:.sdata=.static /MERGE:.xdata=.xcept /NODEFAULTLIB /SUBSYSTEM:CONSOLE /TEST blunder.obj LINK.EXE /DUMP /HEADERS blunder.exe LINK.EXE /EDIT /SECTION:.blunder=.bss /SECTION:.static=.sdata /SECTION:.xcept=.xdata blunder.exe
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. LINK : file alignment: 512, section alignment: 4096 LINK : section '.bss' (C0000080) merged into '.blunder' (C0000080) LINK : section '.sdata' (C0000040) merged into '.static' (C0000040) LINK : section '.xdata' (40000040) merged into '.xcept' (40000040) LINK : warning LNK4253: section '.sdata' not merged into '.data'; already merged into '.static' LINK : warning LNK4253: section '.xdata' not merged into '.rdata'; already merged into '.xcept' Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.exe PE signature found File Type: EXECUTABLE IMAGE FILE HEADER VALUES 14C machine (x86) 5 number of sections FFFFFFFF time date stamp Sun Feb 07 07:28:15 2106 0 file pointer to symbol table 0 number of symbols E0 size of optional header 102 characteristics Executable 32 bit word machine OPTIONAL HEADER VALUES 10B magic # (PE32) 10.00 linker version 200 size of code 600 size of initialized data 200 size of uninitialized data 1000 entry point (00401000) 1000 base of code 2000 base of data 400000 image base (00400000 to 00405FFF) 1000 section alignment 200 file alignment 5.01 operating system version 0.00 image version 5.01 subsystem version 0 Win32 version 6000 size of image 400 size of headers 0 checksum 3 subsystem (Windows CUI) 8540 DLL characteristics Dynamic base NX compatible No structured exception handler Terminal Server Aware 100000 size of stack reserve 1000 size of stack commit 100000 size of heap reserve 1000 size of heap commit 0 loader flags 10 number of directories 0 [ 0] RVA [size] of Export Directory 0 [ 0] RVA [size] of Import Directory 0 [ 0] RVA [size] of Resource Directory 0 [ 0] RVA [size] of Exception Directory 0 [ 0] RVA [size] of Certificates Directory 5000 [ 14] RVA [size] of Base Relocation Directory 0 [ 0] RVA [size] of Debug Directory 0 [ 0] RVA [size] of Architecture Directory 0 [ 0] RVA [size] of Global Pointer Directory 0 [ 0] RVA [size] of Thread Storage Directory 0 [ 0] RVA [size] of Load Configuration Directory 0 [ 0] RVA [size] of Bound Import Directory 0 [ 0] RVA [size] of Import Address Table Directory 0 [ 0] RVA [size] of Delay Import Directory 0 [ 0] RVA [size] of COM Descriptor Directory 0 [ 0] RVA [size] of Reserved Directory SECTION HEADER #1 .text name 20 virtual size 1000 virtual address (00401000 to 0040101F) 200 size of raw data 400 file pointer to raw data (00000400 to 000005FF) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 60000020 flags Code Execute Read SECTION HEADER #2 .blunder name 4 virtual size 2000 virtual address (00402000 to 00402003) 0 size of raw data 0 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers C0000080 flags Uninitialized Data Read Write SECTION HEADER #3 .rdata name 4 virtual size 3000 virtual address (00403000 to 00403003) 200 size of raw data 600 file pointer to raw data (00000600 to 000007FF) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 40000040 flags Initialized Data Read Only SECTION HEADER #4 .data name 4 virtual size 4000 virtual address (00404000 to 00404003) 200 size of raw data 800 file pointer to raw data (00000800 to 000009FF) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers C0000040 flags Initialized Data Read Write SECTION HEADER #5 .reloc name 32 virtual size 5000 virtual address (00405000 to 00405031) 200 size of raw data A00 file pointer to raw data (00000A00 to 00000BFF) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 42000040 flags Initialized Data Discardable Read Only Summary 1000 .blunder 1000 .data 1000 .rdata 1000 .reloc 1000 .text Microsoft (R) COFF/PE Editor Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. blunder.exe : warning LNK4039: section '.xcept' specified with /SECTION option does not exist blunder.exe : warning LNK4039: section '.static' specified with /SECTION option does not existOops: the linker places the (writable)
.bss
alias
.blunder
section not last, i.e. not after the also
writable .data
section, but between the read-only
.text
and .rdata
sections!
OOPS: the linker prints bogus
informational messages and even warnings LNK4253
for
sections which exist neither in its input files nor the output file!
Link the object file blunder.obj
created in
step 1. a third time to generate the executable image file
blunder.exe
, again merging the
.bss
section into the
.blunder
section, now using the
undocumented /LAST
linker option,
then enumerate its headers:
LINK.EXE /LINK /BREPRO /ENTRY:mainCRTStartup /LAST:.blunder /MERGE:.bss=.blunder /NODEFAULTLIB /SUBSYSTEM:CONSOLE /TEST blunder.obj LINK.EXE /DUMP /HEADERS blunder.exe
Microsoft (R) Incremental Linker Version 10.00.40219.386
Copyright (C) Microsoft Corporation. All rights reserved.
LINK : file alignment: 512, section alignment: 4096
LINK : section '.bss' (C0000080) merged into '.blunder' (C0000080)
LINK : section '.sdata' (C0000040) merged into '.data' (C0000040)
LINK : section '.xdata' (40000040) merged into '.rdata' (40000040)
Microsoft (R) COFF/PE Dumper Version 10.00.40219.386
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file blunder.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
5 number of sections
FFFFFFFF time date stamp Sun Feb 07 07:28:15 2106
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
OPTIONAL HEADER VALUES
10B magic # (PE32)
10.00 linker version
200 size of code
600 size of initialized data
200 size of uninitialized data
1000 entry point (00401000)
1000 base of code
2000 base of data
400000 image base (00400000 to 00405FFF)
1000 section alignment
200 file alignment
5.01 operating system version
0.00 image version
5.01 subsystem version
0 Win32 version
6000 size of image
400 size of headers
0 checksum
3 subsystem (Windows CUI)
8540 DLL characteristics
Dynamic base
NX compatible
No structured exception handler
Terminal Server Aware
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
0 [ 0] RVA [size] of Export Directory
0 [ 0] RVA [size] of Import Directory
0 [ 0] RVA [size] of Resource Directory
0 [ 0] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
5000 [ 14] RVA [size] of Base Relocation Directory
0 [ 0] RVA [size] of Debug Directory
0 [ 0] RVA [size] of Architecture Directory
0 [ 0] RVA [size] of Global Pointer Directory
0 [ 0] RVA [size] of Thread Storage Directory
0 [ 0] RVA [size] of Load Configuration Directory
0 [ 0] RVA [size] of Bound Import Directory
0 [ 0] RVA [size] of Import Address Table Directory
0 [ 0] RVA [size] of Delay Import Directory
0 [ 0] RVA [size] of COM Descriptor Directory
0 [ 0] RVA [size] of Reserved Directory
SECTION HEADER #1
.text name
20 virtual size
1000 virtual address (00401000 to 0040101F)
200 size of raw data
400 file pointer to raw data (00000400 to 000005FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
SECTION HEADER #2
.rdata name
4 virtual size
2000 virtual address (00402000 to 00402003)
200 size of raw data
600 file pointer to raw data (00000600 to 000007FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only
SECTION HEADER #3
.data name
4 virtual size
3000 virtual address (00403000 to 00403003)
200 size of raw data
800 file pointer to raw data (00000800 to 000009FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
Read Write
SECTION HEADER #4
.blunder name
4 virtual size
4000 virtual address (00404000 to 00404003)
0 size of raw data
0 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000080 flags
Uninitialized Data
Read Write
SECTION HEADER #5
.reloc name
32 virtual size
5000 virtual address (00405000 to 00405031)
200 size of raw data
A00 file pointer to raw data (00000A00 to 00000BFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
Read Only
Summary
1000 .blunder
1000 .data
1000 .rdata
1000 .reloc
1000 .text
Note: the undocumented
/LAST:‹section›
linker option
places the specified section last, after the .text
,
.rdata
and .data
sections created by the Visual C compiler, but
before the .reloc
section generated by the linker.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
VOID mainCRTStartup(VOID)
{
ExitProcess('VOID');
}
Compile the source file blunder.c
created in
step 1. to generate the object file blunder.obj
,
then enumerate the names and sizes of its
COFF sections:
CL.EXE /c /W4 /Zl blunder.c LINK.EXE /DUMP blunder.obj
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.obj File Type: COFF OBJECT Summary 74 .debug$S 3 .drectve 10 .text
�
LINK.EXE /LINK /ENTRY:mainCRTStartup /EXPORT:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /TEST blunder.obj kernel32.lib LINK.EXE /DUMP /IMPORTS blunder.exe
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. LINK : file alignment: 512, section alignment: 4096 LINK : warning LNK4216: Exported entry point _mainCRTStartup Creating library blunder.lib and object blunder.exp LINK : section '.sdata' (C0000040) merged into '.data' (C0000040) LINK : section '.xdata' (40000040) merged into '.rdata' (40000040) Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.exe File Type: EXECUTABLE IMAGE Section contains the following imports: KERNEL32.dll 402000 Import Address Table 402030 Import Name Table 0 time date stamp 0 Index of first forwarder reference 119 ExitProcess Summary 1000 .rdata 1000 .reloc 1000 .textOops: the linker fails to print messages indicating that the
.edata
and
.idata
sections it generates itself
are both merged into the .rdata
section!
�
LINK.EXE /LINK /ENTRY:mainCRTStartup /EXPORT:mainCRTStartup /NODEFAULTLIB /NOOPTIDATA /SUBSYSTEM:CONSOLE /TEST blunder.obj kernel32.lib LINK.EXE /DUMP /IMPORTS blunder.exe
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. LINK : file alignment: 512, section alignment: 4096 LINK : warning LNK4216: Exported entry point _mainCRTStartup Creating library blunder.lib and object blunder.exp LINK : section '.sdata' (C0000040) merged into '.data' (C0000040) LINK : section '.xdata' (40000040) merged into '.rdata' (40000040) Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.exe File Type: EXECUTABLE IMAGE Section contains the following imports: KERNEL32.dll 403030 Import Address Table 403028 Import Name Table 0 time date stamp 0 Index of first forwarder reference 119 ExitProcess Summary 1000 .idata 1000 .rdata 1000 .reloc 1000 .textNote: with the undocumented
/NOOPTIDATA
linker option
the .idata
section is not merged
into the .rdata
section!
Note: there exists but no corresponding
/NOOPTEDATA
linker option
to disable merging of the .edata
section into the .rdata
section – use the /MERGE:.edata=.export
linker option
to generate a separate .export
section for the
Export Directory instead.
Link.exe
.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2001-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
int main(void)
{}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /X /Zl SET LINK=/ALTERNATENAME:_wmainCRTStartup=_main /BREPRO /FIXED /MANIFEST /MAP /NODEFAULTLIB /RELEASE CL.EXE blunder.cNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ALTERNATENAME:_mainCRTStartup=_main /BREPRO /FIXED /MAP /MANIFEST /NODEFAULTLIB /RELEASE /out:blunder.exe blunder.obj
Display the
Application Manifest
blunder.exe.manifest
created in step 2. to show
the quirk:
TYPE blunder.exe.manifest
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level='asInvoker' uiAccess='false' /> </requestedPrivileges> </security> </trustInfo> </assembly>Oops: I suppose there must be a really compelling reason to mix single and double quotes here!
Display the linker map file blunder.map
and the headers
of the console application blunder.exe
built in
step 2. to show the bug:
TYPE blunder.map LINK.EXE /DUMP /HEADERS blunder.exe
blunder Timestamp is ffffffff (Sun Feb 07 07:28:15 2106) Preferred load address is 00400000 Start Length Name Class 0001:00000000 00000007H .text CODE Address Publics by Value Rva+Base Lib:Object 0000:00000000 ___safe_se_handler_count 00000000 <absolute> 0000:00000000 ___safe_se_handler_table 00000000 <absolute> 0001:00000000 _mainCRTStartup 00401000 f blunder.obj 0001:00000000 _main 00401000 f blunder.obj entry point at 0001:00000000 Static symbols Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.exe PE signature found File Type: EXECUTABLE IMAGE FILE HEADER VALUES 14C machine (x86) 1 number of sections FFFFFFFF time date stamp Sun Feb 07 07:28:15 2106 0 file pointer to symbol table 0 number of symbols E0 size of optional header 103 characteristics Relocations stripped Executable 32 bit word machine OPTIONAL HEADER VALUES 10B magic # (PE32) 10.00 linker version 200 size of code 0 size of initialized data 0 size of uninitialized data 8 entry point (00400008) 1000 base of code 2000 base of data 400000 image base (00400000 to 00401FFF) […]OUCH: while the linker map shows the entry point as expected at the address 0x00401000 of the
main()
function, the header dump shows it but inside the non-executable
DOS
header,
i.e. the console application blunder.exe
will crash
upon start with an execute access violation!
(Optional) If you have the
Debugging Tools for Windows
installed, execute the console application blunder.exe
built in step 2. under the debugger:
CDB.EXE /C g;q /G /g .\blunder.exeNote: if necessary, see the MSDN articles Debugging Using CDB and NTSD and CDB Command-Line Options for an introduction.
Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\blunder.exe Symbol search path is: srv* Executable search path is: ModLoad: 00400000 00402000 image00400000 ModLoad: 779c0000 77b40000 ntdll.dll ModLoad: 75610000 75720000 C:\Windows\syswow64\kernel32.dll ModLoad: 752d0000 75317000 C:\Windows\syswow64\KERNELBASE.dll ModLoad: 75540000 755e1000 C:\Windows\syswow64\ADVAPI32.DLL ModLoad: 757a0000 7584c000 C:\Windows\syswow64\msvcrt.dll ModLoad: 77420000 77439000 C:\Windows\SysWOW64\sechost.dll ModLoad: 77300000 773f0000 C:\Windows\syswow64\RPCRT4.dll ModLoad: 750e0000 75140000 C:\Windows\syswow64\SspiCli.dll ModLoad: 750d0000 750dc000 C:\Windows\syswow64\CRYPTBASE.dll (a34.149c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=7562342b ebx=7efde000 ecx=00000000 edx=00400008 esi=00000000 edi=00000000 eip=00400008 esp=000dff8c ebp=000dff94 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 *** ERROR: Module load completed but symbols could not be loaded for image00400000 image00400000+0x8: 00400008 0400 add al,0 0:000:x86> cdb: Reading initial command 'g;q' (a34.149c): Access violation - code c0000005 (!!! second chance !!!) quit:
Microsoft (R) Windows Debugger Version 6.1.7601.17514 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\blunder.exe Symbol search path is: srv* Executable search path is: ModLoad: 00000001`40000000 00000001`40002000 image00000001`40000000 ModLoad: 00000000`77800000 00000000`7799f000 ntdll.dll ModLoad: 00000000`775e0000 00000000`776ff000 C:\Windows\system32\kernel32.dll ModLoad: 000007fe`fd510000 000007fe`fd577000 C:\Windows\system32\KERNELBASE.dll ModLoad: 000007fe`fd980000 000007fe`fda5b000 C:\Windows\system32\ADVAPI32.DLL ModLoad: 000007fe`fe1c0000 000007fe`fe25f000 C:\Windows\system32\msvcrt.dll ModLoad: 000007fe`fe260000 000007fe`fe27f000 C:\Windows\SYSTEM32\sechost.dll ModLoad: 000007fe`ff250000 000007fe`ff37c000 C:\Windows\system32\RPCRT4.dll (5080.5100): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. *** ERROR: Module load completed but symbols could not be loaded for image00000001`40000000 image00000001_40000000+0x7: 00000001`40000007 000400 add byte ptr [rax+rax],al ds:00000000`eebeaac0=?? 0:000> cdb: Reading initial command 'g;q' (5080.5100): Access violation - code c0000005 (!!! second chance !!!) quit:
The Load Configuration Structure (Image Only):
The load configuration structure (IMAGE_LOAD_CONFIG_DIRECTORY) was formerly used in very limited cases in the Windows NT operating system itself to describe various features too difficult or too large to describe in the file header or optional header of the image. Current versions of the Microsoft linker and Windows XP and later versions of Windows use a new version of this structure for 32-bit x86-based systems that include reserved SEH technology.OUCH¹: the highlighted statement is but wrong –
[…]
The Microsoft linker automatically provides a default load configuration structure to include the reserved SEH data. If the user code already provides a load configuration structure, it must include the new reserved SEH fields. Otherwise, the linker cannot include the reserved SEH data and the image is not marked as containing reserved SEH.
LINK.exe
neither provides an
IMAGE_LOAD_CONFIG_DIRECTORY
structure nor reports its omission with an error message!
The documentation for the /SAFESEH linker option provides but the correct information:
If you link withThe specification of the PE Format continues with the following disinformation:/NODEFAULTLIB
and you want a table of safe exception handlers, you need to supply a load config struct (…) that contains all the entries defined for Visual C++. For example:#include <windows.h> extern DWORD_PTR __security_cookie; /* /GS security cookie */ /* * The following two names are automatically created by the linker for any * image that has the safe exception table present. */ extern PVOID __safe_se_handler_table[]; /* base of safe handler entry table */ extern BYTE __safe_se_handler_count; /* absolute symbol whose address is the count of table entries */ const IMAGE_LOAD_CONFIG_DIRECTORY32 _load_config_used = { sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &__security_cookie, __safe_se_handler_table, (DWORD)(DWORD_PTR) &__safe_se_handler_count };
Load Configuration LayoutOUCH²: the documentation for theThe load configuration structure has the following layout for 32-bit and 64-bit PE files:
Offset Size Field Description 0 4 Characteristics Flags that indicate attributes of the file, currently unused. … … … … 54/78 2 Reserved Must be zero.
IMAGE_LOAD_CONFIG_DIRECTORY
structure but states that the field at offset 0 stores the size of
the structure, and the field at offset 54 (for 32-bit images) or 78
(for 64-bit images) stores the
/DEPENDENTLOADFLAG
!
The .tls section:
The .tls section provides direct PE and COFF support for static thread local storage (TLS). […] a static TLS variable can be defined as follows, without using the Windows API:Ouch: even the very first (highlighted) sentence is wrong – the
__declspec (thread) int tlsFlag = 1;
To support this programming construct, the PE and COFF .tls section specifies the following information: initialization data, callback routines for per-thread initialization and termination, and the TLS index, which are explained in the following discussion.
Note
Statically declared TLS data objects can be used only in statically loaded image files. This fact makes it unreliable to use static TLS data in a DLL unless you know that the DLL, or anything statically linked with it, will never be loaded dynamically with the LoadLibrary API function.
Executable code accesses a static TLS data object through the following steps:
At link time, the linker sets the Address of Index field of the TLS directory. This field points to a location where the program expects to receive the TLS index.
The Microsoft run-time library facilitates this process by defining a memory image of the TLS directory and giving it the special name "__tls_used" (Intel x86 platforms) or "_tls_used" (other platforms). The linker looks for this memory image and uses the data there to create the TLS directory. Other compilers that support TLS and work with the Microsoft linker must use this same technique.
When a thread is created, the loader communicates the address of the thread's TLS array by placing the address of the thread environment block (TEB) in the FS register. A pointer to the TLS array is at the offset of 0x2C from the beginning of TEB. This behavior is Intel x86-specific.
The loader assigns the value of the TLS index to the place that was indicated by the Address of Index field.
The executable code retrieves the TLS index and also the location of the TLS array.
The code uses the TLS index and the TLS array location (multiplying the index by 4 and using it as an offset to the array) to get the address of the TLS data area for the given program and module. Each thread has its own TLS data area, but this is transparent to the program, which does not need to know how data is allocated for individual threads.
An individual TLS data object is accessed as some fixed offset into the TLS data area.
IMAGE_TLS_DIRECTORY
provides the TLS
support.
Note: the .tls
section is required
only when TLS data
is initialised, it is not needed when data is just declared.
Ouch: the initial note is but obsolete and wrong – Windows Vista and later versions of Windows NT support static TLS data in dynamically loaded DLLs!
Note: the multiplier 4 is of course only correct for 32-bit platforms – 64-bit platforms require the multiplier 8.
The documentation misses the following part for the x64 alias AMD64 processor architecture (and corresponding parts for other processor architectures as well):
Note: on the i386 alias x86 platform, the Visual C compiler references (the absolute address of) the external symbol
When a thread is created, the loader communicates the address of the thread's TLS array by placing the address of the thread environment block (TEB) in the GS register. A pointer to the TLS array is at the offset of 0x58 from the beginning of the TEB. This behavior is Intel x64-specific.
__tls_array
despite the fixed value of this offset.
The specification of the PE Format continues:
OOPS: theThe TLS directory has the following format:
Offset (PE32/PE32+) Size (PE32/PE32+) Field Description 0 4/8 Raw Data Start VA The starting address of the TLS template. The template is a block of data that is used to initialize TLS data. The system copies all of this data each time a thread is created, so it must not be corrupted. Note that this address is not an RVA; it is an address for which there should be a base relocation in the .reloc section. 4/8 4/8 Raw Data End VA The address of the last byte of the TLS, except for the zero fill. As with the Raw Data Start VA field, this is a VA, not an RVA. 8/16 4/8 Address of Index The location to receive the TLS index, which the loader assigns. This location is in an ordinary data section, so it can be given a symbolic name that is accessible to the program. 12/24 4/8 Address of Callbacks The pointer to an array of TLS callback functions. The array is null-terminated, so if no callback function is supported, this field points to 4 bytes set to zero. For information about the prototype for these functions, see TLS Callback Functions. 16/32 4 Size of Zero Fill The size in bytes of the template, beyond the initialized data delimited by the Raw Data Start VA and Raw Data End VA fields. The total template size should be the same as the total size of TLS data in the image file. The zero fill is the amount of data that comes after the initialized nonzero data. 20/36 4 Characteristics The four bits [23:20] describe alignment info. Possible values are those defined as IMAGE_SCN_ALIGN_*, which are also used to describe alignment of section in object files. The other 28 bits are reserved for future use.
Raw Data End VAfield contains the address of the first byte after the TLS template!
OUCH: the Size of Zero Fill
field is
not supported at all!
Note: if the size of the initialised data of the
.tls
section in the image file is less than the section
size, the module loader fills the additional uninitialised data with
zeroes, i.e. the Size of Zero Fill
field is superfluous.
Caveat: the documentation lacks the information
that the Visual C compiler puts all data for the
TLS template in
COFF sections
.tls$‹suffix›
– which it declares
but writable instead of read-only
, i.e. it
fails to protect the template data against corruption, an easily
avoidable safety hazard!
/SECTION:.tls,r
linker option
to set the .tls
section read-only.
Inline assembly is not supported on the Itanium and x64 processors.The documentation for the _emit Pseudoinstruction but states:
[…] if _emit
generates an instruction that
modifies the rax register, the
compiler does not know that rax has
changed. […]
OUCH: the RAX
register exists only on
the AMD64 platform, where inline assembly via the
__asm
keyword is but not supported!
HIGH32
of MASM states:
The documentation for the operatorReturns the low 32 bits of expression. MASM expressions are 64-bit values.HIGH32 expression
LOW32
of MASM states:
Returns the low 32 bits of expression. MASM expressions are 64-bit values.LOW32 expression
Create the text file blunder.asm
with the following
content in an arbitrary, preferable empty directory:
; Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
.model flat, C
.code
mov eax, LOW32 0123456789ABCDEFh
mov edx, HIGH32 0123456789ABCDEFh
.const
qword 0123456789ABCDEFh
oword 0123456789ABCDEF0123456789ABCDEFh
end
Assemble the source file blunder.asm
created in
step 1.:
SET ML=/c /W3 /X ML.EXE /FoNUL: blunder.asmNote: the command lines can be copied and pasted as block into a Command Processor window.
Microsoft (R) Macro Assembler Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: blunder.asm blunder.asm(4) : error A2084:constant value too large blunder.asm(5) : error A2084:constant value too largeOUCH: contrary to both highlighted statements of the documentation cited above, (constant) expressions are but 32-bit values!
Create the text file blunder.asm
with the following
content in an arbitrary, preferably empty directory:
; Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
.386
.model flat, C
.code
blunder proc public
mov ecx, 1 shl 31 ; ecx = divisor = 0x80000000,
; edx:eax = arbitrary dividend
div ecx ; eax = arbitrary quotient,
; edx = arbitrary remainder
; < divisor
not edx ; edx:eax = dividend
; = divisor << 32 | arbitrary quotient
; > divisor << 32
div ecx ; raise #DE (divide error exception) via
; quotient overflow
;; ret
blunder endp
end blunder ; writes "/ENTRY:blunder" to '.drectve' section
Assemble and link the source file blunder.asm
created
in step 1.:
SET ML=/W3 /X SET LINK=/NODEFAULTLIB /RELEASE /SUBSYSTEM:CONSOLE ML.EXE blunder.asmNote: the command lines can be copied and pasted as block into a Command Processor window.
Microsoft (R) Macro Assembler Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: blunder.asm Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /NODEFAULTLIB /RELEASE /SUBSYSTEM:CONSOLE /OUT:blunder.exe blunder.obj
Execute the console application blunder.exe
built in
step 2. to show that 231 is equal 0:
VER .\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
Microsoft Windows [Version 6.1.7601] 0xc0000094 (NT: 0xc0000094 STATUS_INTEGER_DIVIDE_BY_ZERO) -- 3221225620 (-1073741676) Error message text: {EXCEPTION} Integer division by zero CertUtil: -error command completed successfully.OUCH: (at least) for the divisor 231, which most obviously differs from 0, Windows’ kernel maps the processor’s
#DE
to the
wrong
NTSTATUS
0xC0000094
alias STATUS_INTEGER_DIVIDE_BY_ZERO
instead to the
correct
0xC0000095
alias STATUS_INTEGER_OVERFLOW
!
(Optional) If you have the
Debugging Tools for Windows
installed, execute the console application blunder.exe
built in step 2. under the debugger:
CDB.EXE /C g;q /G /g .\blunder.exeNote: if necessary, see the MSDN articles Debugging Using CDB and NTSD and CDB Command-Line Options for an introduction.
Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\blunder.exe Symbol search path is: srv* Executable search path is: ModLoad: 00ee0000 00ee2000 image00ee0000 ModLoad: 779c0000 77b40000 ntdll.dll ModLoad: 774d0000 775e0000 C:\Windows\syswow64\kernel32.dll ModLoad: 76080000 760c7000 C:\Windows\syswow64\KERNELBASE.dll ModLoad: 75790000 75831000 C:\Windows\syswow64\ADVAPI32.DLL ModLoad: 75fd0000 7607c000 C:\Windows\syswow64\msvcrt.dll ModLoad: 75e70000 75e89000 C:\Windows\SysWOW64\sechost.dll ModLoad: 75ed0000 75fc0000 C:\Windows\syswow64\RPCRT4.dll ModLoad: 750e0000 75140000 C:\Windows\syswow64\SspiCli.dll ModLoad: 750d0000 750dc000 C:\Windows\syswow64\CRYPTBASE.dll (22f0.26a0): Integer divide-by-zero - code c0000094 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=01dc2000 ebx=7efde000 ecx=80000000 edx=88b1cbd4 esi=00000000 edi=00000000 eip=00ee1009 esp=001bf898 ebp=001bf8a0 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 *** ERROR: Module load completed but symbols could not be loaded for image00ee0000 image00ee0000+0x1009: 00ee1009 f7f1 div eax,ecx 0:000:x86> cdb: Reading initial command 'g;q' (22f0.26a0): Integer divide-by-zero - code c0000094 (!!! second chance !!!) quit:Oops: also notice the bunch of not explicitly referenced DLLs loaded with
Overwrite the text file blunder.asm
created in
step 1. with the following content:
; Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
.code
blunder proc public
mov rcx, 1 shl 63 ; rcx = divisor = 0x8000000000000000,
; rdx:rax = arbitrary dividend
div rcx ; rax = arbitrary quotient,
; rdx = arbitrary remainder
; < divisor
not rdx ; rdx:rax = dividend
; = divisor << 64 | arbitrary quotient
; > divisor << 64
div rcx ; raise #DE (divide error exception) via
; quotient overflow
;; ret
blunder endp
end
Assemble and link the source file blunder.asm
modified
in step 5.:
SET ML=/W3 /X SET LINK=/ENTRY:blunder /NODEFAULTLIB /RELEASE /SUBSYSTEM:CONSOLE ML64.EXE blunder.asmNote: the command lines can be copied and pasted as block into a Command Processor window.
Microsoft (R) Macro Assembler (x64) Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: blunder.asm Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:blunder /NODEFAULTLIB /RELEASE /SUBSYSTEM:CONSOLE /OUT:blunder.exe blunder.obj
Execute the console application blunder.exe
built in
step 6. to show that 263 is equal 0:
VER .\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
Microsoft Windows [Version 6.1.7601] 0xc0000094 (NT: 0xc0000094 STATUS_INTEGER_DIVIDE_BY_ZERO) -- 3221225620 (-1073741676) Error message text: {EXCEPTION} Integer division by zero CertUtil: -error command completed successfully.OUCH: (at least) for the divisor 263, which most obviously differs from 0, Windows’ kernel maps the processor’s
#DE
to the
wrong
NTSTATUS
0xC0000094
alias STATUS_INTEGER_DIVIDE_BY_ZERO
instead to the
correct
0xC0000095
alias STATUS_INTEGER_OVERFLOW
!
(Optional) If you have the
Debugging Tools for Windows
installed, execute the console application blunder.exe
built in step 6. under the debugger:
CDB.EXE /C g;q /G /g .\blunder.exeNote: if necessary, see the MSDN articles Debugging Using CDB and NTSD and CDB Command-Line Options for an introduction.
Microsoft (R) Windows Debugger Version 6.1.7601.17514 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\blunder.exe Symbol search path is: srv* Executable search path is: ModLoad: 00000001`3ff10000 00000001`3ff12000 image00000001`3ff10000 ModLoad: 00000000`77800000 00000000`7799f000 ntdll.dll ModLoad: 00000000`775e0000 00000000`776ff000 C:\Windows\system32\kernel32.dll ModLoad: 000007fe`fd510000 000007fe`fd577000 C:\Windows\system32\KERNELBASE.dll ModLoad: 000007fe`fd980000 000007fe`fda5b000 C:\Windows\system32\ADVAPI32.DLL ModLoad: 000007fe`fe1c0000 000007fe`fe25f000 C:\Windows\system32\msvcrt.dll ModLoad: 000007fe`fe260000 000007fe`fe27f000 C:\Windows\SYSTEM32\sechost.dll ModLoad: 000007fe`ff250000 000007fe`ff37c000 C:\Windows\system32\RPCRT4.dll (2274.3570): Integer divide-by-zero - code c0000094 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. *** ERROR: Module load completed but symbols could not be loaded for image00000001`3ff10000 image00000001_3ff10000+0x1010: 00000001`3ff11010 48f7f1 div rax,rcx 0:000> cdb: Reading initial command 'g;q' (2274.3570): Integer divide-by-zero - code c0000094 (!!! second chance !!!) quit:Oops: again notice the slew of not explicitly referenced DLLs loaded with
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2019-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#include <intrin.h>
#ifndef _WIN64
__int32 mainCRTStartup(void)
{
__int64 arbitrary = __rdtsc();
return _udiv64(1ULL << 63 | arbitrary, 1UL << 31, 0);
}
#else // _WIN64
__int64 mainCRTStartup(void)
{
__int64 arbitrary = __rdtsc();
return _udiv128(1ULL << 63 | arbitrary, arbitrary, 1ULL << 63, 0);
}
#endif // _WIN64
Compile and link the source file blunder.c
created in
step 9.:
SET CL=/Oisy /W4 /Zl SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.cNote: the command lines can be copied and pasted as block into a Command Processor window.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 19.20.27004.0 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. blunder.c Microsoft (R) Incremental Linker Version 19.20.27004.0 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj
Execute the console application blunder.exe
built in
step 10. to prove that 231 as well as
263 are equal 0:
.\blunder.exe CERTUTIL.EXE /ERROR %ERRORLEVEL%
0xc0000094 (NT: 0xc0000094 STATUS_INTEGER_DIVIDE_BY_ZERO) -- 3221225620 (-1073741676) Error message text: {EXCEPTION} Integer division by zero CertUtil: -error command completed successfully.OUCH: (at least) for the divisors 231 and 263, which most obviously differ from 0, Windows’ kernel maps the processor’s
#DE
to the
wrong
NTSTATUS
0xC0000094
alias STATUS_INTEGER_DIVIDE_BY_ZERO
instead to the
correct
0xC0000095
alias STATUS_INTEGER_OVERFLOW
!
RC.exe
:
Start the Command Processor
Cmd.exe
, then execute
the
Resource Compiler
RC.exe
with code page 1200
alias
UTF-16LE
set on the command line:
RC.EXE /C 1200 /X NUL:
Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385 Copyright (C) Microsoft Corporation. All rights reserved. fatal error RC1206: code page specified on command line not in registryOUCH¹: the Resource Compiler fails to accept or support the native encoding of Windows NT!
Create the text file blunder.rc
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#if 0
#pragma code_page(1200) // UTF-16LE
#endif
Compile the source file blunder.rc
created in
step 2. with code page 20127 alias
ASCII
set on the command line:
RC.EXE /C 20127 /X blunder.rc TYPE RCa?????
Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385 Copyright (C) Microsoft Corporation. All rights reserved. blunder.rc(3) : fatal error RC4213: Codepage 1200 (Unicode) not allowed: ignored RCa12345 l i n e 1 " b l u n d e r . r c " # l i n e 1 / / C o p y l e f t ® 2 0 0 4 - 2 0 2 4 , S t e f a n K a n t h a k < s t e f a n . k a n t h a k @ n e x g o . d e > # l i n e 3 # i f 0OUCH²: contrary to the Visual C preprocessor, the preprocessor of the Resource Compiler evaluates its
#pragma code_page()
directive even when it is guarded by
#if… #endif
!
OOPS¹: although the preprocessor of the Resource Compiler supports UTF-16LE encoded source files, it rejects this encoding!
OOPS²: when it terminates with this error, the
Resource Compiler
fails to delete the intermediary
UTF-16LE
encoded preprocessor output file
RCa‹5 decimal digits›
– contrary to
Microsoft’s own recommendation written without
Byte Order Mark!
Overwrite the text file blunder.rc
created in
step 2. with the following content:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
STRINGTABLE
BEGIN
0, "[\0] NUL"
1, "[\a] Audible Alarm"
2, "[\b] Backspace"
3, "[\f] Form Feed"
4, "[\n] Line Feed"
5, "[\r] Carriage Return"
6, "[\t] Horizontal Tabulator"
7, "[\v] Vertical Tabulator"
#ifndef BLUNDER
8, "[\"] Double Quote"
#else
8, "[""] Double Quote"
#endif
9, "[\'] Single Quote"
10, "[\?] Question Mark"
11, "[\\] Backslash"
12, "[\177] DEL"
13, "[\u20AC] Euro Sign"
14, "[\xFEFF] Byte Order Mark"
15, "[\x]"
16, L"[\0] NUL"
17, L"[\a] Audible Alarm"
18, L"[\b] Backspace"
19, L"[\f] Form Feed"
20, L"[\n] Line Feed"
21, L"[\r] Carriage Return"
22, L"[\t] Horizontal Tabulator"
23, L"[\v] Vertical Tabulator"
#ifndef BLUNDER
24, L"[\"] Double Quote"
#else
24, L"[""] Double Quote"
#endif
25, L"[\'] Single Quote"
26, L"[\?] Question Mark"
27, L"[\\] Backslash"
28, L"[\177] DEL"
29, L"[\u20AC] Euro Sign"
30, L"[\xFEFF] Byte Order Mark"
31, L"[\x]"
END
Compile the source file blunder.rc
modified in
step 4.:
RC.EXE /C 20127 /X blunder.rc
Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385 Copyright (C) Microsoft Corporation. All rights reserved. blunder.rc.blunder.rc(14) : error RC2104 : undefined keyword or key name: ]OUCH³: the Resource Compiler fails to support the standard ANSI C89 escape sequence
\"
for the
Double Quote!
Compile the source file blunder.rc
modified in
step 4. a second time, now with the preprocessor macro
BLUNDER
defined:
RC.EXE /C 20127 /D BLUNDER /X blunder.rc
Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385 Copyright (C) Microsoft Corporation. All rights reserved.OOPS³: double quotes must be doubled inside strings!
Dump the raw data of the resource file blunder.res
generated in step 6.:
CERTUTIL.EXE /DUMP blunder.res
0000 ... 0454 0000 00 00 00 00 20 00 00 00 ff ff 00 00 ff ff 00 00 .... ........... 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0020 08 02 00 00 20 00 00 00 ff ff 06 00 ff ff 01 00 .... ........... 0030 00 00 00 00 30 10 09 04 00 00 00 00 00 00 00 00 ....0........... 0040 07 00 5b 00 00 00 5d 00 20 00 4e 00 55 00 4c 00 ..[...]. .N.U.L. 0050 11 00 5b 00 08 00 5d 00 20 00 41 00 75 00 64 00 ..[...]. .A.u.d. 0060 69 00 62 00 6c 00 65 00 20 00 41 00 6c 00 61 00 i.b.l.e. .A.l.a. 0070 72 00 6d 00 0e 00 5b 00 5c 00 62 00 5d 00 20 00 r.m...[.\.b.]. . 0080 42 00 61 00 63 00 6b 00 73 00 70 00 61 00 63 00 B.a.c.k.s.p.a.c. 0090 65 00 0e 00 5b 00 5c 00 66 00 5d 00 20 00 46 00 e...[.\.f.]. .F. 00a0 6f 00 72 00 6d 00 20 00 46 00 65 00 65 00 64 00 o.r.m. .F.e.e.d. 00b0 0d 00 5b 00 0a 00 5d 00 20 00 4c 00 69 00 6e 00 ..[...]. .L.i.n. 00c0 65 00 20 00 46 00 65 00 65 00 64 00 13 00 5b 00 e. .F.e.e.d...[. 00d0 0d 00 5d 00 20 00 43 00 61 00 72 00 72 00 69 00 ..]. .C.a.r.r.i. 00e0 61 00 67 00 65 00 20 00 52 00 65 00 74 00 75 00 a.g.e. .R.e.t.u. 00f0 72 00 6e 00 18 00 5b 00 09 00 5d 00 20 00 48 00 r.n...[...]. .H. 0100 6f 00 72 00 69 00 7a 00 6f 00 6e 00 74 00 61 00 o.r.i.z.o.n.t.a. 0110 6c 00 20 00 54 00 61 00 62 00 75 00 6c 00 61 00 l. .T.a.b.u.l.a. 0120 74 00 6f 00 72 00 17 00 5b 00 5c 00 76 00 5d 00 t.o.r...[.\.v.]. 0130 20 00 56 00 65 00 72 00 74 00 69 00 63 00 61 00 .V.e.r.t.i.c.a. 0140 6c 00 20 00 54 00 61 00 62 00 75 00 6c 00 61 00 l. .T.a.b.u.l.a. 0150 74 00 6f 00 72 00 10 00 5b 00 22 00 5d 00 20 00 t.o.r...[.".]. . 0160 44 00 6f 00 75 00 62 00 6c 00 65 00 20 00 51 00 D.o.u.b.l.e. .Q. 0170 75 00 6f 00 74 00 65 00 11 00 5b 00 5c 00 27 00 u.o.t.e...[.\.'. 0180 5d 00 20 00 53 00 69 00 6e 00 67 00 6c 00 65 00 ]. .S.i.n.g.l.e. 0190 20 00 51 00 75 00 6f 00 74 00 65 00 12 00 5b 00 .Q.u.o.t.e...[. 01a0 5c 00 3f 00 5d 00 20 00 51 00 75 00 65 00 73 00 \.?.]. .Q.u.e.s. 01b0 74 00 69 00 6f 00 6e 00 20 00 4d 00 61 00 72 00 t.i.o.n. .M.a.r. 01c0 6b 00 0d 00 5b 00 5c 00 5d 00 20 00 42 00 61 00 k...[.\.]. .B.a. 01d0 63 00 6b 00 73 00 6c 00 61 00 73 00 68 00 07 00 c.k.s.l.a.s.h... 01e0 5b 00 7f 00 5d 00 20 00 44 00 45 00 4c 00 12 00 [...]. .D.E.L... 01f0 5b 00 5c 00 75 00 32 00 30 00 41 00 43 00 5d 00 [.\.u.2.0.A.C.]. 0200 20 00 45 00 75 00 72 00 6f 00 20 00 53 00 69 00 .E.u.r.o. .S.i. 0210 67 00 6e 00 15 00 5b 00 fe 00 46 00 46 00 5d 00 g.n...[...F.F.]. 0220 20 00 42 00 79 00 74 00 65 00 20 00 4f 00 72 00 .B.y.t.e. .O.r. 0230 64 00 65 00 72 00 20 00 4d 00 61 00 72 00 6b 00 d.e.r. .M.a.r.k. 0240 03 00 5b 00 00 00 5d 00 ec 01 00 00 20 00 00 00 ..[...]..... ... 0250 ff ff 06 00 ff ff 02 00 00 00 00 00 30 10 00 00 ............0... 0260 00 00 00 00 00 00 00 00 07 00 5b 00 00 00 5d 00 ..........[...]. 0270 20 00 4e 00 55 00 4c 00 11 00 5b 00 08 00 5d 00 .N.U.L...[...]. 0280 20 00 41 00 75 00 64 00 69 00 62 00 6c 00 65 00 .A.u.d.i.b.l.e. 0290 20 00 41 00 6c 00 61 00 72 00 6d 00 0c 00 5b 00 .A.l.a.r.m...[. 02a0 5d 00 20 00 42 00 61 00 63 00 6b 00 73 00 70 00 ]. .B.a.c.k.s.p. 02b0 61 00 63 00 65 00 0c 00 5b 00 5d 00 20 00 46 00 a.c.e...[.]. .F. 02c0 6f 00 72 00 6d 00 20 00 46 00 65 00 65 00 64 00 o.r.m. .F.e.e.d. 02d0 0d 00 5b 00 0a 00 5d 00 20 00 4c 00 69 00 6e 00 ..[...]. .L.i.n. 02e0 65 00 20 00 46 00 65 00 65 00 64 00 13 00 5b 00 e. .F.e.e.d...[. 02f0 0d 00 5d 00 20 00 43 00 61 00 72 00 72 00 69 00 ..]. .C.a.r.r.i. 0300 61 00 67 00 65 00 20 00 52 00 65 00 74 00 75 00 a.g.e. .R.e.t.u. 0310 72 00 6e 00 18 00 5b 00 09 00 5d 00 20 00 48 00 r.n...[...]. .H. 0320 6f 00 72 00 69 00 7a 00 6f 00 6e 00 74 00 61 00 o.r.i.z.o.n.t.a. 0330 6c 00 20 00 54 00 61 00 62 00 75 00 6c 00 61 00 l. .T.a.b.u.l.a. 0340 74 00 6f 00 72 00 15 00 5b 00 5d 00 20 00 56 00 t.o.r...[.]. .V. 0350 65 00 72 00 74 00 69 00 63 00 61 00 6c 00 20 00 e.r.t.i.c.a.l. . 0360 54 00 61 00 62 00 75 00 6c 00 61 00 74 00 6f 00 T.a.b.u.l.a.t.o. 0370 72 00 10 00 5b 00 22 00 5d 00 20 00 44 00 6f 00 r...[.".]. .D.o. 0380 75 00 62 00 6c 00 65 00 20 00 51 00 75 00 6f 00 u.b.l.e. .Q.u.o. 0390 74 00 65 00 0f 00 5b 00 5d 00 20 00 53 00 69 00 t.e...[.]. .S.i. 03a0 6e 00 67 00 6c 00 65 00 20 00 51 00 75 00 6f 00 n.g.l.e. .Q.u.o. 03b0 74 00 65 00 10 00 5b 00 5d 00 20 00 51 00 75 00 t.e...[.]. .Q.u. 03c0 65 00 73 00 74 00 69 00 6f 00 6e 00 20 00 4d 00 e.s.t.i.o.n. .M. 03d0 61 00 72 00 6b 00 0d 00 5b 00 5c 00 5d 00 20 00 a.r.k...[.\.]. . 03e0 42 00 61 00 63 00 6b 00 73 00 6c 00 61 00 73 00 B.a.c.k.s.l.a.s. 03f0 68 00 07 00 5b 00 7f 00 5d 00 20 00 44 00 45 00 h...[...]. .D.E. 0400 4c 00 10 00 5b 00 32 00 30 00 41 00 43 00 5d 00 L...[.2.0.A.C.]. 0410 20 00 45 00 75 00 72 00 6f 00 20 00 53 00 69 00 .E.u.r.o. .S.i. 0420 67 00 6e 00 13 00 5b 00 ff fe 5d 00 20 00 42 00 g.n...[...]. .B. 0430 79 00 74 00 65 00 20 00 4f 00 72 00 64 00 65 00 y.t.e. .O.r.d.e. 0440 72 00 20 00 4d 00 61 00 72 00 6b 00 03 00 5b 00 r. .M.a.r.k...[. 0450 00 00 5d 00 ..]. CertUtil: -dump command completed successfully.OUCH⁴: the Resource Compiler translates the standard ANSI C89 escape sequence
\a
for
Audible Alarmto the wrong Unicode code point
U+0008
instead of its
correct code point U+0007
!
OUCH⁵: it fails to support the
standard
ANSI C89
escape sequences
\b
for
Backspace
, \f
for Form Feed
,
\v
for
Vertical Tabulator
,
\'
for the
Single Quote
, and
\?
for the
Question Mark
!
OOPS⁴: it also fails to support the
standard
ANSI C99
escape sequence
\u‹1 to 4 hexadecimal digits›
for
UTF-16
code points
U+‹1 to 4 hexadecimal digits›
.
OUCH⁶: it accepts the
incomplete and invalid escape
sequence \x
without any following hexadecimal digit(s)
and treats it as \0
!
OOPS⁵: its (mis)behaviour for escape sequences in ANSI strings differs from the (mis)behaviour for escape sequences in Unicode strings!
Convert the resource file blunder.res
generated in
step 6. to an object file blunder.obj
and link it
as resource
DLLs
blunder.dll
, then dump the raw data of the
.rsrc
section:
CVTRES.EXE /MACHINE:X86 /READONLY blunder.res LINK.EXE /LINK /DLL /NODEFAULTLIB /NOENTRY blunder.obj LINK.EXE /DUMP /RAWDATA /SECTION:.rsrc blunder.dll
Microsoft (R) Windows Resource To Object Converter Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file blunder.dll File Type: DLL SECTION HEADER #1 .rsrc name 488 virtual size 1000 virtual address (10001000 to 10001487) 600 size of raw data 200 file pointer to raw data (00000200 to 000007FF) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 40000040 flags Initialized Data Read Only RAW DATA #1 10001000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 ................ 10001010: 06 00 00 00 18 00 00 80 00 00 00 00 00 00 00 00 ................ 10001020: 00 00 00 00 00 00 02 00 01 00 00 00 38 00 00 80 ............8... 10001030: 02 00 00 00 50 00 00 80 00 00 00 00 00 00 00 00 ....P........... 10001040: 00 00 00 00 00 00 01 00 00 00 00 00 68 00 00 00 ............h... 10001050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 ................ 10001060: 00 00 00 00 78 00 00 00 90 10 00 00 08 02 00 00 ....x........... 10001070: 00 00 00 00 00 00 00 00 98 12 00 00 EC 01 00 00 ............ì... 10001080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 10001090: 07 00 5B 00 00 00 5D 00 20 00 4E 00 55 00 4C 00 ..[...]. .N.U.L. 100010A0: 11 00 5B 00 08 00 5D 00 20 00 41 00 75 00 64 00 ..[...]. .A.u.d. 100010B0: 69 00 62 00 6C 00 65 00 20 00 41 00 6C 00 61 00 i.b.l.e. .A.l.a. 100010C0: 72 00 6D 00 0E 00 5B 00 5C 00 62 00 5D 00 20 00 r.m...[.\.b.]. . 100010D0: 42 00 61 00 63 00 6B 00 73 00 70 00 61 00 63 00 B.a.c.k.s.p.a.c. 100010E0: 65 00 0E 00 5B 00 5C 00 66 00 5D 00 20 00 46 00 e...[.\.f.]. .F. 100010F0: 6F 00 72 00 6D 00 20 00 46 00 65 00 65 00 64 00 o.r.m. .F.e.e.d. 10001100: 0D 00 5B 00 0A 00 5D 00 20 00 4C 00 69 00 6E 00 ..[...]. .L.i.n. 10001110: 65 00 20 00 46 00 65 00 65 00 64 00 13 00 5B 00 e. .F.e.e.d...[. 10001120: 0D 00 5D 00 20 00 43 00 61 00 72 00 72 00 69 00 ..]. .C.a.r.r.i. 10001130: 61 00 67 00 65 00 20 00 52 00 65 00 74 00 75 00 a.g.e. .R.e.t.u. 10001140: 72 00 6E 00 18 00 5B 00 09 00 5D 00 20 00 48 00 r.n...[...]. .H. 10001150: 6F 00 72 00 69 00 7A 00 6F 00 6E 00 74 00 61 00 o.r.i.z.o.n.t.a. 10001160: 6C 00 20 00 54 00 61 00 62 00 75 00 6C 00 61 00 l. .T.a.b.u.l.a. 10001170: 74 00 6F 00 72 00 17 00 5B 00 5C 00 76 00 5D 00 t.o.r...[.\.v.]. 10001180: 20 00 56 00 65 00 72 00 74 00 69 00 63 00 61 00 .V.e.r.t.i.c.a. 10001190: 6C 00 20 00 54 00 61 00 62 00 75 00 6C 00 61 00 l. .T.a.b.u.l.a. 100011A0: 74 00 6F 00 72 00 10 00 5B 00 22 00 5D 00 20 00 t.o.r...[.".]. . 100011B0: 44 00 6F 00 75 00 62 00 6C 00 65 00 20 00 51 00 D.o.u.b.l.e. .Q. 100011C0: 75 00 6F 00 74 00 65 00 11 00 5B 00 5C 00 27 00 u.o.t.e...[.\.'. 100011D0: 5D 00 20 00 53 00 69 00 6E 00 67 00 6C 00 65 00 ]. .S.i.n.g.l.e. 100011E0: 20 00 51 00 75 00 6F 00 74 00 65 00 12 00 5B 00 .Q.u.o.t.e...[. 100011F0: 5C 00 3F 00 5D 00 20 00 51 00 75 00 65 00 73 00 \.?.]. .Q.u.e.s. 10001200: 74 00 69 00 6F 00 6E 00 20 00 4D 00 61 00 72 00 t.i.o.n. .M.a.r. 10001210: 6B 00 0D 00 5B 00 5C 00 5D 00 20 00 42 00 61 00 k...[.\.]. .B.a. 10001220: 63 00 6B 00 73 00 6C 00 61 00 73 00 68 00 07 00 c.k.s.l.a.s.h... 10001230: 5B 00 7F 00 5D 00 20 00 44 00 45 00 4C 00 12 00 [...]. .D.E.L... 10001240: 5B 00 5C 00 75 00 32 00 30 00 41 00 43 00 5D 00 [.\.u.2.0.A.C.]. 10001250: 20 00 45 00 75 00 72 00 6F 00 20 00 53 00 69 00 .E.u.r.o. .S.i. 10001260: 67 00 6E 00 15 00 5B 00 FE 00 46 00 46 00 5D 00 g.n...[.þ.F.F.]. 10001270: 20 00 42 00 79 00 74 00 65 00 20 00 4F 00 72 00 .B.y.t.e. .O.r. 10001280: 64 00 65 00 72 00 20 00 4D 00 61 00 72 00 6B 00 d.e.r. .M.a.r.k. 10001290: 03 00 5B 00 00 00 5D 00 07 00 5B 00 00 00 5D 00 ..[...]...[...]. 100012A0: 20 00 4E 00 55 00 4C 00 11 00 5B 00 08 00 5D 00 .N.U.L...[...]. 100012B0: 20 00 41 00 75 00 64 00 69 00 62 00 6C 00 65 00 .A.u.d.i.b.l.e. 100012C0: 20 00 41 00 6C 00 61 00 72 00 6D 00 0C 00 5B 00 .A.l.a.r.m...[. 100012D0: 5D 00 20 00 42 00 61 00 63 00 6B 00 73 00 70 00 ]. .B.a.c.k.s.p. 100012E0: 61 00 63 00 65 00 0C 00 5B 00 5D 00 20 00 46 00 a.c.e...[.]. .F. 100012F0: 6F 00 72 00 6D 00 20 00 46 00 65 00 65 00 64 00 o.r.m. .F.e.e.d. 10001300: 0D 00 5B 00 0A 00 5D 00 20 00 4C 00 69 00 6E 00 ..[...]. .L.i.n. 10001310: 65 00 20 00 46 00 65 00 65 00 64 00 13 00 5B 00 e. .F.e.e.d...[. 10001320: 0D 00 5D 00 20 00 43 00 61 00 72 00 72 00 69 00 ..]. .C.a.r.r.i. 10001330: 61 00 67 00 65 00 20 00 52 00 65 00 74 00 75 00 a.g.e. .R.e.t.u. 10001340: 72 00 6E 00 18 00 5B 00 09 00 5D 00 20 00 48 00 r.n...[...]. .H. 10001350: 6F 00 72 00 69 00 7A 00 6F 00 6E 00 74 00 61 00 o.r.i.z.o.n.t.a. 10001360: 6C 00 20 00 54 00 61 00 62 00 75 00 6C 00 61 00 l. .T.a.b.u.l.a. 10001370: 74 00 6F 00 72 00 15 00 5B 00 5D 00 20 00 56 00 t.o.r...[.]. .V. 10001380: 65 00 72 00 74 00 69 00 63 00 61 00 6C 00 20 00 e.r.t.i.c.a.l. . 10001390: 54 00 61 00 62 00 75 00 6C 00 61 00 74 00 6F 00 T.a.b.u.l.a.t.o. 100013A0: 72 00 10 00 5B 00 22 00 5D 00 20 00 44 00 6F 00 r...[.".]. .D.o. 100013B0: 75 00 62 00 6C 00 65 00 20 00 51 00 75 00 6F 00 u.b.l.e. .Q.u.o. 100013C0: 74 00 65 00 0F 00 5B 00 5D 00 20 00 53 00 69 00 t.e...[.]. .S.i. 100013D0: 6E 00 67 00 6C 00 65 00 20 00 51 00 75 00 6F 00 n.g.l.e. .Q.u.o. 100013E0: 74 00 65 00 10 00 5B 00 5D 00 20 00 51 00 75 00 t.e...[.]. .Q.u. 100013F0: 65 00 73 00 74 00 69 00 6F 00 6E 00 20 00 4D 00 e.s.t.i.o.n. .M. 10001400: 61 00 72 00 6B 00 0D 00 5B 00 5C 00 5D 00 20 00 a.r.k...[.\.]. . 10001410: 42 00 61 00 63 00 6B 00 73 00 6C 00 61 00 73 00 B.a.c.k.s.l.a.s. 10001420: 68 00 07 00 5B 00 7F 00 5D 00 20 00 44 00 45 00 h...[...]. .D.E. 10001430: 4C 00 10 00 5B 00 32 00 30 00 41 00 43 00 5D 00 L...[.2.0.A.C.]. 10001440: 20 00 45 00 75 00 72 00 6F 00 20 00 53 00 69 00 .E.u.r.o. .S.i. 10001450: 67 00 6E 00 13 00 5B 00 FF FE 5D 00 20 00 42 00 g.n...[.ÿþ]. .B. 10001460: 79 00 74 00 65 00 20 00 4F 00 72 00 64 00 65 00 y.t.e. .O.r.d.e. 10001470: 72 00 20 00 4D 00 61 00 72 00 6B 00 03 00 5B 00 r. .M.a.r.k...[. 10001480: 00 00 5D 00 00 00 00 00 ..]..... Summary 1000 .rsrc
RC.exe
.
The .rsrc section:
Resources are indexed by a multiple-level binary-sorted tree structure. The general design can incorporate 2**31 levels. By convention, however, Windows uses three levels:
Type Name Language[…]
Each Resource Data entry describes an actual unit of raw data in the Resource Data area. A Resource Data entry has the following format:
Offset Size Field Description 0 4 Data RVA The address of a unit of resource data in the Resource Data area. 4 4 Size The size, in bytes, of the resource data that is pointed to by the Data RVA field. 8 4 Codepage The code page that is used to decode code point values within the resource data. Typically, the code page would be the Unicode code page. 12 4 Reserved, must be 0.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyright © 2004-2024, 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 == 0UL)
return FALSE;
if (!WriteConsole(hConsole, szOutput, dwOutput, &dwConsole, NULL))
return FALSE;
return dwConsole == dwOutput;
}
const LPCWSTR szType[] = {NULL,
L"CURSOR", L"BITMAP", L"ICON", L"MENU", L"DIALOG", L"STRINGTABLE",
L"FONTDIR", L"FONT", L"ACCELERATOR", L"RCDATA", L"MESSAGETABLE", L"GROUP_CURSOR",
L"MENUEX", L"GROUP_ICON", L"NAMETABLE", L"VERSION", L"DLGINCLUDE", L"DIALOGEX",
L"PLUGPLAY", L"VXD", L"ANICURSOR", L"ANIICON", L"HTML", L"MANIFEST"};
VOID WINAPI Resource(HANDLE hConsole,
IMAGE_RESOURCE_DIRECTORY *lpRoot,
IMAGE_RESOURCE_DIRECTORY *lpLevel,
DWORD dwLevel) // 0 = Type, 1 = Id, 2 = Language
{
DWORD dwEntry;
IMAGE_RESOURCE_DIRECTORY_ENTRY *lpEntry;
IMAGE_RESOURCE_DIR_STRING_U *lpUnicode;
IMAGE_RESOURCE_DATA_ENTRY *lpData;
for (lpEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *) (lpLevel + 1),
dwEntry = 0UL;
dwEntry < lpLevel->NumberOfNamedEntries + lpLevel->NumberOfIdEntries;
dwEntry++)
{
if ((lpEntry[dwEntry].Name & IMAGE_RESOURCE_NAME_IS_STRING) == IMAGE_RESOURCE_NAME_IS_STRING)
{
lpUnicode = (IMAGE_RESOURCE_DIR_STRING_U *) ((BYTE *) lpRoot + (lpEntry[dwEntry].Name ^ IMAGE_RESOURCE_NAME_IS_STRING));
PrintConsole(hConsole,
L"\t\t\t\tName = %ls\n" + 2 - dwLevel,
lpUnicode->NameString, lpUnicode->Length);
}
else if (dwLevel > 1UL)
PrintConsole(hConsole,
L"\t\t\t\tLanguage = %hu\n",
lpEntry[dwEntry].Id);
else if (dwLevel > 0UL)
PrintConsole(hConsole,
L"\t\t\tId = %hu\n",
lpEntry[dwEntry].Id);
else
PrintConsole(hConsole,
L"\t\tType = %hu (%ls)\n",
lpEntry[dwEntry].Id, szType[lpEntry[dwEntry].Id]);
PrintConsole(hConsole,
L"\t\t\t\tOffset = 0x%08lX\n" + 2 - dwLevel,
lpEntry[dwEntry].OffsetToData);
if ((lpEntry[dwEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) != IMAGE_RESOURCE_DATA_IS_DIRECTORY)
{
lpData = (IMAGE_RESOURCE_DATA_ENTRY *) ((BYTE *) lpRoot + lpEntry[dwEntry].OffsetToData);
PrintConsole(hConsole,
L"\t\t\t\t\tAddress = 0x%08lX\n"
L"\t\t\t\t\tSize = %lu\n"
L"\t\t\t\t\tCode Page = %lu\n"
L"\t\t\t\t\tReserved = 0x%08lX\n",
lpData->OffsetToData, lpData->Size, lpData->CodePage, lpData->Reserved);
}
else
Resource(hConsole,
lpRoot,
(IMAGE_RESOURCE_DIRECTORY *) ((BYTE *) lpRoot + (lpEntry[dwEntry].OffsetToData ^ IMAGE_RESOURCE_DATA_IS_DIRECTORY)),
dwLevel + 1UL);
}
}
extern const IMAGE_DOS_HEADER __ImageBase;
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
IMAGE_RESOURCE_DIRECTORY *lpResource;
IMAGE_NT_HEADERS *lpPE = (IMAGE_NT_HEADERS *) ((BYTE *) &__ImageBase + __ImageBase.e_lfanew);
DWORD dwError = ERROR_SUCCESS;
HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
dwError = GetLastError();
else
{
if ((lpPE->Signature != IMAGE_NT_SIGNATURE)
|| (lpPE->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_RESOURCE)
|| (lpPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress == 0UL)
|| (lpPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size == 0UL))
dwError = ERROR_BAD_EXE_FORMAT;
else
{
lpResource = (IMAGE_RESOURCE_DIRECTORY *) ((BYTE *) &__ImageBase + lpPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
PrintConsole(hConsole,
L"Resource Directory:\n"
L"\tCharacteristics = 0x%08lX\n"
L"\tTime/Date Stamp = 0x%08lX\n"
L"\tVersion = %hu.%hu\n"
L"\tNamed Entries = %hu\n"
L"\tUnnamed Entries = %hu\n"
L"\tEntries:\n",
lpResource->Characteristics,
lpResource->TimeDateStamp,
lpResource->MajorVersion,
lpResource->MinorVersion,
lpResource->NumberOfNamedEntries,
lpResource->NumberOfIdEntries);
Resource(hConsole, lpResource, lpResource, 0UL);
}
if (!CloseHandle(hConsole))
PrintConsole(hConsole,
L"CloseHandle() returned error %lu\n",
GetLastError());
}
ExitProcess(dwError);
}
Compile and link the source file blunder.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.lib user32.libNote: 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. blunder.c blunder.c(51) : warning C4018: '<' : signed/unsigned mismatch Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib user32.lib
Create the text file blunder.xml
with the following
content in the current directory:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<assembly manifestVersion='1.0' xmlns='urn:schemas-microsoft-com:asm.v1' />
Embed the
Application Manifest
blunder.xml
created in step 3. in the console
application blunder.exe
built in step 2.:
MT.EXE /Manifest blunder.xml /OutputResource:blunder.exe
Microsoft (R) Manifest Tool version 6.1.7716.0 Copyright (c) Microsoft Corporation 2009. All rights reserved.
Execute the console application blunder.exe
modified in
step 4. and evaluate its exit code:
.\blunder.exe ECHO %ERRORLEVEL%
Resource Directory: Characteristics = 0x00000000 Time/Date Stamp = 0x00000000 Version = 4.0 Named Entries = 0 Unnamed Entries = 1 Entries: Type = 24 (MANIFEST) Offset = 0x80000018 Id = 1 Offset = 0x80000030 Language = 1033 Offset = 0x00000048 Address = 0x00003058 Size = 84 Code Page = 1252 Reserved = 0x00000000 0OUCH¹: although Application Manifests must be encoded in UTF-8, the Manifest Tool
MT.exe
emits code page identifier 1252 alias
Windows-1252
instead of the proper 65001 alias CP_UTF8
in the
MANIFEST
resource metadata!
OUCH²: additionally it emits language
identifier 1033 alias
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH)
instead of the proper language identifier 0 alias
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
and the time stamp 0x0 instead of the current date and time in the
resource directory metadata!
Note: contrary to other resource types, especially
dialogues,
menues,
messages
and
strings,
which are selected at runtime to match the users’ preferred
language, Windows’ module loader always uses the
first MANIFEST
resource present in the
.rsrc
section!
Link the console application blunder.exe
a second time,
now with the resource file blunder.res
created in
Blunder № 32:
LINK.EXE /LINK blunder.obj blunder.res kernel32.lib user32.lib
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE
Execute the console application blunder.exe
built in
step 6. and evaluate its exit code:
.\blunder.exe ECHO %ERRORLEVEL%
Resource Directory: Characteristics = 0x00000000 Time/Date Stamp = 0x00000000 Version = 4.0 Named Entries = 0 Unnamed Entries = 1 Entries: Type = 6 (STRINGTABLE) Offset = 0x80000018 Id = 1 Offset = 0x80000038 Language = 1033 Offset = 0x00000068 Address = 0x00003090 Size = 520 Code Page = 0 Reserved = 0x00000000 Id = 2 Offset = 0x80000050 Language = 1033 Offset = 0x00000078 Address = 0x00003298 Size = 492 Code Page = 0 Reserved = 0x00000000 0OUCH³: the Resource Compiler
RC.exe
also fails to set the
proper code page identifier 1200 alias
UTF-16LE
as well as the time stamp and sets the language identifier 1033
alias
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH)
!
Messages are defined in a message text file. The message compiler assigns numbers to each message, and generates a C/C++ include file which the application can use to access a message using a symbolic constant.The documentation for the Win32 function[…]
You can specify the following escape sequences for formatting message text for use by the event viewer or your application. The percent sign character (%) begins all escape sequences. Any other character following a percent sign is displayed without the percent sign.
%n[!format_specifier!]
Describes an insert. Each insert is an entry in the Arguments array in the FormatMessage function. The value of n can be a number between 1 and 99. The format specifier is optional. If no value is specified, the default is !s!. For information about the format specifier, see wsprintf.
The format specifier can use * for either the precision or the width. When specified, they consume inserts numbered n+1 and n+2.
%0
Terminates a message text line without a trailing newline character. This can be used to build a long line or terminate a prompt message without a trailing newline character.
%.
Generates a single period. This can be used to display a period at the beginning of a line, which would otherwise terminate the message text.
%!
Generates a single exclamation point. This can be used to specify an exclamation point immediately after an insert.
%%
Generates a single percent sign.
%n
Generates a hard line break when it occurs at the end of a line. This can be used with FormatMessage to ensure that the message fits a certain width.
%b
Generates a space character. This can be used to ensure an appropriate number of trailing spaces on a line.
%r
Generates a hard carriage return without a trailing newline character.
FormatMessage()
specifies likewise in section Remarks:
Formats a message string. The function requires a message definition as input. The message definition can come from a buffer passed into the function. It can come from a message table resource in an already-loaded module. Or the caller can ask the function to search the system's message table resource(s) for the message definition. The function finds the message definition in a message table resource based on a message identifier and a language identifier. The function copies the formatted message text to an output buffer, processing any embedded insert sequences if requested.The MSDN article System Error Codes (500-999) documents but message texts with[…]
Escape sequence Meaning %0 Terminates a message text line without a trailing new line character. This escape sequence can be used to build up long lines or to terminate the message itself without a trailing new line character. It is useful for prompt messages. %n!format string! Identifies an insert. The value of n can be in the range from 1 through 99. The format string (which must be surrounded by exclamation marks) is optional and defaults to !s! if not specified. […]
%0
escape sequences:
ERROR_UNHANDLED_EXCEPTIONWin32 Error Codes574 (0x23E)
{Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
[…]
ERROR_SYSTEM_PROCESS_TERMINATED
591 (0x24F)
{Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
Start the Command Processor
Cmd.exe
, then execute
the following four command lines to show the blunder:
NET.EXE HELPMSG 574 CERTUTIL.EXE /ERROR 574 NET.EXE HELPMSG 591 CERTUTIL.EXE /ERROR 591Note: the command lines can be copied and pasted as block into a Command Processor window.
{Application Error} The exception s (0x 0x23e (WIN32: 574 ERROR_UNHANDLED_EXCEPTION) -- 574 (574) Error message text: {Application Error} The exception %s (0x CertUtil: -error command completed successfully. {Fatal System Error} The hs system process terminated unexpectedly with a status of 0x 0x24f (WIN32: 591 ERROR_SYSTEM_PROCESS_TERMINATED) -- 591 (591) Error message text: {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x CertUtil: -error command completed successfully.OUCH¹: message texts defined with a stray
%0
, for example in 0x%08lX
, are truncated
when retrieved with the
FormatMessage()
function!
Execute the following two command lines to show proper behaviour:
CERTUTIL.EXE /ERROR 0xC0000144 CERTUTIL.EXE /ERROR 0xC000021A
0xc0000144 (NT: 0xc0000144 STATUS_UNHANDLED_EXCEPTION) -- 3221225796 (-1073741500) Error message text: {Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx. CertUtil: -error command completed successfully. 0xc000021a (NT: 0xc000021a STATUS_SYSTEM_PROCESS_TERMINATED) -- 3221226010 (-1073741286) Error message text: {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down. CertUtil: -error command completed successfully.Note: most obviously
CertUtil.exe
doesn’t use the
FormatMessage()
function for
NTSTATUS
values – the message texts for the
0xC0000144
alias STATUS_UNHANDLED_EXCEPTION
and
0xC000021A
alias STATUS_SYSTEM_PROCESS_TERMINATED
, from which both
Win32 error codes were derived and their message texts
copied, display properly.
Create the text file blunder.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define STATUS_UNHANDLED_EXCEPTION 0xC0000144L
#define STATUS_SYSTEM_PROCESS_TERMINATED 0xC000021AL
const DWORD dwArray[] = {ERROR_SYSTEM_PROCESS_TERMINATED, ERROR_UNHANDLED_EXCEPTION,
STATUS_SYSTEM_PROCESS_TERMINATED, STATUS_UNHANDLED_EXCEPTION};
__declspec(noreturn)
VOID CDECL wmainCRTStartup(VOID)
{
WCHAR szBuffer[1234];
DWORD dwBuffer;
DWORD dwConsole;
DWORD dwError = ERROR_SUCCESS;
DWORD dwIndex = 0UL;
HMODULE hModule = GetModuleHandle(L"NTDLL");
HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
dwError = GetLastError();
else
do
{
dwBuffer = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
hModule,
dwArray[dwIndex],
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
szBuffer,
sizeof(szBuffer) / sizeof(*szBuffer),
(va_list *) NULL);
if (dwBuffer == 0UL)
dwError = GetLastError();
else
{
szBuffer[dwBuffer++] = L'\n';
if (!WriteConsole(hConsole, szBuffer, dwBuffer, &dwConsole, NULL))
dwError = GetLastError();
else
if (dwConsole != dwBuffer)
dwError = ERROR_WRITE_FAULT;
}
} while (++dwIndex < sizeof(dwArray) / sizeof(*dwArray));
ExitProcess(dwError);
}
94999
113996
196069
259693
Compile and link the source file blunder.c
created in
step 3.:
SET CL=/W4 /Zl SET LINK=/ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE CL.EXE blunder.c kernel32.libNote: 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. blunder.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wmainCRTStartup /NODEFAULTLIB /SUBSYSTEM:CONSOLE /out:blunder.exe blunder.obj kernel32.lib
Execute the console application blunder.exe
built in
step 4. and evaluate its exit code:
.\blunder.exe ECHO %ErrorLevel%
{Fatal System Error} The hs system process terminated unexpectedly with a status of 0x {Application Error} The exception s (0x {Fatal System Error} The hs system process terminated unexpectedly with a status of 0x {Application Error} The exception s (0x 0OUCH: �
Certutil
command specifies:
The following table describes the verbs that can be used with the certutil command.
Verbs Description -dump Dump configuration information or files … …
Start the Command Processor
Cmd.exe
, then execute
the following command lines to create the
UTF-16LE
encoded text file blunder.txt
twice and dump it using
the Certutil.exe
utility:
1>blunder.txt "%COMSPEC%" /U /D /C ECHO PAUSE CERTUTIL.EXE /DUMP blunder.txt 1>blunder.txt "%COMSPEC%" /U /D /C ECHO pause CERTUTIL.EXE /DUMP blunder.txt DIR blunder.txt
3c 05 12 14 <... CertUtil: -error command completed successfully. a5 ab ac 7c ...| CertUtil: -error command completed successfully. Volume in drive C has no label. Volume Serial Number is 1957-0427 Directory of C:\Users\Stefan\Desktop 04/27/2018 08:15 PM 14 blunder.txt 1 File(s) 14 bytes 0 Dir(s) 9,876,543,210 bytes freeOUCH¹: � WTF?
Create the
UTF-16LE
encoded text file
blunder.txt
containing the Greek alphabet in capital and small letters in an
arbitrary, preferable empty directory:
ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω
Note: the file blunder.txt
contains 51
Unicode
code points in 102 bytes – a leading
Byte Order Mark
U+FEFF
, one line
of 48 letters from U+0391
to U+03C9
(not contiguous),
followed by a trailing
CR/LF
pair.
Display the file blunder.txt
using the internal
Type
command:
TYPE blunder.txt
ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω
Create the
ANSI
encoded file blunder.tmp
using the internal
Type
command and display it afterwards:
1>blunder.tmp TYPE blunder.txt TYPE blunder.tmp
??G????Ø?????????S??F??Oaß?de??????µ???p?st?f???
Dump the file blunder.txt
created in step 2. using
the Certutil.exe
utility:
CERTUTIL.EXE /DUMP blunder.txt
0000 ... 0032 0000 3f 3f 47 3f 3f 3f 3f 54 3f 3f 3f 3f 3f 3f 3f 3f ??G????T???????? 0010 3f 53 3f 3f 46 3f 3f 4f 61 df 3f 64 65 3f 3f 3f ?S??F??Oa.?de??? 0020 3f 3f 3f b5 3f 3f 3f 70 3f 73 74 3f 66 3f 3f 3f ???.???p?st?f??? 0030 0d 0a .. CertUtil: -dump command completed successfully.OUCH²:
Certutil.exe
converts
UTF-16LE
encoded files to
ANSI
before it dumps their now destroyed content –
a completely braindead approach – and even dares to call this
epic failure successful!
Dump the file blunder.txt
created in step 2. using
the undocumented /ENCODEHEX
verb of the
Certutil.exe
utility and display the output:
CERTUTIL.EXE /ENCODEHEX /F blunder.txt blunder.tmp TYPE blunder.tmp
Input Length = 102 Output Length = 508 CertUtil: -encodehex command completed successfully. 0000 ff fe 91 03 92 03 93 03 94 03 95 03 96 03 97 03 ................ 0010 98 03 99 03 9a 03 9b 03 9c 03 9d 03 9e 03 9f 03 ................ 0020 a0 03 a1 03 a3 03 a4 03 a5 03 a6 03 a7 03 a8 03 ................ 0030 a9 03 b1 03 b2 03 b3 03 b4 03 b5 03 b6 03 b7 03 ................ 0040 b8 03 b9 03 ba 03 bb 03 bc 03 bd 03 be 03 bf 03 ................ 0050 c0 03 c1 03 c3 03 c4 03 c5 03 c6 03 c7 03 c8 03 ................ 0060 c9 03 0d 00 0a 00 ......
Dump the executable file of the
Command Processor, specified by its
absolute, fully qualified path name provided in the environment
variable COMSPEC
:
CERTUTIL.EXE /DUMP "%COMSPEC%"
C:\Windows\system32\cmd.exe: Lang 04b00409 (1200.1033) File 6.1:7601.23403 Product 6.1:7601.23403 CertUtil: -dump command completed successfully.OOPS¹: instead of the expected (hexadecimal) dump,
Certutil.exe
displays some parts of the
VERSIONINFO
resource embedded in the Portable Executable file
Cmd.exe
.
Dump some other executable files located in the
system directory
%SystemRoot%\System32\
,
specified by their unqualified name and extension:
CERTUTIL.EXE /DUMP main.cpl CERTUTIL.EXE /DUMP slmgr.vbs SET PATHEXT
main.cpl: Lang 04b00409 (1200.1033) File 6.1:7601.17514 Product 6.1:7601.17514 CertUtil: -dump command completed successfully. CertUtil: -dump command FAILED: 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND) CertUtil: The system cannot find the file specified. PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSCOOPS²:
Certutil.exe
searches the
PATH
, but does not evaluate the environment variable
PATHEXT
!
Finally dump another executable file located in the
system directory
, specified by just its unqualified name
without extension:
CERTUTIL.EXE /DUMP ntdll
ntdll: Lang 04b00409 (1200.1033) File 6.1:7601.24545 Product 6.1:7601.24545 CertUtil: -dump command completed successfully.OOPS³: when no extension is specified,
Certutil.exe
searches the PATH
for
DLLs!
More
command states:
Displays one screen of output at a time.[…]
<Command> | more [/c] [/p] [/s] [/t<N>] [+<N>] more [[/c] [/p] [/s] [/t<N>] [+<N>]] < [<Drive>:][<Path>]<FileName> more [/c] [/p] [/s] [/t<N>] [+<N>] [<Files>]
Create the
UTF-16LE
encoded text file
blunder.txt
containing the Cyrillic alphabet in capital and small letters in an
arbitrary, preferable empty directory:
ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
ёђѓєѕіїјљњћќѝўџабвгдежзийклмнопрстуфхцчшщъыьэюя
Note: the file blunder.txt
contains 99
Unicode
code points in 198 bytes – a leading
Byte Order Mark
U+FEFF
, a first
line of 47 capital letters from
U+0401
to
U+042F
, followed by an
intermediate
CR/LF
pair, a second line of 47 small letters from
U+0451
to
U+045F
and
U+0430
to
U+044F
, followed by a
trailing
CR/LF
pair.
Display the file blunder.txt
using the internal
Type
command:
TYPE blunder.txt
ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ ёђѓєѕіїјљњћќѝўџабвгдежзийклмнопрстуфхцчшщъыьэюя
Display the file blunder.txt
using the
More
utility:
MORE.COM blunder.txt
??????????????????????????????????????????????? ???????????????????????????????????????????????OUCH:
More.com
converts files from
UTF-16LE
to
ANSI
before it displays their now destroyed content
– a completely braindead approach!
Display the file blunder.txt
a second time:
TYPE blunder.txt | MORE.COM
???????????????????????????????????????????????? ????????????????????????????????????????????????
Package existing files into a cabinet (.cab) file.makecab [/v[n]] [/d var=‹value› ...] [/l ‹dir›] ‹source› [‹destination›] makecab [/v[‹n›]] [/d var=‹value› ...] /f ‹directives_file› […]
Parameter Description ‹source› File to compress. ‹destination› File name to give compressed file. If omitted, the last character of the source file name is replaced with an underscore (_) and used as the destination. /f ‹directives_file› A file with makecab directives (may be repeated). /d var=‹value› Defines variable with specified value. /l ‹dir› Location to place destination (default is current directory). /v[‹n›] Set debugging verbosity level (0=none,...,3=full). /? Displays help at the command prompt.
Start the Command Processor
Cmd.exe
, then execute
the following command lines:
SET TMP=NUL: MAKECAB.EXE "%COMSPEC%"
Cabinet Maker - Lossless Data Compression Tool [Wed Apr 1 01:23:45] File open error (Win32Error=0x7B), retrying NUL:\cab_815_2 [Wed Apr 1 01:23:45] File open error (Win32Error=0x7B), retrying NUL:\cab_815_2 [Wed Apr 1 01:23:45] File open error (Win32Error=0x7B), retrying NUL:\cab_815_2 … ^COUCH: proper error handling is most obviously (next to) impossible for Microsoft’s developers!
Note: the
Win32 error code 123 means
ERROR_INVALID_NAME
– a repetition using the same filename is useless
utter nonsense!
Adds a new subkey or entries from the registry.The TechNet article Reg delete specifies:reg add <KeyName> [{/v ValueName | /ve}] [/t DataType] [/s Separator] [/d Data] [/f]
Parameter Description ‹KeyName› Specifies the full path of the subkey or entry to be added. To specify a remote computer, include the computer name (in the format \\<ComputerName>\) as part of the KeyName. Omitting \\ComputerName\ causes the operation to default to the local computer. The KeyName must include a valid root key. Valid root keys for the local computer are: HKLM, HKCU, HKCR, HKU, and HKCC. If a remote computer is specified, valid root keys are: HKLM and HKU. /v <ValueName> Specifies the name of the registry entry to be added under the specified subkey. /ve Specifies that the registry entry that is added to the registry has a null value. /t <Type> Specifies the type for the registry entry. Type must be one of the following:
REG_SZ
REG_MULTI_SZ
REG_DWORD_BIG_ENDIAN
REG_DWORD
REG_BINARY
REG_DWORD_LITTLE_ENDIAN
REG_LINK
REG_FULL_RESOURCE_DESCRIPTOR
REG_EXPAND_SZ/s <Separator> Specifies the character to be used to separate multiple instances of data when the REG_MULTI_SZ data type is specified and more than one entry needs to be listed. If not specified, the default separator is \0. /d <Data> Specifies the data for the new registry entry. … … /f Adds the registry entry without prompting for confirmation. /? Displays help for reg add at the command prompt.
Deletes a subkey or entries from the registry.Reg delete ‹KeyName› [{/v ‹ValueName› | /ve | /va}] [/f]
Parameter Description ‹KeyName› Specifies the full path of the subkey or entry to be deleted. To specify a remote computer, include the computer name (in the format \\ComputerName\) as part of the KeyName. Omitting \\ComputerName\ causes the operation to default to the local computer. The KeyName must include a valid root key. Valid root keys for the local computer are: HKLM, HKCU, HKCR, HKU, and HKCC. If a remote computer is specified, valid root keys are: HKLM and HKU. /v ‹ValueName› Deletes a specific entry under the subkey. If no entry is specified, then all entries and subkeys under the subkey will be deleted. /ve Specifies that only entries that have no value will be deleted. /va Deletes all entries under the specified subkey. Subkeys under the specified subkey are not deleted. … … /f Deletes the existing registry subkey or entry without asking for confirmation. /? Displays help for reg delete at the command prompt.
Start the Command Processor
Cmd.exe
, then execute
the following command lines:
REG.EXE ADD HKCU\Environment /V TMP 0<NUL:
Value TMP exists, overwrite (Yes/No)? Value TMP exists, overwrite (Yes/No)? Value TMP exists, overwrite (Yes/No)? Value TMP exists, overwrite (Yes/No)? Value TMP exists, overwrite (Yes/No)? … ^COUCH: proper error handling (here: detecting
end of fileon standard input) is most obviously underestimated and not deemed necessary in Redmond!
Note: the demonstration of this
blunder beginner’s error with other
subcommands of the
Reg
utility is left as an exercise to the reader.
REG.EXE DELETE HKCU\Environment /V TMP 0<NUL:
Delete the registry value (Default) (Yes/No)? Delete registry value (Default) (Yes/No)? Delete registry value (Default) (Yes/No)? Delete registry value (Default) (Yes/No)? … ^C
Copies the specified subkeys, entries, and values of the local computer into a file for transfer to other servers.The TechNet article Reg import specifies:
Copies the contents of a file that contains exported registry subkeys, entries, and values into the registry of the local computer.The MSKB article 310516 specifies the format and syntax of registry editor script files that is missing in the documentation referenced above, but is awfully bad!
Note: especially the notation
=hex(2):‹comma separated list of hexadecimal values›
required for REG_EXPAND_SZ
values,
=hex(7):‹comma separated list of hexadecimal values›
required for REG_MULTI_SZ
values and
=hex(11):‹comma separated list of 8 hexadecimal values›
required for REG_QWORD
alias
REG_QWORD_LITTLE_ENDIAN
values is
user-unfriendly.
Create the text file
blunder.reg
with the following content in an arbitrary, preferable empty
directory:
REGEDIT4
[HKEY_CURRENT_USER\Blunder]
""="Blunder"
"none"=hex(0):0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
"binary"=hex(3):0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
"dword"=dword:-1
"dword_little_endian"=hex(4):01,23,45,67,89,ab,cd,ef
"dword_big_endian"=hex(5):01,23,45,67,89,ab,cd,ef
"qword"=qword:0123456789abcdef
"link"=hex(6):
"expand"=expand:"%windir%"
"multi"=multi:"first","last"
"string"="left\right"
''="''"
@='@'
Import the registry entries from the script file
blunder.reg
into the
Registry:
SET __COMPAT_LAYER=RunAsInvoker REGEDIT.EXE blunder.reg
REG.EXE IMPORT blunder.reg ECHO %ERRORLEVEL%
The operation completed successfully.
0
OUCH: despite the multiple syntax errors in
the script file blunder.reg
, the
Registry Console Tool
Reg.exe
yields an
explicit success message!
OOPS: to specify the (unnamed) default entry of a
registry key, instead of the @
an empty
string can be used as registry value name.
Query the imported registry entries:
REG.EXE QUERY HKEY_CURRENT_USER\Blunder ECHO %ERRORLEVEL%
HKEY_CURRENT_USER\Blunder (Default) REG_SZ Blunder none REG_NONE 000102030405060708090A0B0C0D0E0F dword_little_endian REG_DWORD 0x67452301 dword_big_endian REG_DWORD_BIG_ENDIAN 0x67452301 link REG_LINK 0
OUCH²: the
Registry Console Tool
Reg.exe
fails to
distinguish big endian
from little endian
in its
output!
Export the just imported registry entries from the registry key
HKEY_CURRENT_USER\Blunder
to the file
blunder.txt
:
SET __COMPAT_LAYER=RunAsInvoker REGEDIT.EXE /E blunder.txt HKEY_CURRENT_USER\Blunder
REG.EXE EXPORT HKEY_CURRENT_USER\Blunder blunder.txt ECHO %ERRORLEVEL%
The operation completed successfully. 0
Note: with the
undocumented command line option /E
the (graphical) Registry Editor
RegEdit.exe
exports in
UTF-16LE
encoding, and with the undocumented command line
option /A
it exports in
ANSI
encoding.
Display the exported registry key and its entries:
TYPE blunder.txt
Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Blunder] @="Blunder" "none"=hex(0):00,01,02,03,04,05,06,07,08,09,0a,0b,0c,0d,0e,0f "dword_little_endian"=hex(4):01,23,45,67,89,ab,cd,ef "dword_big_endian"=hex(5):01,23,45,67,89,ab,cd,ef "link"=hex(6):Note: indicated by the tag line
Windows Registry Editor Version 5.00
, the
Registry Console Tool
Reg.exe
exports in
UTF-16LE
encoding.
Delete the registry key
HKEY_CURRENT_USER\Blunder
with all its entries:
REG.EXE DELETE HKEY_CURRENT_USER\Blunder /F ECHO %ERRORLEVEL%
The operation completed successfully. 0
RegEdit.exe
instead of the
Registry Console Tool
Reg.exe
is left as an
exercise to the reader.
To insert a Unicode character, type the character code, press ALT, and then press X. For example, to type a dollar symbol ($), type 0024, press ALT, and then press X.The MSKB articles Keyboard shortcuts for international characters and Keyboard shortcuts to add language accent marks in Word and Outlook state:
Contrary to the MSKB articles cited above, the hexadecimal Unicode character code doesn’t need to be typed before the Alt X key combination, and this function is supported in all programs which use an arbitrary Rich Edit Control, not just in Microsoft Office applications! Rich Edit Control, Using Rich Edit Controls
To insert this Press … … The Unicode character for the specified Unicode (hexadecimal) character code The character code, ALT+X
For example, to insert the euro currency symbol €, type 20AC, and then hold down the ALT key and press X.
Create the text file blunder.txt
with the following
content in an arbitrary, preferably empty directory:
24
a9
ae
3b1
3c9
20ac
2122
2190
2191
2192
2193
2194
Open the text file blunder.txt
created in step 1.
with
WordPad.exe
, then
place the cursor at the end of each line and press the
Alt X
key combination twice – first it replaces the
2, 3 or 4 characters left to the cursor with the $, ©, ®,
α, ω, €, ™, ←, ↑, →, ↓
respectively ↔ symbol, second it replaces each symbol with its
(uppercase) hexadecimal
Unicode
character code.
Despite this well-known rule, Microsoft but ships the
system images of Windows Vista and later versions with
a bunch of Policies set only in the
Registry
– the subdirectories
%SystemRoot%\System32\GroupPolicy\Machine\
and
%SystemRoot%\System32\GroupPolicy\User\
with the
registry policy files Registry.pol
where these registry
entries are supposed to be stored are missing!
Due to this omission blunder the
Local Group Policy Editor and the
Local Security Policy snap-in of
the Microsoft Management Console show
these Policies as not configured!
Also missing are the archive
files NTUser.pol
in
the directories %ALLUSERSPROFILE%
alias
%ProgramData%
for the machine and
%USERPROFILE%
for each user where the added as well as
the original, now overwritten or removed registry entries are
supposed to be saved for restoration and roll-back.
The MSDN article Registry Policy File Format provides some details.
Note: Windows 10 20H2 was used here.
Start the Command Processor
Cmd.exe
, then execute
the following command lines to export the registry keys
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies
and HKEY_CURRENT_USER\Software\Policies
of an arbitrary
user account and display them:
REG.EXE EXPORT "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies" blunder.reg TYPE blunder.reg REG.EXE EXPORT "HKEY_CURRENT_USER\Software\Policies" blunder.reg /Y TYPE blunder.regNote: the command lines can be copied and pasted as block into a Command Processor window.
The operation completed successfully.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
"NoDriveTypeAutoRun"=dword:00000091
The operation completed successfully.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Policies]
[HKEY_CURRENT_USER\Software\Policies\Microsoft]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\CA]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\CA\Certificates]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\CA\CRLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\CA\CTLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\Disallowed]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\Disallowed\Certificates]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\Disallowed\CRLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\Disallowed\CTLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\trust]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\trust\Certificates]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\trust\CRLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\trust\CTLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\Certificates]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CRLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CTLs]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CloudContent]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\Cache]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Cache]
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\DataCollection]
[HKEY_CURRENT_USER\Software\Policies\Power]
[HKEY_CURRENT_USER\Software\Policies\Power\PowerSettings]
Export the respective registry keys of the builtin
NT AUTHORITY\SYSTEM
alias
LocalSystem
user account and display them:
REG.EXE EXPORT "HKEY_USERS\S-1-5-18\Software\Policies" blunder.reg /Y TYPE blunder.reg
The operation completed successfully. Windows Registry Editor Version 5.00 [HKEY_USERS\S-1-5-18\Software\Policies] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\CA] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\CA\Certificates] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\CA\CRLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\CA\CTLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\Disallowed] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\Disallowed\Certificates] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\Disallowed\CRLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\Disallowed\CTLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\trust] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\trust\Certificates] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\trust\CRLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\trust\CTLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\TrustedPeople] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\Certificates] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CRLs] [HKEY_USERS\S-1-5-18\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CTLs]
Export the respective registry keys of the
NT AUTHORITY\LOCAL SERVICE
alias
LocalService
,
user account and display them:
REG.EXE EXPORT "HKEY_USERS\S-1-5-19\Software\Policies" blunder.reg /Y TYPE blunder.regNote: this operation requires administrative access rights!
The operation completed successfully. Windows Registry Editor Version 5.00 [HKEY_USERS\S-1-5-19\Software\Policies] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows\CurrentVersion] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\Cache] [HKEY_USERS\S-1-5-19\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Cache] [HKEY_USERS\S-1-5-19\Software\Policies\Power] [HKEY_USERS\S-1-5-19\Software\Policies\Power\PowerSettings]
Export the respective registry keys of the
NT AUTHORITY\NETWORK SERVICE
alias
NetworkService
,
user account and display them:
REG.EXE EXPORT "HKEY_USERS\S-1-5-20\Software\Policies" blunder.reg /Y TYPE blunder.regNote: this operation requires administrative access rights!
The operation completed successfully. Windows Registry Editor Version 5.00 [HKEY_USERS\S-1-5-20\Software\Policies] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\CA] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\CA\Certificates] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\CA\CRLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\CA\CTLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\Disallowed] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\Disallowed\Certificates] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\Disallowed\CRLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\Disallowed\CTLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\trust] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\trust\Certificates] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\trust\CRLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\trust\CTLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\TrustedPeople] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\Certificates] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CRLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\SystemCertificates\TrustedPeople\CTLs] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows\CurrentVersion] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\Cache] [HKEY_USERS\S-1-5-20\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Cache] [HKEY_USERS\S-1-5-20\Software\Policies\Power] [HKEY_USERS\S-1-5-20\Software\Policies\Power\PowerSettings]
Export the registry keys
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies
and HKEY_LOCAL_MACHINE\SOFTWARE\Policies
of the
machine and display them:
REG.EXE EXPORT "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies" blunder.reg /Y TYPE blunder.reg REG.EXE EXPORT "HKEY_LOCAL_MACHINE\SOFTWARE\Policies" blunder.reg /Y TYPE blunder.reg
The operation completed successfully. Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\ActiveDesktop] "NoAddingComponents"=dword:00000001 "NoComponents"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Attachments] "ScanWithAntiVirus"=dword:00000003 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection\Users] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer] "ForceActiveDesktopOn"=dword:00000000 "NoActiveDesktop"=dword:00000001 "NoActiveDesktopChanges"=dword:00000001 "NoRecentDocsHistory"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Ext] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Ext\CLSID] "{1FD49718-1D00-4B19-AF5F-070AF6D5D54C}"="1" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\NonEnum] "{0DF44EAA-FF21-4412-828E-260A8728E7F1}"=dword:00000020 "{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}"=dword:40000021 "{BDEADF00-C265-11D0-BCED-00A0C90AB50F}"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing] "CountryCode"="EN" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System] "ConsentPromptBehaviorAdmin"=dword:00000005 "ConsentPromptBehaviorUser"=dword:00000003 "DSCAutomationHostEnabled"=dword:00000002 "EnableCursorSuppression"=dword:00000001 "EnableFullTrustStartupTasks"=dword:00000002 "EnableInstallerDetection"=dword:00000001 "EnableLUA"=dword:00000001 "EnableSecureUIAPaths"=dword:00000001 "EnableUIADesktopToggle"=dword:00000000 "EnableUwpStartupTasks"=dword:00000002 "EnableVirtualization"=dword:00000001 "PromptOnSecureDesktop"=dword:00000001 "SupportFullTrustStartupTasks"=dword:00000001 "SupportUwpStartupTasks"=dword:00000001 "ValidateAdminCodeSignatures"=dword:00000000 "dontdisplaylastusername"=dword:00000000 "legalnoticecaption"="" "legalnoticetext"="" "scforceoption"=dword:00000000 "shutdownwithoutlogon"=dword:00000001 "undockwithoutlogon"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\UIPI] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\UIPI\Clipboard] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\UIPI\Clipboard\ExceptionFormats] "CF_BITMAP"=dword:00000002 "CF_DIB"=dword:00000008 "CF_DIBV5"=dword:00000011 "CF_OEMTEXT"=dword:00000007 "CF_PALETTE"=dword:00000009 "CF_TEXT"=dword:00000001 "CF_UNICODETEXT"=dword:0000000d The operation completed successfully. Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography\Configuration] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Peernet] "Disabled"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\CA] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\CA\Certificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\CA\CRLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\CA\CTLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Disallowed] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Disallowed\Certificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Disallowed\CRLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Disallowed\CTLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Root] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\Certificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\CRLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\CTLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\trust] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\trust\Certificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\trust\CRLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\trust\CTLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\TrustedPeople] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\TrustedPeople\Certificates] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\TrustedPeople\CRLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\TrustedPeople\CTLs] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\TPM] "OSManagedAuthLevel"=dword:00000005 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Appx] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\BITS] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings] "CallLegacyWCMPolicies"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Cache] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DataCollection] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DriverSearching] "DriverUpdateWizardWuSearchEnabled"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EnhancedStorageDevices] "TCGSecurityActivationDisabled"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Network Connections] "NC_PersonalFirewallConfig"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\NetworkConnectivityStatusIndicator] @="" [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\NetworkProvider] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\NetworkProvider\HardenedPaths] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\safer] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers] "authenticodeenabled"=dword:00000000 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\SettingSync] "EnableBackupForWin8Apps"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WcmSvc] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WcmSvc\GroupPolicy] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WcmSvc\Local] "WCMPresent"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WorkplaceJoin] @="" [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WSDAPI] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WSDAPI\Discovery Proxies] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\Policy Manager] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services] [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\Client] "fEnableUsbBlockDeviceBySetupClass"=dword:00000001 "fEnableUsbNoAckIsochWriteToDevice"=dword:00000050 "fEnableUsbSelectDeviceByInterface"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\Client\UsbBlockDeviceBySetupClasses] "1000"="{3376f4ce-ff8d-40a2-a80f-bb4359d1415c}" [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\Client\UsbSelectDeviceByInterfaces] "1000"="{6bdd1fc6-810f-11d0-bec7-08002be2092f}" [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Windows File Protection] "KnownDllList"="nlhtml.dll"
Windows supports long file names up to 255 characters in length. Windows also generates an MS-DOS-compatible (short) file name in 8.3 format to allow MS-DOS-based or 16-bit Windows-based programs to access the files.The MSKB article 896458 states:
The x64-based versions of Windows don't support 16-bit programs, 16-bit processes, or 16-bit components.121007 210638 226403 Windows components installed on demand Microsoft but ships the installation media for
shortfile names in the system images!
Note: the installation media of
Windows 7 have no 8.3 alias
short
file names in their system images – disabling 8.3
file name generation on the target drive before running the setup
program is therefore sufficient to perform a clean
installation!
shortfile and directory names on a current, preferable fresh installation of Windows 10 or Windows 11.
Start the Command Processor
Cmd.exe
, then execute
the following command lines:
VER 1>blunder.log ( FOR /D /R "%SystemDrive%\" %? IN (*) DO @IF NOT "%~nx?" == "%~snx?" ECHO "%~dp?%~snx?" ) FIND.EXE /C /V "" blunder.log 1>blunder.txt ( FOR /R "%SystemDrive%\" %? IN (*) DO @IF NOT "%~nx?" == "%~snx?" ECHO "%~dp?%~snx?" ) FIND.EXE /C /V "" blunder.txtNote: the command lines can be copied and pasted as block into a Command Processor window.
Caveat: the command lines miss hidden
directories and files as well as directories and files with short
name equal to their long name!
Caveat: unless run under the
NT AUTHORITY\SYSTEM
alias
LocalSystem
user account or with the privilege SeBackupPrivilege
enabled the command lines also miss subdirectories and files in all
directories without List Directory
access
permission for the current user account!
Microsoft Windows [Version 10.0.26100.1742] ---------- blunder.log: 16034 ---------- blunder.txt: 55140
Start the Command Processor
Cmd.exe
with
administrative access rights, then repeat the previous step:
Microsoft Windows [Version 10.0.26100.1742] ---------- blunder.log: 18206 ---------- blunder.txt: 66172
Finally execute the following command line:
FSUTIL.EXE 8dot3name scan /l "%TMP%\blunder.log" /s "%SystemDrive%\\"
Scanning registry... Total affected registry keys: 222 Scanning 8dot3 names... Total files and directories scanned: 148550 Total 8dot3 names found: 84138 Total 8dot3 names stripped: 0 For details on the operations performed please see the log: "C:\Users\ADMINI~1\AppData\Local\Temp\blunder.log"Note: all (here: 222) enumerated registry keys (really: registry entries) are false positives –
FSUtil.exe
(really: its most obviously incompetent developer) considers file
names like $WINDOWS.~BT
and
Clipchamp.Clipchamp_3.0.10220.0_neutral_~_yxz26nhyzhsrt
just due to the ~
to be short!
32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32. WOW64 recognizes Sysnative as a special alias used to indicate that the file system should not redirect the access. This mechanism is flexible and easy to use, therefore, it is the recommended mechanism to bypass file system redirection. Note that 64-bit applications cannot use the Sysnative alias as it is a virtual directory not a real one.
FSUtil.exe
console application to enumerate
hardlinks of files residing in the native system directory.
Start the Command Processor
Cmd.exe
with
administrative access rights, then execute the following single
command line:
IF EXIST "%SystemRoot%\SysWoW64\FSUtil.exe" "%SystemRoot%\SysWoW64\FSUtil.exe" HARDLINK LIST "%SystemRoot%\Sysnative\NTDLL.dll"
Error: The parameter is incorrect.
OUCH: the File System Utilityhas one job, but fails to interact with the File System Redirector!
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.
as iswithout any warranty, neither express nor implied.
cookiesin the web browser.
The web service is operated and provided by
Telekom Deutschland GmbH 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):