[Powershell] Get SLIC Version

Discussion in 'Scripting' started by MrTweek, Dec 8, 2016.

  1. MrTweek

    MrTweek MDL Junior Member

    Apr 13, 2010
    53
    16
    0
    #1 MrTweek, Dec 8, 2016
    Last edited by a moderator: Apr 20, 2017
    Hi, sometimes i have to setup good old win7 mashines and need to know the SLIC Version and Cert. After some research
    How to get the SLIC, i begun to write a little script (as part of an Task Sequence for the MDT 2013 Update 2) for my Deployments. In this Case it shows the embedded SLIC Table informations.

    ## Changelog ##
    - Fixed empty table initialization. (SLIC was reported as missing but it is there...)
    - Pay attention to different SLICs (example ASUS with DELL SLIC table)
    - Allow to search for matching Certificates in a path (using -cert_path C:\MyCerts)

    Code:
    param (
        [string] $cert_path = "",
        [bool] $dump_cert = $false
    )
    
    $SFTCode = @"
    [DllImport("kernel32")] public static extern uint EnumSystemFirmwareTables (uint FirmwareTableProviderSignature, IntPtr pFirmwareTableBuffer, uint BufferSize);
    [DllImport("kernel32")] public static extern uint GetSystemFirmwareTable (uint FirmwareTableProviderSignature, uint FimrwareTableID, IntPtr pFirmwareTableBuffer, uint BufferSize);
    "@
    
    $SFT = Add-Type -MemberDefinition $SFTCode -Name "SFTKlasse" -Language CSharp -UsingNamespace "System.Reflection", "System.Diagnostics", "System.Collections.Generic" -PassThru
    [uint32] $tblLength = $SFT::GetSystemFirmwareTable(0x41435049, 0x43494c53, [IntPtr]::Zero, 0)
    
    if ($tblLength -ne 0)
    {
        [System.byte[]] $table = New-Object byte[]($tblLength)
        [IntPtr] $slicStruct = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($table.Length)
    
        #
        # 0x41435049 = ACPI
        # 0x43494c53 = CILS ("SLIC" reversed)
        #
    
        $SFT::GetSystemFirmwareTable(0x41435049, 0x43494c53, $slicStruct, $table.Length) | Out-Null
        
        #Copy the Content of the Structure into a byte Array "table"
        [System.Runtime.InteropServices.Marshal]::Copy($slicStruct, $table, 0, $table.Length)
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($slicStruct)
        
        if ([System.Text.Encoding]::ASCII.GetString($table, 0, 4) -ne "SLIC")
        {
            Write-Output "The SLIC Signature is not present."
        }
        else
        {
            [uint16] $slicVer = [System.BitConverter]::ToUInt16($table, 226)
            [uint32] $SLICLength = [System.BitConverter]::ToUInt32($table, 4)
            [string] $oemid = [System.Text.Encoding]::ASCII.GetString($table, 10, 6)
            [string] $oemTableid = [System.Text.Encoding]::ASCII.GetString($table, 16, 8)
            [string] $slicstring = [System.Text.Encoding]::ASCII.GetString($table, 204, 14)
            
            Write-Output "========== SLIC =========="
            Write-Output "OEM ID: $oemid"
            Write-Output "SLIC Size: $SLICLength ($tblLength)"
            Write-Output "OEM TableID: $slicstring"
            Write-Output "Version: 2.$slicVer"
    
            #
            # Sometimes we have a SLIC and (maybe) 10 Certs, try to find (a) matching cert(s)...
            #
    
            # If the User did not enter a path so look at script the location
            if ([string]::IsNullOrEmpty($cert_path))
            {
                $cert_path = [System.Environment]::CurrentDirectory
            }
    
    
            if ([IO.Directory]::Exists($cert_path))
            {
                [string[]] $fileEntries = [IO.Directory]::GetFiles($cert_path,"*.XRM-MS")
                
                # cert
                [byte[]] $cert_data = New-Object byte[](128)
                [uint32] $cert_length = 0
                
                [byte[]] $slic_data = New-Object byte[](128)                
                [int] $iMatch = 0
                [uint32] $numCert = 0
                            
                for ($iFile = 0; $iFile -lt $fileEntries.Count; $iFile++)
                {
                    $fil = $fileEntries[$iFile]
                    Write-Progress -Activity "Comparing Certificates..." -Status "Comparing $fil" -PercentComplete (($iFile / $fileEntries.Count) * 100)
    
                    [string] $line = [System.IO.File]::ReadAllText($fil)
        
                    if ($line.Contains("/bios/4.0") -and $line.Contains("</sl:data>"))
                    {
                        [int] $data_start = $line.LastIndexOf("msft:rm/algorithm/bios/4.0") + "msft:rm/algorithm/bios/4.0".Length + 2    
                        [int] $data_end = $line.IndexOf("</sl:data>")
                        [string] $b64String = $line.Substring($data_start, ($data_end - $data_start)).Trim()
    
                        [byte[]] $d = [System.Convert]::FromBase64String($b64String)
    
                        [string] $delta = [System.Text.Encoding]::ASCII.GetString($d, 0, $d.Length).Trim()
                        
                        if (($delta.Contains($oemid)) -and ($fil.Length -gt 3))
                        {
                            [System.Array]::Copy($d, 18, $cert_data, 0, 128)
                            [System.Array]::Copy($table, 64, $slic_data, 0, 128)
                            
                            #
                            # NOTICE: Find a quicker compare method
                            # Compare each byte of the arrays (cert_data) and (slic_data)
                            # The Cert Contains 128 bytes of data which are also stored in the Firmware!
                            #
    
                            for ($i = 0; $i -lt $cert_data.Length; $i++)
                            {
                                $x = $cert_data[$i]
                                $y = $slic_data[$i]
    
                                if ($x -eq $y)
                                {
                                    $iMatch++
                                    
                                    # We need 128 matches otherwise it is not valid
                                    if ($iMatch -eq 128)
                                    {
                                        $numCert++
                                        $cert_length =[System.BitConverter]::ToUInt32($d,0)
                                        Write-Output "Cert[$numCert] file: $fil"
                                        Write-Output "Cert[$numCert] Length: $cert_length bytes"
                                        Write-Output ""
    
                                        #if ($dump_cert -eq $true)
                                        #{
                                        #    [string] $dumpDir = [System.IO.Path]::Combine("C:\",[string]::Format("{2}-{0}-{1}_cert.dmp",$oemid, $oemTableid, $iFile))
                                        #    [System.IO.File]::WriteAllBytes($dumpDir,$d)
                                        #    Write-Output "Cert[$numCert] dumped to $dumpDir"
                                        #}
                                    }
                                }
                            }
                            
                            [system.Array]::Clear($cert_data, 0, $cert_data.Length)
                            [system.Array]::Clear($slic_data, 0, $slic_data.Length)
                            $iMatch = 0
                        }
                    }
                }
            }
            $numCert = 0
            Write-Output "=========================="
        }
    }
    
    For infos about MSDM and SLIC Tables read here:
    http://feishare.com/attachments/article/265/microsoft-software-licensing-tables.pdf

    [​IMG]
    [​IMG]
     
  2. sebus

    sebus MDL Guru

    Jul 23, 2008
    5,895
    1,783
    180
    #2 sebus, Dec 8, 2016
    Last edited by a moderator: Apr 20, 2017
    Does not seem to work:

    Code:
    C:\Users\sebus\Documents>powershell ./GetSlicversion.ps1
    NO VALID SLIC Table!
    Yet good old SLIC Toolkit 3.2 gives:

    Code:
    Dump OK !   ( DELLCBX3_V2.1 )
    That on Dell Precision 7600 (which comes with 2.1 Slic by default, not modded)
     
  3. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    7,707
    24,971
    240
    Does not work here either
     
  4. MrTweek

    MrTweek MDL Junior Member

    Apr 13, 2010
    53
    16
    0
    #4 MrTweek, Dec 8, 2016
    Last edited: Dec 9, 2016
    (OP)
    Fixed and updated -> see post #1
     
  5. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    7,707
    24,971
    240
    All good now
     
  6. MrTweek

    MrTweek MDL Junior Member

    Apr 13, 2010
    53
    16
    0
    I tried to implement certification Compare & and search...

    Updated:
    - Add Experimental Support for searching for matching certificates
     
  7. user_hidden

    user_hidden MDL Expert

    Dec 18, 2007
    1,026
    978
    60
    does not work for me
     
  8. MrTweek

    MrTweek MDL Junior Member

    Apr 13, 2010
    53
    16
    0
    What Error Do you get?
     
  9. Psychoteur

    Psychoteur MDL Novice

    Feb 11, 2013
    3
    0
    0
    I use MDT too but I just did make a folder named OEM inside C:\Windows\system32.
    Inside OEM all the certificats.
    Do a reference image with a generic installation key see MS website and next time you deploy your image to another computer it's activated.