From 1c2884cebae966c01e2c8ed35703de633eb0bd67 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 18 Oct 2021 13:14:43 +0100 Subject: [PATCH] [misc] fallback to using LoadLibrary() when LoadLibraryEx() fails or doesn't apply * Per 2a3e82fa96dc69ef43cabd4e9efd75379ef0f7bd, it looks like some Windows 7 system have trouble with LoadLibraryEx() if they don't have KB2533623 installed (which fixes a MAJOR Windows vulnerability. Some people sure want to leave their system open to hackers...). * Work around this by adding a fallback to LoadLibrary() in GetLibraryHandle() * Also switch to using GetLibraryHandle() in dos.c and using LoadLibrary() in sections where we have the full path (since these calls are not vulnerable). --- res/appstore/Package.appxmanifest | 2 +- src/dos.c | 63 +++++++++++++------------------ src/rufus.c | 3 +- src/rufus.h | 25 ++++++++++-- src/rufus.rc | 10 ++--- src/stdlg.c | 13 ++++--- 6 files changed, 63 insertions(+), 53 deletions(-) diff --git a/res/appstore/Package.appxmanifest b/res/appstore/Package.appxmanifest index 50b7e92e..ab348ba6 100644 --- a/res/appstore/Package.appxmanifest +++ b/res/appstore/Package.appxmanifest @@ -11,7 +11,7 @@ + Version="3.17.1839.0" /> Rufus diff --git a/src/dos.c b/src/dos.c index 55042cde..245890fe 100644 --- a/src/dos.c +++ b/src/dos.c @@ -2,7 +2,7 @@ * Rufus: The Reliable USB Formatting Utility * DOS boot file extraction, from the FAT12 floppy image in diskcopy.dll * (MS WinME DOS) or from the embedded FreeDOS resource files - * Copyright © 2011-2020 Pete Batard + * Copyright © 2011-2021 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -150,7 +150,8 @@ static void FatDateTimeToSystemTime(PLARGE_INTEGER SystemTime, PFAT_DATETIME Fat } /* Fix seconds value that might get beyond the bound */ - if (TimeFields.Second > 59) TimeFields.Second = 0; + if (TimeFields.Second > 59) + TimeFields.Second = 0; /* Perform conversion to system time if possible */ if (!RtlTimeFieldsToTime(&TimeFields, SystemTime)) { @@ -169,13 +170,13 @@ static BOOL Patch_COMMAND_COM(size_t filestart, size_t filesize) { const BYTE expected[8] = { 0x15, 0x80, 0xFA, 0x03, 0x75, 0x10, 0xB8, 0x0E }; - uprintf("Patching COMMAND.COM...\n"); + uprintf("Patching COMMAND.COM..."); if (filesize != 93040) { - uprintf(" unexpected file size\n"); + uprintf(" unexpected file size"); return FALSE; } if (memcmp(&DiskImage[filestart+0x650c], expected, sizeof(expected)) != 0) { - uprintf(" unexpected binary data\n"); + uprintf(" unexpected binary data"); return FALSE; } DiskImage[filestart+0x6510] = 0xeb; @@ -186,13 +187,13 @@ static BOOL Patch_IO_SYS(size_t filestart, size_t filesize) { const BYTE expected[8] = { 0xFA, 0x80, 0x75, 0x09, 0x8D, 0xB6, 0x99, 0x00 }; - uprintf("Patching IO.SYS...\n"); + uprintf("Patching IO.SYS..."); if (filesize != 116736) { - uprintf(" unexpected file size\n"); + uprintf(" unexpected file size"); return FALSE; } if (memcmp(&DiskImage[filestart+0x3a8], expected, sizeof(expected)) != 0) { - uprintf(" unexpected binary data\n"); + uprintf(" unexpected binary data"); return FALSE; } DiskImage[filestart+0x3aa] = 0xeb; @@ -213,7 +214,7 @@ static BOOL ExtractFAT(int entry, const char* path) PDIR_ENTRY dir_entry = (PDIR_ENTRY)&DiskImage[FAT12_ROOTDIR_OFFSET + entry*FAT_BYTES_PER_DIRENT]; if ((path == NULL) || ((safe_strlen(path) + 14) > sizeof(filename))) { - uprintf("invalid path supplied for MS-DOS FAT extraction\n"); + uprintf("invalid path supplied for MS-DOS FAT extraction"); return FALSE; } static_strcpy(filename, path); @@ -235,8 +236,8 @@ static BOOL ExtractFAT(int entry, const char* path) filestart = (dir_entry->FirstCluster + FAT12_CLUSTER_OFFSET)*FAT12_CLUSTER_SIZE; filesize = dir_entry->FileSize; if ((filestart + filesize) > DiskImageSize) { - uprintf("FAT File %s would be out of bounds: %X, %X\n", filename, filestart, filesize); - uprintf("%X, %X\n", dir_entry->FirstCluster, dir_entry->FileSize); + uprintf("FAT File %s would be out of bounds: %X, %X", filename, filestart, filesize); + uprintf("%X, %X", dir_entry->FirstCluster, dir_entry->FileSize); return FALSE; } @@ -251,12 +252,12 @@ static BOOL ExtractFAT(int entry, const char* path) hFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, dir_entry->Attributes, NULL); if (hFile == INVALID_HANDLE_VALUE) { - uprintf("Unable to create file '%s': %s.\n", filename, WindowsErrorString()); + uprintf("Unable to create file '%s': %s.", filename, WindowsErrorString()); return FALSE; } if (!WriteFileWithRetry(hFile, &DiskImage[filestart], (DWORD)filesize, &Size, WRITE_RETRIES)) { - uprintf("Could not write file '%s': %s.\n", filename, WindowsErrorString()); + uprintf("Could not write file '%s': %s.", filename, WindowsErrorString()); safe_closehandle(hFile); return FALSE; } @@ -278,7 +279,7 @@ static BOOL ExtractFAT(int entry, const char* path) } safe_closehandle(hFile); - uprintf("Successfully wrote '%s' (%d bytes)\n", filename, filesize); + uprintf("Successfully wrote '%s' (%d bytes)", filename, filesize); return TRUE; } @@ -287,9 +288,7 @@ static BOOL ExtractFAT(int entry, const char* path) image included as resource "BINFILE" in diskcopy.dll */ static BOOL ExtractMSDOS(const char* path) { - char dllname[MAX_PATH] = "C:\\Windows\\System32"; int i, j; - UINT len; BOOL r = FALSE; HMODULE hDLL = NULL; char locale_path[MAX_PATH]; @@ -305,15 +304,9 @@ static BOOL ExtractMSDOS(const char* path) static_strcat(locale_path, "LOCALE\\"); CreateDirectoryA(locale_path, NULL); - len = GetSystemDirectoryA(dllname, sizeof(dllname)); - if ((len == 0) || (len >= sizeof(dllname))) { - uprintf("Unable to get system directory: %s\n", WindowsErrorString()); - goto out; - } - static_strcat(dllname, "\\diskcopy.dll"); - hDLL = LoadLibraryExA(dllname, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + hDLL = GetLibraryHandle("diskcopy"); if (hDLL == NULL) { - uprintf("Unable to open %s: %s\n", dllname, WindowsErrorString()); + uprintf("Unable to open 'diskcopy.dll': %s", WindowsErrorString()); goto out; } @@ -324,16 +317,16 @@ static BOOL ExtractMSDOS(const char* path) // Sanity check if (DiskImageSize < 700*KB) { - uprintf("MS-DOS disk image is too small (%d bytes)\n", dllname, DiskImageSize); + uprintf("MS-DOS disk image is too small (%d bytes)", DiskImageSize); goto out; } - for (i=0, r=TRUE; r && i sizeof(filename))) { - uprintf("invalid path supplied for FreeDOS extraction\n"); + uprintf("invalid path supplied for FreeDOS extraction"); return FALSE; } @@ -389,12 +380,12 @@ BOOL ExtractFreeDOS(const char* path) hFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, (i<2)?(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM):FILE_ATTRIBUTE_NORMAL, NULL); if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) { - uprintf("Unable to create file '%s': %s.\n", filename, WindowsErrorString()); + uprintf("Unable to create file '%s': %s.", filename, WindowsErrorString()); return FALSE; } if (!WriteFileWithRetry(hFile, res_data, res_size, &Size, WRITE_RETRIES)) { - uprintf("Could not write file '%s': %s.\n", filename, WindowsErrorString()); + uprintf("Could not write file '%s': %s.", filename, WindowsErrorString()); safe_closehandle(hFile); return FALSE; } @@ -403,7 +394,7 @@ BOOL ExtractFreeDOS(const char* path) // thus we would need to have a separate header with each file's timestamps safe_closehandle(hFile); - uprintf("Successfully wrote '%s' (%d bytes)\n", filename, res_size); + uprintf("Successfully wrote '%s' (%d bytes)", filename, res_size); if ((i == 4) || (i == 10) || (i == 16) || (i == 22) || (i == ARRAYSIZE(res_name)-1)) UpdateProgress(OP_FILE_COPY, -1.0f); diff --git a/src/rufus.c b/src/rufus.c index b6abd5a5..c4521db2 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -3221,8 +3221,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // nail... Also, no, Coverity, we never need to care about freeing kernel32 as a library. // coverity[leaked_storage] pfSetDefaultDllDirectories = (SetDefaultDllDirectories_t) - GetProcAddress(LoadLibraryExW(kernel32_path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32), - "SetDefaultDllDirectories"); + GetProcAddress(LoadLibraryW(kernel32_path), "SetDefaultDllDirectories"); if (pfSetDefaultDllDirectories != NULL) pfSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32); diff --git a/src/rufus.h b/src/rufus.h index 4090a131..e7a24971 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -676,22 +676,41 @@ extern void StrArrayDestroy(StrArray* arr); * pfFormatEx = (FormatEx_t) GetProcAddress(GetDLLHandle("fmifs"), "FormatEx"); * to make it accessible. */ -#define MAX_LIBRARY_HANDLES 32 +#define MAX_LIBRARY_HANDLES 64 extern HMODULE OpenedLibrariesHandle[MAX_LIBRARY_HANDLES]; extern uint16_t OpenedLibrariesHandleSize; #define OPENED_LIBRARIES_VARS HMODULE OpenedLibrariesHandle[MAX_LIBRARY_HANDLES]; uint16_t OpenedLibrariesHandleSize = 0 #define CLOSE_OPENED_LIBRARIES while(OpenedLibrariesHandleSize > 0) FreeLibrary(OpenedLibrariesHandle[--OpenedLibrariesHandleSize]) static __inline HMODULE GetLibraryHandle(char* szLibraryName) { HMODULE h = NULL; - if ((h = GetModuleHandleA(szLibraryName)) == NULL) { + wchar_t* wszLibraryName = NULL; + int size; + if (szLibraryName == NULL || szLibraryName[0] == 0) + goto out; + size = MultiByteToWideChar(CP_UTF8, 0, szLibraryName, -1, NULL, 0); + if (size <= 1) // An empty string would be size 1 + goto out; + if ((wszLibraryName = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL) + goto out; + if (MultiByteToWideChar(CP_UTF8, 0, szLibraryName, -1, wszLibraryName, size) != size) + goto out; + // If the library is already opened, just return a handle (that doesn't need to be freed) + if ((h = GetModuleHandleW(wszLibraryName)) == NULL) { if (OpenedLibrariesHandleSize >= MAX_LIBRARY_HANDLES) { uprintf("Error: MAX_LIBRARY_HANDLES is too small\n"); } else { - h = LoadLibraryExA(szLibraryName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + h = LoadLibraryExW(wszLibraryName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + // Some Windows 7 platforms (most likely the ones missing KB2533623 per + // the official LoadLibraryEx doc) return "[0x####007F] The specified + // procedure could not be found" when using the Ex version. + if ((h == NULL) && (SCODE_CODE(GetLastError()) == ERROR_PROC_NOT_FOUND)) + h = LoadLibraryW(wszLibraryName); if (h != NULL) OpenedLibrariesHandle[OpenedLibrariesHandleSize++] = h; } } +out: + free(wszLibraryName); return h; } #define PF_TYPE(api, ret, proc, args) typedef ret (api *proc##_t)args diff --git a/src/rufus.rc b/src/rufus.rc index fa93318a..0b8ca805 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.17.1838" +CAPTION "Rufus 3.17.1839" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,17,1838,0 - PRODUCTVERSION 3,17,1838,0 + FILEVERSION 3,17,1839,0 + PRODUCTVERSION 3,17,1839,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.17.1838" + VALUE "FileVersion", "3.17.1839" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2021 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.17.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.17.1838" + VALUE "ProductVersion", "3.17.1839" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index 9769a599..088176d9 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -2037,26 +2037,27 @@ static void CALLBACK AlertPromptHook(HWINEVENTHOOK hWinEventHook, DWORD Event, H void SetAlertPromptMessages(void) { - HMODULE mui_lib; + HMODULE hMui; char mui_path[MAX_PATH]; // Fetch the localized strings in the relevant MUI // Must use sysnative_dir rather than system_dir as we may not find the MUI's otherwise + // Also don't bother with LibLibraryEx() since we have a full path here. static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", sysnative_dir, GetCurrentMUI()); - mui_lib = LoadLibraryExU(mui_path, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); - if (mui_lib != NULL) { + hMui = LoadLibraryU(mui_path); + if (hMui != NULL) { // 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text) // 4125 = "Microsoft Windows" (dialog title) // 4126 = "Format disk" (button) - if (LoadStringU(mui_lib, 4125, title_str[0], sizeof(title_str[0])) <= 0) { + if (LoadStringU(hMui, 4125, title_str[0], sizeof(title_str[0])) <= 0) { static_strcpy(title_str[0], "Microsoft Windows"); uprintf("Warning: Could not locate localized format prompt title string in '%s': %s", mui_path, WindowsErrorString()); } - if (LoadStringU(mui_lib, 4126, button_str, sizeof(button_str)) <= 0) { + if (LoadStringU(hMui, 4126, button_str, sizeof(button_str)) <= 0) { static_strcpy(button_str, "Format disk"); uprintf("Warning: Could not locate localized format prompt button string in '%s': %s", mui_path, WindowsErrorString()); } - FreeLibrary(mui_lib); + FreeLibrary(hMui); } static_strcpy(title_str[1], lmprintf(MSG_149)); }