我有一个经过数字签名的dll文件。我需要编写一个PowerShell命令,该命令将为我提供用于数字签名的摘要算法。
我的Dll同时具有SHA1和SHA256,并且我需要两个值。
我尝试了以下解决方案,但仅提供SHA1
How to extract digest algorithm from signed dll using PowerShell?
命令:
Get-AuthenticodeSignature $file.Filename |
%{ $_.SignerCertificate.SignatureAlgorithm.friendlyname }
答案 0 :(得分:0)
经过一番搜索,我发现this blog的Vadims Podāns具有称为Get-AuthenticodeSignatureEx
的功能,如果文件具有此功能,则确实可以获取主要和辅助(嵌套)证书签名。
我在该代码中添加了一些内容,以从发行者的X500DistinghuishedName中解析出友好名称,并确保嵌套签名也具有SigningTime
时间戳。
功能:
function Get-AuthenticodeSignatureEx {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[String[]]$FilePath
)
begin {
$signature = @"
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
int dwObjectType,
[MarshalAs(UnmanagedType.LPWStr)]
string pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
ref int pdwMsgAndCertEncodingType,
ref int pdwContentType,
ref int pdwFormatType,
ref IntPtr phCertStore,
ref IntPtr phMsg,
ref IntPtr ppvContext
);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptMsgGetParam(
IntPtr hCryptMsg,
int dwParamType,
int dwIndex,
byte[] pvData,
ref int pcbData
);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptMsgClose(
IntPtr hCryptMsg
);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CertCloseStore(
IntPtr hCertStore,
int dwFlags
);
"@
Add-Type -AssemblyName System.Security
Add-Type -MemberDefinition $signature -Namespace PKI -Name Crypt32
$CERT_QUERY_OBJECT_FILE = 0x1
$CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 0x400
$CERT_QUERY_FORMAT_FLAG_BINARY = 0x2
function getTimeStamps($SignerInfo) {
$retValue = @()
foreach ($CounterSignerInfos in $Infos.CounterSignerInfos) {
$sTime = ($CounterSignerInfos.SignedAttributes |
Where-Object{$_.Oid.Value -eq "1.2.840.113549.1.9.5"}).Values |
Where-Object {$_.SigningTime -ne $null}
$tsObject = New-Object psobject -Property @{
Certificate = $CounterSignerInfos.Certificate
SigningTime = $sTime.SigningTime.ToLocalTime()
}
$retValue += $tsObject
}
$retValue
}
function getIssuerName($SignerInfo) {
# helper function to parse the name out of the X500DistinghuishedName formatted 'Issuer' string
if ($SignerInfo.Certificate.Issuer -match 'O=([^,]+)') { $matches[1] }
elseif ($SignerInfo.Certificate.Issuer -match 'CN=([^,]+)') { $matches[1] }
else { $SignerInfo.Certificate.Issuer }
}
}
process {
Get-AuthenticodeSignature -FilePath $FilePath | ForEach-Object {
$Output = $_
if ($Output.SignerCertificate) {
$pdwMsgAndCertEncodingType = 0
$pdwContentType = 0
$pdwFormatType = 0
[IntPtr]$phCertStore = [IntPtr]::Zero
[IntPtr]$phMsg = [IntPtr]::Zero
[IntPtr]$ppvContext = [IntPtr]::Zero
$return = [PKI.Crypt32]::CryptQueryObject(
$CERT_QUERY_OBJECT_FILE,
$Output.Path,
$CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
$CERT_QUERY_FORMAT_FLAG_BINARY,
0,
[ref]$pdwMsgAndCertEncodingType,
[ref]$pdwContentType,
[ref]$pdwFormatType,
[ref]$phCertStore,
[ref]$phMsg,
[ref]$ppvContext
)
if (!$return) {return}
$pcbData = 0
$return = [PKI.Crypt32]::CryptMsgGetParam($phMsg,29,0,$null,[ref]$pcbData)
if (!$return) {return}
$pvData = New-Object byte[] -ArgumentList $pcbData
$return = [PKI.Crypt32]::CryptMsgGetParam($phMsg,29,0,$pvData,[ref]$pcbData)
$SignedCms = New-Object Security.Cryptography.Pkcs.SignedCms
$SignedCms.Decode($pvData)
$Infos = $SignedCms.SignerInfos[0]
$Output | Add-Member -MemberType NoteProperty -Name IssuerName -Value (getIssuerName $Infos)
$Output | Add-Member -MemberType NoteProperty -Name DigestAlgorithm -Value $Infos.DigestAlgorithm.FriendlyName
$Output | Add-Member -MemberType NoteProperty -Name TimeStamps -Value (getTimeStamps $Infos)
$second = $Infos.UnsignedAttributes | ?{$_.Oid.Value -eq "1.3.6.1.4.1.311.2.4.1"}
if ($second) {
$value = $second.Values | ?{$_.Oid.Value -eq "1.3.6.1.4.1.311.2.4.1"}
$SignedCms2 = New-Object Security.Cryptography.Pkcs.SignedCms
$SignedCms2.Decode($value.RawData)
$Output | Add-Member -MemberType NoteProperty -Name NestedSignature -Value $null
$Infos = $SignedCms2.SignerInfos[0]
$nested = New-Object psobject -Property @{
SignerCertificate = $Infos.Certificate
IssuerName = getIssuerName $Infos
DigestAlgorithm = $Infos.DigestAlgorithm.FriendlyName
TimeStamps = getTimeStamps $Infos
}
# the nested certificate usually does not have a this, so use from the primary certificate
if (!$nested.TimeStamps) { $nested.TimeStamps = $Output.Timestamps }
$Output.NestedSignature = $nested
}
$Output
[void][PKI.Crypt32]::CryptMsgClose($phMsg)
[void][PKI.Crypt32]::CertCloseStore($phCertStore,0)
}
else {
$Output
}
}
}
end {}
}
有了该功能,您可以像这样使用它:
$sig = Get-AuthenticodeSignatureEx "C:\Windows\Microsoft.NET\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll"
$result = @($sig | Select-Object IssuerName, DigestAlgorithm, @{Name = 'TimeStamp'; Expression = {$_.TimeStamps.SigningTime}})
if ($sig.NestedSignature) {
$result += $sig.NestedSignature | Select-Object IssuerName, DigestAlgorithm, @{Name = 'TimeStamp'; Expression = {$_.TimeStamps.SigningTime}}
}
$result
我的机器上的输出:
IssuerName DigestAlgorithm TimeStamp ---------- --------------- --------- Microsoft Corporation sha1 25-7-2019 4:18:14 Microsoft Corporation sha256 25-7-2019 4:18:14
答案 1 :(得分:0)
以下综合文章可能有一个起点:Reading multiple signatures from signed file with PowerShell。
Get-AuthenticodeSignature
cmdlet具有以下限制:
- 仅获取第一个签名;
- 如果签名带有时间戳,则不提供签名时间;
- 未提供签名算法信息。
…从技术上讲,Microsoft authenticode签名支持 一次只有一个签名。附加签名作为嵌套完成 签名。
他们编写了Get-AuthenticodeSignature
cmdlet的扩展版,作为根据Attribution-ShareAlike 4.0 International许可获得许可的功能。
不幸的是,当前的Get-AuthenticodeSignatureEx
函数似乎不足以支持两个以上的签名。
但是,有SignTool.exe。该工具会随 Visual Studio 自动安装。
示例(使用/v
开关:打印详细的成功和状态消息。这可能还会提供有关错误的更多信息。如果要查看有关签名者的信息,则应使用此选项。< / em>)
d:\bat> 2>NUL "c:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe" verify /pa /all C:\WINDOWS\system32\OpenCL.dll
File: C:\Windows\System32\OpenCL.dll Index Algorithm Timestamp ======================================== 0 sha1 Authenticode 1 sha256 RFC3161 2 sha256 RFC3161 Successfully verified: C:\Windows\System32\OpenCL.dll
例如,以下.ps1
脚本可以找到所有签名两次以上的文件:
$signtool="c:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\signtool.exe"
Get-ChildItem -File |
ForEach-Object {
$aux = . "$signtool" verify /pa /all $_.FullName 2>$null
if ( $aux -match "^2|^3|^4|^5|^6|^7|^8|^9" ) {
$aux
}
}
(当前使用Get-ChildItem C:\Windows\System32\nvh*.dll
来限制运行时间和输出大小):
D:\PShell\tests\AuthenticodeSignTool.ps1
File: C:\Windows\System32\nvhdagenco6420103.dll Index Algorithm Timestamp ======================================== 0 sha1 Authenticode 1 sha256 RFC3161 2 sha256 RFC3161 3 sha256 RFC3161 Successfully verified: C:\Windows\System32\nvhdagenco6420103.dll File: C:\Windows\System32\nvhdap64.dll Index Algorithm Timestamp ======================================== 0 sha1 Authenticode 1 sha256 RFC3161 2 sha256 RFC3161 3 sha256 RFC3161 Successfully verified: C:\Windows\System32\nvhdap64.dll