Skip to content

Commit

Permalink
[wue] add an expert feature to restrict a Windows installation to S Mode
Browse files Browse the repository at this point in the history
* This is placed behind an expert wall (Ctrl-Alt-E) on account that:
  - If you happen to boot a Windows To Go drive in S Mode on a computer, it may set any
    existing Windows installation there to S Mode as well, *even if their disk is offline!*
  - It can be *exceedingly* tricky to get out of S Mode, as the SkuPolicyRequired registry
    trick alone may not be enough (i.e. You can have very much a Windows install in S Mode
    *without* SkuPolicyRequired being set anywhere).
* Also set version to rufus-next and fix a ChangeLog typo.
  • Loading branch information
pbatard committed Aug 15, 2023
1 parent 5084317 commit c5ad16f
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 29 deletions.
2 changes: 1 addition & 1 deletion ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ o Version 4.2 (2023.07.26)
Add saving and restoring current drive to/from compressed VHDX image
Add saving and restoring current drive to/from compressed FFU (Full Flash Update) image [EXPERIMENTAL]
Fix a crash when trying to open Windows ISOs, with the MinGW compiled x86 32-bit version
Fix an issue where ISOs that contain a boot image with an 'EFI' label are not be detected bootable
Fix an issue where ISOs that contain a boot image with an 'EFI' label are not detected as bootable
Increase the ISO → ESP limit for Debian 12 netinst images
Ensure that the main partition size is aligned to the cluster size

Expand Down
20 changes: 10 additions & 10 deletions configure
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for rufus 4.2.
# Generated by GNU Autoconf 2.71 for rufus 4.3.
#
# Report bugs to <https://github.com/pbatard/rufus/issues>.
#
Expand Down Expand Up @@ -611,8 +611,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='4.2'
PACKAGE_STRING='rufus 4.2'
PACKAGE_VERSION='4.3'
PACKAGE_STRING='rufus 4.3'
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
PACKAGE_URL='https://rufus.ie'

Expand Down Expand Up @@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures rufus 4.2 to adapt to many kinds of systems.
\`configure' configures rufus 4.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
Expand Down Expand Up @@ -1336,7 +1336,7 @@ fi

if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of rufus 4.2:";;
short | recursive ) echo "Configuration of rufus 4.3:";;
esac
cat <<\_ACEOF
Expand Down Expand Up @@ -1428,7 +1428,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
rufus configure 4.2
rufus configure 4.3
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
Expand Down Expand Up @@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by rufus $as_me 4.2, which was
It was created by rufus $as_me 4.3, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
Expand Down Expand Up @@ -2767,7 +2767,7 @@ fi
# Define the identity of the package.
PACKAGE='rufus'
VERSION='4.2'
VERSION='4.3'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
Expand Down Expand Up @@ -5309,7 +5309,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by rufus $as_me 4.2, which was
This file was extended by rufus $as_me 4.3, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
Expand Down Expand Up @@ -5365,7 +5365,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
rufus config.status 4.2
rufus config.status 4.3
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AC_INIT([rufus], [4.2], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AC_INIT([rufus], [4.3], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4])
Expand Down
2 changes: 2 additions & 0 deletions res/loc/rufus.loc
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ 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"
t MSG_346 "Restrict Windows to S-Mode (INCOMPATIBLE with online account bypass)"
t MSG_347 "Expert Mode"
# 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
38 changes: 28 additions & 10 deletions src/rufus.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ BOOL usb_debug, use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALS
BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE;
BOOL write_as_image = FALSE, write_as_esp = FALSE, use_vds = FALSE, ignore_boot_marker = FALSE;
BOOL appstore_version = FALSE, is_vds_available = TRUE, persistent_log = FALSE, has_ffu_support = FALSE;
BOOL expert_mode = FALSE;
float fScale = 1.0f;
int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0;
int default_fs, fs_type, boot_type, partition_type, target_type;
Expand Down Expand Up @@ -1514,8 +1515,8 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if ((WindowsVersion.Version >= WINDOWS_8) && IS_WINDOWS_1X(img_report)) {
StrArray options;
int arch = _log2(img_report.has_efi >> 1);
uint8_t map[8] = { 0 }, b = 1;
StrArrayCreate(&options, 2);
uint16_t map[16] = { 0 }, b = 1;
StrArrayCreate(&options, 8);
StrArrayAdd(&options, lmprintf(MSG_332), TRUE);
MAP_BIT(UNATTEND_OFFLINE_INTERNAL_DRIVES);
if (img_report.win_version.build >= 22500) {
Expand All @@ -1529,16 +1530,20 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
MAP_BIT(UNATTEND_DUPLICATE_LOCALE);
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
if (expert_mode) {
StrArrayAdd(&options, lmprintf(MSG_346), TRUE);
MAP_BIT(UNATTEND_FORCE_S_MODE);
}
i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328),
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE), username_index);
options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index);
StrArrayDestroy(&options);
if (i < 0)
goto out;
// Remap i to the correct bit positions before calling CreateUnattendXml()
i = remap8(i, map, TRUE);
i = remap16(i, map, TRUE);
unattend_xml_path = CreateUnattendXml(arch, i | UNATTEND_WINDOWS_TO_GO);
// Keep the bits we didn't process
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
unattend_xml_mask &= ~(remap16(0x1ff, map, TRUE));
// And add back the bits we did process
unattend_xml_mask |= i;
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
Expand Down Expand Up @@ -1576,8 +1581,8 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if ((WindowsVersion.Version >= WINDOWS_8) && IS_WINDOWS_1X(img_report) && (!is_windows_to_go)) {
StrArray options;
int arch = _log2(img_report.has_efi >> 1);
uint8_t map[8] = { 0 }, b = 1;
StrArrayCreate(&options, 4);
uint16_t map[16] = { 0 }, b = 1;
StrArrayCreate(&options, 10);
if (IS_WINDOWS_11(img_report)) {
StrArrayAdd(&options, lmprintf(MSG_329), TRUE);
MAP_BIT(UNATTEND_SECUREBOOT_TPM_MINRAM);
Expand All @@ -1595,15 +1600,19 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
StrArrayAdd(&options, lmprintf(MSG_335), TRUE);
MAP_BIT(UNATTEND_DISABLE_BITLOCKER);
if (expert_mode) {
StrArrayAdd(&options, lmprintf(MSG_346), TRUE);
MAP_BIT(UNATTEND_FORCE_S_MODE);
}
i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328),
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE), username_index);
options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index);
StrArrayDestroy(&options);
if (i < 0)
goto out;
i = remap8(i, map, TRUE);
i = remap16(i, map, TRUE);
unattend_xml_path = CreateUnattendXml(arch, i);
// Remember the user preferences for the current session.
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
unattend_xml_mask &= ~(remap16(0x1ff, map, TRUE));
unattend_xml_mask |= i;
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
}
Expand Down Expand Up @@ -3556,6 +3565,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
enable_file_indexing = ReadSettingBool(SETTING_ENABLE_FILE_INDEXING);
enable_VHDs = !ReadSettingBool(SETTING_DISABLE_VHDS);
enable_extra_hashes = ReadSettingBool(SETTING_ENABLE_EXTRA_HASHES);
expert_mode = ReadSettingBool(SETTING_EXPERT_MODE);
ignore_boot_marker = ReadSettingBool(SETTING_IGNORE_BOOT_MARKER);
persistent_log = ReadSettingBool(SETTING_PERSISTENT_LOG);
save_image_type = ReadSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE);
Expand Down Expand Up @@ -4074,6 +4084,14 @@ extern int TestHashes(void);
}

// Other hazardous cheat modes require Ctrl + Alt
// Ctrl-Alt-E => Expert Mode
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'E') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
expert_mode = !expert_mode;
WriteSettingBool(SETTING_EXPERT_MODE, expert_mode);
PrintStatusTimeout(lmprintf(MSG_347), expert_mode);
continue;
}
// Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!!
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
Expand Down
3 changes: 2 additions & 1 deletion src/rufus.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ typedef struct {
#define UNATTEND_DUPLICATE_LOCALE 0x00020
#define UNATTEND_SET_USER 0x00040
#define UNATTEND_DISABLE_BITLOCKER 0x00080
#define UNATTEND_FORCE_S_MODE 0x00100
#define UNATTEND_DEFAULT_MASK 0x000FF
#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go

Expand All @@ -580,7 +581,7 @@ typedef struct {
#define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_SET_USER)
#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_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES)
#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)

/*
Expand Down
12 changes: 6 additions & 6 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.2.2074"
CAPTION "Rufus 4.3.2075"
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 @@ -392,8 +392,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,2,2074,0
PRODUCTVERSION 4,2,2074,0
FILEVERSION 4,3,2075,0
PRODUCTVERSION 4,3,2075,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.2.2074"
VALUE "FileVersion", "4.3.2075"
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 "OriginalFilename", "rufus-4.3.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.2.2074"
VALUE "ProductVersion", "4.3.2075"
END
END
BLOCK "VarFileInfo"
Expand Down
1 change: 1 addition & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern char* ini_file;
#define SETTING_ENABLE_USB_DEBUG "EnableUsbDebug"
#define SETTING_ENABLE_VMDK_DETECTION "EnableVmdkDetection"
#define SETTING_ENABLE_WIN_DUAL_EFI_BIOS "EnableWindowsDualUefiBiosMode"
#define SETTING_EXPERT_MODE "ExpertMode"
#define SETTING_FORCE_LARGE_FAT32_FORMAT "ForceLargeFat32Formatting"
#define SETTING_IGNORE_BOOT_MARKER "IgnoreBootMarker"
#define SETTING_INCLUDE_BETAS "CheckForBetas"
Expand Down
9 changes: 9 additions & 0 deletions src/wue.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ char* CreateUnattendXml(int arch, int flags)
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
fprintf(fd, " <RunSynchronous>\n");
// This part was picked from https://github.com/AveYo/MediaCreationTool.bat/blob/main/bypass11/AutoUnattend.xml
// NB: This is INCOMPATIBLE with S-Mode below
if (flags & UNATTEND_NO_ONLINE_ACCOUNT) {
uprintf("• Bypass online account requirement");
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
Expand Down Expand Up @@ -226,6 +227,14 @@ char* CreateUnattendXml(int arch, int flags)
fprintf(fd, " <SanPolicy>4</SanPolicy>\n");
fprintf(fd, " </component>\n");
}
if (flags & UNATTEND_FORCE_S_MODE) {
uprintf("• Enforce S Mode");
fprintf(fd, " <component name=\"Microsoft-Windows-CodeIntegrity\" processorArchitecture=\"%s\" language=\"neutral\" "
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
fprintf(fd, " <SkuPolicyRequired>1</SkuPolicyRequired>\n");
fprintf(fd, " </component>\n");
}
fprintf(fd, " </settings>\n");
}

Expand Down

13 comments on commit c5ad16f

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Investigate how the heck Microsoft enforces S Mode globally even for installs that were offline and computers that were disconnected from the network. UEFI vars?"

an SiPolicy is used for this, at one point it was WinSiPolicy.p7b, but it might have changed since. As such, NV|BS-only UEFI lock variables exist for this, like for skusipolicy.

@pbatard
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the input.

I gathered that, since the registry key to turn S mode on is called SkuPolicyRequired, the whole thing was indeed linked to using some UEFI variables and some WDAC policies.

Since it was annoying getting out of S Mode on the machine I tested with (I basically had to create a dummy MS account from a Windows To Go install and install the "get out of S-Mode" Microsoft Store app), I'm not in a hurry to experiment with this again, at least until I have another test machine to play with, that I can afford to keep in S Mode for some time, and where I can dump the UEFI vars before and after S Mode is enabled, to figure out what's actually going on on the UEFI side.

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at winload to see what it does.

WinSiPolicyVersion/WinSiPolicyUpdateSigners variables are used to detect if S Mode is enabled.

winload does also check for Kernel_CI_SKU_UNLOCKED variable in same namespace (NV|BS|RT, as the variable is in MS namespace with a name starts with "Kernel_", NT will prevent writes to it from usermode), if it's present it will delete the lock variables, so this is most likely what the official S Mode disable process sets.

@pbatard
Copy link
Owner Author

@pbatard pbatard commented on c5ad16f Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again, you are very much spot on! 😄

I played again with S Mode, and saw these WinSiPolicyVersion and WinSiPolicyUpdateSigners variables created, which in turn forced S Mode to be applied to any Windows installation residing on the same machine.
It should be noted however that these variables are only created if Secure Boot is enabled (so, if you run an S Mode Windows To Go without Secure Boot on one machine and reboot to an existing installation, then that existing installation will not be turned to S Mode), which kind of makes sense since Microsoft did target S Mode for Secure Boot enabled devices as there wouldn't be much point restricting these platforms otherwise.

I did not see any Kernel_** variable created after installing the Get me out of S Mode app (which, for the record, disables S Mode instantly without the need for a reboot). As a matter of fact, since I did not reboot into the newly non S Mode Windows after I installed the app, but into my existing Windows Pro install (after a quick UEFI Shell detour to dump the vars where I found that they were still present, albeit with WinSiPolicyUpdateSigners slightly altered), I found that the existing install was still running in S Mode, so I guess the WinSiPolicyVersion and WinSiPolicyUpdateSigners variables are only deleted by Windows after you reboot the previously-S-Mode-enabled-but-now-disabled install.

At any rate, this allowed to validate that deleting those variables manually was enough to restore the existing install to full mode, which validates that all Windows looks at, when not using the SkuPolicyRequired registry key, are whether these UEFI variables are present and valid (and I surmise that creating the SkuPolicyRequired registry key does in turn create these UEFI variables, which is something I may try to validate later on).

I think I'll try to publish a blog or wiki post somewhere to synthesize this data (unless you want to do it yourself) along with a startup.nsh that can be used with a UEFI Shell boot media to remove these variables, for people who want to switch out of S Mode without installing the MS app.

And just for completion, here's the dump of the 2 variables I saw on my system:

Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:WinSiPolicyVersion' DataSize = 0x08
  00000000: 00 00 BF 3A 00 00 0A 00-                         *...:....*
Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:WinSiPolicyUpdateSigners' DataSize = 0xA3
  00000000: 01 00 00 00 00 00 00 00-0C 80 00 00 20 00 00 00  *............ ...*
  00000010: 00 00 00 00 50 E9 51 59-06 F8 FF FF 01 00 00 00  *....P.QY........*
  00000020: 0B 00 00 00 20 9C 47 59-06 F8 FF FF 00 00 02 00  *.... .GY........*
  00000030: 00 00 00 00 7C E9 51 59-06 F8 FF FF 00 00 02 00  *....|.QY........*
  00000040: 00 00 00 00 84 E9 51 59-06 F8 FF FF 00 00 02 00  *......QY........*
  00000050: 00 00 00 00 8C E9 51 59-06 F8 FF FF 00 00 00 00  *......QY........*
  00000060: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................*
  00000070: 00 00 00 00 4E 80 BE 10-7C 86 0D E8 96 38 4B 3E  *....N...|....8K>*
  00000080: FF 50 50 4D C2 D7 6A C7-15 1D F3 10 2A 44 50 63  *.PPM..j.....*DPc*
  00000090: 7A 03 21 46 0A 2B 06 01-04 01 82 37 0A 03 06 00  *z.!F.+.....7....*
  000000A0: 00 00 00                                         *...*

@pbatard
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now my one small annoyance with this is that I'd like Rufus to be able to report if Windows is running in S Mode (since Rufus can also be installed from the Windows Store), but I'm not sure I want to go as far as adding code that looks into the system's UEFI variables just to do that, as I'm pretty sure this will drastically increase false positive results with AV providers (because why on earth would an application that creates bootable drives want to read the system's UEFI nvars if not for something nefarious?). I got to wonder if msinfo does poke at the UEFI vars, or if it gets its data from WDAC or something else to report on whether the system is running in S Mode...

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pbatard
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! This is exactly what I was looking for.

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meanwhile, I looked at how the "official" way to disable S mode works.

The Windows Store product ID for disabling S mode is BF712690PMLF. Metadata for this product ID shows it gives you a license for package family name Microsoft.Windows.ConsumerUnlock_8wekyb3d8bbwe.

When installing a store license, clipsvc.dll checks for this package family name (actually, it checks against a table containing 4 values: { L"Microsoft.Windows.CommercialUnlock_8wekyb3d8bbwe", L"Microsoft.Windows.ConsumerUnlock_8wekyb3d8bbwe", L"Microsoft.Windows.TestUnlock_8wekyb3d8bbwe", L"Microsoft.Windows.ManagedUnlock_8wekyb3d8bbwe" }).

If it matches, it takes an alternate codepath. It gets the license, ensures wldp!WldpQueryWindowsLockdownRestriction does not return WLDP_WINDOWS_LOCKDOWN_RESTRICTION_NOUNLOCK_PERMANENT (this ends up becoming a registry read; if it does return this value then clipsvc function returns error). Then it gets the value of UnlockTokenB64 from the license, base64 decodes it, then passes it to NtSetSystemInformation(SystemCodeIntegrityUnlockInformation).

This syscall ends up going into ci.dll and in particular ci!CiSetUnlockInformation. If called from usermode the usermode caller is required to be Windows or WinTCB signed (maybe that means Windows/WinTCB PPL at least too, not sure).

The buffer passed to this syscall is expected to be a signed supplemental Secure Boot Policy of type {AF77ACF3-9404-46FD-B23E-15E9D7892A26} and tied to a device-specific 256-bit UnlockID (stored in UEFI variable CopyOfUnlockID).

If all checks against the Secure Boot Policy pass (correct signature; is supplemental policy; type is correct; UnlockID matches), it gets written out to EFIESP:\EFI\Microsoft\Boot\Policies\UnlockToken.pol (winload will load this on subsequent boots), SkuPolicyRequired and ManufacturingMode registry values (in HKLM\SYSTEM\CurrentControlSet\Control\CI\Policy) are deleted, System Integrity policies are refreshed, and other applications are notified that S Mode has been disabled by NtUpdateWnfStateData(WNF_CI_SMODE_CHANGE).

So the official way to disable S mode involves getting a signed UnlockToken.pol wrapped in a Windows Store app license.

@pbatard
Copy link
Owner Author

@pbatard pbatard commented on c5ad16f Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this further. Your explanation matches some of the findings I got with further testing which are:

  • Deleting WinSiPolicyVersion and WinSiPolicyUpdateSigners for an install that is been set to S Mode from the get go (through setting SkuPolicyRequired in an answer file) is simply not enough to disable S Mode. This method of disabling S Mode only works for non restricted Windows installations that happen to have been turned to S Mode because of a separate S Mode install was carried out on the same machine.
  • If you did enable S Mode for a specific device, e.g. an SSD drive running Windows To Go, then erased that device to create a new Windows To Go installation, then, if Secure Boot is enabled, bootmgr/winload will forcefully prevent boot which, due to Microsoft's obnoxious short-sightedness in not returning an explicit security error then, but instead returning UEFI error 17 (No mapping), will lead to most systems declaring that the media is not bootable (whereas the media most certainly did boot and did execute the MS bootloader). So, until you disable Secure Boot, you can end up with perfectly fine bootable media that Microsoft tricks users into thinking that they are not bootable. So, indeed, we are definitely seeing Microsoft trying to lock S Mode so much that they're doing more harm than good all the people who will have no idea that Microsoft can make it look like black (bootable) is white (unbootable)...This was just the UEFI Lock from working with a v1 22H2 ISO and not a v2, see below.

Considering all the bullshit that S Mode entails, I am seriously considering removing the newly added ability to create S Mode installation of Windows from Rufus, even when standing behind an expert mode, because, whereas I added it for people who might have reasons to want to test S Mode, my experiments lead me to conclude that S Mode needs to die a horrible death, and that whoever at Microsoft pushed for an S Mode "feature" to be added to Windows should be moved to a damp office, without any Wwindows, in a remote basement.

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would be bootmgr, probably due to missing EFIESP:\EFI\Microsoft\Boot\winsipolicy.p7b.

If winload errors and returns back to bootmgr, bootmgr will show something on screen.

@pbatard
Copy link
Owner Author

@pbatard pbatard commented on c5ad16f Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're probably correct. My understanding so far however was that post 2023.05 bootloaders should not care about the presence of a specific .p7b to allow boot, and I'm testing with a 2023.05 22H2 v1 media.

I have validated that while I do have the UEFI SkuSiPolicy* Lock variables, the WinSiPolicy* ones are not present, so I'm not sure why boot with a post may Win 11 image would fail.
I did have a ConfigCIPolicyIndiv var, but deleting it still doesn't make Win 11 22H2 v1 media boot. There are a couple of other short MS variables as well, which I have not tried to delete:

Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:BootDebugPolicyApplied' DataSize = 0x01
  00000000: 2A                                               ***
Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:CurrentActivePolicy' DataSize = 0x01
  00000000: 00                                               *.*
Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:BootingDeviceTypeInfo' DataSize = 0x04
  00000000: 01 01 04 00                                      *....*
Variable NV+BS '77FA9ABD-0359-4D32-BD60-28F4E78F784B:WindowsBootChainSvn' DataSize = 0x04
  00000000: 01 00 00 00                                      *....*
Variable NV+RT+BS+AT '77FA9ABD-0359-4D32-BD60-28F4E78F784B:CurrentPolicy' DataSize = 0x01
  00000000: 02                                               *.*

@pbatard
Copy link
Owner Author

@pbatard pbatard commented on c5ad16f Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah shoot, now I get it. 22H2 v1 is pre 2023.05, whereas you want 22H2 v2 for the patched bootloaders.
So I was testing with an image that should indeed prevent boot through UEFI Lock.

@Wack0
Copy link

@Wack0 Wack0 commented on c5ad16f Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About those additional variables:

BootDebugPolicyApplied was set as part of one of the rounds of policyhax fixes to prevent an attacker using mobilestartup to install a vulnerable secure boot policy (mobilestartup does check and set that var itself)
CurrentActivePolicy is the "newer" (post-policyhax fix) legacy secure boot policy variable (replacing CurrentPolicy after its effective revocation, see below)
BootingDeviceTypeInfo is set by some sipolicy related code in bootmgr, it describes boot device and structure is: BYTE IsRemovableMedia; BYTE PartitionType; BYTE BlockIoType; BYTE DeviceType; - for that example, that means device type=block io, block io type=unknown, partition type=mbr, removable media=true
WindowsBootChainSvn is set by bootmgr (to 1) and on other boot application load (to the value in its SECURITYVERSIONNUMBER resource if present and greater than the existing value)
CurrentPolicy is the old (pre-policyhax fix) legacy secure boot policy variable, it was effectively revoked by setting it to authenticated (signed by a specific MS cert+pubkey) dummy data; this was the effective policyhax fix (assuming UEFI firmware could handle it, some UEFI firmware implementations did not, either by failing the write or by bricking the system)

Please sign in to comment.