工作中碰到需要判断一个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 }