From 52ca79816f920659d1ef4d2ce696ca6c215fa776 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 29 Mar 2024 00:41:52 +0000 Subject: [PATCH] [md5sum] Add md5sum.txt creation and runtime UEFI validation * This allows *runtime* validation of UEFI bootable media, such as Windows or Linux installers, which, considering the unreliability of USB flash drives, we assert is a a much better proposal than write-time validation that utilities like balenaEcther (and to a lesser extent MCT) provide. * Based on uefi-md5sum (https://github.com/pbatard/uefi-md5sum). * Unconditionally activated on ISO extraction for GPT targets for now. This will be changed to a user selectable option later. --- src/format.c | 10 +++- src/hash.c | 144 ++++++++++++++++++++++++++++++++++++++++++++-- src/iso.c | 157 +++++++++++++++++++++++---------------------------- src/rufus.c | 5 ++ src/rufus.h | 59 +++++++++---------- src/rufus.rc | 10 ++-- src/wue.c | 13 +++++ 7 files changed, 272 insertions(+), 126 deletions(-) diff --git a/src/format.c b/src/format.c index afac766e..4abe5105 100644 --- a/src/format.c +++ b/src/format.c @@ -71,6 +71,7 @@ static float format_percent = 0.0f; static int task_number = 0, actual_fs_type; static unsigned int sec_buf_pos = 0; extern const int nb_steps[FS_MAX]; +extern const char* md5sum_name[2]; extern uint32_t dur_mins, dur_secs; extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files; extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing; @@ -1035,11 +1036,11 @@ BOOL WritePBR(HANDLE hLogicalVolume) uprintf(using_msg, bt_to_name(), "FAT32"); for (i = 0; i < 2; i++) { if (!is_fat_32_fs(fp)) { - uprintf("New volume does not have a %s FAT32 boot sector - aborting", i?"secondary":"primary"); + uprintf("New volume does not have a %s FAT32 boot sector - aborting", i ? "secondary" : "primary"); break; } - uprintf("Confirmed new volume has a %s FAT32 boot sector", i?"secondary":"primary"); - uprintf("Setting %s FAT32 boot sector for boot...", i?"secondary":"primary"); + uprintf("Confirmed new volume has a %s FAT32 boot sector", i ? "secondary" : "primary"); + uprintf("Setting %s FAT32 boot sector for boot...", i ? "secondary" : "primary"); if (boot_type == BT_FREEDOS) { if (!write_fat_32_fd_br(fp, 0)) break; } else if (boot_type == BT_REACTOS) { @@ -1964,8 +1965,11 @@ DWORD WINAPI FormatThread(void* param) } } } + UpdateProgress(OP_FINALIZE, -1.0f); PrintInfoDebug(0, MSG_233); + if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso) && (!windows_to_go)) + UpdateMD5Sum(drive_name, md5sum_name[img_report.has_md5sum ? img_report.has_md5sum - 1 : 0]); if (IsChecked(IDC_EXTENDED_LABEL)) SetAutorun(drive_name); // Issue another complete remount before we exit, to ensure we're clean diff --git a/src/hash.c b/src/hash.c index 53a9c18d..3635c860 100644 --- a/src/hash.c +++ b/src/hash.c @@ -60,6 +60,7 @@ #endif #include +#include #include #include #include @@ -103,14 +104,18 @@ /* Globals */ char hash_str[HASH_MAX][150]; -uint32_t proc_bufnum, hash_count[HASH_MAX] = { MD5_HASHSIZE, SHA1_HASHSIZE, SHA256_HASHSIZE, SHA512_HASHSIZE }; HANDLE data_ready[HASH_MAX] = { 0 }, thread_ready[HASH_MAX] = { 0 }; DWORD read_size[NUM_BUFFERS]; -BOOL enable_extra_hashes = FALSE; +BOOL enable_extra_hashes = FALSE, validate_md5sum = FALSE; uint8_t ALIGNED(64) buffer[NUM_BUFFERS][BUFFER_SIZE]; -extern int default_thread_priority; -uint32_t pe256ssp_size = 0; uint8_t* pe256ssp = NULL; +uint32_t proc_bufnum, hash_count[HASH_MAX] = { MD5_HASHSIZE, SHA1_HASHSIZE, SHA256_HASHSIZE, SHA512_HASHSIZE }; +uint32_t pe256ssp_size = 0; +uint64_t md5sum_totalbytes; +StrArray modified_files = { 0 }; + +extern int default_thread_priority; +extern const char* efi_bootname[ARCH_MAX]; /* * Rotate 32 or 64 bit integers by n bytes. @@ -2122,6 +2127,137 @@ void PrintRevokedBootloaderInfo(void) uprintf("WARNING: Could not parse this system's SkuSiPolicy.p7b for additional revoked UEFI bootloaders"); } +/* + * Updates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...) + * use to validate the media. Because we may alter some of the validated files + * to add persistence and whatnot, we need to alter the MD5 list as a result. + * The format of the file is expected to always be " " on + * individual lines. + * This function is also used to finalize the md5sum.txt we create for use with + * our uefi-md5sum bootloaders. + */ +void UpdateMD5Sum(const char* dest_dir, const char* md5sum_name) +{ + BOOL display_header = TRUE; + BYTE* res_data; + DWORD res_size; + HANDLE hFile; + intptr_t pos; + uint32_t i, j, size, md5_size, new_size; + uint8_t sum[MD5_HASHSIZE]; + char md5_path[64], path1[64], path2[64], *md5_data = NULL, *new_data = NULL, *str_pos; + char *d, *s, *p; + + if (!img_report.has_md5sum && !validate_md5sum) + goto out; + + static_sprintf(md5_path, "%s\\%s", dest_dir, md5sum_name); + md5_size = read_file(md5_path, (uint8_t**)&md5_data); + if (md5_size == 0) + goto out; + + for (i = 0; i < modified_files.Index; i++) { + for (j = 0; j < (uint32_t)strlen(modified_files.String[i]); j++) + if (modified_files.String[i][j] == '\\') + modified_files.String[i][j] = '/'; + str_pos = strstr(md5_data, &modified_files.String[i][2]); + if (str_pos == NULL) + // File is not listed in md5 sums + continue; + if (display_header) { + uprintf("Updating %s:", md5_path); + display_header = FALSE; + } + uprintf("● %s", &modified_files.String[i][2]); + pos = str_pos - md5_data; + HashFile(HASH_MD5, modified_files.String[i], sum); + while ((pos > 0) && (md5_data[pos - 1] != '\n')) + pos--; + assert(IS_HEXASCII(md5_data[pos])); + for (j = 0; j < 16; j++) { + md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4)); + md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15)); + } + } + + // If we validate md5sum we need to update the original bootloader names and add md5sum_totalbytes + if (validate_md5sum) { + new_size = md5_size; + new_data = malloc(md5_size + 1024); + assert(new_data != NULL); + if (new_data == NULL) + goto out; + // Will be nonzero if we created the file, otherwise zero + if (md5sum_totalbytes != 0) { + snprintf(new_data, md5_size + 1024, "# md5sum_totalbytes = 0x%llx\n", md5sum_totalbytes); + new_size += (uint32_t)strlen(new_data); + d = &new_data[strlen(new_data)]; + } else { + d = new_data; + } + s = md5_data; + for (p = md5_data; (p = StrStrIA(p, " ./efi/boot/boot")) != NULL; ) { + for (i = 1; i < ARRAYSIZE(efi_bootname); i++) { + if (p[12 + strlen(efi_bootname[i])] != 0x0a) + continue; + p[12 + strlen(efi_bootname[i])] = 0; + if (lstrcmpiA(&p[12], efi_bootname[i]) == 0) { + res_data = (BYTE*)GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_MD5_BOOT + i), + _RT_RCDATA, efi_bootname[i], &res_size, FALSE); + static_sprintf(path1, "%s\\%s", dest_dir, &p[3]); + for (j = 0; j < strlen(path1); j++) + if (path1[j] == '/') path1[j] = '\\'; + static_strcpy(path2, path1); + path2[strlen(path2) - 4] = 0; + static_strcat(path2, "_original.efi"); + if (res_data != NULL && MoveFileU(path1, path2)) { + uprintf("Renamed: %s → %s", path1, path2); + hFile = CreateFileA(path1, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) { + uprintf("Could not create '%s': %s.", path1, WindowsErrorString()); + MoveFileU(path2, path1); + continue; + } + if (!WriteFileWithRetry(hFile, res_data, res_size, NULL, WRITE_RETRIES)) { + uprintf("Could not write '%s': %s.", path1, WindowsErrorString()); + safe_closehandle(hFile); + MoveFileU(path2, path1); + continue; + } + safe_closehandle(hFile); + uprintf("Created: %s (%s)", path1, SizeToHumanReadable(res_size, FALSE, FALSE)); + size = (uint32_t)(p - s) + 12 + (uint32_t)strlen(efi_bootname[i]) - 4; + memcpy(d, s, size); + d = &d[size]; + strcpy(d, "_original.efi\n"); + new_size += 9; + d = &d[14]; + s = &p[12 + strlen(efi_bootname[i]) + 1]; + // TODO: Update sources/boot.wim if we modified it + // Also, we'll need to keep a copy of the size of boot.wim BEFORE we alter it + // so we can adjust md5sum_totalbytes + } + } + p[12 + strlen(efi_bootname[i])] = 0x0a; + } + p = &p[12]; + } + p = &md5_data[md5_size]; + memcpy(d, s, p - s); + free(md5_data); + md5_data = new_data; + md5_size = new_size; + } + + write_file(md5_path, md5_data, md5_size); + free(md5_data); + +out: + // We no longer need the string array at this stage + StrArrayDestroy(&modified_files); +} + #if defined(_DEBUG) || defined(TEST) || defined(ALPHA) /* Convert a lowercase hex string to binary. Returned value must be freed */ uint8_t* to_bin(const char* str) diff --git a/src/iso.c b/src/iso.c index fbdcba7e..391bf8ec 100644 --- a/src/iso.c +++ b/src/iso.c @@ -82,8 +82,10 @@ typedef struct { RUFUS_IMG_REPORT img_report; int64_t iso_blocking_status = -1; -extern BOOL preserve_timestamps, enable_ntfs_compression; +extern uint64_t md5sum_totalbytes; +extern BOOL preserve_timestamps, enable_ntfs_compression, validate_md5sum; extern HANDLE format_thread; +extern StrArray modified_files; BOOL enable_iso = TRUE, enable_joliet = TRUE, enable_rockridge = TRUE, has_ldlinux_c32; #define ISO_BLOCKING(x) do {x; iso_blocking_status++; } while(0) static const char* psz_extract_dir; @@ -92,7 +94,7 @@ const char* bootmgr_efi_name = "bootmgr.efi"; static const char* grldr_name = "grldr"; static const char* ldlinux_name = "ldlinux.sys"; static const char* ldlinux_c32 = "ldlinux.c32"; -static const char* md5sum_name[] = { "MD5SUMS", "md5sum.txt" }; +const char* md5sum_name[2] = { "md5sum.txt", "MD5SUMS" }; static const char* casper_dirname = "/casper"; static const char* proxmox_dirname = "/proxmox"; const char* efi_dirname = "/efi/boot"; @@ -124,7 +126,8 @@ static const int64_t old_c32_threshold[NB_OLD_C32] = OLD_C32_THRESHOLD; static uint8_t joliet_level = 0; static uint64_t total_blocks, extra_blocks, nb_blocks, last_nb_blocks; static BOOL scan_only = FALSE; -static StrArray config_path, isolinux_path, modified_path; +static FILE* fd_md5sum = NULL; +static StrArray config_path, isolinux_path; static char symlinked_syslinux[MAX_PATH]; // Ensure filenames do not contain invalid FAT32 or NTFS characters @@ -475,66 +478,11 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha } if (modified) - StrArrayAdd(&modified_path, psz_fullpath, TRUE); + StrArrayAdd(&modified_files, psz_fullpath, TRUE); free(src); } -// This updates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...) -// use to validate the media. Because we may alter some of the validated files -// to add persistence and whatnot, we need to alter the MD5 list as a result. -// The format of the file is expected to always be " " on -// individual lines. -static void update_md5sum(void) -{ - BOOL display_header = TRUE; - intptr_t pos; - uint32_t i, j, size, md5_size; - uint8_t* buf = NULL, sum[16]; - char md5_path[64], * md5_data = NULL, * str_pos; - - if (!img_report.has_md5sum) - goto out; - - assert(img_report.has_md5sum <= ARRAYSIZE(md5sum_name)); - if (img_report.has_md5sum > ARRAYSIZE(md5sum_name)) - goto out; - - static_sprintf(md5_path, "%s\\%s", psz_extract_dir, md5sum_name[img_report.has_md5sum - 1]); - md5_size = read_file(md5_path, (uint8_t**)&md5_data); - if (md5_size == 0) - goto out; - - for (i = 0; i < modified_path.Index; i++) { - str_pos = strstr(md5_data, &modified_path.String[i][2]); - if (str_pos == NULL) - // File is not listed in md5 sums - continue; - if (display_header) { - uprintf("Updating %s:", md5_path); - display_header = FALSE; - } - uprintf("● %s", &modified_path.String[i][2]); - pos = str_pos - md5_data; - size = read_file(modified_path.String[i], &buf); - if (size == 0) - continue; - HashBuffer(HASH_MD5, buf, size, sum); - free(buf); - while ((pos > 0) && (md5_data[pos - 1] != '\n')) - pos--; - for (j = 0; j < 16; j++) { - md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4)); - md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15)); - } - } - - write_file(md5_path, md5_data, md5_size); - free(md5_data); - -out: - StrArrayDestroy(&modified_path); -} static void print_extracted_file(char* psz_fullpath, uint64_t file_length) { @@ -586,9 +534,10 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; + HASH_CONTEXT ctx; BOOL r, is_identical; int length; - size_t i, nb; + size_t i, j, nb; char tmp[128], *psz_fullpath = NULL, *psz_sanpath = NULL; const char* psz_basename; udf_dirent_t *p_udf_dirent2; @@ -669,16 +618,22 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha else goto out; } else { + if (fd_md5sum != NULL) + hash_init[HASH_MD5](&ctx); while (file_length > 0) { if (FormatStatus) goto out; - nb = MIN(ISO_BUFFER_SIZE / UDF_BLOCKSIZE, (file_length + UDF_BLOCKSIZE - 1) / UDF_BLOCKSIZE); + nb = (size_t)MIN(ISO_BUFFER_SIZE / UDF_BLOCKSIZE, (file_length + UDF_BLOCKSIZE - 1) / UDF_BLOCKSIZE); read = udf_read_block(p_udf_dirent, buf, nb); if (read < 0) { uprintf(" Error reading UDF file %s", &psz_fullpath[strlen(psz_extract_dir)]); goto out; } buf_size = (DWORD)MIN(file_length, read); + if (fd_md5sum != NULL) { + md5sum_totalbytes += buf_size; + hash_write[HASH_MD5](&ctx, buf, buf_size); + } ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)); if (!r || (wr_size != buf_size)) { uprintf(" Error writing file: %s", r ? "Short write detected" : WindowsErrorString()); @@ -691,6 +646,12 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha last_nb_blocks = nb_blocks; } } + if (fd_md5sum != NULL) { + hash_final[HASH_MD5](&ctx); + for (j = 0; j < MD5_HASHSIZE; j++) + fprintf(fd_md5sum, "%02x", ctx.buf[j]); + fprintf(fd_md5sum, " ./%s\n", &psz_fullpath[3]); + } } if ((preserve_timestamps) && (!SetFileTime(file_handle, to_filetime(udf_get_attribute_time(p_udf_dirent)), to_filetime(udf_get_access_time(p_udf_dirent)), to_filetime(udf_get_modification_time(p_udf_dirent))))) @@ -726,6 +687,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; + HASH_CONTEXT ctx; BOOL is_symlink, is_identical, create_file, free_p_statbuf = FALSE; int length, r = 1; char psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL; @@ -737,7 +699,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioISO9660FileList_t* p_entlist = NULL; - size_t i, nb; + size_t i, j, nb; lsn_t lsn; int64_t file_length; @@ -921,28 +883,42 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) uprintf(" Error writing file: %s", WindowsErrorString()); goto out; } - } else for (i = 0; file_length > 0; i += nb) { - if (FormatStatus) - goto out; - lsn = p_statbuf->lsn + (lsn_t)i; - nb = MIN(ISO_BUFFER_SIZE / ISO_BLOCKSIZE, (file_length + ISO_BLOCKSIZE - 1) / ISO_BLOCKSIZE); - if (iso9660_iso_seek_read(p_iso, buf, lsn, (long)nb) != (nb * ISO_BLOCKSIZE)) { - uprintf(" Error reading ISO9660 file %s at LSN %lu", - psz_iso_name, (long unsigned int)lsn); - goto out; + } else { + if (fd_md5sum != NULL) + hash_init[HASH_MD5](&ctx); + for (i = 0; file_length > 0; i += nb) { + if (FormatStatus) + goto out; + lsn = p_statbuf->lsn + (lsn_t)i; + nb = (size_t)MIN(ISO_BUFFER_SIZE / ISO_BLOCKSIZE, (file_length + ISO_BLOCKSIZE - 1) / ISO_BLOCKSIZE); + if (iso9660_iso_seek_read(p_iso, buf, lsn, (long)nb) != (nb * ISO_BLOCKSIZE)) { + uprintf(" Error reading ISO9660 file %s at LSN %lu", + psz_iso_name, (long unsigned int)lsn); + goto out; + } + buf_size = (DWORD)MIN(file_length, ISO_BUFFER_SIZE); + if (fd_md5sum != NULL) { + md5sum_totalbytes += buf_size; + hash_write[HASH_MD5](&ctx, buf, buf_size); + } + ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)); + if (!r || wr_size != buf_size) { + uprintf(" Error writing file: %s", r ? "Short write detected" : WindowsErrorString()); + goto out; + } + file_length -= wr_size; + nb_blocks += nb; + if (nb_blocks - last_nb_blocks >= PROGRESS_THRESHOLD) { + UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks + + ((fs_type != FS_NTFS) ? extra_blocks : 0)); + last_nb_blocks = nb_blocks; + } } - buf_size = (DWORD)MIN(file_length, ISO_BUFFER_SIZE); - ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)); - if (!r || wr_size != buf_size) { - uprintf(" Error writing file: %s", r ? "Short write detected" : WindowsErrorString()); - goto out; - } - file_length -= wr_size; - nb_blocks += nb; - if (nb_blocks - last_nb_blocks >= PROGRESS_THRESHOLD) { - UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks + - ((fs_type != FS_NTFS) ? extra_blocks : 0)); - last_nb_blocks = nb_blocks; + if (fd_md5sum != NULL) { + hash_final[HASH_MD5](&ctx); + for (j = 0; j < MD5_HASHSIZE; j++) + fprintf(fd_md5sum, "%02x", ctx.buf[j]); + fprintf(fd_md5sum, " ./%s\n", &psz_fullpath[3]); } } if (preserve_timestamps) { @@ -1098,7 +1074,17 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan) last_nb_blocks = 0; iso_blocking_status = 0; symlinked_syslinux[0] = 0; - StrArrayCreate(&modified_path, 8); + StrArrayCreate(&modified_files, 8); + if (validate_md5sum) { + md5sum_totalbytes = 0; + // If there isn't an already existing md5sum.txt create one + if (img_report.has_md5sum != 1) { + static_sprintf(path, "%s\\%s", dest_dir, md5sum_name[0]); + fd_md5sum = fopenU(path, "wb"); + if (fd_md5sum == NULL) + uprintf("WARNING: Could not create '%s'", md5sum_name[0]); + } + } } // First try to open as UDF - fallback to ISO if it failed @@ -1397,7 +1383,8 @@ out: uprintf("Could not move %s → %s", path, dst_path, WindowsErrorString()); } } - update_md5sum(); + if (fd_md5sum != NULL) + fclose(fd_md5sum); } iso9660_close(p_iso); udf_close(p_udf); diff --git a/src/rufus.c b/src/rufus.c index f51ec143..a2630df0 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -94,6 +94,7 @@ static char uppercase_select[2][64], uppercase_start[64], uppercase_close[64], u extern HANDLE update_check_thread, wim_thread; extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes, is_bootloader_revoked; +extern BOOL validate_md5sum; extern BYTE* fido_script; extern HWND hFidoDlg; extern uint8_t* grub2_buf; @@ -1441,6 +1442,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; is_bootloader_revoked = FALSE; + validate_md5sum = FALSE; safe_free(grub2_buf); if (ComboBox_GetCurSel(hDeviceList) == CB_ERR) @@ -1567,6 +1569,9 @@ static DWORD WINAPI BootCheckThread(LPVOID param) ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL); goto out; } + // TODO: Move this option to a user selection + validate_md5sum = TRUE; + uprintf("Will add runtime UEFI media validation through 'md5sum.txt'"); } else if ( ((fs_type == FS_NTFS) && !HAS_WINDOWS(img_report) && !HAS_GRUB(img_report) && (!HAS_SYSLINUX(img_report) || (SL_MAJOR(img_report.sl_version) <= 5))) || ((IS_FAT(fs_type)) && (!HAS_SYSLINUX(img_report)) && (!allow_dual_uefi_bios) && !IS_EFI_BOOTABLE(img_report) && diff --git a/src/rufus.h b/src/rufus.h index 800a7a39..7108dde3 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -625,6 +625,35 @@ typedef struct { #define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES | UNATTEND_FORCE_S_MODE) #define UNATTEND_DEFAULT_SELECTION_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_OFFLINE_INTERNAL_DRIVES) +/* Hash tables */ +typedef struct htab_entry { + uint32_t used; + char* str; + void* data; +} htab_entry; +typedef struct htab_table { + htab_entry* table; + uint32_t size; + uint32_t filled; +} htab_table; +#define HTAB_EMPTY {NULL, 0, 0} +extern BOOL htab_create(uint32_t nel, htab_table* htab); +extern void htab_destroy(htab_table* htab); +extern uint32_t htab_hash(char* str, htab_table* htab); + +/* Basic String Array */ +typedef struct { + char** String; + uint32_t Index; // Current array size + uint32_t Max; // Maximum array size +} StrArray; +extern void StrArrayCreate(StrArray* arr, uint32_t initial_size); +extern int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL); +extern int32_t StrArrayFind(StrArray* arr, const char* str); +extern void StrArrayClear(StrArray* arr); +extern void StrArrayDestroy(StrArray* arr); +#define IsStrArrayEmpty(arr) (arr.Index == 0) + /* * Globals */ @@ -758,6 +787,7 @@ extern HANDLE CreateFileWithTimeout(LPCSTR lpFileName, DWORD dwDesiredAccess, DW extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); extern BOOL HashFile(const unsigned type, const char* path, uint8_t* sum); extern BOOL PE256File(const char* path, uint8_t* hash); +extern void UpdateMD5Sum(const char* dest_dir, const char* md5sum_name); extern BOOL HashBuffer(const unsigned type, const uint8_t* buf, const size_t len, uint8_t* sum); extern BOOL IsFileInDB(const char* path); extern int IsBootloaderRevoked(const char* path); @@ -787,35 +817,6 @@ extern uint32_t ResolveDllAddress(dll_resolver_t* resolver); DWORD WINAPI HashThread(void* param); -/* Hash tables */ -typedef struct htab_entry { - uint32_t used; - char* str; - void* data; -} htab_entry; -typedef struct htab_table { - htab_entry *table; - uint32_t size; - uint32_t filled; -} htab_table; -#define HTAB_EMPTY {NULL, 0, 0} -extern BOOL htab_create(uint32_t nel, htab_table* htab); -extern void htab_destroy(htab_table* htab); -extern uint32_t htab_hash(char* str, htab_table* htab); - -/* Basic String Array */ -typedef struct { - char** String; - uint32_t Index; // Current array size - uint32_t Max; // Maximum array size -} StrArray; -extern void StrArrayCreate(StrArray* arr, uint32_t initial_size); -extern int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL ); -extern int32_t StrArrayFind(StrArray* arr, const char* str); -extern void StrArrayClear(StrArray* arr); -extern void StrArrayDestroy(StrArray* arr); -#define IsStrArrayEmpty(arr) (arr.Index == 0) - /* * typedefs for the function prototypes. Use the something like: * PF_DECL(FormatEx); diff --git a/src/rufus.rc b/src/rufus.rc index 39d3125d..962ccae6 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.5.2119" +CAPTION "Rufus 4.5.2120" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -397,8 +397,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,5,2119,0 - PRODUCTVERSION 4,5,2119,0 + FILEVERSION 4,5,2120,0 + PRODUCTVERSION 4,5,2120,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -416,13 +416,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.5.2119" + VALUE "FileVersion", "4.5.2120" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "� 2011-2024 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.5.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.5.2119" + VALUE "ProductVersion", "4.5.2120" END END BLOCK "VarFileInfo" diff --git a/src/wue.c b/src/wue.c index 091fa3fe..e43020fb 100644 --- a/src/wue.c +++ b/src/wue.c @@ -47,6 +47,9 @@ char *unattend_xml_path = NULL, unattend_username[MAX_USERNAME_LENGTH]; BOOL is_bootloader_revoked = FALSE; extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files; +extern BOOL validate_md5sum; +extern uint64_t md5sum_totalbytes; +extern StrArray modified_files; /// /// Create an installation answer file containing the sections specified by the flags. @@ -808,6 +811,10 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) CloseHandle(CreateFileU(appraiserres_dll_src, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); uprintf("Created '%s' placeholder", appraiserres_dll_src); + if (validate_md5sum) { + md5sum_totalbytes -= _filesizeU(appraiserres_dll_dst); + StrArrayAdd(&modified_files, appraiserres_dll_src, TRUE); + } } } @@ -815,6 +822,8 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) // We only need to mount boot.wim if we have windowsPE data to deal with. If // not, we can just copy our unattend.xml in \sources\$OEM$\$$\Panther\. if (flags & UNATTEND_WINPE_SETUP_MASK) { + if (validate_md5sum) + md5sum_totalbytes -= _filesizeU(boot_wim_path); uprintf("Mounting '%s[%d]'...", boot_wim_path, wim_index); // Some "unofficial" ISOs have a modified boot.wim that doesn't have Windows Setup at index 2... if (!WimIsValidIndex(boot_wim_path, wim_index)) { @@ -929,6 +938,10 @@ out: if (mount_path) { uprintf("Unmounting '%s[%d]'...", boot_wim_path, wim_index); WimUnmountImage(boot_wim_path, wim_index, TRUE); + if (validate_md5sum) { + md5sum_totalbytes += _filesizeU(boot_wim_path); + StrArrayAdd(&modified_files, boot_wim_path, TRUE); + } UpdateProgressWithInfo(OP_PATCH, MSG_325, PATCH_PROGRESS_TOTAL, PATCH_PROGRESS_TOTAL); } free(mount_path);