工作中碰到需要判断一个PE文件是否是所确认的文件,而不是被替换过的。直接判断文件名的话有些不保险,别人只要修改下文件名,就可以以假乱真。
因而需要判断额外的信息;由于文件有数字签名,判断数字签名因而是一个比较好的方法,但是如果只是判断数字签名是否有效也不够,别人只要用自己的证书重新签名就可以了,所以需要判断证书签名者信息。
验证文件数字签名是否有效可以使用函数 WinVerifyTrust
取得文件数字签名证书信息需要使用函数 CryptQueryObject。
下面是一段从网上搜到的获得文件数字签名证书信息的代码:
1 #include < windows.h >
2 #include < wincrypt.h >
3 #include < wintrust.h >
4 #include < stdio.h >
5 #include < tchar.h >
6 #pragma comment(lib, "crypt32.lib")
7 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
8 typedef struct {
9 LPWSTR lpszProgramName;
10 LPWSTR lpszPublisherLink;
11 LPWSTR lpszMoreInfoLink;
12 } SPROG_PUBLISHERINFO, * PSPROG_PUBLISHERINFO;
13 BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
14 PSPROG_PUBLISHERINFO Info);
15 BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME * st);
16 BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext);
17 BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo,
18 PCMSG_SIGNER_INFO * pCounterSignerInfo);
19 int _tmain( int argc, TCHAR * argv[])
20 {
21 WCHAR szFileName[MAX_PATH];
22 HCERTSTORE hStore = NULL;
23 HCRYPTMSG hMsg = NULL;
24 PCCERT_CONTEXT pCertContext = NULL;
25 BOOL fResult;
26 DWORD dwEncoding, dwContentType, dwFormatType;
27 PCMSG_SIGNER_INFO pSignerInfo = NULL;
28 PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
29 DWORD dwSignerInfo;
30 CERT_INFO CertInfo;
31 SPROG_PUBLISHERINFO ProgPubInfo;
32 SYSTEMTIME st;
33 ZeroMemory( & ProgPubInfo, sizeof (ProgPubInfo));
34 __try
35 {
36 if (argc != 2 )
37 {
38 _tprintf(_T( " Usage: SignedFileInfo <filename>\n " ));
39 return 0 ;
40 }
41 #ifdef UNICODE
42 lstrcpynW(szFileName, argv[ 1 ], MAX_PATH);
43 #else
44 if (mbstowcs(szFileName, argv[ 1 ], MAX_PATH) == - 1 )
45 {
46 printf( " Unable to convert to unicode.\n " );
47 __leave;
48 }
49 #endif
50 // Get message handle and store handle from the signed file.
51 fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
52 szFileName,
53 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
54 CERT_QUERY_FORMAT_FLAG_BINARY,
55 0 ,
56 & dwEncoding,
57 & dwContentType,
58 & dwFormatType,
59 & hStore,
60 & hMsg,
61 NULL);
62 if ( ! fResult)
63 {
64 _tprintf(_T( " CryptQueryObject failed with %x\n " ), GetLastError());
65 __leave;
66 }
67 // Get signer information size.
68 fResult = CryptMsgGetParam(hMsg,
69 CMSG_SIGNER_INFO_PARAM,
70 0 ,
71 NULL,
72 & dwSignerInfo);
73 if ( ! fResult)
74 {
75 _tprintf(_T( " CryptMsgGetParam failed with %x\n " ), GetLastError());
76 __leave;
77 }
78 // Allocate memory for signer information.
79 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
80 if ( ! pSignerInfo)
81 {
82 _tprintf(_T( " Unable to allocate memory for Signer Info.\n " ));
83 __leave;
84 }
85 // Get Signer Information.
86 fResult = CryptMsgGetParam(hMsg,
87 CMSG_SIGNER_INFO_PARAM,
88 0 ,
89 (PVOID)pSignerInfo,
90 & dwSignerInfo);
91 if ( ! fResult)
92 {
93 _tprintf(_T( " CryptMsgGetParam failed with %x\n " ), GetLastError());
94 __leave;
95 }
96 // Get program name and publisher information from
97 // signer info structure.
98 if (GetProgAndPublisherInfo(pSignerInfo, & ProgPubInfo))
99 {
100 if (ProgPubInfo.lpszProgramName != NULL)
101 {
102 wprintf(L " Program Name : %s\n " ,
103 ProgPubInfo.lpszProgramName);
104 }
105 if (ProgPubInfo.lpszPublisherLink != NULL)
106 {
107 wprintf(L " Publisher Link : %s\n " ,
108 ProgPubInfo.lpszPublisherLink);
109 }
110 if (ProgPubInfo.lpszMoreInfoLink != NULL)
111 {
112 wprintf(L " MoreInfo Link : %s\n " ,
113 ProgPubInfo.lpszMoreInfoLink);
114 }
115 }
116 _tprintf(_T( " \n " ));
117 // Search for the signer certificate in the temporary
118 // certificate store.
119 CertInfo.Issuer = pSignerInfo -> Issuer;
120 CertInfo.SerialNumber = pSignerInfo -> SerialNumber;
121 pCertContext = CertFindCertificateInStore(hStore,
122 ENCODING,
123 0 ,
124 CERT_FIND_SUBJECT_CERT,
125 (PVOID) & CertInfo,
126 NULL);
127 if ( ! pCertContext)
128 {
129 _tprintf(_T( " CertFindCertificateInStore failed with %x\n " ),
130 GetLastError());
131 __leave;
132 }
133 // Print Signer certificate information.
134 _tprintf(_T( " Signer Certificate:\n\n " ));
135 PrintCertificateInfo(pCertContext);
136 _tprintf(_T( " \n " ));
137 // Get the timestamp certificate signerinfo structure.
138 if (GetTimeStampSignerInfo(pSignerInfo, & pCounterSignerInfo))
139 {
140 // Search for Timestamp certificate in the temporary
141 // certificate store.
142 CertInfo.Issuer = pCounterSignerInfo -> Issuer;
143 CertInfo.SerialNumber = pCounterSignerInfo -> SerialNumber;
144 pCertContext = CertFindCertificateInStore(hStore,
145 ENCODING,
146 0 ,
147 CERT_FIND_SUBJECT_CERT,
148 (PVOID) & CertInfo,
149 NULL);
150 if ( ! pCertContext)
151 {
152 _tprintf(_T( " CertFindCertificateInStore failed with %x\n " ),
153 GetLastError());
154 __leave;
155 }
156 // Print timestamp certificate information.
157 _tprintf(_T( " TimeStamp Certificate:\n\n " ));
158 PrintCertificateInfo(pCertContext);
159 _tprintf(_T( " \n " ));
160 // Find Date of timestamp.
161 if (GetDateOfTimeStamp(pCounterSignerInfo, & st))
162 {
163 _tprintf(_T( " Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n " ),
164 st.wMonth,
165 st.wDay,
166 st.wYear,
167 st.wHour,
168 st.wMinute);
169 }
170 _tprintf(_T( " \n " ));
171 }
172 }
173 __finally
174 {
175 // Clean up.
176 if (ProgPubInfo.lpszProgramName != NULL)
177 LocalFree(ProgPubInfo.lpszProgramName);
178 if (ProgPubInfo.lpszPublisherLink != NULL)
179 LocalFree(ProgPubInfo.lpszPublisherLink);
180 if (ProgPubInfo.lpszMoreInfoLink != NULL)
181 LocalFree(ProgPubInfo.lpszMoreInfoLink);
182 if (pSignerInfo != NULL) LocalFree(pSignerInfo);
183 if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo);
184 if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
185 if (hStore != NULL) CertCloseStore(hStore, 0 );
186 if (hMsg != NULL) CryptMsgClose(hMsg);
187 }
188 return 0 ;
189 }
190 BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
191 {
192 BOOL fReturn = FALSE;
193 LPTSTR szName = NULL;
194 DWORD dwData;
195 __try
196 {
197 // Print Serial Number.
198 _tprintf(_T( " Serial Number: " ));
199 dwData = pCertContext -> pCertInfo -> SerialNumber.cbData;
200 for (DWORD n = 0 ; n < dwData; n ++ )
201 {
202 _tprintf(_T( " %02x " ),
203 pCertContext -> pCertInfo -> SerialNumber.pbData[dwData - (n + 1 )]);
204 }
205 _tprintf(_T( " \n " ));
206 // Get Issuer name size.
207 if ( ! (dwData = CertGetNameString(pCertContext,
208 CERT_NAME_SIMPLE_DISPLAY_TYPE,
209 CERT_NAME_ISSUER_FLAG,
210 NULL,
211 NULL,
212 0 )))
213 {
214 _tprintf(_T( " CertGetNameString failed.\n " ));
215 __leave;
216 }
217 // Allocate memory for Issuer name.
218 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof (TCHAR));
219 if ( ! szName)
220 {
221 _tprintf(_T( " Unable to allocate memory for issuer name.\n " ));
222 __leave;
223 }
224 // Get Issuer name.
225 if ( ! (CertGetNameString(pCertContext,
226 CERT_NAME_SIMPLE_DISPLAY_TYPE,
227 CERT_NAME_ISSUER_FLAG,
228 NULL,
229 szName,
230 dwData)))
231 {
232 _tprintf(_T( " CertGetNameString failed.\n " ));
233 __leave;
234 }
235 // print Issuer name.
236 _tprintf(_T( " Issuer Name: %s\n " ), szName);
237 LocalFree(szName);
238 szName = NULL;
239 // Get Subject name size.
240 if ( ! (dwData = CertGetNameString(pCertContext,
241 CERT_NAME_SIMPLE_DISPLAY_TYPE,
242 0 ,
243 NULL,
244 NULL,
245 0 )))
246 {
247 _tprintf(_T( " CertGetNameString failed.\n " ));
248 __leave;
249 }
250 // Allocate memory for subject name.
251 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof (TCHAR));
252 if ( ! szName)
253 {
254 _tprintf(_T( " Unable to allocate memory for subject name.\n " ));
255 __leave;
256 }
257 // Get subject name.
258 if ( ! (CertGetNameString(pCertContext,
259 CERT_NAME_SIMPLE_DISPLAY_TYPE,
260 0 ,
261 NULL,
262 szName,
263 dwData)))
264 {
265 _tprintf(_T( " CertGetNameString failed.\n " ));
266 __leave;
267 }
268 // Print Subject Name.
269 _tprintf(_T( " Subject Name: %s\n " ), szName);
270 fReturn = TRUE;
271 }
272 __finally
273 {
274 if (szName != NULL) LocalFree(szName);
275 }
276 return fReturn;
277 }
278 LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
279 {
280 LPWSTR outputString = NULL;
281 outputString = (LPWSTR)LocalAlloc(LPTR,
282 (wcslen(inputString) + 1 ) * sizeof (WCHAR));
283 if (outputString != NULL)
284 {
285 lstrcpyW(outputString, inputString);
286 }
287 return outputString;
288 }
289 BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
290 PSPROG_PUBLISHERINFO Info)
291 {
292 BOOL fReturn = FALSE;
293 PSPC_SP_OPUS_INFO OpusInfo = NULL;
294 DWORD dwData;
295 BOOL fResult;
296 __try
297 {
298 // Loop through authenticated attributes and find
299 // SPC_SP_OPUS_INFO_OBJID OID.
300 for (DWORD n = 0 ; n < pSignerInfo -> AuthAttrs.cAttr; n ++ )
301 {
302 if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID,
303 pSignerInfo -> AuthAttrs.rgAttr[n].pszObjId) == 0 )
304 {
305 // Get Size of SPC_SP_OPUS_INFO structure.
306 fResult = CryptDecodeObject(ENCODING,
307 SPC_SP_OPUS_INFO_OBJID,
308 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].pbData,
309 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].cbData,
310 0 ,
311 NULL,
312 & dwData);
313 if ( ! fResult)
314 {
315 _tprintf(_T( " CryptDecodeObject failed with %x\n " ),
316 GetLastError());
317 __leave;
318 }
319 // Allocate memory for SPC_SP_OPUS_INFO structure.
320 OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
321 if ( ! OpusInfo)
322 {
323 _tprintf(_T( " Unable to allocate memory for Publisher Info.\n " ));
324 __leave;
325 }
326 // Decode and get SPC_SP_OPUS_INFO structure.
327 fResult = CryptDecodeObject(ENCODING,
328 SPC_SP_OPUS_INFO_OBJID,
329 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].pbData,
330 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].cbData,
331 0 ,
332 OpusInfo,
333 & dwData);
334 if ( ! fResult)
335 {
336 _tprintf(_T( " CryptDecodeObject failed with %x\n " ),
337 GetLastError());
338 __leave;
339 }
340 // Fill in Program Name if present.
341 if (OpusInfo -> pwszProgramName)
342 {
343 Info -> lpszProgramName =
344 AllocateAndCopyWideString(OpusInfo -> pwszProgramName);
345 }
346 else
347 Info -> lpszProgramName = NULL;
348 // Fill in Publisher Information if present.
349 if (OpusInfo -> pPublisherInfo)
350 {
351 switch (OpusInfo -> pPublisherInfo -> dwLinkChoice)
352 {
353 case SPC_URL_LINK_CHOICE:
354 Info -> lpszPublisherLink =
355 AllocateAndCopyWideString(OpusInfo -> pPublisherInfo -> pwszUrl);
356 break ;
357 case SPC_FILE_LINK_CHOICE:
358 Info -> lpszPublisherLink =
359 AllocateAndCopyWideString(OpusInfo -> pPublisherInfo -> pwszFile);
360 break ;
361 default :
362 Info -> lpszPublisherLink = NULL;
363 break ;
364 }
365 }
366 else
367 {
368 Info -> lpszPublisherLink = NULL;
369 }
370 // Fill in More Info if present.
371 if (OpusInfo -> pMoreInfo)
372 {
373 switch (OpusInfo -> pMoreInfo -> dwLinkChoice)
374 {
375 case SPC_URL_LINK_CHOICE:
376 Info -> lpszMoreInfoLink =
377 AllocateAndCopyWideString(OpusInfo -> pMoreInfo -> pwszUrl);
378 break ;
379 case SPC_FILE_LINK_CHOICE:
380 Info -> lpszMoreInfoLink =
381 AllocateAndCopyWideString(OpusInfo -> pMoreInfo -> pwszFile);
382 break ;
383 default :
384 Info -> lpszMoreInfoLink = NULL;
385 break ;
386 }
387 }
388 else
389 {
390 Info -> lpszMoreInfoLink = NULL;
391 }
392 fReturn = TRUE;
393 break ; // Break from for loop.
394 } // lstrcmp SPC_SP_OPUS_INFO_OBJID
395 } // for
396 }
397 __finally
398 {
399 if (OpusInfo != NULL) LocalFree(OpusInfo);
400 }
401 return fReturn;
402 }
403 BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME * st)
404 {
405 BOOL fResult;
406 FILETIME lft, ft;
407 DWORD dwData;
408 BOOL fReturn = FALSE;
409 // Loop through authenticated attributes and find
410 // szOID_RSA_signingTime OID.
411 for (DWORD n = 0 ; n < pSignerInfo -> AuthAttrs.cAttr; n ++ )
412 {
413 if (lstrcmpA(szOID_RSA_signingTime,
414 pSignerInfo -> AuthAttrs.rgAttr[n].pszObjId) == 0 )
415 {
416 // Decode and get FILETIME structure.
417 dwData = sizeof (ft);
418 fResult = CryptDecodeObject(ENCODING,
419 szOID_RSA_signingTime,
420 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].pbData,
421 pSignerInfo -> AuthAttrs.rgAttr[n].rgValue[ 0 ].cbData,
422 0 ,
423 (PVOID) & ft,
424 & dwData);
425 if ( ! fResult)
426 {
427 _tprintf(_T( " CryptDecodeObject failed with %x\n " ),
428 GetLastError());
429 break ;
430 }
431 // Convert to local time.
432 FileTimeToLocalFileTime( & ft, & lft);
433 FileTimeToSystemTime( & lft, st);
434 fReturn = TRUE;
435 break ; // Break from for loop.
436 } // lstrcmp szOID_RSA_signingTime
437 } // for
438 return fReturn;
439 }
440 BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO * pCounterSignerInfo)
441 {
442 PCCERT_CONTEXT pCertContext = NULL;
443 BOOL fReturn = FALSE;
444 BOOL fResult;
445 DWORD dwSize;
446 __try
447 {
448 * pCounterSignerInfo = NULL;
449 // Loop through unathenticated attributes for
450 // szOID_RSA_counterSign OID.
451 for (DWORD n = 0 ; n < pSignerInfo -> UnauthAttrs.cAttr; n ++ )
452 {
453 if (lstrcmpA(pSignerInfo -> UnauthAttrs.rgAttr[n].pszObjId,
454 szOID_RSA_counterSign) == 0 )
455 {
456 // Get size of CMSG_SIGNER_INFO structure.
457 fResult = CryptDecodeObject(ENCODING,
458 PKCS7_SIGNER_INFO,
459 pSignerInfo -> UnauthAttrs.rgAttr[n].rgValue[ 0 ].pbData,
460 pSignerInfo -> UnauthAttrs.rgAttr[n].rgValue[ 0 ].cbData,
461 0 ,
462 NULL,
463 & dwSize);
464 if ( ! fResult)
465 {
466 _tprintf(_T( " CryptDecodeObject failed with %x\n " ),
467 GetLastError());
468 __leave;
469 }
470 // Allocate memory for CMSG_SIGNER_INFO.
471 * pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
472 if ( !* pCounterSignerInfo)
473 {
474 _tprintf(_T( " Unable to allocate memory for timestamp info.\n " ));
475 __leave;
476 }
477 // Decode and get CMSG_SIGNER_INFO structure
478 // for timestamp certificate.
479 fResult = CryptDecodeObject(ENCODING,
480 PKCS7_SIGNER_INFO,
481 pSignerInfo -> UnauthAttrs.rgAttr[n].rgValue[ 0 ].pbData,
482 pSignerInfo -> UnauthAttrs.rgAttr[n].rgValue[ 0 ].cbData,
483 0 ,
484 (PVOID) * pCounterSignerInfo,
485 & dwSize);
486 if ( ! fResult)
487 {
488 _tprintf(_T( " CryptDecodeObject failed with %x\n " ),
489 GetLastError());
490 __leave;
491 }
492 fReturn = TRUE;
493 break ; // Break from for loop.
494 }
495 }
496 }
497 __finally
498 {
499 // Clean up.
500 if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
501 }
502 return fReturn;
503 }