Skip to content

Commit

Permalink
fix(packages): src for restorehealth/sfc (#1103)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
he3als committed Jul 14, 2024
1 parent bf84637 commit fad3993
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 57 deletions.
2 changes: 0 additions & 2 deletions src/playbook/Configuration/atlas/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ actions:
)
-NoInteraction
option: 'defender-disable'
runas: currentUserElevated
wait: true
exeDir: true
- !powerShell:
Expand All @@ -52,6 +51,5 @@ actions:
-UninstallPackages @('*Z-Atlas-NoDefender-Package*')
-NoInteraction
option: 'defender-enable'
runas: currentUserElevated
wait: true
exeDir: true
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
116 changes: 77 additions & 39 deletions src/playbook/Executables/AtlasModules/Scripts/packageInstall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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 #
# ======================================================================================================================= #
Expand Down

0 comments on commit fad3993

Please sign in to comment.