Skip to content

Commit

Permalink
[wue] add experimental option to replace Windows bootloaders with the…
Browse files Browse the repository at this point in the history
… 24H2 _EX versions

* This aims at creating installation media that is compatible with systems where
  'Microsoft Windows Production PCA 2011' has been revoked.
* Doesn't work, since the bootloaders being applied by the first stage installer come
  from \sources\install.wim[#]\windows\system32\Recovery\Winre.wim[#]\Windows\Boot\
  (instead of \sources\boot.wim[#]\Windows\Boot\ as one would naturally expect) and
  Microsoft botched the ones they included there by using completely vulnerable (and
  therefore revoked) ones.
  See #2244 (comment).
* Still, I sure haven't gone through this excruciating ACL bullshit for nothing, so
  you get an experimental option, behind the expert mode curtain.
  • Loading branch information
pbatard committed Oct 8, 2024
1 parent c800448 commit fd5c366
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 49 deletions.
1 change: 1 addition & 0 deletions res/loc/rufus.loc
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ t MSG_346 "Restrict Windows to S-Mode (INCOMPATIBLE with online account bypass)"
t MSG_347 "Expert Mode"
t MSG_348 "Extracting archive files: %s"
t MSG_349 "Use Rufus MBR"
t MSG_350 "Use 'Windows UEFI CA 2023' signed bootloaders [EXPERIMENTAL]"
# 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"
Expand Down
73 changes: 73 additions & 0 deletions src/msapi_utf8.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <stdio.h>
#include <shlobj.h>
#include <ctype.h>
#include <aclapi.h>
#include <accctrl.h>
#include <commdlg.h>
#include <shellapi.h>
#include <shlwapi.h>
Expand Down Expand Up @@ -89,6 +91,9 @@ static __inline char* wchar_to_utf8(const wchar_t* wstr)
int size = 0;
char* str = NULL;

if (wstr == NULL)
return NULL;

// Convert the empty string too
if (wstr[0] == 0)
return (char*)calloc(1, 1);
Expand Down Expand Up @@ -568,6 +573,52 @@ static __inline const char* PathFindFileNameU(const char* szPath)
return &szPath[i];
}

static __inline char* PathCombineU(char* lpDest, char* lpDir, char* lpFile)
{
wchar_t* wret = NULL;
DWORD err = ERROR_INVALID_DATA;
wchar_t wlpDest[MAX_PATH];
wconvert(lpDir);
wconvert(lpFile);
wret = PathCombineW(wlpDest, wlpDir, wlpFile);
err = GetLastError();
wfree(lpDir);
wfree(lpFile);
if (wret == NULL)
return NULL;
wchar_to_utf8_no_alloc(wlpDest, lpDest, MAX_PATH);
SetLastError(err);
return lpDest;
}

static __inline HANDLE FindFirstFileU(char* lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
{
HANDLE ret = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW wFindFileData = { 0 };
wconvert(lpFileName);
ret = FindFirstFileW(wlpFileName, &wFindFileData);
if (ret != INVALID_HANDLE_VALUE) {
memcpy(lpFindFileData, &wFindFileData, offsetof(WIN32_FIND_DATAW, cFileName));
wchar_to_utf8_no_alloc(wFindFileData.cFileName, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
wchar_to_utf8_no_alloc(wFindFileData.cAlternateFileName, lpFindFileData->cAlternateFileName, sizeof(lpFindFileData->cAlternateFileName));
}
wfree(lpFileName);
return ret;
}

static __inline BOOL FindNextFileU(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
{
BOOL ret = FALSE;
WIN32_FIND_DATAW wFindFileData = { 0 };
ret = FindNextFileW(hFindFile, &wFindFileData);
if (ret) {
memcpy(lpFindFileData, &wFindFileData, offsetof(WIN32_FIND_DATAW, cFileName));
wchar_to_utf8_no_alloc(wFindFileData.cFileName, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName));
wchar_to_utf8_no_alloc(wFindFileData.cAlternateFileName, lpFindFileData->cAlternateFileName, sizeof(lpFindFileData->cAlternateFileName));
}
return ret;
}

// This function differs from regular GetTextExtentPoint in that it uses a zero terminated string
static __inline BOOL GetTextExtentPointU(HDC hdc, const char* lpString, LPSIZE lpSize)
{
Expand Down Expand Up @@ -819,6 +870,28 @@ static __inline BOOL SetFileAttributesU(const char* lpFileName, DWORD dwFileAttr
return ret;
}

static __inline DWORD GetNamedSecurityInfoU(const char* lpObjectName, SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo, PSID* ppsidOwner, PSID* ppsidGroup, PACL* ppDacl,
PACL* ppSacl, PSECURITY_DESCRIPTOR* ppSecurityDescriptor)
{
DWORD ret;
wconvert(lpObjectName);
ret = GetNamedSecurityInfoW(wlpObjectName, ObjectType, SecurityInfo, ppsidOwner, ppsidGroup,
ppDacl, ppSacl, ppSecurityDescriptor);
wfree(lpObjectName);
return ret;
}

static __inline DWORD SetNamedSecurityInfoU(const char* lpObjectName, SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl)
{
DWORD ret;
wconvert(lpObjectName);
ret = SetNamedSecurityInfoW(wlpObjectName, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl);
wfree(lpObjectName);
return ret;
}

static __inline int SHCreateDirectoryExU(HWND hwnd, const char* pszPath, SECURITY_ATTRIBUTES *psa)
{
int ret = ERROR_INVALID_DATA;
Expand Down
31 changes: 27 additions & 4 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ char* replace_in_token_data(const char* filename, const char* token, const char*
}

/*
* Replace all 'c' characters in string 'src' with the substring 'rep'
* Replace all 'c' characters in string 'src' with the substring 'rep'.
* The returned string is allocated and must be freed by the caller.
*/
char* replace_char(const char* src, const char c, const char* rep)
Expand Down Expand Up @@ -1300,6 +1300,30 @@ char* replace_char(const char* src, const char c, const char* rep)
return res;
}

/*
* Remove all instances of substring 'sub' form string 'src.
* The returned string is allocated and must be freed by the caller.
*/
char* remove_substr(const char* src, const char* sub)
{
size_t i, j, str_len = safe_strlen(src), sub_len = safe_strlen(sub);
char* res;

if ((src == NULL) || (sub == NULL) || (sub_len > str_len))
return NULL;

res = (char*)calloc(str_len + 1, 1);
if (res == NULL)
return NULL;
for (i = 0, j = 0; i <= str_len; ) {
if (i <= str_len - sub_len && memcmp(&src[i], sub, sub_len) == 0)
i += sub_len;
else
res[j++] = src[i++];
}
return res;
}

/*
* Internal recursive call for get_data_from_asn1(). Returns FALSE on error, TRUE otherwise.
*/
Expand Down Expand Up @@ -1697,8 +1721,7 @@ uint8_t* RvaToPhysical(uint8_t* buf, uint32_t rva)
static BOOL FoundResourceRva = FALSE;
uint32_t FindResourceRva(const wchar_t* name, uint8_t* root, uint8_t* dir, uint32_t* len)
{
uint32_t rva;
WORD i;
uint32_t i, rva;
IMAGE_RESOURCE_DIRECTORY* _dir = (IMAGE_RESOURCE_DIRECTORY*)dir;
IMAGE_RESOURCE_DIRECTORY_ENTRY* dir_entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)&_dir[1];
IMAGE_RESOURCE_DIR_STRING_U* dir_string;
Expand All @@ -1711,7 +1734,7 @@ uint32_t FindResourceRva(const wchar_t* name, uint8_t* root, uint8_t* dir, uint3
if (root == dir)
FoundResourceRva = FALSE;

for (i = 0; i < _dir->NumberOfNamedEntries + _dir->NumberOfIdEntries; i++) {
for (i = 0; i < (uint32_t)_dir->NumberOfNamedEntries + _dir->NumberOfIdEntries; i++) {
if (!FoundResourceRva && i < _dir->NumberOfNamedEntries) {
dir_string = (IMAGE_RESOURCE_DIR_STRING_U*)(root + dir_entry[i].NameOffset);
if (dir_string->Length != wcslen(name) ||
Expand Down
6 changes: 5 additions & 1 deletion src/rufus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1586,6 +1586,10 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
StrArrayAdd(&options, lmprintf(MSG_335), TRUE);
MAP_BIT(UNATTEND_DISABLE_BITLOCKER);
if (expert_mode) {
if (!appstore_version && img_report.win_version.build >= 26100) {
StrArrayAdd(&options, lmprintf(MSG_350), TRUE);
MAP_BIT(UNATTEND_USE_MS2023_BOOTLOADERS);
}
StrArrayAdd(&options, lmprintf(MSG_346), TRUE);
MAP_BIT(UNATTEND_FORCE_S_MODE);
}
Expand All @@ -1597,7 +1601,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
i = remap16(i, map, TRUE);
unattend_xml_path = CreateUnattendXml(arch, i);
// Remember the user preferences for the current session.
unattend_xml_mask &= ~(remap16(0x1ff, map, TRUE));
unattend_xml_mask &= ~(remap16(UNATTEND_FULL_MASK, map, TRUE));
unattend_xml_mask |= i;
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
}
Expand Down
12 changes: 11 additions & 1 deletion src/rufus.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,17 +629,24 @@ typedef struct {
#define UNATTEND_SET_USER 0x00040
#define UNATTEND_DISABLE_BITLOCKER 0x00080
#define UNATTEND_FORCE_S_MODE 0x00100
#define UNATTEND_USE_MS2023_BOOTLOADERS 0x00200
#define UNATTEND_FULL_MASK 0x003FF
#define UNATTEND_DEFAULT_MASK 0x000FF
#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go

#define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM)
#define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT)
#define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_SET_USER | UNATTEND_DUPLICATE_LOCALE)
#define UNATTEND_OOBE_INTERNATIONAL_MASK (UNATTEND_DUPLICATE_LOCALE)
#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER)
#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER | UNATTEND_USE_MS2023_BOOTLOADERS)
#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)

/* Used with ListDirectoryContent */
#define LIST_DIR_TYPE_FILE 0x01
#define LIST_DIR_TYPE_DIRECTORY 0x02
#define LIST_DIR_TYPE_RECURSIVE 0x80

/* Hash tables */
typedef struct htab_entry {
uint32_t used;
Expand Down Expand Up @@ -786,6 +793,7 @@ extern char* get_token_data_buffer(const char* token, unsigned int n, const char
extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix);
extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix);
extern char* replace_char(const char* src, const char c, const char* rep);
extern char* remove_substr(const char* src, const char* sub);
extern void parse_update(char* buf, size_t len);
extern void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str, uint8_t asn1_type, size_t* data_len);
extern int sanitize_label(char* label);
Expand Down Expand Up @@ -835,6 +843,8 @@ extern uint16_t GetPeArch(uint8_t* buf);
extern uint8_t* GetPeSection(uint8_t* buf, const char* name, uint32_t* len);
extern uint8_t* RvaToPhysical(uint8_t* buf, uint32_t rva);
extern uint32_t FindResourceRva(const wchar_t* name, uint8_t* root, uint8_t* dir, uint32_t* len);
extern DWORD ListDirectoryContent(StrArray* arr, char* dir, uint8_t type);
extern BOOL TakeOwnership(LPCSTR lpszOwnFile);
#define GetTextWidth(hDlg, id) GetTextSize(GetDlgItem(hDlg, id), NULL).cx

DWORD WINAPI HashThread(void* param);
Expand Down
10 changes: 5 additions & 5 deletions src/rufus.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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.6.2200"
CAPTION "Rufus 4.6.2201"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
Expand Down Expand Up @@ -399,8 +399,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,6,2200,0
PRODUCTVERSION 4,6,2200,0
FILEVERSION 4,6,2201,0
PRODUCTVERSION 4,6,2201,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -418,13 +418,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.6.2200"
VALUE "FileVersion", "4.6.2201"
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.6.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.6.2200"
VALUE "ProductVersion", "4.6.2201"
END
END
BLOCK "VarFileInfo"
Expand Down
72 changes: 72 additions & 0 deletions src/stdfn.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <sddl.h>
#include <gpedit.h>
#include <assert.h>
#include <accctrl.h>
#include <aclapi.h>

#include "re.h"
#include "rufus.h"
Expand Down Expand Up @@ -1242,3 +1244,73 @@ BOOL UnmountRegistryHive(const HKEY key, const char* pszHiveName)

return (status == ERROR_SUCCESS);
}

/*
* Take administrative ownership of a file or directory, and grant all access rights.
*/
BOOL TakeOwnership(LPCSTR lpszOwnFile)
{
BOOL ret = FALSE;
HANDLE hToken = NULL;
PSID pSIDAdmin = NULL;
PACL pOldDACL = NULL, pNewDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
EXPLICIT_ACCESS ea = { 0 };

if (lpszOwnFile == NULL)
return FALSE;

// Create a SID for the BUILTIN\Administrators group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSIDAdmin))
goto out;

// Open a handle to the access token for the calling process.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
goto out;

// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
goto out;

// Set the owner in the object's security descriptor.
if (SetNamedSecurityInfoU(lpszOwnFile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION,
pSIDAdmin, NULL, NULL, NULL) != ERROR_SUCCESS)
goto out;

// Disable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
goto out;

// Get a pointer to the existing DACL.
if (GetNamedSecurityInfoU(lpszOwnFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
goto out;

// Initialize an EXPLICIT_ACCESS structure for the new ACE
// with full control for Administrators.
ea.grfAccessPermissions = GENERIC_ALL;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = (LPTSTR)pSIDAdmin;

// Create a new ACL that merges the new ACE into the existing DACL.
if (SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
goto out;

// Try to modify the object's DACL.
if (SetNamedSecurityInfoU(lpszOwnFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
goto out;

ret = TRUE;

out:
FreeSid(pSIDAdmin);
LocalFree(pNewDACL);
safe_closehandle(hToken);
return ret;
}
Loading

0 comments on commit fd5c366

Please sign in to comment.