diff --git a/Docs/src/history.but b/Docs/src/history.but index 5a767f2c..a37485b0 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -12,7 +12,7 @@ Released on ? ?th, 201? \b FileReadUTF16LE now skips the optional BOM at the start of a file -\b SHFolder.dll is loaded with full path to prevent dll hijacking +\b LoadLibrary security hardening to prevent dll hijacking \S2{} Minor Changes diff --git a/Source/exehead/Main.c b/Source/exehead/Main.c index b8f52463..bdcc1693 100644 --- a/Source/exehead/Main.c +++ b/Source/exehead/Main.c @@ -28,6 +28,12 @@ #include "exec.h" #include "plugin.h" +#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS +#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400 +#endif +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif #ifndef SHTDN_REASON_FLAG_PLANNED #define SHTDN_REASON_FLAG_PLANNED 0x80000000 #endif @@ -98,6 +104,16 @@ EXTERN_C void NSISWinMainNOCRT() } #endif + { + // bug #1125: Don't load modules from the application nor current directory. + // SetDefaultDllDirectories() allows us to restrict implicitly loaded and + // dynamically loaded modules (with relative paths) to just + // %windir%\System32 and directories added with AddDllDirectory(). + // This prevents DLL search order attacks (CAPEC-471). + FARPROC fp = myGetProcAddress(MGA_SetDefaultDllDirectories); + if (fp) ((BOOL(WINAPI*)(DWORD))fp)(LOAD_LIBRARY_SEARCH_SYSTEM32|LOAD_LIBRARY_SEARCH_USER_DIRS); + } + // Because myGetProcAddress now loads dlls with a full path // under GetSystemDirectory() the previous issues in <= v3.0b2 with // 'SetOutPath' and/or 'File "shfolder.dll"' no longer apply. diff --git a/Source/exehead/util.c b/Source/exehead/util.c index c93e5871..c502ad0e 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -1063,6 +1063,7 @@ struct MGA_FUNC struct MGA_FUNC MGA_FUNCS[] = { #ifdef _UNICODE + {"KERNEL32", "SetDefaultDllDirectories"}, #ifndef _WIN64 {"KERNEL32", "GetDiskFreeSpaceExW"}, {"KERNEL32", "GetUserDefaultUILanguage"}, @@ -1076,6 +1077,7 @@ struct MGA_FUNC MGA_FUNCS[] = { {"VERSION", "VerQueryValueW"} }; #else + {"KERNEL32", "SetDefaultDllDirectories"}, {"KERNEL32", "GetDiskFreeSpaceExA"}, {"KERNEL32", "GetUserDefaultUILanguage"}, {"ADVAPI32", "RegDeleteKeyExA"}, @@ -1096,7 +1098,7 @@ struct MGA_FUNC MGA_FUNCS[] = { * @param func Enum value that indexes the MGA_FUNCS array. * @return Pointer to the function identified by the enum value. */ -void * NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func) +void* NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func) { #ifdef UNICODE static const TCHAR dllpathfmt[] = _T("%s%hs.dll"); // Strings in MGA_FUNC are always ANSI diff --git a/Source/exehead/util.h b/Source/exehead/util.h index ba0d75c0..9acf0bc6 100644 --- a/Source/exehead/util.h +++ b/Source/exehead/util.h @@ -119,6 +119,7 @@ void NSISCALL mini_memcpy(void *out, const void *in, UINT_PTR cb); #endif enum myGetProcAddressFunctions { + MGA_SetDefaultDllDirectories, // Win8+ but exists on Vista/2008/7/2008R2 if KB2533623 is installed #ifndef _WIN64 MGA_GetDiskFreeSpaceEx, MGA_GetUserDefaultUILanguage, @@ -127,12 +128,12 @@ enum myGetProcAddressFunctions { MGA_InitiateShutdown, MGA_SHAutoComplete, // x64 can link to shlwapi directly but as long as MGA_SHGetFolderPath is used we can stick with myGetProcAddress MGA_SHGetFolderPath, // TODO: This can probably call something else directly on x64 - MGA_GetFileVersionInfoSize, // Version.dll exists in all Windows versions, it is delay loaded to avoid dll hijacking [bug #1125] + MGA_GetFileVersionInfoSize, // Version.dll exists in all Windows versions, it is delay loaded to avoid DLL hijacking [bug #1125] MGA_GetFileVersionInfo, MGA_VerQueryValue }; -void * NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func); +void*NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func); void NSISCALL MessageLoop(UINT uCheckedMsg); /**