diff --git a/Docs/src/history.but b/Docs/src/history.but index 9745fc8e..20ba5da9 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -12,6 +12,8 @@ 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 + \S2{} Minor Changes \b Fixed System plugin GUID type output bug on Win98 diff --git a/Source/exehead/Main.c b/Source/exehead/Main.c index 4276d865..fb5c85c9 100644 --- a/Source/exehead/Main.c +++ b/Source/exehead/Main.c @@ -98,17 +98,17 @@ EXTERN_C void NSISWinMainNOCRT() } #endif - // load shfolder.dll before any script code is executed to avoid - // weird situations where SetOutPath or even the extraction of - // shfolder.dll will cause unexpected behavior. - // - // this also prevents the following: - // - // SetOutPath "C:\Program Files\NSIS" # maybe read from reg - // File shfolder.dll - // Delete $PROGRAMFILES\shfolder.dll # can't be deleted, as the - // # new shfolder.dll is used - // # to find its own path. + // 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. + // All MGA dlls still need to be loaded early here because installers + // running under WoW64 might disable WoW64 FS redirection in .onInit and + // because GetSystemDirectory() can return the native system32 path we need + // the redirection to be turned off so LoadLibrary uses the correct folder. + // Note: We also import directly from KERNEL32, ADVAPI32 and SHELL32 so they + // are exempt from this requirement and SHELL32 imports from SHLWAPI on + // WoW64 systems and it is also on the KnownDLLs list so + // SHLWAPI also gets a pass and that just leaves SHFOLDER. g_SHGetFolderPath = myGetProcAddress(MGA_SHGetFolderPath); { diff --git a/Source/exehead/util.c b/Source/exehead/util.c index 31577298..03c57602 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -1113,12 +1113,25 @@ struct MGA_FUNC MGA_FUNCS[] = { */ void * NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func) { - const char *dll = MGA_FUNCS[func].dll; - HMODULE hModule = GetModuleHandleA(dll); +#ifdef UNICODE + static const TCHAR dllpathfmt[] = _T("%s%hs.dll"); // Strings in MGA_FUNC are always ANSI +#else + static const TCHAR dllpathfmt[] = _T("%s%s.dll"); +#endif + HMODULE hModule; + const char *dllname = MGA_FUNCS[func].dll; + TCHAR buf[MAX_PATH+1+20+4+!0]; // 20+4 is more than enough for the dllnames we are using + + UINT cch = GetSystemDirectory(buf, MAX_PATH); + if (cch > MAX_PATH) // MAX_PATH was somehow not large enough and we don't support + cch = 0; // \\?\ paths so we have to settle for just the name. + wsprintf(buf + cch, dllpathfmt, _T("\\") + (!cch || buf[cch-1] == '\\'), dllname); + + hModule = GetModuleHandleA(dllname); // Avoid LoadLibrary if possible because + if (!hModule) // it can crash on 64-bit dlls if + hModule = LoadLibrary(buf); // WoW64 FS redirection is off. if (!hModule) - hModule = LoadLibraryA(dll); - if (!hModule) - return NULL; + return (FARPROC) hModule; // Optimized "return NULL;" return GetProcAddress(hModule, MGA_FUNCS[func].func); }