SafeDLLPath.pas 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. unit SafeDLLPath;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. To provide protection against "DLL preloading" attacks, this unit calls
  8. SetDefaultDllDirectories. SetDefaultDllDirectories is available on Windows 8
  9. and newer, and on previous versions that have the KB2533623 update installed.
  10. If SetDefaultDllDirectories is not available:
  11. -It calls SetDllDirectory('') to prevent LoadLibrary from searching the current
  12. directory for DLLs.
  13. -It then preloads a list of system DLLs which are known to be loaded unsafely
  14. by older or unpatched versions of Windows.
  15. Also see:
  16. -http://wixtoolset.org/development/wips/5184-burn-clean-room/
  17. -https://github.com/firegiant/wix3/blob/master/src/libs/dutil/apputil.cpp
  18. -https://github.com/firegiant/wix3/blob/master/src/burn/stub/stub.cpp
  19. -https://sourceforge.net/p/nsis/code/HEAD/tree/NSIS/trunk/Source/exehead/Main.c
  20. It also calls SetSearchPathMode to enable "safe search mode", which causes
  21. SearchPath, and callers of SearchPath such as CreateProcess, to search the
  22. current directory after the system directories (rather than before).
  23. Finally, it calls SetProcessDEPPolicy (where available) to enable DEP for
  24. the lifetime of the process. (This has nothing to do with search paths;
  25. it's just convenient to put the call here.)
  26. This unit should be listed at the top of the program's "uses" clause to
  27. ensure that it runs prior to any LoadLibrary calls that other units might
  28. make during their initialization. (The System unit will always initialize
  29. first, though.)
  30. }
  31. interface
  32. implementation
  33. uses
  34. Windows;
  35. const
  36. LOAD_LIBRARY_SEARCH_SYSTEM32 = $00000800;
  37. BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE = $00000001;
  38. BASE_SEARCH_PATH_PERMANENT = $00008000;
  39. PROCESS_DEP_ENABLE = $00000001;
  40. var
  41. KernelModule: HMODULE;
  42. SystemDir: String;
  43. SetDefaultDllDirectoriesFunc: function(DirectoryFlags: DWORD): BOOL; stdcall;
  44. DidSetDefaultDllDirectories: Boolean;
  45. SetDllDirectoryFunc: function(lpPathName: PWideChar): BOOL; stdcall;
  46. SetSearchPathModeFunc: function(Flags: DWORD): BOOL; stdcall;
  47. SetProcessDEPPolicyFunc: function(dwFlags: DWORD): BOOL; stdcall;
  48. function StrPas(Str: PChar): string;
  49. begin
  50. Result := Str;
  51. end;
  52. function GetSystemDir: String;
  53. var
  54. Buf: array[0..MAX_PATH-1] of Char;
  55. begin
  56. GetSystemDirectory(Buf, SizeOf(Buf) div SizeOf(Buf[0]));
  57. Result := StrPas(Buf);
  58. end;
  59. function SafeLoadLibrary(const Filename: String): HMODULE;
  60. var
  61. SaveErrorMode: UINT;
  62. SaveFPUControlWord: Word;
  63. begin
  64. SaveErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  65. try
  66. SaveFPUControlWord := Get8087Cw;
  67. try
  68. Result := LoadLibrary(PChar(Filename));
  69. finally
  70. Set8087Cw(SaveFPUControlWord);
  71. end;
  72. finally
  73. SetErrorMode(SaveErrorMode);
  74. end;
  75. end;
  76. initialization
  77. KernelModule := GetModuleHandle(kernel32);
  78. DidSetDefaultDllDirectories := False;
  79. SetDefaultDllDirectoriesFunc := GetProcAddress(KernelModule, PAnsiChar('SetDefaultDllDirectories'));
  80. if Assigned(SetDefaultDllDirectoriesFunc) then
  81. DidSetDefaultDllDirectories := SetDefaultDllDirectoriesFunc(LOAD_LIBRARY_SEARCH_SYSTEM32);
  82. if not DidSetDefaultDllDirectories then begin
  83. SetDllDirectoryFunc := GetProcAddress(KernelModule, PAnsiChar('SetDllDirectoryW'));
  84. if Assigned(SetDllDirectoryFunc) then
  85. SetDllDirectoryFunc('');
  86. SystemDir := GetSystemDir;
  87. if SystemDir <> '' then begin
  88. if SystemDir[Length(SystemDir)] <> '\' then
  89. SystemDir := SystemDir + '\';
  90. //list of system dlls to preload including source:
  91. // NSIS: Vista: OleInitialize calls NtUserCreateWindowEx and that pulls in UXTheme.dll
  92. SafeLoadLibrary(SystemDir + 'uxtheme.dll');
  93. // NSIS: Vista: SHGetFileInfo ends up in SHELL32.kfapi::GetUserProfileDir and that pulls in UserEnv.dll
  94. SafeLoadLibrary(SystemDir + 'userenv.dll');
  95. // NSIS: XP: SHGetFileInfo ends up in CMountPoint::_InitLocalDriveHelper and that pulls in SetupAPI.dll
  96. SafeLoadLibrary(SystemDir + 'setupapi.dll');
  97. // NSIS: Vista: SHGetFileInfo ... SHELL32.SHILAliasTranslate ... SHELL32.ApphelpCheckShellObject;
  98. SafeLoadLibrary(SystemDir + 'apphelp.dll');
  99. // NSIS: Vista: SHGetFileInfo ... SHELL32.SHILAliasTranslate ... SHLWAPI.#187 ... SHLWAPI.#505/SHPropertyBag_ReadGUID
  100. SafeLoadLibrary(SystemDir + 'propsys.dll');
  101. // NSIS: Win7 without KB2533623: UXTheme pulls in DWMAPI.dll
  102. // Mail: Windows 7 SP1: combase.dll -> ole32.dll -> shell32.dll -> dwmapi.dll
  103. SafeLoadLibrary(SystemDir + 'dwmapi.dll');
  104. // NSIS: Win7 without KB2533623: OleInitialize ... RPCRT4.UuidCreate ... RPCRT4.GenerateRandomNumber
  105. // Mail: oleaut32.dll -> rpcrt4.dll -> cryptbase.dll
  106. SafeLoadLibrary(SystemDir + 'cryptbase.dll');
  107. // NSIS: Vista: SHFileOperation ... SHELL32.CProgressDialogUI::_Setup ... SHELL32.GetRoleTextW
  108. SafeLoadLibrary(SystemDir + 'oleacc.dll');
  109. // Mail: Windows 7 SP1: oleaut32.dll -> ole32.dll -> crypt32.dll -> version.dll
  110. // WIX3: required by Burn
  111. SafeLoadLibrary(SystemDir + 'version.dll');
  112. // Mail: Windows 7 SP1: oleaut32.dll -> ole32.dll -> crypt32.dll -> profapi.dll
  113. SafeLoadLibrary(SystemDir + 'profapi.dll');
  114. // WIX3: required by CLSIDFromProgID() when loading clbcatq.dll
  115. SafeLoadLibrary(SystemDir + 'comres.dll');
  116. // WIX3: required by CLSIDFromProgID() when loading msxml?.dll
  117. // NSIS: XP.SP2&SP3: SHAutoComplete ... OLE32!InitializeCatalogIfNecessary ... OLE32!CComCatalog::TryToLoadCLB
  118. SafeLoadLibrary(SystemDir + 'clbcatq.dll');
  119. // NSIS: Win7 without KB2533623: SHGetFileInfo ... SetEntriesInAcl ... ADVAPI32!AccProvpLoadMartaFunctions
  120. SafeLoadLibrary(SystemDir + 'ntmarta.dll');
  121. {
  122. // WIX3: required by Burn
  123. SafeLoadLibrary(SystemDir + 'cabinet.dll');
  124. // WIX3: required by Burn
  125. SafeLoadLibrary(SystemDir + 'msi.dll');
  126. // WIX3: required by Burn
  127. SafeLoadLibrary(SystemDir + 'wininet.dll');
  128. // WIX3: required by DecryptFile() when loading crypt32.dll
  129. SafeLoadLibrary(SystemDir + 'msasn1.dll');
  130. // WIX3: required by DecryptFile() when loading feclient.dll
  131. SafeLoadLibrary(SystemDir + 'crypt32.dll');
  132. // WIX3: unsafely loaded by DecryptFile()
  133. SafeLoadLibrary(SystemDir + 'feclient.dll');
  134. }
  135. end;
  136. end;
  137. SetSearchPathModeFunc := GetProcAddress(KernelModule, PAnsiChar('SetSearchPathMode'));
  138. if Assigned(SetSearchPathModeFunc) then
  139. SetSearchPathModeFunc(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE or
  140. BASE_SEARCH_PATH_PERMANENT);
  141. SetProcessDEPPolicyFunc := GetProcAddress(KernelModule, PAnsiChar('SetProcessDEPPolicy'));
  142. if Assigned(SetProcessDEPPolicyFunc) then
  143. SetProcessDEPPolicyFunc(PROCESS_DEP_ENABLE);
  144. end.