本文转自 http://www.blogbus.com/softone-logs/105678346.html
作者:Eckel Chung blog地址:http://softone.blogbus.com/ 转载请保留
—————————————————————————
(1)前言
和网上大量的讨论如何制作数字签名和验证数字签名的文章本同,本文使用微软自带的API进行PE文件数字签名有效性的验证,使用语言C#。
我们可以在windows系统下直接右键查看某个PE文件数字签名的有效性,如下图:
这让我们想到,微软必然自带了对PE文件数字签名的验证办法,经过查找资料,确定其来自下图所示的dll文件里的WinVerifyTrust函数。
1 2 |
[DllImport("wintrust.dll", PreserveSig = true, SetLastError = false)] private static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData); |
关于这个函数的使用,可以查看MSDN上的说明 。
(2) 构建将要用到的数据结构
根据微软官方材料,我们在使用这个函数前还得先准备几个数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
using System; using System.Runtime.InteropServices; namespace VerifyDigitalSignature { public enum AllocMethod { HGlobal, CoTaskMem } public enum UnionChoice { File = 1, Catalog, Blob, Signer, Cert } public enum UiChoice { All = 1, NoUI, NoBad, NoGood } public enum RevocationCheckFlags { None = 0, WholeChain } public enum StateAction { Ignore = 0, Verify, Close, AutoCache, AutoCacheFlush } public enum TrustProviderFlags { UseIE4Trust = 1, NoIE4Chain = 2, NoPolicyUsage = 4, RevocationCheckNone = 16, RevocationCheckEndCert = 32, RevocationCheckChain = 64, RecovationCheckChainExcludeRoot = 128, Safer = 256, HashOnly = 512, UseDefaultOSVerCheck = 1024, LifetimeSigning = 2048 } public enum UIContext { Execute = 0, Install } #region UnmanagedPointer class internal sealed class UnmanagedPointer : IDisposable { private IntPtr m_ptr; private AllocMethod m_meth; internal UnmanagedPointer( IntPtr ptr, AllocMethod method ) { m_meth = method; m_ptr = ptr; } ~UnmanagedPointer() { Dispose( false ); } #region IDisposable Members private void Dispose( bool disposing ) { if ( m_ptr != IntPtr.Zero ) { if ( m_meth == AllocMethod.HGlobal ) { Marshal.FreeHGlobal( m_ptr ); } else if ( m_meth == AllocMethod.CoTaskMem ) { Marshal.FreeCoTaskMem( m_ptr ); } m_ptr = IntPtr.Zero; } if ( disposing ) { GC.SuppressFinalize( this ); } } public void Dispose() { Dispose( true ); } #endregion public static implicit operator IntPtr( UnmanagedPointer ptr ) { return ptr.m_ptr; } } #endregion internal struct WINTRUST_FILE_INFO : IDisposable { public WINTRUST_FILE_INFO( string fileName, Guid subject ) { cbStruct = (uint)Marshal.SizeOf( typeof( WINTRUST_FILE_INFO ) ); pcwszFilePath = fileName; if ( subject != Guid.Empty ) { pgKnownSubject = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Guid ) ) ); Marshal.StructureToPtr( subject, pgKnownSubject, true ); } else { pgKnownSubject = IntPtr.Zero; } hFile = IntPtr.Zero; } public uint cbStruct; [MarshalAs( UnmanagedType.LPTStr )] public string pcwszFilePath; public IntPtr hFile; public IntPtr pgKnownSubject; #region IDisposable Members public void Dispose() { Dispose( true ); } private void Dispose( bool disposing ) { if ( pgKnownSubject != IntPtr.Zero ) { Marshal.DestroyStructure( this.pgKnownSubject, typeof( Guid ) ); Marshal.FreeHGlobal( this.pgKnownSubject ); } } #endregion } [StructLayout( LayoutKind.Sequential )] internal struct WINTRUST_DATA : IDisposable { public WINTRUST_DATA( WINTRUST_FILE_INFO fileInfo ) { this.cbStruct = (uint)Marshal.SizeOf( typeof( WINTRUST_DATA ) ); pInfoStruct = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( WINTRUST_FILE_INFO ) ) ); Marshal.StructureToPtr( fileInfo, pInfoStruct, true ); this.dwUnionChoice = UnionChoice.File; pPolicyCallbackData = IntPtr.Zero; pSIPCallbackData = IntPtr.Zero; dwUIChoice = UiChoice.NoUI; fdwRevocationChecks = RevocationCheckFlags.None; dwStateAction = StateAction.Ignore; hWVTStateData = IntPtr.Zero; pwszURLReference = IntPtr.Zero; dwProvFlags = TrustProviderFlags.Safer; dwUIContext = UIContext.Execute; } public uint cbStruct; public IntPtr pPolicyCallbackData; public IntPtr pSIPCallbackData; public UiChoice dwUIChoice; public RevocationCheckFlags fdwRevocationChecks; public UnionChoice dwUnionChoice; public IntPtr pInfoStruct; public StateAction dwStateAction; public IntPtr hWVTStateData; private IntPtr pwszURLReference; public TrustProviderFlags dwProvFlags; public UIContext dwUIContext; #region IDisposable Members public void Dispose() { Dispose( true ); } private void Dispose( bool disposing ) { if ( dwUnionChoice == UnionChoice.File ) { //WINTRUST_FILE_INFO info = new WINTRUST_FILE_INFO(); //Marshal.PtrToStructure(pInfoStruct, info); //info.Dispose(); Marshal.DestroyStructure( pInfoStruct, typeof( WINTRUST_FILE_INFO ) ); } Marshal.FreeHGlobal( pInfoStruct ); } #endregion } } |
(3)构建我们的验证类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.Win32; namespace VerifyDigitalSignature { public class Authentication { [DllImport( "wintrust.dll", PreserveSig = true, SetLastError = false )] private static extern uint WinVerifyTrust( IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData ); private static List<Guid> GetTrustGuid() { //HKEY_LOCAL_MACHINESOFTWAREMicrosoftCryptographyProvidersTrustInitialization List<Guid> trustGuids = new List<Guid>(); RegistryKey hklm = Registry.LocalMachine; RegistryKey initialization = hklm.OpenSubKey( @"SOFTWAREMicrosoftCryptographyProvidersTrustInitialization" ); string[] guidNames = initialization.GetSubKeyNames(); foreach ( string guidName in guidNames ) { trustGuids.Add( new Guid( guidName ) ); } return trustGuids; } public static uint CSWinVerifyTrust( string fileName ) { uint result = 1516356; try { List<Guid> trustGuids = GetTrustGuid(); foreach ( Guid guid in trustGuids ) { Guid wintrust_action_generic_verify_v2 = guid; WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO( fileName, Guid.Empty ); WINTRUST_DATA data = new WINTRUST_DATA( fileInfo ); UnmanagedPointer guidPtr = new UnmanagedPointer( Marshal.AllocHGlobal( Marshal.SizeOf( typeof( Guid ) ) ), AllocMethod.HGlobal ); UnmanagedPointer wvtDataPtr = new UnmanagedPointer( Marshal.AllocHGlobal( Marshal.SizeOf( typeof( WINTRUST_DATA ) ) ), AllocMethod.HGlobal ); IntPtr pGuid = guidPtr; IntPtr pData = wvtDataPtr; Marshal.StructureToPtr( wintrust_action_generic_verify_v2, pGuid, true ); Marshal.StructureToPtr( data, pData, true ); result = WinVerifyTrust( IntPtr.Zero, pGuid, pData ); if ( result == 0 ) { break; } } } catch ( Exception ex ) { throw new Exception( "VerifyDigitalSignature error.", ex ); } return result; } } } |
注意这里,WinVerifyTrust的返回值有多种,0表示数字签名各项指标都是正常的,其他代码我们下一部分再来讨论。
实测通过: