In executable installation programs, which typically need or request
administrative privileges and are run from unsafe locations like the
user’s Downloads
directory or a Temp
directory
where this vulnerability is trivial to exploit, it becomes
especially dangerous.
‹filename›.dll
acts as static redirector
or transparent proxy to its corresponding target
DLL
%SystemRoot%\System32\‹filename›.dll
located in Windows’ system directory, accomplished through the relative pathname
System32\‹filename›
of the target
DLL used in the
forwarded exports.
Note: export forwarding
is a feature of
Windows’ module loader and used in quite some
Windows system
DLLs; an
application or a(nother)
DLL which
references a forwarded export receives the address of the targeted
export.
Note: while searching for DLLs specified without absolute (fully qualified) pathname, Windows’ module loader maps executable modules with matching filenames into memory, independent of their target execution environment. Upon mismatch of the execution environments it discards and unloads the modules, then continues searching.
Tempdirectory
%TMP%\
alias
%USERPROFILE%\AppData\Local\Temp\
and the
system’s Tempdirectory
%SystemRoot%\Temp\
, then wait: sooner or later a poorly
written program will be run in one of the Tempdirectories and load some of the DLLs placed there.
export forwardingis limited to target DLLs with the
.dll
file extension.
Note: to include
DLLs with file
extension .acm
, .ax
, .cpl
,
.drv
, .ime
, .ocx
,
.tsp
etc. in the testbed, for example
WinSPOOL.drv
,
MSCTFIME.ime
or HHCtrl.ocx
,
build forwarder
DLLs for them and
create hardlinks ‹filename›.dll
of the
target DLLs in
Windows’ system directory
.
ShlWAPI.dll
from Windows 7 and newer versions of
Windows NT exports SHCreateStreamWrapper
as an invalid forward to
SHUNIMPL.#UNIMPL_SHCreateStreamWrapper
!
Note:
ShUnimpl.dll
is the
graveyard
for obsolete and now unimplemented functions of
Windows’ shell
from prior versions of
Windows NT.
‹filename›.dll
with
exports
(both by name and by ordinal) forwarded to their corresponding
target DLLs
%SystemRoot%\System32\‹filename›.dll
located in Windows’ system directory, using import libraries and export files generated on the fly from the exports of the target DLLs.
For some of the details see the MSDN article Working with Import Libraries and Export Files.
Note: the forwarder DLLs are pure Win32 executables, for use on Windows XP and newer versions of Windows NT as well as Windows PE, they build without the MSVCRT libraries.
Note: the sample console output shown below every command line was produced with the Microsoft Visual C++ Compiler 2010 SP1 from update 2519277, using the header files, import libraries and utility programs from the Windows SDK v7.1.
Create the text file DLLDUMMY.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>
__declspec(dllimport)
INT WINAPI MessageBoxTimeoutA(HWND hwnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType,
WORD wLanguageId,
DWORD dwMilliseconds);
__declspec(safebuffers)
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
#ifdef REASON
static const LPCSTR szReason[4] = {"DLL_PROCESS_DETACH",
"DLL_PROCESS_ATTACH",
"DLL_THREAD_ATTACH",
"DLL_THREAD_DETACH"};
#endif
#ifdef INTERNAL
extern const IMAGE_DOS_HEADER __ImageBase;
LPCSTR szModule = "<unknown>";
IMAGE_NT_HEADERS *ntHeader = (IMAGE_NT_HEADERS *) ((LPBYTE) &__ImageBase + __ImageBase.e_lfanew);
DWORD dwRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD dwSize = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if ((dwRVA != 0) && (dwSize >= sizeof(IMAGE_EXPORT_DIRECTORY)))
{
dwRVA = ((IMAGE_EXPORT_DIRECTORY *) ((LPBYTE) &__ImageBase + dwRVA))->Name;
if (dwRVA != 0)
szModule = (LPCSTR) ((LPBYTE) &__ImageBase + dwRVA);
}
#else
CHAR szModule[MAX_PATH];
DWORD dwModule = GetModuleFileNameA(hinstDLL, szModule, sizeof(szModule));
if (dwModule == 0)
szModule[0] = '\0';
else if (dwModule >= sizeof(szModule))
szModule[sizeof(szModule) - 1] = '\0';
#endif
MessageBoxTimeoutA(HWND_DESKTOP,
#ifdef REASON
szReason[fdwReason],
#else
GetCommandLineA(),
#endif
szModule,
MB_OK | MB_ICONINFORMATION,
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
12345);
return fdwReason == DLL_PROCESS_ATTACH;
}
__declspec(dllexport)
const CHAR ASCIIString[] = "Supercalifragilisticexpialidocious";
For details and reference see the
MSDN articles
DllMain entry point
and
Dynamic-Link Library Entry-Point Function,
plus
IMAGE_NT_HEADERS structure,
IMAGE_OPTIONAL_HEADER structure
and
IMAGE_DATA_DIRECTORY structure.
Note: this program uses no C
runtime
function, it builds without the
MSVCRT
libraries!
Note: the entry-point function can have an
arbitrary name; _DllMainCRTStartup
is the default name
Link.exe
uses
for DLLs.
Note: modification of the source file
DLLDUMMY.C
to retrieve and display more or other
information than only the
DLL’s
(internal) name from its export directory
or its
(fully qualified) pathname and the reason of the call or the
process’ command line is left as an exercise to the reader.
Note: follow the guidance given in the MSDN article Dynamic-Link Library Best Practices when you modify the source code!
Compile the object file DLLDUMMY.OBJ
from the source
file DLLDUMMY.C
created in step 1.:
CL.EXE /Brepro /c /DINTERNAL /DREASON /GA /GF /GS /Gy /O1 /Os /Oy- /TcDLLDUMMY.C /W4 /ZlFor details and reference see the MSDN articles Compiler Options and Linker Options.
Note: if necessary, see the MSDN article Use the Microsoft C++ toolset from the command line for an introduction.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. DLLDUMMY.C DLLDUMMY.C(19) : warning C4100: 'lpvReserved' : unreferenced formal parameter DLLDUMMY.C(17) : warning C4100: 'hinstDLL' : unreferenced formal parameter
The following 26 optional substeps demonstrate primarily the behaviour of Windows’ module loader and are therefore hidden per default; click the view buttom to show them, or the hide buttom to hide them again.
DLLDUMMY.DLL
from the object file
DLLDUMMY.OBJ
compiled in step 2.:
LINK.EXE /LINK /BREPRO /DEFAULTLIB:USER32.LIB /DLL /DYNAMICBASE /ENTRY:_DllMainCRTStartup /EXPORT:ASCIIString,DATA /LARGEADDRESSAWARE /NOCOFFGRPINFO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:DLLDUMMY.DLL /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.OBJFor details and reference see the MSDN article Linker Options.
Note: use the value of the
/OSVERSION:
argument to indicate the targeted version
of Windows NT.
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Creating library DLLDUMMY.lib and object DLLDUMMY.exp
DLLDUMMY.DLL
linked in the preceding
substep 3. A. explicitly, implicitly calling its
entry-point function
_DllMainCRTStartup()
twice:
MSIEXEC.EXE /Y "%CD%\DLLDUMMY.DLL" REGSVR32.EXE "%CD%\DLLDUMMY.DLL" RUNDLL32.EXE "%CD%\DLLDUMMY.DLL",* DLL minesweeperFor details and reference see the MSDN article Run-Time Dynamic Linking.
Note: it’s sufficient to run just one of these command lines.
Note: on 64-bit editions of Windows,
the execution environments of DLLDUMMY.DLL
and
MSIExec.exe
must match!
Note: the error message boxes displayed from
RegSvr32.exe
and
RunDLL32.exe
are expected:
DLLDUMMY.DLL
does neither implement any of the functions
DllInstall()
,
DllRegisterServer()
and
DllUnregisterServer()
called from the
Regsvr32 tool,
nor the
Rundll32 Interface.
DLLDUMMY.COM
from the
object file DLLDUMMY.OBJ
compiled in step 2., now
without flagging it as
DLL:
LINK.EXE /LINK /BREPRO /DEFAULTLIB:USER32.LIB /DYNAMICBASE /ENTRY:_DllMainCRTStartup /EXPORT:ASCIIString,DATA /LARGEADDRESSAWARE /NOCOFFGRPINFO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:DLLDUMMY.COM /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.OBJ
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. Creating library DLLDUMMY.lib and object DLLDUMMY.exp
DLLDUMMY.COM
linked in the preceding
substep 3. C. instead of DLLDUMMY.DLL
:
MSIEXEC.EXE /Y "%CD%\DLLDUMMY.COM" REGSVR32.EXE "%CD%\DLLDUMMY.COM" RUNDLL32.EXE "%CD%\DLLDUMMY.COM",* DLL minesweeperThe executable module
DLLDUMMY.COM
is loaded, but due
to the missing DLL
flag Windows’ module loader does not call the
_DllMainCRTStartup()
entry-point function.
Note: on 64-bit editions of Windows,
the execution environments of DLLDUMMY.COM
and
MSIExec.exe
must match!
DLLDUMMY.COM
as application,
either from the command line or per double-click:
.\DLLDUMMY.COMThis should result in an
access violationexception with
NTSTATUS
0xC0000005
alias STATUS_ACCESS_VIOLATION
due to mismatch of the
entry-point functions: while
DLL entry-point
functions _DllMainCRTStartup()
have to be called with
three arguments, application entry-point functions
*MainCRTStartup()
are but called without argument(s);
the stack as well as the registers used to pass arguments contain
just arbitrary garbage.
Note: on the I386 alias x86 processor architecture, this mismatch additionally corrupts the stack upon return from the entry-point function!
DLLDUMMY.DLL
linked in substep 3. A. as
Windows application DLLDUMMY.EXE
, either
from the command line or per double-click:
COPY DLLDUMMY.DLL DLLDUMMY.EXE .\DLLDUMMY.EXE
Access denied
DLLDUMMY.C
created
in step 1. with the following content:
// Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(dllimport)
extern const CHAR ASCIIString[];
__declspec(noreturn)
VOID CDECL WinMainCRTStartup(VOID)
{
INT i = MessageBoxExA(HWND_DESKTOP,
ASCIIString,
"DLLDUMMY.EXE",
MB_OK | MB_ICONINFORMATION,
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));
ExitProcess(i);
}
Note: this program uses no Cruntime function!
Note: the entry-point function can have an
arbitrary name, WinMainCRTStartup
is just the default
name
Link.exe
uses
for Windows applications.
DLLDUMMY.TMP
from the source
file DLLDUMMY.C
overwritten in the preceding
substep 3. G.:
CL.EXE /Brepro /c /FoDLLDUMMY.TMP /GA /GF /GS /Gy /O1 /Os /Oy- /TcDLLDUMMY.C /W4 /ZlFor details and reference see the MSDN articles Compiler Options and Linker Options.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. DLLDUMMY.C
DLLDUMMY.EXE
from the object file
DLLDUMMY.TMP
compiled in the preceding
substep 3. H. and the import library
DLLDUMMY.LIB
created in substep 3. A.:
LINK.EXE /LINK /BREPRO /DEFAULTLIB:DLLDUMMY.LIB /DEFAULTLIB:KERNEL32.LIB /DEFAULTLIB:USER32.LIB /DYNAMICBASE /ENTRY:WinMainCRTStartup /LARGEADDRESSAWARE /NOCOFFGRPINFO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:DLLDUMMY.EXE /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.TMPFor details and reference see the MSDN articles Entry-Point Symbol and Linker Options.
Note: use the value of the
/OSVERSION:
argument to indicate the targeted version
of Windows NT.
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
DLLDUMMY.EXE
linked in the
preceding substep 3. I., implicitly loading and
executing the DLL
DLLDUMMY.DLL
linked in substep 3. A.:
.\DLLDUMMY.EXEFor details and reference see the MSDN article Load-Time Dynamic Linking.
Note: the
DLL’s
entry-point function
_DllMainCRTStartup()
is called before
and after the application’s entry-point
function WinMainCRTStartup()
, which displays the text
string Supercalifragilisticexpialidocious exported from
DLLDUMMY.DLL
in a message box.
DLLDUMMY.DLL
linked in substep 3. A. into
your Tempdirectory
%TMP%\
and execute the
application DLLDUMMY.EXE
linked in
substep 3. I. again:
MOVE DLLDUMMY.DLL "%TMP%" .\DLLDUMMY.EXESince the DLL
DLLDUMMY.DLL
is not found in the search path,
Windows’ module loader displays an error message
box.
Note: the error is expected and intended here!
DLLDUMMY.COM
linked in
substep 3. C. to DLLDUMMY.DLL
and execute
the application DLLDUMMY.EXE
linked in
substep 3. I. once more:
RENAME DLLDUMMY.COM DLLDUMMY.DLL .\DLLDUMMY.EXEThe application
DLLDUMMY.EXE
loads the executable
module DLLDUMMY.DLL
and displays the exported text
string Supercalifragilisticexpialidocious again.
Note: Windows’ module loader but
does not call the _DllMainCRTStartup()
entry-point
function of the executable module since it is not flagged as
DLL.
DLLDUMMY.DLL
, add your
Tempdirectory
%TMP%\
to the search path and
execute the application DLLDUMMY.EXE
again:
ERASE DLLDUMMY.DLL PATH %TMP%;%PATH% .\DLLDUMMY.EXEThe application
DLLDUMMY.EXE
loads the
DLL.
%TMP%\DLLDUMMY.DLL
and displays the exported text
string Supercalifragilisticexpialidocious again.
Note: the
DLL’s
entry-point function
_DllMainCRTStartup()
is called before
and after the application’s entry-point
function WinMainCRTStartup()
.
ASCIIString
, for example the command processor
Cmd.exe
, as
DLLDUMMY.DLL
into the current (working) directory, next
to the application DLLDUMMY.EXE
, and execute the
application DLLDUMMY.EXE
again:
COPY "%ComSpec%" DLLDUMMY.DLL .\DLLDUMMY.EXESince the symbol
ASCIIString
referenced from
DLLDUMMY.EXE
is not present in the executable module
DLLDUMMY.DLL
, Windows’ module
loader displays an error message box.
Note: the error is expected and intended here!
Note: on 64-bit editions of Windows,
the execution environments of DLLDUMMY.EXE
and
DLLDUMMY.DLL
alias
Cmd.exe
must match!
DLLDUMMY.DLL
into the current
(working) directory and execute the application
DLLDUMMY.EXE
again:
COPY /Y "%SystemRoot%\SysWoW64\Version.dll" DLLDUMMY.DLL .\DLLDUMMY.EXEThe application
DLLDUMMY.EXE
loads the
DLL
%TMP%\DLLDUMMY.DLL
and displays the exported text
string Supercalifragilisticexpialidocious again.
Note: Windows’ module loader
skips the executable module DLLDUMMY.DLL
due to its
wrong
execution environment and continues its search.
DLLDUMMY.XML
with the following
content:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="Kernel32.dll" />
<file name="User32.dll" />
</assembly>
For details and reference see the
MSDN article
Application Manifests.
Note: the file
element overrides the
search order completey, including the
Known DLLs
feature!
DLLDUMMY.XML
created in
the preceding substep 3. P. in the application
DLLDUMMY.EXE
linked in substep 3. E.:
MT.EXE /manifest DLLDUMMY.XML /outputresource:DLLDUMMY.EXE;#1
Microsoft (R) Manifest Tool version 6.1.7716.0 Copyright (c) Microsoft Corporation 2009. All rights reserved.
%TMP%\DLLDUMMY.DLL
back into the current (working)
directory and execute the application DLLDUMMY.EXE
modified in the preceding substep 3. Q.:
MOVE /Y "%TMP%\DLLDUMMY.DLL" .\DLLDUMMY.EXESince Windows’ module loader needs to load the dependent DLLs
Kernel32.dll
and
User32.dll
now only from the application directorythis fails!
Note: the error is expected and intended here!
system directoryinto the
application directory, which happens to be the current (working) directory
.
, then execute the
modified application DLLDUMMY.EXE
again:
COPY "%SystemRoot%\System32\Kernel32.dll" COPY "%SystemRoot%\System32\User32.dll" .\DLLDUMMY.EXEBypassing the search order completely, the dependent but
Known DLLs
Kernel32.dll
and
User32.dll
are loaded from the application directoryinstead from the
system directory
%SystemRoot%\System32\
!
Note: on 64-bit editions of Windows,
the execution environments of DLLDUMMY.EXE
and the
dependent DLLs must
match!
DLLDUMMY.XML
created in
substep 3. P. with the following content:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file loadFrom="%SystemDrive%\Temp\Kernel32.dll" name="Kernel32.dll" />
<file loadFrom="%SystemDrive%\Temp\User32.dll" name="User32.dll" />
</assembly>
For details and reference see the
MSDN article
Application Manifests.
Note: the loadFrom
attribute of the
file
element is not documented by
Microsoft!
DLLDUMMY.XML
overwritten in the preceding substep 3. T. in the
DLL
DLLDUMMY.DLL
linked in substep 3. A.:
MT.EXE /manifest DLLDUMMY.XML /outputresource:DLLDUMMY.DLL;#2
Microsoft (R) Manifest Tool version 6.1.7716.0 Copyright (c) Microsoft Corporation 2009. All rights reserved.
DLLDUMMY.EXE
again:
.\DLLDUMMY.EXESince Windows’ module loader can’t load the modified dependents’
DLLDUMMY.DLL
dependents
Kernel32.dll
and
User32.dll
from the absolute (fully qualified) path specified in its embedded
application manifest this fails.
Note: the error is expected and intended here!
Note: the trivial fix
is left as an exercise
to the reader!
DLLDUMMY.DLL
modified in substep 3. U.
explicitly, using applications which have the dependent
Known DLLsalready loaded from Windows’
system directory
%SystemRoot%\System32\
:
MSIEXEC.EXE /Y "%CD%\DLLDUMMY.DLL" REGSVR32.EXE "%CD%\DLLDUMMY.DLL" RUNDLL32.EXE "%CD%\DLLDUMMY.DLL",* DLL minesweeperSince Windows’ module loader can’t neither load these DLLs from the absolute (fully qualified) path specified in the embedded application manifest, nor (re)use the already loaded DLLs due to the different absolute (fully qualified) pathnames, this fails!
Note: the error is expected and intended here!
Note: the trivial fix
is again left as an
exercise to the reader!
DLLDUMMY.C
created in
step 1. with the following content:
// Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
__declspec(safebuffers)
BOOL CDECL PrintConsoleA(HANDLE hConsole, [SA_FormatString(Style="printf")] LPCSTR lpFormat, ...)
{
CHAR szOutput[1024];
DWORD dwOutput;
DWORD dwConsole;
va_list vaInput;
va_start(vaInput, lpFormat);
dwOutput = wvsprintfA(szOutput, lpFormat, vaInput);
va_end(vaInput);
if (dwOutput == 0)
return FALSE;
if (!WriteConsoleA(hConsole, szOutput, dwOutput, &dwConsole, NULL))
return FALSE;
return dwConsole == dwOutput;
}
__declspec(noreturn)
VOID CDECL mainCRTStartup(VOID)
{
DWORD dwError = ERROR_SUCCESS;
HANDLE hError = GetStdHandle(STD_ERROR_HANDLE);
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hDLL = LoadLibraryA("DLLDUMMY.DLL");
if (hDLL == NULL)
PrintConsoleA(hError,
"LoadLibrary() returned error %lu\n",
dwError = GetLastError());
else
{
PrintConsoleA(hOutput,
"LoadLibrary() returned success: DLLDUMMY.DLL loaded at address 0x%p\n",
hDLL);
if (!FreeLibrary(hDLL))
PrintConsoleA(hError,
"FreeLibrary() returned error %lu\n",
dwError = GetLastError());
}
ExitProcess(dwError);
}
Note: this program uses no Cruntime function!
Note: the entry-point function can have an
arbitrary name, mainCRTStartup
is just the default name
Link.exe
uses
for command line alias console
programs.
DLLDUMMY.TMP
from the source
file DLLDUMMY.C
overwritten in the preceding
substep 3. W.:
CL.EXE /Brepro /c /FoDLLDUMMY.TMP /GA /GF /GS /Gy /O1 /Os /Oy- /TcDLLDUMMY.C /W4 /ZlFor details and reference see the MSDN articles Compiler Options and Linker Options.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. DLLDUMMY.C
consoleprogram
DLLDUMMY.COM
from the
object file DLLDUMMY.TMP
compiled in the preceding
substep 3. X:
LINK.EXE /LINK /BREPRO /DEFAULTLIB:KERNEL32.LIB /DEFAULTLIB:USER32.LIB /DYNAMICBASE /ENTRY:mainCRTStartup /LARGEADDRESSAWARE /NOCOFFGRPINFO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:DLLDUMMY.COM /RELEASE /SUBSYSTEM:CONSOLE /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.TMPFor details and reference see the MSDN articles Entry-Point Symbol and Linker Options.
Note: use the value of the
/OSVERSION:
argument to indicate the targeted version
of Windows NT.
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
consoleprogram
DLLDUMMY.COM
linked
in the preceding substep 3. Y., attempting to load and
execute the DLL
DLLDUMMY.DLL
modified in substep 3. U.:
.\DLLDUMMY.COM
LoadLibrary() returned error 126Since Windows’ module loader can’t neither load the dependent but
Known DLLs
Kernel32.dll
and
User32.dll
from the absolute (fully qualified) path specified in the embedded
application manifest, nor (re)use these already loaded
DLLs due to the
different absolute (fully qualified) pathnames, this fails!
For the translation
of the Win32 error code, see
ERROR_MOD_NOT_FOUND
.
Note: the error is expected and intended here!
Note: the trivial fix
is again left as an
exercise to the reader!
Create the text file DLLDUMMY.CMD
with the following
content:
@Echo Off
Rem Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
Echo LIBRARY "%~n1"
Echo.
Echo EXPORTS
SetLocal EnableExtensions
For /F "Delims= Skip=16 UseBackQ" %%@ In ("%~2") Do If "%%@" == " Summary" (Exit /B) Else Call :EXPORTS "%~n1" "%%@"
EndLocal
Exit /B
:EXPORTS
Set LIBRARY=System32\%~1
Set LINE=%2
Set LINE=%LINE:<=^^^^^^^<%
Set LINE=%LINE:>=^^^^^^^>%
Set LINE=%LINE:~1,-1%
Set ORDINAL=%LINE:~4,7%
Set ORDINAL=%ORDINAL: =%
Set HINT=%LINE:~12,4%
Set RVA=%LINE:~17,8%
Set NAME=%LINE:~26%
If "%HINT%" == " " Goto :ORDINAL
If "%NAME%" == "[NONAME]" Goto :ORDINAL
If "%RVA%" == " " Goto :FORWARD
:NAME
Echo %NAME%=%LIBRARY%.%NAME% @%ORDINAL%
Goto :EOF
:ORDINAL
Echo @%ORDINAL%=%LIBRARY%.#%ORDINAL% @%ORDINAL% NONAME
Goto :EOF
:FORWARD
Set NAME=%NAME: (forwarded to ==%
Echo %NAME:~0,-1% @%ORDINAL%
Goto :EOF
For details and reference see the
MSDN articles
Rules for Module-Definition Statements,
EXPORTS
and
LIBRARY.
Note: modification of the batch script
DLLDUMMY.CMD
to target
DLLs located in
subdirectories of the system directory
is left as an exercise
to the reader.
Dump the
exports
of an arbitrary DLL
‹filename›.dll
located in
Windows’ system directory
%SystemRoot%\System32\
to the temporary text file
DLLDUMMY.TXT
:
LINK.EXE /DUMP /EXPORTS /OUT:DLLDUMMY.TXT "%SystemRoot%\System32\‹filename›.dll"
Microsoft (R) COFF/PE Dumper Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
Generate the intermediary
module definition file
DLLDUMMY.DEF
from the text file
DLLDUMMY.TXT
dumped in step 5., using the batch
script DLLDUMMY.CMD
created in step 4.:
CALL DLLDUMMY.CMD ‹filename› DLLDUMMY.TXT 1>DLLDUMMY.DEFNote: for DLLs without exports but more than 9 sections§, like the
nativeDLLs
mcupdate_AuthenticAMD.dll
and
mcupdate_GenuineIntel.dll
,
the batch script DLLDUMMY.CMD
fails to generate a valid
module definition file,
which typically results in a linker error during the next two steps;
discard such errors for nativeDLLs, as these are not loaded and executed in Win32 processes.
§ For details and reference see the MSDN articles PE Format, Peering Inside the PE: A Tour of the Win32 Portable Executable File Format, An In-Depth Look into the Win32 Portable Executable File Format and An In-Depth Look into the Win32 Portable Executable File Format, Part 2.
Build the intermediary import library DLLDUMMY.LIB
and
the intermediary export file DLLDUMMY.EXP
from the
module definition file DLLDUMMY.DEF
generated in
step 6.:
LINK.EXE /LIB /BREPRO /DEF:DLLDUMMY.DEF /NODEFAULTLIB /OUT:DLLDUMMY.LIBFor details and reference see the MSDN article Building an Import Library and Export File.
Microsoft (R) Library Manager Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved. LINK : warning LNK4068: /MACHINE not specified; defaulting to X86 Creating library DLLDUMMY.LIB and object DLLDUMMY.exp
Build the DLL
‹filename›.dll
from the object file
DLLDUMMY.OBJ
compiled in step 2., using the import
library DLLDUMMY.LIB
and the export file
DLLDUMMY.EXP
built in step 7.:
LINK.EXE /LINK /BREPRO /DEFAULTLIB:DLLDUMMY.LIB /DEFAULTLIB:USER32.LIB /DLL /DYNAMICBASE /ENTRY:_DllMainCRTStartup /LARGEADDRESSAWARE /NOCOFFGRPINFO /NXCOMPAT /OPT:REF /OSVERSION:‹major›.‹minor› /OUT:"‹filename›.dll" /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /VERSION:1.0 DLLDUMMY.OBJ DLLDUMMY.EXPFor details and reference see the MSDN articles Using an Import Library and Export File and Linker Options.
Note: use the value of the
/OSVERSION:
argument to indicate the targeted version
of Windows NT.
Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
Repeat the steps 5. through 8. for every
DLL located in
Windows’ system directory
%SystemRoot%\System32\
to build a complete minefield.
Erase all intermediary and temporary files:
ERASE DLLDUMMY.DEF DLLDUMMY.DLL DLLDUMMY.EXE DLLDUMMY.EXP DLLDUMMY.LIB DLLDUMMY.TMP DLLDUMMY.TXT DLLDUMMY.XML
Optionally sign and timestamp all forwarder DLLs built in steps 5. through 9.:
SIGNTOOL.EXE Sign /A /D "DLL Minesweeper" /DU "https://skanthak.hier-im-netz.de/minesweeper.html" /T "http://timestamp.digicert.com/" /V *.dll SIGNTOOL.EXE Sign /AS /D "DLL Minesweeper" /DU "https://skanthak.hier-im-netz.de/minesweeper.html" /FD SHA256 /TD SHA256 /TR "http://timestamp.digicert.com/" /V *.dllFor details and reference see the MSDN articles Using SignTool to Sign a File and SignTool.
makefile
DLLDUMMY.MAK
performs the (mandatory) steps 1. through 10. shown above.
inline files, localised for English and German, and needs the
icon
DLLDUMMY.ICO
.
Note: translations of the
MESSAGETABLE
and
STRINGTABLE
resources into other languages are welcome!
The enhanced variant of the forwarder
DLL displays a
message box with detailed information and writes an entry to
Windows’ Event Log, using the source
Vulnerability and Exploit Detector.
Download both files into an arbitrary, preferable empty directory, then run the following command line:
NMAKE.EXE /R /F DLLDUMMY.MAK test sign allNote: if you don’t have a code-signing certificate, omit the
sign
target!
Note: if necessary, see the MSDN article Use the Microsoft C++ toolset from the command line for an introduction.
Microsoft (R) Program Maintenance Utility Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. MC.EXE /b /c /n /u /v /z DLLDUMMY /U nm4D7E.tmp MC: Compiling nm4D7E.tmp nm4D7E.tmp(3) : warning : Redefining value of English Writing .\DLLDUMMY_GER.bin [a0000001 .. a0000001] - 688 bytes [a0000003 .. a0000003] - 1216 bytes Total of 2 messages, 1932 bytes Writing .\DLLDUMMY_ENU.bin [a0000001 .. a0000001] - 600 bytes [a0000003 .. a0000003] - 1104 bytes Total of 2 messages, 1732 bytes CL.EXE /Brepro /Bv /c /DCALLER /DEVENTLOG /DGSCOOKIE /DSOUND /DTHREAD /DUSERICON /FoDLLDUMMY.OBJ /GA /GF /GS /Gy /nologo /O1 /Os /Oy- /Tcnm4D83.tmp /W4 /Zl Compiler Passes: C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\cl.exe: Version 16.00.40219.1 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\c1.dll: Version 16.00.40219.400 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\c1xx.dll: Version 16.00.40219.400 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\c2.dll: Version 16.00.40219.449 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\link.exe: Version 10.00.40219.386 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\mspdb100.dll: Version 10.00.40219.478 C:\Program Files\Microsoft Visual Studio 10.0\VC\Bin\1033\clui.dll: Version 16.00.40219.1 nm4D83.tmp nm4D83.tmp(109) : warning C4047: 'initializing' : 'DWORD' differs in levels of indirection from 'DWORD_PTR *' nm4D83.tmp(110) : warning C4047: 'initializing' : 'DWORD' differs in levels of indirection from 'LPVOID *' nm4D83.tmp(111) : warning C4047: 'initializing' : 'DWORD' differs in levels of indirection from 'BYTE *' nm4D83.tmp(252) : warning C4201: nonstandard extension used : nameless struct/union nm4D83.tmp(613) : warning C4090: 'function' : different 'const' qualifiers nm4D83.tmp(624) : warning C4090: 'function' : different 'const' qualifiers nm4D83.tmp(816) : warning C4090: 'function' : different 'const' qualifiers RC.EXE /DUNICODE /FoDLLDUMMY.RES /L 0 /N /R /V nm4D91.tmp Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385 Copyright (C) Microsoft Corporation. All rights reserved. Using codepage 1252 as default Creating DLLDUMMY.RES RC: RCPP -CP 1252 -f .\RCa07820 -g \RDa07820 -DRC_INVOKED -D_WIN32 -pc\:/ -E -I. -I .\ -I . -I C:\Program Files\Microsoft Visual Studio 10.0\VC\Include -I C:\Program Files\Microsoft SDKs\Windows\v7.1\Include -D UNICODE C:\Program Files\Microsoft Visual Studio 10.0\VC\Include\string.h(54) : warning RC4011: identifier truncated to '_CRT_SECURE_CPP_OVERLOAD_STANDA' C:\Program Files\Microsoft Visual Studio 10.0\VC\Include\string.h(76) : warning RC4011: identifier truncated to '_CRT_SECURE_CPP_OVERLOAD_SECURE' nm4D91.tmp. Writing MESSAGETABLE:1, lang:0x7, size 1932. Writing MESSAGETABLE:1, lang:0x9, size 1732... Writing ICON:1, lang:0x0, size 9640 Writing ICON:2, lang:0x0, size 4264 Writing ICON:3, lang:0x0, size 1128 Writing GROUP_ICON:1, lang:0x0, size 48. Writing 24:1, lang:0x0, size 1249. Writing VERSION:1, lang:0x0, size 2336 Writing STRING:1, lang:0x7, size 470 Writing STRING:1, lang:0x9, size 376 CVTRES.EXE /BREPRO /NOLOGO /OUT:DLLDUMMY.CVT /READONLY DLLDUMMY.RES CVTRES : warning CVT4001: machine type not specified; assumed X86 LINK.EXE /LINK /ALLOWBIND:NO /BREPRO /DLL /DYNAMICBASE /ENTRY:_DllMainCRTStartup /LARGEADDRESSAWARE /NOCOFFGRPINFO /NODEFAULTLIB /NOLOGO /NXCOMPAT /OPT:REF /OSVERSION:5.1 /OUT:DLLDUMMY.DLL /RELEASE /SUBSYSTEM:WINDOWS /SWAPRUN:CD,NET /TEST /VERSION:1.0 DLLDUMMY.OBJ DLLDUMMY.CVT ADVAPI32.LIB KERNEL32.LIB USER32.LIB LINK : file alignment: 512, section alignment: 4096 LINK : section '.sdata' (C0000040) merged into '.data' (C0000040) LINK : section '.xdata' (40000040) merged into '.rdata' (40000040) RUNDLL32.EXE ".\DLLDUMMY.DLL",* Vulnerability and Exploit Detector SIGNTOOL.EXE Sign /A /D "Vulnerability and Exploit Detector" /DU "https://skanthak.hier-im-netz.de/minesweeper.html" /T "http://timestamp.digicert.com/" /V DLLDUMMY.DLL The following certificate was selected: Issued to: Stefan Kanthak Issued by: WEB.DE TrustCenter E-Mail Certification Authority Expires: 15.12.2018 02:16:19 SHA1 hash: 8C5B7521404177AC54131302066BB069102E830E Attempting to sign: DLLDUMMY.DLL Successfully signed and timestamped: DLLDUMMY.DLL Number of files successfully Signed: 1 Number of warnings: 0 Number of errors: 0 Call DLLDUMMY.CMD accessibilitycpl … wmiutils
minefield.
Call the PrintUIEntry
function of
PrintUI.dll
:
RUNDLL32.EXE PRINTUI.DLL,PrintUIEntry /?Note: for details and reference see the MSKB article 189105 and the TechNet article Rundll32 printui.dll,PrintUIEntry.
Call the PrintUIEntry
function of
PrintUI.dll
through the forwarder
DLL
PRINTUI.DLL
to test its proper function:
RUNDLL32.EXE "%CD%\PRINTUI.DLL",PrintUIEntry /?
Copy RunDLL32.exe
into the
minefield
, then use it to call the PrintUIEntry
function of
PrintUI.dll
located in Windows’ system directory
:
COPY "%SystemRoot%\System32\RUNDLL32.EXE" .\RUNDLL32.EXE "%SystemRoot%\System32\PRINTUI.DLL",PrintUIEntry /?Note: enjoy the
fireworks!
PrintUI.exe
into
the minefieldand execute it there:
COPY "%SystemRoot%\System32\PRINTUI.EXE" .\PRINTUI.EXENote: enjoy the
fireworks, now performed with administrative privileges and access rights!
shell, i.e. Windows Explorer, in the
minefield.
Create the text file EXEDUMMY.C
with the following
content in the directory where you built the minefield
:
// Copyright © 2004-2024, Stefan Kanthak <stefan.kanthak@nexgo.de>
#define _WIN32_WINNT 0x0500
#include <windows.h>
__declspec(noreturn)
VOID CDECL wWinMainCRTStartup(VOID)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (hr == S_OK)
hr = ShellExecuteW(NULL, NULL, L".", NULL, NULL, SW_SHOWNORMAL);
CoUninitialize();
ExitProcess(hr);
}
Note: the Win32 functions
CoInitializeEx()
,
CoUninitialize()
,
ExitProcess()
and
ShellExecute()
are provided by
Kernel32.dll
,
OLE32.dll
and
Shell32.dll
, which are
Known DLLs. The application itself and all its (static) load-time dependencies can therefore assumed to be safe.
Compile the object file EXEDUMMY.OBJ
from the source
file EXEDUMMY.C
created in step 1., then link the
application EXEDUMMY.EXE
from the object file:
CL.EXE /Zl /W4 /Ox /GAFy /c /Brepro EXEDUMMY.C LINK.EXE /BREPRO /DYNAMICBASE /ENTRY:wWinMainCRTStartup /NOCOFFGRPINFO /NODEFAULTLIB /NXCOMPAT /OPT:REF /RELEASE /SUBSYSTEM:WINDOWS EXEDUMMY.OBJ KERNEL32.LIB OLE32.LIB SHELL32.LIB
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. EXEDUMMY.C EXEDUMMY.C(13) : warning C4047: '=' : 'HRESULT' differs in levels of indirection from 'HINSTANCE' Microsoft (R) Incremental Linker Version 10.00.40219.386 Copyright (C) Microsoft Corporation. All rights reserved.
Execute the application EXEDUMMY.EXE
per double-click
and enjoy the fireworks
again!
minefield.
Download the makefile
DLLDUMMY.MAK
and the icon
DLLDUMMY.ICO
into your Temp
directory %TMP%\
:
BITSADMIN.EXE /TRANSFER MineSweeper /DOWNLOAD /PRIORITY FOREGROUND https://skanthak.hier-im-netz.de/download/DLLDUMMY.MAK "%TMP%\DLLDUMMY.MAK" https://skanthak.hier-im-netz.de/download/DLLDUMMY.ICO "%TMP%\DLLDUMMY.ICO"
Create a new directory with an arbitrary name, for example
MineSweeper\
, in the root directory of the
Windows drive:
MKDIR "%SystemDrive%\MineSweeper"
Create the subdirectory
%SystemDrive%\MineSweeper\System32\
in the empty
directory created in step 2., then copy the makefile
DLLDUMMY.MAK
and the icon
DLLDUMMY.ICO
downloaded in step 1. into the new
subdirectory:
MKDIR "%SystemDrive%\MineSweeper\System32" COPY "%TMP%\DLLDUMMY.MAK" "%SystemDrive%\MineSweeper\System32" COPY "%TMP%\DLLDUMMY.ICO" "%SystemDrive%\MineSweeper\System32"
1 file(s) copied. 1 file(s) copied.
Start the 32-bit build environment for 32-bit targets in the
subdirectory %SystemDrive%\MineSweeper\System32\
created in step 3., then build the minefield
of 32-bit
forwarder DLLs in
this subdirectory and clean up:
NMAKE.EXE /R /F DLLDUMMY.MAK all clean ERASE DLLDUMMY.*
On a 64-bit installation, rename the subdirectory
%SystemDrive%\MineSweeper\System32\
created in
step 3. to %SystemDrive%\MineSweeper\SysWoW64\
,
then create the subdirectory
%SystemDrive%\MineSweeper\System32\
and copy the
makefile
DLLDUMMY.MAK
plus the icon
DLLDUMMY.ICO
downloaded in step 1. into the new
subdirectory:
MOVE "%SystemDrive%\MineSweeper\System32" SysWoW64 MKDIR "%SystemDrive%\MineSweeper\System32" COPY "%TMP%\DLLDUMMY.MAK" "%SystemDrive%\MineSweeper\System32" COPY "%TMP%\DLLDUMMY.ICO" "%SystemDrive%\MineSweeper\System32"
1 file(s) copied. 1 file(s) copied.
On a 64-bit installation, start the 64-bit build environment for
64-bit targets in the subdirectory
%SystemDrive%\MineSweeper\System32\
created in
step 5., then build a minefield
of 64-bit
forwarder DLLs in
this subdirectory and clean up:
NMAKE.EXE /R /F DLLDUMMY.MAK all clean ERASE DLLDUMMY.*
Copy all programs %SystemRoot%\*.exe
into the
subdirectory %SystemDrive%\MineSweeper\System32\
:
COPY "%SystemRoot%\*.exe" "%SystemDrive%\MineSweeper\System32"
13 file(s) copied.
On a 64-bit installation, create hardlinks of
copy all files %SystemRoot%\SysWoW64\*
which
are missing in the subdirectory
%SystemDrive%\MineSweeper\SysWoW64\
, and create
junctions to all subdirectories %SystemRoot%\SysWoW64\*
in the subdirectory
%SystemDrive%\MineSweeper\SysWoW64\
:
FOR %? IN ("%SystemRoot%\SysWoW64\*") DO @IF NOT EXIST "%SystemDrive%\MineSweeper\SysWoW64\%~nx?" MKLINK /H "%SystemDrive%\MineSweeper\SysWoW64\%~nx?" "%~?" 2>NUL: || COPY "%~?" "%SystemDrive%\MineSweeper\SysWoW64\%~nx?" FOR /D %? IN ("%SystemRoot%\SysWoW64\*") DO @MKLINK /J "%SystemDrive%\MineSweeper\SysWoW64\%~nx?" "%~?"
1 file(s) copied. … 1 file(s) copied. Junction created for C:\MineSweeper\SysWoW64\… <<===>> C:\Windows\SysWoW64\… … Junction created for C:\MineSweeper\SysWoW64\… <<===>> C:\Windows\SysWoW64\…
Create hardlinks of Copy all files
%SystemRoot%\System32\*
which are missing in the
subdirectory %SystemDrive%\MineSweeper\System32\
, and
create junctions to all subdirectories
%SystemRoot%\System32\*
in the subdirectory
%SystemDrive%\MineSweeper\System32\
:
FOR %? IN ("%SystemRoot%\System32\*") DO @IF NOT EXIST "%SystemDrive%\MineSweeper\System32\%~nx?" MKLINK /H "%SystemDrive%\MineSweeper\System32\%~nx?" "%~?" 2>NUL: || COPY "%~?" "%SystemDrive%\MineSweeper\System32\%~nx?" FOR /D %? IN ("%SystemRoot%\System32\*") DO @MKLINK /J "%SystemDrive%\MineSweeper\System32\%~nx?" "%~?"
1 file(s) copied. … 1 file(s) copied. Junction created for C:\MineSweeper\System32\… <<===>> C:\Windows\System32\… … Junction created for C:\MineSweeper\SysWoW64\… <<===>> C:\Windows\SysWoW64\…
Create hardlinks of Copy all files
%SystemRoot%\*
which are missing in the directory
%SystemDrive%\MineSweeper\
, and create junctions to all
subdirectories %SystemRoot%\*
which are missing in the
directory %SystemDrive%\MineSweeper\
:
FOR %? IN ("%SystemRoot%\*") DO @IF NOT EXIST "%SystemDrive%\MineSweeper\%~nx?" MKLINK /H "%SystemDrive%\MineSweeper\%~nx?" "%~?" 2>NUL: || COPY "%~?" "%SystemDrive%\MineSweeper\%~nx?" FOR /D %? IN ("%SystemRoot%\*") DO @IF NOT EXIST "%SystemDrive%\MineSweeper\%~nx?" MKLINK /J "%SystemDrive%\MineSweeper\%~nx?" "%~?"
1 file(s) copied. … 1 file(s) copied. Junction created for C:\MineSweeper\… <<===>> C:\Windows\… … Junction created for C:\MineSweeper\… <<===>> C:\Windows\…
Start arbitrary programs, especially those copied from the
subdirectories %SystemRoot%\System32\
and
%SystemRoot%\SysWoW64\
plus the directory
%SystemRoot%\
into the subdirectories
%SystemDrive%\MineSweeper\System32\
and
%SystemDrive%\MineSweeper\SysWoW64\
plus the directory
%SystemDrive%\MineSweeper\
, those registered in the
Start Menu
and those which request elevation, perform
arbitrary actions like …, and notice which programs or
actions yield the message box shown above!
Optionally set the user environment variable SystemRoot
to the value %SystemDrive%\MineSweeper
and repeat the
previous step 11.:
SETX.EXE SystemRoot "%SystemDrive%\MineSweeper"
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):