<# .SYNOPSIS Calculate hash for Set-Association function .VERSION 7.1.4 .DATE 24.02.2026 .COPYRIGHT (c) 2014—2026 Team Sophia .LINK https://github.com/farag2/Sophia-Script-for-Windows #> function Get-Hash { [CmdletBinding()] [OutputType([string])] Param ( [Parameter( Mandatory = $true, Position = 0 )] [string] $ProgId, [Parameter( Mandatory = $true, Position = 1 )] [string] $Extension, [Parameter( Mandatory = $true, Position = 2 )] [string] $SubKey ) $Signature = @{ Namespace = "WinAPI" Name = "PatentHash" Language = "CSharp" CompilerParameters = $CompilerParameters MemberDefinition = @" public static uint[] WordSwap(byte[] a, int sz, byte[] md5) { if (sz < 2 || (sz & 1) == 1) { throw new ArgumentException(String.Format("Invalid input size: {0}", sz), "sz"); } unchecked { uint o1 = 0; uint o2 = 0; int ta = 0; int ts = sz; int ti = ((sz - 2) >> 1) + 1; uint c0 = (BitConverter.ToUInt32(md5, 0) | 1) + 0x69FB0000; uint c1 = (BitConverter.ToUInt32(md5, 4) | 1) + 0x13DB0000; for (uint i = (uint)ti; i > 0; i--) { uint n = BitConverter.ToUInt32(a, ta) + o1; ta += 8; ts -= 2; uint v1 = 0x79F8A395 * (n * c0 - 0x10FA9605 * (n >> 16)) + 0x689B6B9F * ((n * c0 - 0x10FA9605 * (n >> 16)) >> 16); uint v2 = 0xEA970001 * v1 - 0x3C101569 * (v1 >> 16); uint v3 = BitConverter.ToUInt32(a, ta - 4) + v2; uint v4 = v3 * c1 - 0x3CE8EC25 * (v3 >> 16); uint v5 = 0x59C3AF2D * v4 - 0x2232E0F1 * (v4 >> 16); o1 = 0x1EC90001 * v5 + 0x35BD1EC9 * (v5 >> 16); o2 += o1 + v2; } if (ts == 1) { uint n = BitConverter.ToUInt32(a, ta) + o1; uint v1 = n * c0 - 0x10FA9605 * (n >> 16); uint v2 = 0xEA970001 * (0x79F8A395 * v1 + 0x689B6B9F * (v1 >> 16)) - 0x3C101569 * ((0x79F8A395 * v1 + 0x689B6B9F * (v1 >> 16)) >> 16); uint v3 = v2 * c1 - 0x3CE8EC25 * (v2 >> 16); o1 = 0x1EC90001 * (0x59C3AF2D * v3 - 0x2232E0F1 * (v3 >> 16)) + 0x35BD1EC9 * ((0x59C3AF2D * v3 - 0x2232E0F1 * (v3 >> 16)) >> 16); o2 += o1 + v2; } uint[] ret = new uint[2]; ret[0] = o1; ret[1] = o2; return ret; } } public static uint[] Reversible(byte[] a, int sz, byte[] md5) { if (sz < 2 || (sz & 1) == 1) { throw new ArgumentException(String.Format("Invalid input size: {0}", sz), "sz"); } unchecked { uint o1 = 0; uint o2 = 0; int ta = 0; int ts = sz; int ti = ((sz - 2) >> 1) + 1; uint c0 = BitConverter.ToUInt32(md5, 0) | 1; uint c1 = BitConverter.ToUInt32(md5, 4) | 1; for (uint i = (uint)ti; i > 0; i--) { uint n = (BitConverter.ToUInt32(a, ta) + o1) * c0; n = 0xB1110000 * n - 0x30674EEF * (n >> 16); ta += 8; ts -= 2; uint v1 = 0x5B9F0000 * n - 0x78F7A461 * (n >> 16); uint v2 = 0x1D830000 * (0x12CEB96D * (v1 >> 16) - 0x46930000 * v1) + 0x257E1D83 * ((0x12CEB96D * (v1 >> 16) - 0x46930000 * v1) >> 16); uint v3 = BitConverter.ToUInt32(a, ta - 4) + v2; uint v4 = 0x16F50000 * c1 * v3 - 0x5D8BE90B * (c1 * v3 >> 16); uint v5 = 0x2B890000 * (0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16)) + 0x7C932B89 * ((0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16)) >> 16); o1 = 0x9F690000 * v5 - 0x405B6097 * (v5 >> 16); o2 += o1 + v2; } if (ts == 1) { uint n = BitConverter.ToUInt32(a, ta) + o1; uint v1 = 0xB1110000 * c0 * n - 0x30674EEF * ((c0 * n) >> 16); uint v2 = 0x5B9F0000 * v1 - 0x78F7A461 * (v1 >> 16); uint v3 = 0x1D830000 * (0x12CEB96D * (v2 >> 16) - 0x46930000 * v2) + 0x257E1D83 * ((0x12CEB96D * (v2 >> 16) - 0x46930000 * v2) >> 16); uint v4 = 0x16F50000 * c1 * v3 - 0x5D8BE90B * ((c1 * v3) >> 16); uint v5 = 0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16); o1 = 0x9F690000 * (0x2B890000 * v5 + 0x7C932B89 * (v5 >> 16)) - 0x405B6097 * ((0x2B890000 * v5 + 0x7C932B89 * (v5 >> 16)) >> 16); o2 += o1 + v2; } uint[] ret = new uint[2]; ret[0] = o1; ret[1] = o2; return ret; } } public static long MakeLong(uint left, uint right) { return (long)left << 32 | (long)right; } "@ } if (-not ("WinAPI.PatentHash" -as [type])) { Add-Type @Signature } function Get-KeyLastWriteTime ($SubKey) { $LastModified = [WinAPI.Action]::GetLastModified([Microsoft.Win32.RegistryHive]::CurrentUser,$SubKey) $FileTime = ([DateTime]::New($LastModified.Year, $LastModified.Month, $LastModified.Day, $LastModified.Hour, $LastModified.Minute, 0, $LastModified.Kind)).ToFileTime() return [string]::Format("{0:x8}{1:x8}", $FileTime -shr 32, $FileTime -band [uint32]::MaxValue) } function Get-DataArray { [OutputType([array])] # Secret static string stored in %SystemRoot%\SysWOW64\%SystemRoot%\System32\shell32.dll $userExperience = "User Choice set via Windows User Experience {D18B6DD5-6124-4341-9318-804003BAFA0B}" # Get user SID $userSID = (Get-CimInstance -ClassName Win32_UserAccount | Where-Object -FilterScript {$_.Name -eq $env:USERNAME}).SID $KeyLastWriteTime = Get-KeyLastWriteTime -SubKey $SubKey $baseInfo = ("{0}{1}{2}{3}{4}" -f $Extension, $userSID, $ProgId, $KeyLastWriteTime, $userExperience).ToLowerInvariant() $StringToUTF16LEArray = [System.Collections.ArrayList]@([System.Text.Encoding]::Unicode.GetBytes($baseInfo)) $StringToUTF16LEArray += (0,0) return $StringToUTF16LEArray } function Get-PatentHash { [OutputType([string])] param ( [Parameter(Mandatory = $true)] [byte[]] $Array, [Parameter(Mandatory = $true)] [byte[]] $MD5 ) $Size = $Array.Count $ShiftedSize = ($Size -shr 2) - ($Size -shr 2 -band 1) * 1 [uint32[]]$Array1 = [WinAPI.PatentHash]::WordSwap($Array, [int]$ShiftedSize, $MD5) [uint32[]]$Array2 = [WinAPI.PatentHash]::Reversible($Array, [int]$ShiftedSize, $MD5) $Ret = [WinAPI.PatentHash]::MakeLong($Array1[1] -bxor $Array2[1], $Array1[0] -bxor $Array2[0]) return [System.Convert]::ToBase64String([System.BitConverter]::GetBytes([Int64]$Ret)) } $DataArray = Get-DataArray $DataMD5 = [System.Security.Cryptography.HashAlgorithm]::Create("MD5").ComputeHash($DataArray) $Hash = Get-PatentHash -Array $DataArray -MD5 $DataMD5 return $Hash }