Advertisement
Laughing_Mantis

PatchExtract.ps1 by Greg Linares (@Laughing_Mantis)

Oct 15th, 2015
1,293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. ================
  3. PATCHEXTRACT.PS1
  4. =================
  5. Microsoft MSU Patch Extraction and Patch OrganizationUtility by Greg Linares (@Laughing_Mantis)
  6.  
  7. This Powershell script will extract a Microsoft MSU update file and then organize the output of extracted files and folders.
  8.  
  9. Organization of the output files is based on the patch's files and will organize them based on their archicture (x86, x64, or wow64)
  10. as well as their content-type, ie: resource and catalog files will be moved to a JUNK subfolder and patch binaries and index files will
  11. goto a PATCH folder.
  12.  
  13. This script was developed in order to aid reverse engineers in quickly organizing patches so they can be binary diffed faster and easier.
  14. This was especially developed with the new bulk Microsoft Kernel patches in mind.
  15.  
  16. Example output folder structure ouput would be similar to this:
  17.  
  18. C:\PATCHES\MS15-XXX\PRE
  19.     -x86
  20.         - x86 Binary patched files
  21.     -x64
  22.         - x64 binary patched files
  23.     -WOW64
  24.         - syswow64 binary patched files
  25.     -JUNK
  26.         - resource, catalog, mum, and other non-binary based patched files
  27.     -PATCH
  28.         - original patch, cabs and xml files from the extraction
  29.        
  30.        
  31. =============
  32. REQUIREMENTS
  33. =============
  34. 'expand.exe' to be present in %WINDIR%\SYSTEM32 (it is by default) - It will execute this file @ the current users permissions
  35. A valid Microsoft MSU patch file to extract (PATCH variable)
  36. Directory and File write/creation permissions to the PATH folder specified
  37.        
  38.    
  39. =======    
  40. USAGE
  41. =======
  42.  
  43. Powershell -ExecutionPolicy Bypass -File PatchExtract.ps1 -Patch C:\Patches\Windows6.1-KB3088195-x64.msu -Path C:\Patches\MS15-XXX\POST\
  44.  
  45.  
  46. This would extract the patch file C:\Patches\Windows6.1-KB3088195-x64.msu to the folder C:\Patches\MS15-XXX\POST\.
  47. It will then create all the sub organization folders within C:\Patches\MS15-XXX\POST\ folder.
  48.  
  49. (Note: the optional Powershell parameters '-ExecutionPolicy Bypass' is necessary in some environments to overcome Powershell execution restrictions)
  50.  
  51. ==========
  52. ARGUMENTS
  53. ==========
  54. -PATCH <STRING:Filename> [REQUIRED] [NO DEFAULT]
  55.     Specifies the MSU file that will be extracted to the specified PATH folder and then organized into the x86, x64, WOW, JUNK, and BIN folders specified
  56.     Extract command will be "expand -F:* <PATCH> <PATH>"
  57.     Non MSU files have not been tested however if the extraction does not generate a CAB file of the same name (indicator of successful extraction of MSU files)
  58.     the script assumes extraction failed.
  59.    
  60. -PATH <STRING:FolderPath> [REQUIRED] [NO DEFAULT]
  61.     Specified the folder that the PATCH file will be extracted and organized into
  62.     If the specified folders does not exist yet, the user will be prompted if they want to create it.
  63.     Relative paths '.\POST' can be used but it has not extensively been tested.
  64.    
  65.  
  66. -x86 <STRING:Foldername> [OPTIONAL] [DEFAULT='x86']
  67.  
  68.     Specifies the folder name within $PATH to store x86 patch binaries
  69.     example: -x86 32bit
  70.    
  71.    
  72. -x64 <STRING:Foldername> [OPTIONAL] [DEFAULT='x64']
  73.  
  74.     Specifies the folder name within $PATH to store x64 patch binaries
  75.     example: -x64 64bit
  76.    
  77. -WOW <STRING:Foldername> [OPTIONAL] [DEFAULT='WOW64']
  78.  
  79.     Specifies the folder name within $PATH to store wow64 type patch binaries
  80.     example: -WOW sysWOW64
  81.    
  82. -JUNK <STRING:Foldername> [OPTIONAL] [DEFAULT='JUNK']
  83.  
  84.     Specifies the folder name within $PATH to store resource, catalog, and other generally useless for diffing patch binaries
  85.     example: -JUNK res
  86.    
  87.    
  88. -BIN <STRING:Foldername> [OPTIONAL] [DEFAULT='PATCH']
  89.  
  90.     Specifies the folder name within $PATH to store extraction xml and original patch msu and cab files
  91.     example: -BIN bin
  92.  
  93.  
  94. ================
  95. VERSION HISTORY
  96. ================
  97. I originally wrote this as an ugly batch file sometime between 2014 and 2015 as a way to organize folders but it was incomplete and buggy
  98.  
  99. Oct 15, 2015 - Initial Public Release 1.0
  100.  
  101.  
  102.  
  103. ==========
  104. LICENSING
  105. ==========
  106. This script is provided free as beer.  It probably has some bugs and coding issues, however if you like it or find it useful please give me a shout out on twitter @Laughing_Mantis.  
  107. Feedback is encouraged and I will be likely releasing new scripts and tools and training in the future if it is welcome.
  108.  
  109.  
  110. -GLin
  111.  
  112. #>
  113.  
  114.  
  115.  
  116.  
  117. Param
  118. (
  119.  
  120.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  121.     [ValidateNotNullOrEmpty()]
  122.     [string]$PATCH = "",
  123.    
  124.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  125.     [ValidateNotNullOrEmpty()]
  126.     [string]$PATH = "",
  127.    
  128.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  129.     [string]$x86 = "x86",
  130.    
  131.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  132.     [string]$x64 = "x64",
  133.    
  134.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  135.     [string]$WOW = "WOW64",
  136.    
  137.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  138.     [string]$JUNK = "JUNK",
  139.    
  140.     [Parameter(ValueFromPipelineByPropertyName = $true)]
  141.     [string]$BIN = "PATCH"
  142.        
  143. )
  144.  
  145. Clear-Host
  146.  
  147. if ($PATCH -eq "")
  148. {
  149.     Throw ("Error: No PATCH file specified.  Specify a valid Microsoft MSU Patch with the -PATCH argument")
  150.    
  151. }
  152.  
  153. if ($PATH -eq "")
  154. {
  155.     Throw ("Error: No PATH folder specified.  Specify a folder name to extract $PATCH to using the -PATH argument")
  156.    
  157. }
  158.  
  159. #Bug Fix (Resolve-Path Error if invalid path was specified before the path was created)
  160.  
  161.  
  162. if (!(Test-Path $PATCH))
  163. {
  164.     Throw ("Error: Specified PATCH file ($PATCH) does not exist.  Specify a valid Microsoft MSU Patch file with the -PATCH argument.")
  165. }
  166.  
  167. if (!($PATCH.ToUpper().EndsWith(".MSU")))
  168. {
  169.     Do
  170.     {
  171.         $Attempt = Read-Host ("Warning: Specified PATCH file ($PATCH) is not a MSU file type. Do you still want to attempt extraction? [Y] or [N]")
  172.     }
  173.     Until ('Y', 'y', 'n', 'N' -ccontains $Attempt)
  174.     if ($Attempt.ToUpper() -eq 'N')
  175.     {
  176.         Write-Host ("Exiting...")
  177.         Exit
  178.     }
  179. }
  180.  
  181. if (!(Test-Path $PATH))
  182. {
  183.     Do
  184.     {
  185.         $Attempt = Read-Host ("Warning: Specified PATH folder ($PATH) does not exist. Do you want to create it? [Y] or [N]")
  186.     }
  187.     Until ('Y', 'y', 'n', 'N' -ccontains $Attempt)
  188.     if ($Attempt.ToUpper() -eq 'N')
  189.     {
  190.         Write-Host ("Exiting...")
  191.         Exit
  192.     }
  193.     else
  194.     {
  195.         New-Item $PATH -Force -ItemType Directory
  196.         Write-Host "Created $PATH Folder" -ForegroundColor Green
  197.     }
  198. }
  199.  
  200. $PATCH = Resolve-Path $PATCH
  201. $PATH = Resolve-Path $PATH
  202.  
  203. Write-Host "Patch to Extract: $PATCH"
  204. Write-Host "Extraction Path: $PATH"
  205. Write-Host "x86 File Storage Folder Name: $x86"
  206. Write-Host "x64 File Storage Folder Name: $x64"
  207. Write-Host "WOW64 File Storage Folder Name: $WOW"
  208. Write-Host "Junk File Storage Folder Name: $JUNK"
  209. Write-Host "Orignal Patch File Storage Folder Name: $BIN"
  210.  
  211. $SYSPATH = Join-Path -path (get-item env:\windir).Value -ChildPath "system32"
  212.  
  213. $EXPAND = Join-Path -path $SYSPATH -ChildPath "expand.exe"
  214.  
  215.  
  216. if (!(Test-Path $EXPAND))
  217. {
  218.     Throw ("Error: Cannot find 'Expand.exe' in the $SYSPATH folder.")
  219. }
  220.  
  221. $ARG = "-F:* " + $PATCH + " " + $PATH
  222.  
  223. Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Green
  224.  
  225. Start-Process -File $EXPAND -ArgumentList $ARG -Wait
  226.  
  227. $CAB = Join-Path -path $PATH -ChildPath $((Get-ChildItem $PATCH).Basename + ".CAB")
  228.  
  229. if (!(Test-Path $CAB))
  230. {
  231.     Throw "Error: Patch .CAB File ($CAB) does not exist.  Patch Extraction failed"
  232. }
  233.  
  234. $ARG = " -F:* " + $CAB + " " + $PATH
  235.  
  236. Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Green
  237.  
  238. Start-Process -File $EXPAND -ArgumentList $ARG -Wait
  239.  
  240.  
  241. $PATCHx86 = Join-Path -path $PATH -ChildPath $x86
  242. $PATCHx64 = Join-Path -path $PATH -ChildPath $x64
  243. $PATCHWOW = Join-Path -path $PATH -ChildPath $WOW
  244. $PATCHJUNK = Join-Path -path $PATH -ChildPath $JUNK
  245. $PATCHCAB = Join-Path -path $PATH -ChildPath $BIN
  246.  
  247.  
  248. if (!(Test-Path $PATCHx86 -pathType Container))
  249. {
  250.     New-Item $PATCHx86 -Force -ItemType Directory
  251.     Write-Host "Making $PATCHx86 Folder" -ForegroundColor Green
  252. }
  253.  
  254. if (!(Test-Path $PATCHx64 -pathType Container))
  255. {
  256.     New-Item $PATCHx64 -Force -ItemType Directory
  257.     Write-Host "Making $PATCHx64 Folder" -ForegroundColor Green
  258. }
  259.  
  260. if (!(Test-Path $PATCHWOW -pathType Container))
  261. {
  262.     New-Item $PATCHWOW -Force -ItemType Directory
  263.     Write-Host "Making $PATCHWOW Folder" -ForegroundColor Green
  264. }
  265.  
  266. if (!(Test-Path $PATCHJUNK -pathType Container))
  267. {
  268.     New-Item $PATCHJUNK -Force -ItemType Directory
  269.     Write-Host "Making $PATCHJUNK Folder" -ForegroundColor Green
  270. }
  271.  
  272. if (!(Test-Path $PATCHCAB -pathType Container))
  273. {
  274.     New-Item $PATCHCAB -Force -ItemType Directory
  275.     Write-Host "Making $PATCHCAB Folder" -ForegroundColor Green
  276. }
  277.  
  278.  
  279. $PATCHFolders = Get-ChildItem -Path $PATH -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}
  280.  
  281. foreach ($folder in $PATCHFolders)
  282. {
  283.     if ($folder.Name.Contains(".resources_"))
  284.     {
  285.         Move-Item $folder.FullName $PATCHJUNK -Force
  286.         Write-Host "Moving $folder to $PATCHJUNK" -ForegroundColor Green
  287.         Continue
  288.     }
  289.     else
  290.     {
  291.         if ($folder.Name.StartsWith("x86_"))
  292.         {
  293.             Move-Item $folder.FullName $PATCHx86 -Force
  294.             Write-Host "Moving $folder to $PATCHx86" -ForegroundColor Green
  295.             Continue
  296.         }
  297.        
  298.         if ($folder.Name.StartsWith("amd64_"))
  299.         {
  300.             Move-Item $folder.FullName $PATCHx64 -Force
  301.             Write-Host "Moving $folder to $PATCHx64" -ForegroundColor Green
  302.             Continue
  303.         }
  304.        
  305.         if ($folder.Name.StartsWith("wow64_"))
  306.         {
  307.             Move-Item $folder.FullName $PATCHWOW -Force
  308.             Write-Host "Moving $folder to $PATCHWOW" -ForegroundColor Green
  309.             Continue
  310.         }
  311.     }
  312. }
  313.  
  314. $Junkfiles = Get-ChildItem -Path $PATH -Force -ErrorAction SilentlyContinue
  315.  
  316.  
  317. foreach ($JunkFile in $Junkfiles)
  318. {
  319.    
  320.     try
  321.     {
  322.         if (($JunkFile.Name.EndsWith(".manifest")) -or ($JunkFile.Name.EndsWith(".cat")) -or ($JunkFile.Name.EndsWith(".mum")))
  323.         {
  324.             Move-Item $JunkFile.FullName $PATCHJUNK -Force -ErrorAction SilentlyContinue
  325.             Write-Host "Moving $JunkFile to $PATCHJUNK" -ForegroundColor Green
  326.             Continue
  327.         }
  328.        
  329.         if (($JunkFile.Name.EndsWith(".cab")) -or ($JunkFile.Name.EndsWith(".xml")) -or ($JunkFile.Name.EndsWith(".msu")) -or ($JunkFile.Name.EndsWith("pkgProperties.txt")))
  330.         {
  331.             Move-Item $JunkFile.FullName $PATCHCAB -Force -ErrorAction SilentlyContinue
  332.             Write-Host "Moving $JunkFile to $PATCHCAB" -ForegroundColor Green
  333.             Continue
  334.         }
  335.         if ($JunkFile.Name -eq "patch")
  336.         {
  337.             Move-Item $JunkFile.FullName $PATCHCAB -Force -ErrorAction SilentlyContinue
  338.             Write-Host "Moving $JunkFile to $PATCHCAB" -ForegroundColor Green
  339.             Continue
  340.         }
  341.     }
  342.     catch
  343.     {
  344.         Write-Host "Error Processing ($JunkFile.Fullname)" -ForegroundColor Red
  345.     }
  346. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement