From fad3993363ad834f4c2baaf60a04f8ee4656cc52 Mon Sep 17 00:00:00 2001 From: he3als <65787561+he3als@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:54:41 +0100 Subject: [PATCH] fix(packages): src for restorehealth/sfc (#1103) RestoreHealth/SFC can't find the Atlas packages on Windows Update, which caused a "Source not found" error to be displayed before. This commit fixes that by having a dynamically created alternate repair source that has the sources for the Atlas packages. This fixes the error. Other changes: - Don't import the cert for the package, not needed - Permanently add the test cert path, needed for RestoreHealth/SFC (has no known security implications to my knowledge) - sxsc fork generates a new inaccessible (only on the GitHub Runner) certificate on each build as a little security thing --- .../Configuration/atlas/components.yml | 2 - .../7. Security/Defender/Toggle Defender.cmd | 10 +- .../Telemetry Components.cmd | 10 +- .../AtlasModules/Scripts/packageInstall.ps1 | 116 ++++++++++++------ 4 files changed, 81 insertions(+), 57 deletions(-) diff --git a/src/playbook/Configuration/atlas/components.yml b/src/playbook/Configuration/atlas/components.yml index 51f2797151..c40a58d2ef 100644 --- a/src/playbook/Configuration/atlas/components.yml +++ b/src/playbook/Configuration/atlas/components.yml @@ -42,7 +42,6 @@ actions: ) -NoInteraction option: 'defender-disable' - runas: currentUserElevated wait: true exeDir: true - !powerShell: @@ -52,6 +51,5 @@ actions: -UninstallPackages @('*Z-Atlas-NoDefender-Package*') -NoInteraction option: 'defender-enable' - runas: currentUserElevated wait: true exeDir: true diff --git a/src/playbook/Executables/AtlasDesktop/7. Security/Defender/Toggle Defender.cmd b/src/playbook/Executables/AtlasDesktop/7. Security/Defender/Toggle Defender.cmd index 8ba61ff511..c82eb7c6bc 100644 --- a/src/playbook/Executables/AtlasDesktop/7. Security/Defender/Toggle Defender.cmd +++ b/src/playbook/Executables/AtlasDesktop/7. Security/Defender/Toggle Defender.cmd @@ -7,14 +7,8 @@ if not exist "%script%" ( exit /b 1 ) -set "___args="%~f0" %*" -fltmc > nul 2>&1 || ( - echo Administrator privileges are required. - powershell -c "Start-Process -Verb RunAs -FilePath 'cmd' -ArgumentList """/c $env:___args"""" 2> nul || ( - echo You must run this script as admin. - if "%*"=="" pause - exit /b 1 - ) +whoami /user | find /i "S-1-5-18" > nul 2>&1 || ( + call RunAsTI.cmd "%~f0" %* exit /b ) diff --git a/src/playbook/Executables/AtlasDesktop/8. Troubleshooting/Telemetry Components.cmd b/src/playbook/Executables/AtlasDesktop/8. Troubleshooting/Telemetry Components.cmd index 487fe5fe29..a1863102d6 100644 --- a/src/playbook/Executables/AtlasDesktop/8. Troubleshooting/Telemetry Components.cmd +++ b/src/playbook/Executables/AtlasDesktop/8. Troubleshooting/Telemetry Components.cmd @@ -7,14 +7,8 @@ if not exist "%script%" ( exit /b 1 ) -set "___args="%~f0" %*" -fltmc > nul 2>&1 || ( - echo Administrator privileges are required. - powershell -c "Start-Process -Verb RunAs -FilePath 'cmd' -ArgumentList """/c $env:___args"""" 2> nul || ( - echo You must run this script as admin. - if "%*"=="" pause - exit /b 1 - ) +whoami /user | find /i "S-1-5-18" > nul 2>&1 || ( + call RunAsTI.cmd "%~f0" %* exit /b ) diff --git a/src/playbook/Executables/AtlasModules/Scripts/packageInstall.ps1 b/src/playbook/Executables/AtlasModules/Scripts/packageInstall.ps1 index 792e914d02..5d8a891726 100644 --- a/src/playbook/Executables/AtlasModules/Scripts/packageInstall.ps1 +++ b/src/playbook/Executables/AtlasModules/Scripts/packageInstall.ps1 @@ -12,13 +12,17 @@ param ( [switch]$FailMessage ) +if (!([Security.Principal.WindowsIdentity]::GetCurrent().User.Value -eq 'S-1-5-18')) { + throw "This script must be ran as TrustedInstaller/SYSTEM." +} + # ======================================================================================================================= # # INITIAL VARIABLES # # ======================================================================================================================= # $sys32 = [Environment]::GetFolderPath('System') +$windir = [Environment]::GetFolderPath('Windows') $safeModePackageList = "$sys32\safeModePackagesToInstall.atlasmodule" -$env:path = "$([Environment]::GetFolderPath('Windows'));$sys32;$sys32\Wbem;$sys32\WindowsPowerShell\v1.0;$([Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory());" + $env:path -$certRegPath = "HKLM:\Software\Microsoft\SystemCertificates\ROOT\Certificates" +$env:path = "$windir;$sys32;$sys32\Wbem;$sys32\WindowsPowerShell\v1.0;" + $env:path $errorLevel = $warningLevel = 0 $arm = ((Get-CimInstance -Class Win32_ComputerSystem).SystemType -match 'ARM64') -or ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') @@ -295,66 +299,100 @@ if (!$matchedPackages) { # PROCESS PACKAGES # # ======================================================================================================================= # function ProcessCab($cabPath) { + $filePath = Split-Path $cabPath -Leaf + Write-Host "`nInstalling $filePath..." -ForegroundColor Cyan + Write-Host ("-" * 84) -ForegroundColor Magenta + + Write-Host "[INFO] Checking certificate..." try { - $filePath = Split-Path $cabPath -Leaf - Write-Host "`nInstalling $filePath..." -ForegroundColor Cyan - Write-Host ("-" * 84) -ForegroundColor Magenta - - Write-Host "[INFO] Importing and checking certificate..." - try { - $cert = (Get-AuthenticodeSignature $cabPath).SignerCertificate - foreach ($usage in $cert.Extensions.EnhancedKeyUsages) { - if ($usage.Value -ne "1.3.6.1.4.1.311.10.3.6") { - $correctUsage = $true - break - } - } - if (!$correctUsage) { - Write-Host "[ERROR] Cert doesn't have Windows System Component Verification, can't continue." -ForegroundColor Red - $script:errorLevel++ - return $false - } - - $certPath = [System.IO.Path]::GetTempFileName() - [System.IO.File]::WriteAllBytes($certPath, $cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)) - Import-Certificate $certPath -CertStoreLocation "Cert:\LocalMachine\Root" | Out-Null - Copy-Item -Path "$certRegPath\$($cert.Thumbprint)" "$certRegPath\8A334AA8052DD244A647306A76B8178FA215F344" -Force | Out-Null - } catch { - Write-Host "[ERROR] Cert error from '$cabPath': $_" -ForegroundColor Red + $cert = (Get-AuthenticodeSignature $cabPath).SignerCertificate + if ($cert.Extensions.EnhancedKeyUsages.Value -ne "1.3.6.1.4.1.311.10.3.6") { + Write-Host "[ERROR] Cert doesn't have proper key usages, can't continue." -ForegroundColor Red $script:errorLevel++ return $false } - Write-Host "[INFO] Adding package..." - try { - Add-WindowsPackage -Online -PackagePath $cabPath -NoRestart -IgnoreCheck -LogLevel 1 *>$null - } catch { - Write-Host "[ERROR] Error when adding package '$cabPath': $_" -ForegroundColor Red - $script:errorLevel++ - return $false + # add test cert + # isn't cleared later as it's required for the alt repair source + $certRegPath = "HKLM:\Software\Microsoft\SystemCertificates\ROOT\Certificates\8A334AA8052DD244A647306A76B8178FA215F344" + if (!(Test-Path "$certRegPath")) { + New-Item -Path $certRegPath -Force | Out-Null } - } finally { - Write-Host "[INFO] Cleaning up certificates..." - Get-ChildItem "Cert:\LocalMachine\Root\$($cert.Thumbprint)" | Remove-Item -Force | Out-Null - Remove-Item "$certRegPath\8A334AA8052DD244A647306A76B8178FA215F344" -Force -Recurse | Out-Null + } catch { + Write-Host "[ERROR] Cert error from '$cabPath': $_" -ForegroundColor Red + $script:errorLevel++ + return $false + } + + Write-Host "[INFO] Adding package..." + try { + Add-WindowsPackage -Online -PackagePath $cabPath -NoRestart -IgnoreCheck -LogLevel 1 *>$null + } catch { + Write-Host "[ERROR] Error when adding package '$cabPath': $_" -ForegroundColor Red + $script:errorLevel++ + return $false } + Write-Host "[INFO] Completed sucessfully." return $true } +# Fixes RestoreHealth/SFC 'Sources' error +# https://learn.microsoft.com/windows-hardware/manufacture/desktop/configure-a-windows-repair-source +# https://github.com/Atlas-OS/Atlas/issues/1103 +function MakeRepairSource { + $version = '38655.38527.65535.65535' + $srcPath = "$([Environment]::GetFolderPath('Windows'))\AtlasModules\Packages\WinSxS" + + Write-Host "`nMaking repair source..." -ForegroundColor Cyan + Write-Host ("-" * 84) -ForegroundColor Magenta + + # get list of Atlas manifests + Write-Host "[INFO] Getting manifests..." + $manifests = Get-ChildItem "$([Environment]::GetFolderPath('Windows'))\WinSxS\Manifests" -File -Filter "*$version*" + if ($manifests.Count -eq 0) { + Write-Host "[WARN] No manifests found! Can't create repair source." -ForegroundColor Yellow + return $false + } + + # create new repair source folder + if (Test-Path $srcPath -PathType Container) { + Write-Host "[INFO] Deleting old RepairSrc..." + Remove-Item $srcPath -Force -Recurse + } + Write-Host "[INFO] Creating RepairSrc path..." + New-Item "$srcPath\Manifests" -Force -ItemType Directory | Out-Null + + # hardlink all the manifests to the repair source + Write-Host "[INFO] Hard linking manifests..." + foreach ($manifest in $manifests) { + New-Item -ItemType HardLink -Path "$srcPath\Manifests\$manifest" -Target $manifest.FullName | Out-Null + } + + # adds the repair source policy + Set-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Servicing" -Name LocalSourcePath -Value "$srcPath" -Type ExpandString | Out-Null +} + if ($matchedPackages) { $packagesToProcess = $matchedPackages } else { $packagesToProcess = $openFileDialog.FileNames } +$successPackages = @() $failedPackages = @() $packagesToProcess | ForEach-Object { - if (!(ProcessCab $_)) { + if (ProcessCab $_) { + $successPackages += $_ + } else { $failedPackages += $_ } } +if ($successPackages.Count -ne 0) { + MakeRepairSource +} + # ======================================================================================================================= # # RESTART # # ======================================================================================================================= #