Last active
December 16, 2025 23:37
-
-
Save secdev02/c5cef7a9630313ee116494c9d68210ce to your computer and use it in GitHub Desktop.
Extractor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Extracts a specific file from nested CAB files within an MSU package. | |
| .DESCRIPTION | |
| Extracts MSU to get CAB files, then extracts a specific file by name, | |
| and performs additional expansion rounds if the file is itself a CAB. | |
| .PARAMETER MsuPath | |
| Path to the MSU file. | |
| .PARAMETER TargetFileName | |
| Name of the specific file to extract (e.g., "Windows10.0-KB5001234.cab"). | |
| .PARAMETER OutputPath | |
| Directory where files will be extracted. | |
| .EXAMPLE | |
| .\Expand-MsuFile.ps1 -MsuPath "KB5001234.msu" -TargetFileName "Windows10.0-KB5001234.cab" | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory=$true)] | |
| [string]$MsuPath, | |
| [Parameter(Mandatory=$true)] | |
| [string]$TargetFileName, | |
| [Parameter(Mandatory=$false)] | |
| [string]$OutputPath | |
| ) | |
| # Check if MSU file exists | |
| if (-not (Test-Path $MsuPath)) { | |
| Write-Error "MSU file not found: $MsuPath" | |
| exit 1 | |
| } | |
| # Get absolute path | |
| $MsuPath = (Resolve-Path $MsuPath).Path | |
| $msuFileName = [System.IO.Path]::GetFileNameWithoutExtension($MsuPath) | |
| # Set output path if not specified | |
| if ([string]::IsNullOrEmpty($OutputPath)) { | |
| $msuDirectory = [System.IO.Path]::GetDirectoryName($MsuPath) | |
| $OutputPath = Join-Path $msuDirectory ($msuFileName + "_extracted") | |
| } | |
| # Create output directory | |
| if (-not (Test-Path $OutputPath)) { | |
| New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null | |
| } | |
| # Create temp directory | |
| $tempPath = Join-Path $env:TEMP ("msu_temp_" + [System.Guid]::NewGuid().ToString()) | |
| New-Item -ItemType Directory -Path $tempPath -Force | Out-Null | |
| Write-Host "Step 1: Extracting MSU..." -ForegroundColor Cyan | |
| Write-Host "Source: $MsuPath" -ForegroundColor Gray | |
| # Extract MSU | |
| $expandArgs = "-F:* `"$MsuPath`" `"$tempPath`"" | |
| $result = Start-Process -FilePath "expand.exe" -ArgumentList $expandArgs -Wait -PassThru -NoNewWindow | |
| if ($result.ExitCode -ne 0) { | |
| Write-Error "Failed to extract MSU (exit code: $($result.ExitCode))" | |
| Remove-Item -Path $tempPath -Recurse -Force | |
| exit 1 | |
| } | |
| Write-Host "MSU extracted" -ForegroundColor Green | |
| # Step 2: Find the target file | |
| Write-Host "`nStep 2: Looking for '$TargetFileName'..." -ForegroundColor Cyan | |
| $targetFile = Get-ChildItem -Path $tempPath -Filter $TargetFileName -Recurse -File | Select-Object -First 1 | |
| if ($null -eq $targetFile) { | |
| Write-Error "Target file '$TargetFileName' not found in MSU" | |
| Write-Host "`nAvailable files:" -ForegroundColor Yellow | |
| Get-ChildItem -Path $tempPath -Recurse -File | ForEach-Object { Write-Host " $($_.Name)" } | |
| Remove-Item -Path $tempPath -Recurse -Force | |
| exit 1 | |
| } | |
| Write-Host "Found: $($targetFile.FullName)" -ForegroundColor Green | |
| # Step 3: Extract the target file (first CAB) | |
| $temp2Path = Join-Path $tempPath "extract1" | |
| New-Item -ItemType Directory -Path $temp2Path -Force | Out-Null | |
| Write-Host "`nStep 3: Extracting first layer..." -ForegroundColor Cyan | |
| $expandArgs = "-F:* `"$($targetFile.FullName)`" `"$temp2Path`"" | |
| $result = Start-Process -FilePath "expand.exe" -ArgumentList $expandArgs -Wait -PassThru -NoNewWindow | |
| if ($result.ExitCode -ne 0) { | |
| Write-Warning "First extraction returned exit code: $($result.ExitCode)" | |
| } | |
| $extractedFiles = Get-ChildItem -Path $temp2Path -File | |
| Write-Host "Extracted $($extractedFiles.Count) file(s)" -ForegroundColor Green | |
| # Step 4: Check for nested CAB and extract again | |
| Write-Host "`nStep 4: Looking for nested CAB..." -ForegroundColor Cyan | |
| $nestedCab = Get-ChildItem -Path $temp2Path -Filter "*.cab" -File | Select-Object -First 1 | |
| if ($null -ne $nestedCab) { | |
| Write-Host "Found nested CAB: $($nestedCab.Name)" -ForegroundColor Yellow | |
| Write-Host "Performing second expansion..." -ForegroundColor Cyan | |
| $expandArgs = "-F:* `"$($nestedCab.FullName)`" `"$OutputPath`"" | |
| $result = Start-Process -FilePath "expand.exe" -ArgumentList $expandArgs -Wait -PassThru -NoNewWindow | |
| if ($result.ExitCode -eq 0) { | |
| Write-Host "Final extraction complete!" -ForegroundColor Green | |
| } else { | |
| Write-Warning "Second extraction returned exit code: $($result.ExitCode)" | |
| } | |
| } else { | |
| Write-Host "No nested CAB found, copying files to output..." -ForegroundColor Yellow | |
| Copy-Item -Path (Join-Path $temp2Path "*") -Destination $OutputPath -Recurse -Force | |
| } | |
| # Clean up temp directory | |
| Write-Host "`nCleaning up..." -ForegroundColor Cyan | |
| Remove-Item -Path $tempPath -Recurse -Force | |
| Write-Host "`n==================================" -ForegroundColor Green | |
| Write-Host "Extraction complete!" -ForegroundColor Green | |
| Write-Host "Output: $OutputPath" -ForegroundColor Green | |
| Write-Host "==================================" -ForegroundColor Green | |
| # Show extracted files | |
| $finalFiles = Get-ChildItem -Path $OutputPath -File -Recurse | |
| Write-Host "`nExtracted $($finalFiles.Count) file(s):" -ForegroundColor Cyan | |
| $finalFiles | Select-Object -First 20 | ForEach-Object { Write-Host " $($_.Name)" -ForegroundColor Gray } | |
| if ($finalFiles.Count -gt 20) { | |
| Write-Host " ... and $($finalFiles.Count - 20) more" -ForegroundColor Gray | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Applies a delta patch to reconstruct the complete PE file | |
| .DESCRIPTION | |
| Takes a delta patch file and the original system file, then applies the patch | |
| to create the complete updated PE file. Supports PA30, PA19, DCN1, DCM1 formats. | |
| .PARAMETER DeltaFile | |
| Path to the delta patch file | |
| .PARAMETER SourceFile | |
| Path to the original system file (if not provided, will auto-search) | |
| .PARAMETER OutputFile | |
| Path where the complete PE will be saved | |
| .EXAMPLE | |
| .\Apply-DeltaPatch.ps1 -DeltaFile "prjflt.sys" | |
| .EXAMPLE | |
| .\Apply-DeltaPatch.ps1 -DeltaFile "prjflt.sys" -SourceFile "C:\Windows\System32\drivers\prjflt.sys" -OutputFile "prjflt_new.sys" | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory=$true)] | |
| [string]$DeltaFile, | |
| [Parameter(Mandatory=$false)] | |
| [string]$SourceFile, | |
| [Parameter(Mandatory=$false)] | |
| [string]$OutputFile | |
| ) | |
| function Get-DeltaInfo { | |
| param([string]$FilePath) | |
| $bytes = New-Object byte[] 16 | |
| $stream = [System.IO.File]::OpenRead($FilePath) | |
| $stream.Read($bytes, 0, 16) | Out-Null | |
| $stream.Close() | |
| $signature = [System.Text.Encoding]::ASCII.GetString($bytes[0..3]) | |
| return @{ | |
| Signature = $signature | |
| IsPA30 = ($signature -eq "PA30") | |
| IsPA19 = ($signature -eq "PA19") | |
| IsDCN1 = ($signature -eq "DCN1") | |
| IsDCM1 = ($signature -eq "DCM1") | |
| IsDelta = ($signature -eq "PA30" -or $signature -eq "PA19" -or $signature -eq "DCN1" -or $signature -eq "DCM1") | |
| } | |
| } | |
| function Find-SystemFile { | |
| param([string]$FileName) | |
| Write-Host " Searching for: $FileName" -ForegroundColor Gray | |
| $searchPaths = @( | |
| "$env:SystemRoot\System32\drivers", | |
| "$env:SystemRoot\System32", | |
| "$env:SystemRoot\SysWOW64", | |
| "$env:SystemRoot\WinSxS" | |
| ) | |
| foreach ($path in $searchPaths) { | |
| if (Test-Path $path) { | |
| Write-Host " Checking: $path" -ForegroundColor DarkGray | |
| $found = Get-ChildItem -Path $path -Filter $FileName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($found) { | |
| Write-Host " Found!" -ForegroundColor Green | |
| return $found.FullName | |
| } | |
| } | |
| } | |
| return $null | |
| } | |
| function Invoke-DeltaAPI { | |
| param( | |
| [string]$SourcePath, | |
| [string]$DeltaPath, | |
| [string]$TargetPath | |
| ) | |
| Write-Host "`n[Method 1] Windows Delta API (msdelta.dll)" -ForegroundColor Cyan | |
| try { | |
| # Load msdelta.dll | |
| $signature = @' | |
| [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
| public static extern bool ApplyDeltaB( | |
| long ApplyFlags, | |
| string SourceName, | |
| string DeltaName, | |
| string TargetName); | |
| [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
| public static extern bool ApplyDeltaW( | |
| long ApplyFlags, | |
| string SourceName, | |
| string DeltaName, | |
| string TargetName); | |
| '@ | |
| Add-Type -MemberDefinition $signature -Name DeltaPatcher -Namespace Win32 -ErrorAction Stop | |
| Write-Host " Loaded msdelta.dll" -ForegroundColor Green | |
| Write-Host " Applying delta patch..." -ForegroundColor Gray | |
| # Try ApplyDeltaB first | |
| $result = [Win32.DeltaPatcher]::ApplyDeltaB(0, $SourcePath, $DeltaPath, $TargetPath) | |
| if ($result) { | |
| Write-Host " SUCCESS! Delta applied with ApplyDeltaB" -ForegroundColor Green | |
| return $true | |
| } | |
| # Try ApplyDeltaW | |
| $result = [Win32.DeltaPatcher]::ApplyDeltaW(0, $SourcePath, $DeltaPath, $TargetPath) | |
| if ($result) { | |
| Write-Host " SUCCESS! Delta applied with ApplyDeltaW" -ForegroundColor Green | |
| return $true | |
| } | |
| $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() | |
| Write-Warning " Failed with error code: 0x$($errorCode.ToString('X8'))" | |
| return $false | |
| } catch { | |
| Write-Warning " Could not use Delta API: $_" | |
| return $false | |
| } | |
| } | |
| function Invoke-ExpandDelta { | |
| param( | |
| [string]$SourcePath, | |
| [string]$DeltaPath, | |
| [string]$TargetPath | |
| ) | |
| Write-Host "`n[Method 2] expand.exe with delta support" -ForegroundColor Cyan | |
| try { | |
| # Create temp directory | |
| $tempDir = Join-Path $env:TEMP ("delta_expand_" + [System.Guid]::NewGuid().ToString().Substring(0,8)) | |
| New-Item -ItemType Directory -Path $tempDir -Force | Out-Null | |
| # Copy files to temp | |
| $tempSource = Join-Path $tempDir "source" | |
| $tempDelta = Join-Path $tempDir "delta" | |
| Copy-Item $SourcePath $tempSource -Force | |
| Copy-Item $DeltaPath $tempDelta -Force | |
| Write-Host " Running expand.exe..." -ForegroundColor Gray | |
| # Try expand with -R flag (handles deltas) | |
| $expandArgs = "-R `"$tempDelta`" -F:* `"$tempDir`"" | |
| $proc = Start-Process -FilePath "expand.exe" -ArgumentList $expandArgs -Wait -PassThru -NoNewWindow | |
| # Check if output was created | |
| $possibleOutputs = Get-ChildItem -Path $tempDir -File | Where-Object { $_.Name -ne "source" -and $_.Name -ne "delta" } | |
| if ($possibleOutputs -and $possibleOutputs.Count -gt 0) { | |
| Copy-Item $possibleOutputs[0].FullName $TargetPath -Force | |
| Remove-Item $tempDir -Recurse -Force | |
| Write-Host " SUCCESS! File expanded" -ForegroundColor Green | |
| return $true | |
| } | |
| Remove-Item $tempDir -Recurse -Force | |
| Write-Warning " expand.exe did not produce output" | |
| return $false | |
| } catch { | |
| Write-Warning " expand.exe method failed: $_" | |
| return $false | |
| } | |
| } | |
| function Invoke-DeltaPatcherTool { | |
| param( | |
| [string]$SourcePath, | |
| [string]$DeltaPath, | |
| [string]$TargetPath | |
| ) | |
| Write-Host "`n[Method 3] Looking for delta patcher tools..." -ForegroundColor Cyan | |
| # Check for common delta tools | |
| $tools = @( | |
| @{Name="DeltaPatcher"; Path="deltapatcher.exe"; Args="`"$SourcePath`" `"$DeltaPath`" `"$TargetPath`""}, | |
| @{Name="pa30patch"; Path="pa30patch.exe"; Args="`"$SourcePath`" `"$DeltaPath`" `"$TargetPath`""} | |
| ) | |
| foreach ($tool in $tools) { | |
| $toolPath = (Get-Command $tool.Path -ErrorAction SilentlyContinue).Source | |
| if ($toolPath) { | |
| Write-Host " Found: $($tool.Name)" -ForegroundColor Green | |
| Write-Host " Running..." -ForegroundColor Gray | |
| $proc = Start-Process -FilePath $toolPath -ArgumentList $tool.Args -Wait -PassThru -NoNewWindow | |
| if ($proc.ExitCode -eq 0 -and (Test-Path $TargetPath)) { | |
| Write-Host " SUCCESS!" -ForegroundColor Green | |
| return $true | |
| } | |
| } | |
| } | |
| Write-Host " No delta patcher tools found in PATH" -ForegroundColor Yellow | |
| return $false | |
| } | |
| # Main script | |
| Write-Host "========================================" -ForegroundColor Cyan | |
| Write-Host "Delta Patch Decompression Tool" -ForegroundColor Cyan | |
| Write-Host "========================================" -ForegroundColor Cyan | |
| # Validate delta file | |
| if (-not (Test-Path $DeltaFile)) { | |
| Write-Error "Delta file not found: $DeltaFile" | |
| exit 1 | |
| } | |
| $DeltaFile = (Resolve-Path $DeltaFile).Path | |
| $deltaFileName = [System.IO.Path]::GetFileName($DeltaFile) | |
| $deltaSize = (Get-Item $DeltaFile).Length | |
| Write-Host "`nDelta File: $deltaFileName" -ForegroundColor Yellow | |
| Write-Host "Path: $DeltaFile" -ForegroundColor Gray | |
| Write-Host "Size: $([math]::Round($deltaSize/1KB, 2)) KB" -ForegroundColor Gray | |
| # Check delta type | |
| $deltaInfo = Get-DeltaInfo -FilePath $DeltaFile | |
| Write-Host "`nDelta Format: $($deltaInfo.Signature)" -ForegroundColor Yellow | |
| if (-not $deltaInfo.IsDelta) { | |
| Write-Error "This doesn't appear to be a delta patch file (signature: $($deltaInfo.Signature))" | |
| exit 1 | |
| } | |
| Write-Host " ✓ Confirmed delta patch" -ForegroundColor Green | |
| # Find or validate source file | |
| Write-Host "`n----------------------------------------" -ForegroundColor Cyan | |
| Write-Host "Finding Original File" -ForegroundColor Cyan | |
| Write-Host "----------------------------------------" -ForegroundColor Cyan | |
| if ([string]::IsNullOrEmpty($SourceFile)) { | |
| Write-Host " No source file specified, searching system..." -ForegroundColor Gray | |
| $SourceFile = Find-SystemFile -FileName $deltaFileName | |
| } | |
| if (-not $SourceFile -or -not (Test-Path $SourceFile)) { | |
| Write-Error "Cannot find original file: $deltaFileName" | |
| Write-Host "`nYou need to specify the original file with -SourceFile parameter" -ForegroundColor Yellow | |
| Write-Host "Example: -SourceFile `"C:\Windows\System32\drivers\$deltaFileName`"" -ForegroundColor Gray | |
| exit 1 | |
| } | |
| $SourceFile = (Resolve-Path $SourceFile).Path | |
| $sourceSize = (Get-Item $SourceFile).Length | |
| Write-Host "`nSource File Found:" -ForegroundColor Green | |
| Write-Host " Path: $SourceFile" -ForegroundColor Gray | |
| Write-Host " Size: $([math]::Round($sourceSize/1KB, 2)) KB" -ForegroundColor Gray | |
| # Setup output file | |
| if ([string]::IsNullOrEmpty($OutputFile)) { | |
| $deltaDir = [System.IO.Path]::GetDirectoryName($DeltaFile) | |
| $baseName = [System.IO.Path]::GetFileNameWithoutExtension($deltaFileName) | |
| $ext = [System.IO.Path]::GetExtension($deltaFileName) | |
| $OutputFile = Join-Path $deltaDir ($baseName + "_patched" + $ext) | |
| } | |
| Write-Host "`nOutput File:" -ForegroundColor Cyan | |
| Write-Host " $OutputFile" -ForegroundColor Gray | |
| # Try different methods | |
| Write-Host "`n----------------------------------------" -ForegroundColor Cyan | |
| Write-Host "Applying Delta Patch" -ForegroundColor Cyan | |
| Write-Host "----------------------------------------" -ForegroundColor Cyan | |
| $success = $false | |
| # Method 1: Windows Delta API | |
| $success = Invoke-DeltaAPI -SourcePath $SourceFile -DeltaPath $DeltaFile -TargetPath $OutputFile | |
| # Method 2: expand.exe | |
| if (-not $success) { | |
| $success = Invoke-ExpandDelta -SourcePath $SourceFile -DeltaPath $DeltaFile -TargetPath $OutputFile | |
| } | |
| # Method 3: External tools | |
| if (-not $success) { | |
| $success = Invoke-DeltaPatcherTool -SourcePath $SourceFile -DeltaPath $DeltaFile -TargetPath $OutputFile | |
| } | |
| # Check result | |
| Write-Host "`n========================================" -ForegroundColor Cyan | |
| if ($success -and (Test-Path $OutputFile)) { | |
| $outputSize = (Get-Item $OutputFile).Length | |
| Write-Host "SUCCESS! Complete PE File Created!" -ForegroundColor Green | |
| Write-Host "========================================" -ForegroundColor Green | |
| Write-Host "`nOutput File: $OutputFile" -ForegroundColor Cyan | |
| Write-Host "Size: $([math]::Round($outputSize/1KB, 2)) KB" -ForegroundColor Gray | |
| # Verify it's a PE | |
| $peBytes = New-Object byte[] 2 | |
| $stream = [System.IO.File]::OpenRead($OutputFile) | |
| $stream.Read($peBytes, 0, 2) | Out-Null | |
| $stream.Close() | |
| if ($peBytes[0] -eq 0x4D -and $peBytes[1] -eq 0x5A) { | |
| Write-Host "✓ Verified: Valid PE file (MZ header)" -ForegroundColor Green | |
| # Show file info | |
| try { | |
| $versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($OutputFile) | |
| Write-Host "`nFile Information:" -ForegroundColor Cyan | |
| Write-Host " Description: $($versionInfo.FileDescription)" -ForegroundColor Gray | |
| Write-Host " Version: $($versionInfo.FileVersion)" -ForegroundColor Gray | |
| Write-Host " Product: $($versionInfo.ProductName)" -ForegroundColor Gray | |
| } catch { | |
| Write-Host "`n(Could not read version info)" -ForegroundColor DarkGray | |
| } | |
| } else { | |
| Write-Warning "File created but doesn't have PE signature" | |
| } | |
| Write-Host "`nYou can now analyze this file with:" -ForegroundColor Cyan | |
| Write-Host " - PE-bear" -ForegroundColor Gray | |
| Write-Host " - IDA Pro / Ghidra" -ForegroundColor Gray | |
| Write-Host " - CFF Explorer" -ForegroundColor Gray | |
| Write-Host " - dumpbin /headers `"$OutputFile`"" -ForegroundColor Gray | |
| } else { | |
| Write-Host "FAILED - Could Not Apply Delta Patch" -ForegroundColor Red | |
| Write-Host "========================================" -ForegroundColor Red | |
| Write-Host "`nPossible solutions:" -ForegroundColor Yellow | |
| Write-Host " 1. Wrong source file version - make sure source matches the delta" -ForegroundColor Gray | |
| Write-Host " 2. Try downloading delta tools:" -ForegroundColor Gray | |
| Write-Host " - DeltaPatcher from GitHub" -ForegroundColor Gray | |
| Write-Host " - pa30patch.exe" -ForegroundColor Gray | |
| Write-Host " 3. Use DISM to extract:" -ForegroundColor Gray | |
| Write-Host " dism /Online /Get-Packages" -ForegroundColor Gray | |
| Write-Host " 4. Check Windows Update log for the correct base version" -ForegroundColor Gray | |
| exit 1 | |
| } | |
| Write-Host "`n========================================" -ForegroundColor Cyan |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment