From 0363bfe503d76d6e1d9a22a61e850f8ccbf79f50 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 5 Jul 2023 18:36:58 +0100 Subject: [PATCH] [misc] add an address resolver for internal DLL function calls * Not sure if we'll use this to hook into FfuCaptureImage()/FfuApplyImage()/FfuMountImage() directly. But at least, if we ever need it, it's there... --- res/loc/rufus.loc | 3 ++ src/drive.c | 10 ++-- src/net.c | 4 +- src/pki.c | 2 +- src/rufus.c | 15 +++++- src/rufus.h | 13 ++++- src/rufus.rc | 10 ++-- src/stdio.c | 123 ++++++++++++++++++++++++++++++++++++++++++++-- 8 files changed, 160 insertions(+), 20 deletions(-) diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index 73394841..224c4ee3 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -606,6 +606,9 @@ t MSG_341 "a Windows Recovery Screen (BSOD) with '%s'" t MSG_342 "Compressed VHDX Image" t MSG_343 "Uncompressed VHD Image" t MSG_344 "Full Flash Update Image" +t MSG_345 "Some additional data must be downloaded from Microsoft to use this functionality:\n" + "- Select 'Yes' to connect to the Internet and download it\n" + "- Select 'No' to cancel the operation" # 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/drive.c b/src/drive.c index d51fb4d3..e015a287 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1541,7 +1541,7 @@ static BOOL StoreEspInfo(GUID* guid) static_sprintf(key_name[0], "ToggleEsp%02u", j); str = ReadSettingStr(key_name[0]); if ((str == NULL) || (str[0] == 0)) - return WriteSettingStr(key_name[0], GuidToString(guid)); + return WriteSettingStr(key_name[0], GuidToString(guid, TRUE)); } // All slots are used => Move every key down and add to last slot // NB: No, we don't care that the slot we remove may not be the oldest. @@ -1550,7 +1550,7 @@ static BOOL StoreEspInfo(GUID* guid) static_sprintf(key_name[1], "ToggleEsp%02u", j + 1); WriteSettingStr(key_name[0], ReadSettingStr(key_name[1])); } - return WriteSettingStr(key_name[1], GuidToString(guid)); + return WriteSettingStr(key_name[1], GuidToString(guid, TRUE)); } static GUID* GetEspGuid(uint8_t index) @@ -1990,7 +1990,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys case PARTITION_STYLE_GPT: SelectedDrive.PartitionStyle = PARTITION_STYLE_GPT; suprintf("Partition type: GPT, NB Partitions: %d", DriveLayout->PartitionCount); - suprintf("Disk GUID: %s", GuidToString(&DriveLayout->Gpt.DiskId)); + suprintf("Disk GUID: %s", GuidToString(&DriveLayout->Gpt.DiskId, TRUE)); suprintf("Max parts: %d, Start Offset: %" PRIi64 ", Usable = %" PRIi64 " bytes", DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart); for (i = 0; i < DriveLayout->PartitionCount; i++) { @@ -2006,7 +2006,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name); suprintf(" Detected File System: %s", GetFsName(hPhysical, DriveLayout->PartitionEntry[i].StartingOffset)); suprintf(" ID: %s\r\n Size: %s (%" PRIi64 " bytes)\r\n Start Sector: %" PRIi64 ", Attributes: 0x%016" PRIX64, - GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId), + GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId, TRUE), SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE), DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / SelectedDrive.SectorSize, @@ -2646,5 +2646,5 @@ const char* GetGPTPartitionType(const GUID* guid) { int i; for (i = 0; (i < ARRAYSIZE(gpt_type)) && !CompareGUID(guid, gpt_type[i].guid); i++); - return (i < ARRAYSIZE(gpt_type)) ? gpt_type[i].name : GuidToString(guid); + return (i < ARRAYSIZE(gpt_type)) ? gpt_type[i].name : GuidToString(guid, TRUE); } diff --git a/src/net.c b/src/net.c index a6748cb7..ff394433 100644 --- a/src/net.c +++ b/src/net.c @@ -915,7 +915,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param) // thinking that Rufus is doing something malicious... IGNORE_RETVAL(CoCreateGuid(&guid)); // coverity[fixed_size_dest] - strcpy(&pipe[9], GuidToString(&guid)); + strcpy(&pipe[9], GuidToString(&guid, TRUE)); static_sprintf(icon_path, "%s%s.ico", temp_dir, APPLICATION_NAME); ExtractAppIcon(icon_path, TRUE); @@ -973,7 +973,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param) assert((fido_script != NULL) && (fido_len != 0)); - static_sprintf(script_path, "%s%s.ps1", temp_dir, GuidToString(&guid)); + static_sprintf(script_path, "%s%s.ps1", temp_dir, GuidToString(&guid, TRUE)); hFile = CreateFileU(script_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, NULL); if (hFile == INVALID_HANDLE_VALUE) { uprintf("Unable to create download script '%s': %s", script_path, WindowsErrorString()); diff --git a/src/pki.c b/src/pki.c index 2b4cc2da..1d6a674d 100644 --- a/src/pki.c +++ b/src/pki.c @@ -860,7 +860,7 @@ BOOL ParseSKUSiPolicy(void) goto out; } if (!CompareGUID(&Header->PolicyTypeGUID, &SKU_CODE_INTEGRITY_POLICY)) { - uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID)); + uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID, TRUE)); goto out; } diff --git a/src/rufus.c b/src/rufus.c index 7d79b564..0855d345 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1861,7 +1861,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) 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) { + if (DownloadToFileOrBufferEx(DISKCOPY_URL, tmp, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) != DISKCOPY_SIZE) { ret = BOOTCHECK_DOWNLOAD_ERROR; goto out; } @@ -3787,7 +3787,18 @@ extern int TestHashes(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')) { - TestHashes(); +// TestHashes(); + dll_resolver_t resolver = { 0 }; + resolver.path = "C:\\Windows\\System32\\Dism\\FfuProvider.dll"; + resolver.count = 3; + resolver.name = calloc(resolver.count, sizeof(char*)); + resolver.address = calloc(resolver.count, sizeof(uint32_t)); + resolver.name[0] = "FfuCaptureImage"; + resolver.name[1] = "FfuApplyImage"; + resolver.name[2] = "FfuMountImage"; + uprintf("Got %d resolved addresses", ResolveDllAddress(&resolver)); + free(resolver.name); + free(resolver.address); continue; } #endif diff --git a/src/rufus.h b/src/rufus.h index 485a409e..84ec91a3 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -121,10 +121,10 @@ #define SEVENZIP_URL "https://7-zip.org/" // Generated by following https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/ #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 SYMBOL_SERVER_USER_AGENT "Microsoft-Symbol-Server/10.0.22621.755" #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) @@ -472,6 +472,14 @@ typedef struct ext_t { const char** description; } ext_t; +/* DLL address resolver */ +typedef struct { + char* path; + uint32_t count; + char** name; + uint32_t* address; // 32-bit will do, as we're not dealing with >4GB DLLs... +} dll_resolver_t; + #ifndef __VA_GROUP__ #define __VA_GROUP__(...) __VA_ARGS__ #endif @@ -613,7 +621,7 @@ extern void _UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_ #define UpdateProgressWithInfoForce(op, msg, processed, total) _UpdateProgressWithInfo(op, msg, processed, total, TRUE) #define UpdateProgressWithInfoInit(hProgressDialog, bNoAltMode) UpdateProgressWithInfo(OP_INIT, (int)bNoAltMode, (uint64_t)(uintptr_t)hProgressDialog, 0); extern const char* StrError(DWORD error_code, BOOL use_default_locale); -extern char* GuidToString(const GUID* guid); +extern char* GuidToString(const GUID* guid, BOOL bDecorated); extern GUID* StringToGuid(const char* str); extern char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units); extern char* TimestampToHumanReadable(uint64_t ts); @@ -723,6 +731,7 @@ extern HICON CreateMirroredIcon(HICON hiconOrg); extern HANDLE CreatePreallocatedFile(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, LONGLONG fileSize); +extern uint32_t ResolveDllAddress(dll_resolver_t* resolver); #define GetTextWidth(hDlg, id) GetTextSize(GetDlgItem(hDlg, id), NULL).cx DWORD WINAPI HashThread(void* param); diff --git a/src/rufus.rc b/src/rufus.rc index 9cb6ccb7..0f3d4b52 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.2.2065" +CAPTION "Rufus 4.2.2066" 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,2,2065,0 - PRODUCTVERSION 4,2,2065,0 + FILEVERSION 4,2,2066,0 + PRODUCTVERSION 4,2,2066,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.2.2065" + VALUE "FileVersion", "4.2.2066" 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.2.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.2.2065" + VALUE "ProductVersion", "4.2.2066" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 3a242042..f784683b 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -28,20 +28,25 @@ #include #include #include +#include #include #include #include #include "rufus.h" +#include "missing.h" +#include "settings.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" -#define FACILITY_WIM 322 +#define FACILITY_WIM 322 +#define DEFAULT_BASE_ADDRESS 0x100000000ULL /* * Globals */ +const HANDLE hRufus = (HANDLE)0x0000005275667573ULL; // "\0\0\0Rufus" HWND hStatus; size_t ubuffer_pos = 0; char ubuffer[UBUFFER_SIZE]; // Buffer for ubpushf() messages we don't log right away @@ -683,12 +688,13 @@ const char *WindowsErrorString(void) return err_string; } -char* GuidToString(const GUID* guid) +char* GuidToString(const GUID* guid, BOOL bDecorated) { static char guid_string[MAX_GUID_STRING_LENGTH]; if (guid == NULL) return NULL; - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + sprintf(guid_string, bDecorated ? "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}" : + "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", (uint32_t)guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); @@ -1143,3 +1149,114 @@ HANDLE CreatePreallocatedFile(const char* lpFileName, DWORD dwDesiredAccess, return fileHandle; } + +// The following calls are used to resolve the addresses of DLL function calls +// that are not publicly exposed by Microsoft. This is accomplished by downloading +// the relevant .pdb and looking up the relevant address there. Once an address is +// found, it is stored in the Rufus settings so that it can be reused. + +PF_TYPE_DECL(WINAPI, BOOL, SymInitialize, (HANDLE, PCSTR, BOOL)); +PF_TYPE_DECL(WINAPI, DWORD64, SymLoadModuleEx, (HANDLE, HANDLE, PCSTR, PCSTR, DWORD64, DWORD, PMODLOAD_DATA, DWORD)); +PF_TYPE_DECL(WINAPI, BOOL, SymGetModuleInfo64, (HANDLE, DWORD64, PIMAGEHLP_MODULE64)); +PF_TYPE_DECL(WINAPI, BOOL, SymUnloadModule64, (HANDLE, DWORD64)); +PF_TYPE_DECL(WINAPI, BOOL, SymEnumSymbols, (HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID)); +PF_TYPE_DECL(WINAPI, BOOL, SymCleanup, (HANDLE)); + +BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext) +{ + dll_resolver_t* resolver = (dll_resolver_t*)UserContext; + uint32_t i; + + for (i = 0; i < resolver->count; i++) { + if (safe_strcmp(pSymInfo->Name, resolver->name[i]) == 0) { + resolver->address[i] = (uint32_t)pSymInfo->Address; +#if defined(_DEBUG) + uprintf("%08x: %s", resolver->address[i], resolver->name[i]); +#endif + } + } + + return TRUE; +} + +uint32_t ResolveDllAddress(dll_resolver_t* resolver) +{ + uint32_t r = 0; + uint32_t i; + char url[MAX_PATH], saved_id[MAX_PATH], path[MAX_PATH]; + DWORD64 base_address; + IMAGEHLP_MODULE64 info = { sizeof(IMAGEHLP_MODULE64) }; + + PF_INIT(SymInitialize, DbgHelp); + PF_INIT(SymLoadModuleEx, DbgHelp); + PF_INIT(SymGetModuleInfo64, DbgHelp); + PF_INIT(SymUnloadModule64, DbgHelp); + PF_INIT(SymEnumSymbols, DbgHelp); + PF_INIT(SymCleanup, DbgHelp); + + if (pfSymInitialize == NULL || pfSymLoadModuleEx == NULL || pfSymGetModuleInfo64 == NULL || + pfSymUnloadModule64 == NULL || pfSymEnumSymbols == NULL || pfSymCleanup == NULL || + resolver->count == 0 || resolver->path == NULL || resolver->name == NULL || resolver->address == NULL) + return 0; + + if (!pfSymInitialize(hRufus, NULL, FALSE)) { + uprintf("Could not initialize DLL symbol handler"); + return 0; + } + + // Get the PDB unique address from the DLL + base_address = pfSymLoadModuleEx(hRufus, NULL, resolver->path, NULL, DEFAULT_BASE_ADDRESS, 0, NULL, 0); + if (base_address == 0ULL || !pfSymGetModuleInfo64(hRufus, base_address, &info)) { + uprintf("Could not obtain DLL symbol info"); + goto out; + } + assert(base_address == DEFAULT_BASE_ADDRESS); + pfSymUnloadModule64(hRufus, base_address); + + // Check settings to see if we have existing data for these DLL calls. + for (i = 0; i < resolver->count; i++) { + static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), + GuidToString(&info.PdbSig70, FALSE), (int)info.PdbAge, resolver->name[i]); + resolver->address[i] = ReadSetting32(saved_id); + if (resolver->address[i] == 0) + break; + } + + if (i == resolver->count) { + // No need to download the PDB + r = resolver->count; + goto out; + } + + // Download the PDB from Microsoft's symbol servers + if (MessageBoxExU(hMainDialog, lmprintf(MSG_345), lmprintf(MSG_115), + MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES) + goto out; + static_sprintf(path, "%s\\%s.pdb", temp_dir, info.ModuleName); + static_sprintf(url, "http://msdl.microsoft.com/download/symbols/%s.pdb/%s%x/%s.pdb", + info.ModuleName, GuidToString(&info.PdbSig70, FALSE), (int)info.PdbAge, info.ModuleName); + if (DownloadToFileOrBufferEx(url, path, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) < 200 * KB) + goto out; + + // NB: SymLoadModuleEx() does not load a PDB unless the file has an explicit '.pdb' extension + base_address = pfSymLoadModuleEx(hRufus, NULL, path, NULL, DEFAULT_BASE_ADDRESS, 0, NULL, 0); + assert(base_address == DEFAULT_BASE_ADDRESS); + pfSymEnumSymbols(hRufus, base_address, "*!*", EnumSymProc, resolver); + DeleteFileU(path); + + // Store the addresses + r = 0; + for (i = 0; i < resolver->count; i++) { + static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), + GuidToString(&info.PdbSig70, FALSE), (int)info.PdbAge, resolver->name[i]); + if (resolver->address[i] != 0) { + WriteSetting32(saved_id, resolver->address[i]); + r++; + } + } + +out: + pfSymUnloadModule64(hRufus, base_address); + pfSymCleanup(hRufus); + return r; +}