From 3afa139d7a20756fdd7474d31142a29a9d0d887d Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 24 May 2023 17:52:25 +0100 Subject: [PATCH] [dos] reinstate MS-DOS boot disk creation for Windows 10 and later platforms * The BlackLotus malware shows that it is possible to download individual executables and DLLs straight from Microsoft's symbol servers, so we use that capability to download the missing Windows 8.1 'diskcopy.dll', that contains the flat floppy disk image with MS-DOS files we need. See: https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/ * Also reorder entries in the "Boot selection" dropdown. * Also use CreateFileWithTimeout() in GetLogicalName(). --- res/loc/ChangeLog.txt | 3 +++ res/loc/rufus.loc | 5 +++++ src/dos.c | 34 +++++++++++++++----------------- src/drive.c | 4 ++-- src/net.c | 20 ++++++++++--------- src/rufus.c | 45 ++++++++++++++++++++----------------------- src/rufus.h | 10 +++++++++- src/rufus.rc | 10 +++++----- 8 files changed, 71 insertions(+), 60 deletions(-) diff --git a/res/loc/ChangeLog.txt b/res/loc/ChangeLog.txt index c5903005..77f2d980 100644 --- a/res/loc/ChangeLog.txt +++ b/res/loc/ChangeLog.txt @@ -5,6 +5,9 @@ To edit a translation, please make sure to follow: https://github.com/pbatard/rufus/wiki/Localization#Editing_an_existing_translation Or simply download https://files.akeo.ie/pollock/pollock-1.5.exe and follow its directions. +o v4.?? (202?.??.??) + - *NEW* MSG_337 "An additional file ('diskcopy.dll') must be downloaded from Microsoft to install MS-DOS (...)" + o v3.22 (2023.??.??) // MSG_144 is aimed the the ISO download feature - *UPDATED* MSG_144 "Temporarily banned by Microsoft for requesting too many downloads (...)" -> "Download of Windows ISOs is unavailable due to Microsoft having altered their website to prevent it." diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index 07008191..cca0f0b4 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -593,6 +593,11 @@ t MSG_333 "Create a local account with username:" t MSG_334 "Set regional options to the same values as this user's" t MSG_335 "Disable BitLocker automatic device encryption" t MSG_336 "Persistent log" +t MSG_337 "An additional file ('diskcopy.dll') must be downloaded from Microsoft to install MS-DOS:\n" + "- Select 'Yes' to connect to the Internet and download it\n" + "- Select 'No' to cancel the operation\n\n" + "Note: The file will be downloaded in the current application directory and will be reused " + "automatically if present." # The following messages are for the Windows Store listing only and are not used by the application t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc." t MSG_901 "Official site: %s" diff --git a/src/dos.c b/src/dos.c index 6ffb426c..c5a228ec 100644 --- a/src/dos.c +++ b/src/dos.c @@ -33,6 +33,7 @@ #include "rufus.h" #include "missing.h" #include "resource.h" +#include "msapi_utf8.h" #include "dos.h" @@ -289,8 +290,9 @@ static BOOL ExtractMSDOS(const char* path) { int i, j; BOOL r = FALSE; - HMODULE hDLL = NULL; + uint8_t* diskcopy_buffer = NULL; char locale_path[MAX_PATH]; + char diskcopy_dll_path[MAX_PATH]; char* extractlist[] = { "MSDOS SYS", "COMMAND COM", "IO SYS", "MODE COM", "KEYB COM", "KEYBOARDSYS", "KEYBRD2 SYS", "KEYBRD3 SYS", "KEYBRD4 SYS", "DISPLAY SYS", "EGA CPI", "EGA2 CPI", "EGA3 CPI" }; @@ -298,28 +300,22 @@ static BOOL ExtractMSDOS(const char* path) if (path == NULL) return FALSE; + // There should be a diskcopy.dll in the user's AppData directory. + // Since we're working with a known copy of diskcopy.dll, just load it + // in memory and point to the known disk image resource buffer. + static_sprintf(diskcopy_dll_path, "%s\\%s\\diskcopy.dll", app_data_dir, FILES_DIR); + if (read_file(diskcopy_dll_path, &diskcopy_buffer) != DISKCOPY_SIZE) { + uprintf("'diskcopy.dll' was either not found or is invalid"); + goto out; + } + DiskImage = &diskcopy_buffer[DISKCOPY_IMAGE_OFFSET]; + DiskImageSize = DISKCOPY_IMAGE_SIZE; + // Reduce the visible mess by placing all the locale files into a subdir static_strcpy(locale_path, path); static_strcat(locale_path, "LOCALE\\"); CreateDirectoryA(locale_path, NULL); - hDLL = GetLibraryHandle("diskcopy"); - if (hDLL == NULL) { - uprintf("Unable to open 'diskcopy.dll': %s", WindowsErrorString()); - goto out; - } - - DiskImageSize = 0; - DiskImage = (BYTE*)GetResource(hDLL, MAKEINTRESOURCEA(1), "BINFILE", "disk image", &DiskImageSize, TRUE); - if (DiskImage == NULL) - goto out; - - // Sanity check - if (DiskImageSize < 700*KB) { - uprintf("MS-DOS disk image is too small (%d bytes)", DiskImageSize); - goto out; - } - for (i = 0, r = TRUE; r && i < FAT_FN_DIR_ENTRY_LAST; i++) { if (DiskImage[FAT12_ROOTDIR_OFFSET + i * FAT_BYTES_PER_DIRENT] == FAT_DIRENT_DELETED) continue; @@ -335,7 +331,7 @@ static BOOL ExtractMSDOS(const char* path) r = SetDOSLocale(path, FALSE); out: - safe_free(DiskImage); + safe_free(diskcopy_buffer); return r; } diff --git a/src/drive.c b/src/drive.c index 25067af4..13d21d96 100644 --- a/src/drive.c +++ b/src/drive.c @@ -307,8 +307,8 @@ char* GetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrail continue; } - hDrive = CreateFileA(volume_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + hDrive = CreateFileWithTimeout(volume_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, 3000); if (hDrive == INVALID_HANDLE_VALUE) { suprintf("Could not open GUID volume '%s': %s", volume_name, WindowsErrorString()); continue; diff --git a/src/net.c b/src/net.c index 1be933ca..e4c64bc7 100644 --- a/src/net.c +++ b/src/net.c @@ -273,10 +273,10 @@ static __inline BOOL is_WOW64(void) } // Open an Internet session -static HINTERNET GetInternetSession(BOOL bRetry) +static HINTERNET GetInternetSession(const char* user_agent, BOOL bRetry) { int i; - char agent[64]; + char default_agent[64]; BOOL decodingSupport = TRUE; VARIANT_BOOL InternetConnection = VARIANT_FALSE; DWORD dwFlags, dwTimeout = NET_SESSION_TIMEOUT, dwProtocolSupport = HTTP_PROTOCOL_FLAG_HTTP2; @@ -314,10 +314,11 @@ static HINTERNET GetInternetSession(BOOL bRetry) SetLastError(ERROR_INTERNET_DISCONNECTED); goto out; } - static_sprintf(agent, APPLICATION_NAME "/%d.%d.%d (Windows NT %lu.%lu%s)", + static_sprintf(default_agent, APPLICATION_NAME "/%d.%d.%d (Windows NT %lu.%lu%s)", rufus_version[0], rufus_version[1], rufus_version[2], WindowsVersion.Major, WindowsVersion.Minor, is_WOW64() ? "; WOW64" : ""); - hSession = pfInternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + hSession = pfInternetOpenA((user_agent == NULL) ? default_agent : user_agent, + INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); // Set the timeouts pfInternetSetOptionA(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, (LPVOID)&dwTimeout, sizeof(dwTimeout)); pfInternetSetOptionA(hSession, INTERNET_OPTION_SEND_TIMEOUT, (LPVOID)&dwTimeout, sizeof(dwTimeout)); @@ -341,7 +342,8 @@ out: * Note that when a buffer is used, the actual size of the buffer is one more than its reported * size (with the extra byte set to 0) to accommodate for calls that need a NUL-terminated buffer. */ -uint64_t DownloadToFileOrBuffer(const char* url, const char* file, BYTE** buffer, HWND hProgressDialog, BOOL bTaskBarProgress) +uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char* user_agent, + BYTE** buffer, HWND hProgressDialog, BOOL bTaskBarProgress) { const char* accept_types[] = {"*/*\0", NULL}; const char* short_name; @@ -395,7 +397,7 @@ uint64_t DownloadToFileOrBuffer(const char* url, const char* file, BYTE** buffer } hostname[sizeof(hostname)-1] = 0; - hSession = GetInternetSession(TRUE); + hSession = GetInternetSession(user_agent, TRUE); if (hSession == NULL) { uprintf("Could not open Internet session: %s", WinInetErrorString()); goto out; @@ -427,7 +429,7 @@ uint64_t DownloadToFileOrBuffer(const char* url, const char* file, BYTE** buffer if (DownloadStatus != 200) { error_code = ERROR_INTERNET_ITEM_NOT_FOUND; SetLastError(ERROR_SEVERITY_ERROR | FAC(FACILITY_HTTP) | error_code); - uprintf("Unable to access file: %d", DownloadStatus); + uprintf("%s: %d", (DownloadStatus == 404) ? "File not found" : "Unable to access file", DownloadStatus); goto out; } dwSize = sizeof(strsize); @@ -705,7 +707,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) static_sprintf(agent, APPLICATION_NAME "/%d.%d.%d (Windows NT %lu.%lu%s)", rufus_version[0], rufus_version[1], rufus_version[2], WindowsVersion.Major, WindowsVersion.Minor, is_WOW64() ? "; WOW64" : ""); - hSession = GetInternetSession(FALSE); + hSession = GetInternetSession(NULL, FALSE); if (hSession == NULL) goto out; hConnection = pfInternetConnectA(hSession, UrlParts.lpszHostName, UrlParts.nPort, @@ -1125,7 +1127,7 @@ BOOL IsDownloadable(const char* url) hostname[sizeof(hostname) - 1] = 0; // Open an Internet session - hSession = GetInternetSession(FALSE); + hSession = GetInternetSession(NULL, FALSE); if (hSession == NULL) goto out; diff --git a/src/rufus.c b/src/rufus.c index 8e900dc1..b27cef68 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -226,12 +226,11 @@ static void SetBootOptions(void) IGNORE_RETVAL(ComboBox_ResetContent(hBootType)); IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, lmprintf(MSG_279)), BT_NON_BOOTABLE)); - if (WindowsVersion.Version < WINDOWS_10) // The diskcopy.dll along with its MS-DOS floppy image was removed in Windows 10 - IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "MS-DOS"), BT_MSDOS)); - IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "FreeDOS"), BT_FREEDOS)); - image_index = (WindowsVersion.Version < WINDOWS_10) ? 3 : 2; IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path), BT_IMAGE)); + image_index = 1; + IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "MS-DOS"), BT_MSDOS)); + IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "FreeDOS"), BT_FREEDOS)); if (advanced_mode_device) { static_sprintf(tmp, "Syslinux %s", embedded_sl_version_str[0]); @@ -1824,9 +1823,25 @@ static DWORD WINAPI BootCheckThread(LPVOID param) } else if (boot_type == BT_MSDOS) { if ((size_check) && (ComboBox_GetCurItemData(hClusterSize) >= 65536)) { // MS-DOS cannot boot from a drive using a 64 kilobytes Cluster size - MessageBoxExU(hMainDialog, lmprintf(MSG_110), lmprintf(MSG_111), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); + MessageBoxExU(hMainDialog, lmprintf(MSG_110), lmprintf(MSG_111), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid); goto out; } + static_sprintf(tmp, "%s\\%s\\diskcopy.dll", app_data_dir, FILES_DIR); + if (_accessU(tmp, 0) != -1) { + uprintf("Will reuse '%s' for MS-DOS installation", tmp); + } else { + r = MessageBoxExU(hMainDialog, lmprintf(MSG_337), lmprintf(MSG_115), + MB_YESNOCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid); + if (r != IDYES) + goto out; + IGNORE_RETVAL(_chdirU(app_data_dir)); + IGNORE_RETVAL(_mkdir(FILES_DIR)); + IGNORE_RETVAL(_chdir(FILES_DIR)); + if (DownloadToFileOrBufferEx(DISKCOPY_URL, tmp, DISKCOPY_USER_AGENT, NULL, hMainDialog, FALSE) != DISKCOPY_SIZE) { + ret = BOOTCHECK_DOWNLOAD_ERROR; + goto out; + } + } } else if (boot_type == BT_GRUB4DOS) { IGNORE_RETVAL(_chdirU(app_data_dir)); IGNORE_RETVAL(_mkdir(FILES_DIR)); @@ -3823,25 +3838,7 @@ extern int TestChecksum(void); // Ctrl-T => Alternate Test mode that doesn't require a full rebuild if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN))) && (msg.wParam == 'T')) { - char tmp[256], c; - char label[256] = "2.06-blah-bli-ubutnu.23.2.1-blo"; - size_t i; - for (i = strlen(label); i > 0; i--) { - c = label[i]; - if (c != 0 && c != '.' && c != '-') - continue; - label[i] = 0; - static_sprintf(tmp, "%s/%s-%s/core.img", FILES_URL, "grub", label); - uprintf(tmp); - label[i] = c; - } -// TestChecksum(); - //FILE* fd = fopen("D:\\ISOs\\vol.txt", "r"); - //while (fgets(label, 256, fd) != NULL) { - // sanitize_label(label); - // uprintf(label); - //} - //fclose(fd); + TestChecksum(); continue; } #endif diff --git a/src/rufus.h b/src/rufus.h index 05209daf..e56b5165 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -120,6 +120,11 @@ #define SECURE_BOOT_MORE_INFO_URL "https://github.com/pbatard/rufus/wiki/FAQ#Why_do_I_need_to_disable_Secure_Boot_to_use_UEFINTFS" #define WPPRECORDER_MORE_INFO_URL "https://github.com/pbatard/rufus/wiki/FAQ#BSODs_with_Windows_To_Go_drives_created_from_Windows_10_1809_ISOs" #define SEVENZIP_URL "https://www.7-zip.org" +#define DISKCOPY_URL "https://msdl.microsoft.com/download/symbols/diskcopy.dll/54505118173000/diskcopy.dll" +#define DISKCOPY_USER_AGENT "Microsoft-Symbol-Server/10.0.22621.755" +#define DISKCOPY_SIZE 0x16ee00 +#define DISKCOPY_IMAGE_OFFSET 0x66d8 +#define DISKCOPY_IMAGE_SIZE 0x168000 #define DEFAULT_ESP_MOUNT_POINT "S:\\" #define IS_POWER_OF_2(x) ((x != 0) && (((x) & ((x) - 1)) == 0)) #define IGNORE_RETVAL(expr) do { (void)(expr); } while(0) @@ -654,7 +659,10 @@ extern BOOL MountRegistryHive(const HKEY key, const char* pszHiveName, const cha extern BOOL UnmountRegistryHive(const HKEY key, const char* pszHiveName); extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue); extern LONG GetEntryWidth(HWND hDropDown, const char* entry); -extern uint64_t DownloadToFileOrBuffer(const char* url, const char* file, BYTE** buffer, HWND hProgressDialog, BOOL bTaskBarProgress); +extern uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char* user_agent, + BYTE** buffer, HWND hProgressDialog, BOOL bTaskBarProgress); +#define DownloadToFileOrBuffer(url, file, buffer, hProgressDialog, bTaskBarProgress) \ + DownloadToFileOrBufferEx(url, file, NULL, buffer, hProgressDialog, bTaskBarProgress) extern DWORD DownloadSignedFile(const char* url, const char* file, HWND hProgressDialog, BOOL PromptOnError); extern HANDLE DownloadSignedFileThreaded(const char* url, const char* file, HWND hProgressDialog, BOOL bPromptOnError); extern INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); diff --git a/src/rufus.rc b/src/rufus.rc index 699cbe40..efe4cebc 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 4.0.2039" +CAPTION "Rufus 4.0.2040" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -392,8 +392,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,0,2039,0 - PRODUCTVERSION 4,0,2039,0 + FILEVERSION 4,0,2040,0 + PRODUCTVERSION 4,0,2040,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -411,13 +411,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.0.2039" + VALUE "FileVersion", "4.0.2040" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.0.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.0.2039" + VALUE "ProductVersion", "4.0.2040" END END BLOCK "VarFileInfo"