|
| 1 | +[CmdletBinding()] |
| 2 | +param ( |
| 3 | +) |
| 4 | + |
| 5 | +<# |
| 6 | +C# code to expose SHLoadIndirectString(), derived from: |
| 7 | + Title: Expand-IndirectString.ps1 |
| 8 | + Author: Jason Fossen, Enclave Consulting LLC (www.sans.org/sec505) |
| 9 | + Date: 20 September 2016 |
| 10 | + URL: https://github.com/SamuelArnold/StarKill3r/blob/master/Star%20Killer/Star%20Killer/bin/Debug/Scripts/SANS-SEC505-master/scripts/Day1-PowerShell/Expand-IndirectString.ps1 |
| 11 | +
|
| 12 | +Jason has released his code to public domain. |
| 13 | +#> |
| 14 | +$CSharpSHLoadIndirectString = @' |
| 15 | +using System; |
| 16 | +using System.Text; |
| 17 | +using System.Runtime.InteropServices; |
| 18 | +
|
| 19 | +public class IndirectStrings |
| 20 | +{ |
| 21 | + [DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)] |
| 22 | + internal static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved); |
| 23 | +
|
| 24 | + public static string GetIndirectString(string indirectString) |
| 25 | + { |
| 26 | + StringBuilder lptStr = new StringBuilder(1024); |
| 27 | + int returnValue = SHLoadIndirectString(indirectString, lptStr, (uint)lptStr.Capacity, IntPtr.Zero); |
| 28 | +
|
| 29 | + return returnValue == 0 ? lptStr.ToString() : null; |
| 30 | + } |
| 31 | +} |
| 32 | +'@ |
| 33 | + |
| 34 | +# Add the IndirectStrings type to PowerShell |
| 35 | +Add-Type -TypeDefinition $CSharpSHLoadIndirectString -Language CSharp |
| 36 | + |
| 37 | +<# |
| 38 | +Usage examples: |
| 39 | +
|
| 40 | + $instr1 = '@%SystemRoot%\system32\shell32.dll,-21801' |
| 41 | + $instr2 = '@{This.is.deliberately.invalid}' |
| 42 | + $instr3 = '@{c5e2524a-ea46-4f67-841f-6a9465d9d515_10.0.18362.267_neutral_neutral_cw5n1h2txyewy?ms-resource://FileExplorer/Resources/AppxManifest_DisplayName}' |
| 43 | +
|
| 44 | + [IndirectStrings]::GetIndirectString( $instr1 ) |
| 45 | + [IndirectStrings]::GetIndirectString( $instr2 ) |
| 46 | + [IndirectStrings]::GetIndirectString( $instr3 ) |
| 47 | +#> |
| 48 | + |
| 49 | +# Get a list of Appx packages |
| 50 | +$AppxPackages = Get-AppxPackage -Verbose |
| 51 | +$AppxSum = $AppxPackages.Count |
| 52 | + |
| 53 | +# Create an array to store Appx identities |
| 54 | +Class AppxIdentity { |
| 55 | + [ValidateNotNullOrEmpty()][string]$Name |
| 56 | + [string]$DisplayNameResolved |
| 57 | + [string]$DisplayNameRaw |
| 58 | +} |
| 59 | +[AppxIdentity[]]$AppxIdentities = [AppxIdentity[]]::New($AppxSum) |
| 60 | + |
| 61 | +# Access the AppX repository in the Registry |
| 62 | +Push-Location "Registry::HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages" |
| 63 | + |
| 64 | +for ($i = 0; $i -lt $AppxSum; $i++) { |
| 65 | + # These variables help make the code more compact |
| 66 | + # AXN, AXF and AXI respectively mean AppX Name, AppX Fullname and AppX Identity |
| 67 | + $AXN = $AppxPackages[$i].Name |
| 68 | + $AXF = $AppxPackages[$i].PackageFullName |
| 69 | + $AXI = New-Object -TypeName AppxIdentity |
| 70 | + |
| 71 | + # The first property is easy to acquire |
| 72 | + $AXI.Name = $AXN |
| 73 | + |
| 74 | + #The display name is stored in the Registry |
| 75 | + If (Test-Path $AXF) { |
| 76 | + try { |
| 77 | + $AXI.DisplayNameRaw = (Get-ItemProperty -Path $AXF -Name DisplayName).DisplayName |
| 78 | + if ($AXI.DisplayNameRaw -match '^@') { |
| 79 | + $AXI.DisplayNameResolved = [IndirectStrings]::GetIndirectString( $AXI.DisplayNameRaw ) |
| 80 | + if ($AXI.DisplayNameResolved -eq '') { |
| 81 | + Write-Warning "$($AXN): Could not resolve the display name." |
| 82 | + } |
| 83 | + } else { |
| 84 | + $AXI.DisplayNameResolved = $AXI.DisplayNameRaw |
| 85 | + if ($AXI.DisplayNameRaw -match '^ms-resource\:') { |
| 86 | + Write-Verbose = 'For the want of an @, a kingdom is lost.' |
| 87 | + } |
| 88 | + } |
| 89 | + } catch { |
| 90 | + Write-Verbose "$($AXN): There are no display names associated with this package." |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + #Hand over the gather info to the array |
| 95 | + $AppxIdentities[$i] = $AXI |
| 96 | +} |
| 97 | + |
| 98 | +Pop-Location |
| 99 | + |
| 100 | +$AppxIdentities |
0 commit comments