Artof Computer Programming
Note: some cases of desinformation presented below were published 25 (in words: twenty-five) years ago and never corrected!
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, the Windows Software Development Kit 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 WTF
DWORD dwCount;
LPWSTR *lpArray;
LONG ntStatus = NetEnumerateServiceAccounts((LPWSTR) NULL,
0UL,
&dwCount,
&lpArray);
#elif WTF == 1
BOOL wtf;
LPBYTE lpBuffer;
LONG ntStatus = -NetIsServiceAccount((LPWSTR) NULL,
(LPWSTR) NULL,
&wtf);
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=/DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE lmaccess.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.
lmaccess.c
Microsoft (R) Incremental Linker Version 10.00.40219.386
Copyright (C) Microsoft Corporation. All rights reserved.
/DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE
/out:lmaccess.exe
lmaccess.obj
lmaccess.obj : error LNK2019: unresolved external symbol _NetEnumerateServiceAccounts referenced in function _mainCRTStartup@0
lmaccess.exe : fatal error LNK1120: 1 unresolved externals
OUCH²: most obviously nobody
at Microsoft tests or uses their own
The undecorated symbol name
_NetEnumerateServiceAccounts
in the error message
indicates 2 omissions bugs in
the declaration of the function prototype for
NetEnumerateServiceAccounts()
in the header file lmaccess.h
: the
mandatory calling convention
__stdcall
and the (optional) storage class attribute
__declspec
(dllimport)
are missing!
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
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj
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
WTF
defined:
CL.EXE /DWTF lmaccess.c
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj lmaccess.obj : error LNK2019: unresolved external symbol _NetIsServiceAccount referenced in function _mainCRTStartup@0 lmaccess.obj : error LNK2019: unresolved external symbol _NetQueryServiceAccount referenced in function _mainCRTStartup@0 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 /DWTF /Gz lmaccess.c
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj
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
WTF
defined as 0:
CL.EXE /DWTF=0 lmaccess.c
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj lmaccess.obj : error LNK2019: unresolved external symbol _NetAddServiceAccount referenced in function _mainCRTStartup@0 lmaccess.obj : error LNK2019: unresolved external symbol _NetRemoveServiceAccount referenced in function _mainCRTStartup@0 lmaccess.exe : fatal error LNK1120: 2 unresolved externalsOUCH⁶: the declarations of the function prototypes for
NetAddServiceAccount()
and
NetRemoveServiceAccount()
are as faulty as these for
NetEnumerateServiceAccounts()
,
NetIsServiceAccount()
and
NetQueryServiceAccount()
!
Repeat the previous step 10., now with the
/Gz
compiler option too:
CL.EXE /DWTF=0 /Gz lmaccess.c
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:netapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:lmaccess.exe lmaccess.obj
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, the Windows Software Development Kit 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=/DEFAULTLIB:kernel32.lib /DEFAULTLIB:advapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE ntsecapi.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. ntsecapi.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:advapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:ntsecapi.exe ntsecapi.obj ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction041 referenced in function _mainCRTStartup@0 ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction040 referenced in function _mainCRTStartup@0 ntsecapi.obj : error LNK2019: unresolved external symbol _SystemFunction036 referenced in function _mainCRTStartup@0 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
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. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:advapi32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:ntsecapi.exe ntsecapi.obj
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) -- 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=/DEFAULTLIB:loadperf.lib /DLL /NOENTRY CL.EXE loadperf.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. 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. /DEFAULTLIB:loadperf.lib /DLL /NOENTRY /out:loadperf.exe loadperf.objOOPS: 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, the Windows Software Development Kit 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=/DEFAULTLIB:wintrust.lib /DLL /NOENTRY CL.EXE mscat.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. 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. /DEFAULTLIB:wintrust.lib /DLL /NOENTRY /out:mscat.exe mscat.objOOPS: 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, the Windows Software Development Kit 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=/DEFAULTLIB:wintrust.lib /DLL /NOENTRY CL.EXE wintrust.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. 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. /DEFAULTLIB:wintrust.lib /DLL /NOENTRY /out:wintrust.exe wintrust.objOOPS: contrary to their documentation all functions can be linked statically with their import library
wintrust.lib
!
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 wtf.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, "WTF?", 4UL, NULL, (LPOVERLAPPED) NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file wtf.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:wtf.exe wtf.obj
Execute the console application wtf.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 .\wtf.exe ECHO %ERRORLEVEL%
Microsoft Windows [Version 6.1.7601] WTF? 0OOPS: contrary to the highlighted statement of the documentation cited above, lpNumberOfBytesWritten can be
NULL
on Windows 7!
_chkstk()
states since more than 20 years:
_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 compilers is but 4096 too; 8192
The documentation for the
/Gs
compiler option states:
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.By 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.
_alloca()
states since more than 20 years:
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!
Create the text file wtf.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
wtf 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
wtf endp
end wtf ; writes "/ENTRY:wtf" to '.drectve' section
Assemble and link the source file wtf.asm
created in
step 1.:
SET ML=/W3 /X SET LINK=/SUBSYSTEM:CONSOLE ML.EXE wtf.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: wtf.asm Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /SUBSYSTEM:CONSOLE /OUT:wtf.exe wtf.obj
Execute the console application wtf.exe
built in
step 2. to show that 231 is equal 0:
VER .\wtf.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
!
Overwrite the text file wtf.asm
created in step 1.
with the following content:
; Copyleft © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
.code
wtf 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
wtf endp
end
Assemble and link the source file wtf.asm
modified in
step 4.:
SET ML=/W3 /X SET LINK=/ENTRY:wtf /SUBSYSTEM:CONSOLE ML64.EXE wtf.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: wtf.asm Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:wtf /SUBSYSTEM:CONSOLE /OUT:wtf.exe wtf.obj
Execute the console application wtf.exe
built in
step 5. to show that 263 is equal 0:
VER .\wtf.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
!
If you have the
Debugging Tools for Windows installed,
execute the console applications wtf.exe
built in
step 1. and step 5. under the debugger:
NTSD.EXE .\wtf.exeNote: if necessary, see the MSDN article Debugging Using CDB and NTSD for an introduction.
Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\wtf.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): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=00000000 ecx=ed9b0000 edx=0022e038 esi=fffffffe edi=00000000 eip=77a610a6 esp=001bf414 ebp=001bf440 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!LdrpDoDebuggerBreak+0x2c: 77a610a6 cc int 3 0:000> g (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 *** WARNING: Unable to verify checksum for image00ee0000 *** ERROR: Module load completed but symbols could not be loaded for image00ee0000 image00ee0000+0x1009: 00ee1009 f7f1 div eax,ecx 0:000> q quit:Oops: also notice the slew of unreferenced DLLs loaded with
Create the text file wtf.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 wtf.c
created in
step 8.:
SET CL=/Oisy /W4 /Zl SET LINK=/ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE wtf.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. wtf.c Microsoft (R) Incremental Linker Version 19.20.27004.0 Copyright (C) Microsoft Corporation. All rights reserved. /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:wtf.exe wtf.obj
Execute the console application wtf.exe
built in
step 9. to prove that 231 as well as
263 are equal 0:
.\wtf.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
!
Cmd.exe
supports arithmetic
operations with its builtin
Set
command.
Using command redirection operators
Using command redirection operators
Start the Command Processor and execute the following 4 command lines to show the first stupid bug:
SET /A -2147483648 SET /A ~2147483647 SET /A ~2147483647 / -1 SET /A ~2147483647 % -1
Invalid number. Numbers are limited to 32-bits of precision. -2147483648 Invalid number. Numbers are limited to 32-bits of precision.Oops: although valid, a literal −2147483648, the smallest signed 32-bit integer, is reported as
invalid number.
OUCH¹: on systems with i386 or AMD64 processor, the Command Processor crashes computing the modulus of −2147483648 ÷ −1 (which happens to be 0, the only number smaller in magnitude than the divisor −1)!
Note: dividing −2147483648, the smallest
signed 32-bit integer, by −1 yields the quotient 2147483648,
which is but not representable as signed 32-bit
integer and therefore produces an overflow (really: raises a
divide error exception
alias #DE
) that the
Command Processor fails to handle, i.e.
neither prevents nor catches for the modulus operator, while it does
so for the division operator!
Note: integer overflow and failure to catch the eventually resulting exception are well-known weaknesses, documented as CWE-190: Integer Overflow or Wraparound and CWE-248: Uncaught Exception in the CWE™; they allow well-known attacks like CAPEC-92: Forced Integer Overflow documented in the CAPEC™.
Start the Command Processor and execute the following 8 command lines to show surprising behaviour as well as the second stupid bug:
SET COMSPEC=. EXIT | EXIT SET COMSPEC=wtf EXIT | EXIT SET PATHEXT= EXIT | EXIT SET COMSPEC= EXIT | EXIT
'.' is not recognized as an internal or external command, operable program or batch file. '.COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC' is not recognized as an internal or external command, operable program or batch file. '' is not recognized as an internal or external command, operable program or batch file.OUCH²: the Command Processor crashes with an access violation reading address
0x00000000
when an arbitrary
builtin command is run in a pipeline and the environment variable
COMSPEC
is missing!
Note: properly implemented, the
Command Processor would not (ab)use the
value of the environment variable COMSPEC
to execute
builtin commands in the child processes of pipelines, but evaluate
its own path name with the Win32 function
GetModuleFileName()
instead!
Note: (ab)using environment variables to locate executables is a well-known weakness, documented as CWE-73: External Control of File Name or Path in the CWE™; it allows well-known attacks like CAPEC-13: Subverting Environment Variable Values documented in the CAPEC™.
Note: the crash induced by the absence of the
environment variable COMSPEC
is a
well-known weakness too, documented as
CWE-248: Uncaught Exception
and
CWE-476: NULL Pointer Dereference
in the
CWE™.
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: despite the fixed value of this offset, the Visual C compiler references the 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
on the i386
alias x86 platform.
The MSDN article PE Format continues:
The TLS directory has the following format:Note: the documentation lacks the information that the Visual C compiler puts all data for the TLS template in COFF sections
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.
.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!
OOPS: the
Raw Data End VA
field 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.
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 MSDN article /SAFESEH (Image has Safe Exception Handlers) gives the correct information:
If you link withThe specification of the PE format continues with the following desinformation:/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 /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 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
!
Remarks, the documentation of the linker option
/ENTRY:‹symbol›
states:
RemarksOuch: no prototypes are given 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.
If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether
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
main
orWinMain
is defined.The functions
main
,WinMain
, andDllMain
are the three forms of the user-defined entry point.
Create the text file wtf.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 WTF
#error
#elif WTF == 0 // DLL
int DllMain(void *module, int reason, void *context)
{
return module != context, reason == 1;
}
#elif WTF == 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 WTF == 2 // ANSI console program
int main(int argc, char *argv[], char *envp[])
{
return *envp != argv[argc];
}
#elif WTF == 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 WTF == 4 // UNICODE console program
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
return *envp != argv[argc];
}
#elif WTF == 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 WTF == 6 // ANSI Windows program
int WinMain(void *current, void *previous, char cmdline[], int show)
{
return current != previous, *cmdline != show;
}
#elif WTF == 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 WTF == 8 // UNICODE Windows program
int wWinMain(void *current, void *previous, wchar_t cmdline[], int show)
{
return current != previous, *cmdline != show;
}
#elif WTF == 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);
}
#endif // WTF
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
wtf.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 /DWTF=1 /Fodllmain.obj wtf.c CL.EXE /DWTF=3 /Fomain.obj wtf.c CL.EXE /DWTF=5 /Fowmain.obj wtf.c CL.EXE /DWTF=7 /Fowinmain.obj wtf.c CL.EXE /DWTF=9 /Fowwinmain.obj wtf.c LINK.EXE /LIB /MACHINE:I386 /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. wtf.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.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
wtf.c
created in step 1. 5 times and (try to) link
each generated object file wtf.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 /DWTF=0 /Gz /LD wtf.c CL.EXE /DWTF=2 /Gd wtf.c CL.EXE /DWTF=4 /Gd wtf.c CL.EXE /DWTF=6 /Gz wtf.c CL.EXE /DWTF=8 /Gz wtf.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.dll /dll /implib:wtf.lib wtf.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.exe wtf.obj LINK : error LNK2001: unresolved external symbol _mainCRTStartup wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.exe wtf.obj LINK : error LNK2001: unresolved external symbol _wmainCRTStartup wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.exe wtf.obj LINK : error LNK2001: unresolved external symbol _WinMainCRTStartup wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.exe wtf.obj LINK : error LNK2001: unresolved external symbol _wWinMainCRTStartup wtf.exe : fatal error LNK1120: 1 unresolved externalsOUCH: contrary to the documentation cited above, the linker expects the entry point functions for applications to be defined using the
__cdecl
calling and naming convention!
// Copyleft © 2001-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
#pragma comment
specifies:
Places a comment record into an object file or executable file.OUCH: the highlighted statement is misleading and wrong, the 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 wtf.c
with the following
content in an arbitrary, preferable empty directory:
// Copyleft © 2001-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
int wtf(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:wtf.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 wtf.c
created in
step 1.:
SET CL=/Gz /W4 /X /Zl SET LINK= CL.EXE wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /out:wtf.exe wtf.obj wtf.obj : warning LNK4070: /OUT:wtf.dll directive in .EXP differs from output filename 'wtf.exe'; ignoring directive wtf.obj : warning LNK4229: invalid directive '/VERBOSE' encountered; ignored Creating library wtf.lib and object wtf.exp
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 processor
Cmd.exe
supports up to 8191 characters on the command line.
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!
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.
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 overestimated!
Note: the demonstration of this
(mis)behaviour 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
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.
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!
Note: the
Win32 error code 123 means
ERROR_INVALID_NAME
,
a repetition using the same filename is pretty useless
utter nonsense!
Command-Line Reference
HIGH32
of MASM specifies:
The documentation for the operatorReturns the low 32 bits of expression. MASM expressions are 64-bit values.HIGH32 expression
LOW32
of MASM specifies:
Returns the low 32 bits of expression. MASM expressions are 64-bit values.LOW32 expression
Create the text file wtf.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 wtf.asm
created in
step 1.:
SET ML=/c /W3 /X ML.EXE /FoNUL: wtf.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: wtf.asm wtf.asm(4) : error A2084:constant value too large wtf.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!
ExpandEnvironmentStrings()
states:
Expands environment-variable strings and replaces them with the values defined for the current user.
Create the text file wtf.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 mainCRTStartup(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 == 0)
dwError = GetLastError();
else
if (!WriteConsole(hError, szExpand, dwExpand - 1, NULL, (LPOVERLAPPED) NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file wtf.c
created in
step 1.:
SET CL=/W4 /Zl SET LINK=/DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DEFAULTLIB:kernel32.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:wtf.exe wtf.obj
Execute the console application wtf.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% .\wtf.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()
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 wtf.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 mainCRTStartup(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), NULL, (LPOVERLAPPED) NULL))
dwError = GetLastError();
ExitProcess(dwError);
}
Compile and link the source file wtf.c
created in
step 1.:
SET CL=/Oi /W4 /Zl SET LINK=/DEFAULTLIB:kernel32.lib /DEFAULTLIB:userenv.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE CL.EXE wtf.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. wtf.c Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. /DEFAULTLIB:kernel32.lib /DEFAULTLIB:userenv.lib /ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /out:wtf.exe wtf.obj
Execute the console application wtf.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 .\wtf.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()
expands (some) user environment variables when its first argument is
NULL
!
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):