[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.
This commit is contained in:
Pete Batard 2024-03-29 00:41:52 +00:00
parent b7568ab30a
commit 52ca79816f
No known key found for this signature in database
GPG Key ID: 38E0CF5E69EDD671
7 changed files with 272 additions and 126 deletions

View File

@ -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

View File

@ -60,6 +60,7 @@
#endif
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
@ -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 "<MD5SUM> <FILE_PATH>" 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)

157
src/iso.c
View File

@ -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 "<MD5SUM> <FILE_PATH>" 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);

View File

@ -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) &&

View File

@ -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);

View File

@ -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", "<22> 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"

View File

@ -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;
/// <summary>
/// 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);