include: Add STORAGE_HOTPLUG_INFO structure.
[wine.git] / dlls / imagehlp / integrity.c
blob0085387159d525cae5c1838766e6dcfbd465d1d6
1 /*
2 * IMAGEHLP library
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2003 Mike McCormack
6 * Copyright 2009 Owen Rudge for CodeWeavers
7 * Copyright 2010 Juan Lang
8 * Copyright 2010 Andrey Turkin
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <stdarg.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "winternl.h"
31 #include "winnt.h"
32 #include "winver.h"
33 #include "imagehlp.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
39 * These functions are partially documented at:
40 * http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
43 #define HDR_FAIL -1
44 #define HDR_NT32 0
45 #define HDR_NT64 1
47 /***********************************************************************
48 * IMAGEHLP_GetNTHeaders (INTERNAL)
50 * Return the IMAGE_NT_HEADERS for a PE file, after validating magic
51 * numbers and distinguishing between 32-bit and 64-bit files.
53 static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64)
55 IMAGE_DOS_HEADER dos_hdr;
56 DWORD count;
57 BOOL r;
59 TRACE("handle %p\n", handle);
61 if ((!nt32) || (!nt64))
62 return HDR_FAIL;
64 /* read the DOS header */
65 count = SetFilePointer(handle, 0, NULL, FILE_BEGIN);
67 if (count == INVALID_SET_FILE_POINTER)
68 return HDR_FAIL;
70 count = 0;
72 r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL);
74 if (!r)
75 return HDR_FAIL;
77 if (count != sizeof dos_hdr)
78 return HDR_FAIL;
80 /* verify magic number of 'MZ' */
81 if (dos_hdr.e_magic != IMAGE_DOS_SIGNATURE)
82 return HDR_FAIL;
84 if (pe_offset != NULL)
85 *pe_offset = dos_hdr.e_lfanew;
87 /* read the PE header */
88 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
90 if (count == INVALID_SET_FILE_POINTER)
91 return HDR_FAIL;
93 count = 0;
95 r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL);
97 if (!r)
98 return HDR_FAIL;
100 if (count != sizeof(IMAGE_NT_HEADERS32))
101 return HDR_FAIL;
103 /* verify NT signature */
104 if (nt32->Signature != IMAGE_NT_SIGNATURE)
105 return HDR_FAIL;
107 /* check if we have a 32-bit or 64-bit executable */
108 switch (nt32->OptionalHeader.Magic)
110 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
111 return HDR_NT32;
113 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
114 /* Re-read as 64-bit */
116 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
118 if (count == INVALID_SET_FILE_POINTER)
119 return HDR_FAIL;
121 count = 0;
123 r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL);
125 if (!r)
126 return HDR_FAIL;
128 if (count != sizeof(IMAGE_NT_HEADERS64))
129 return HDR_FAIL;
131 /* verify NT signature */
132 if (nt64->Signature != IMAGE_NT_SIGNATURE)
133 return HDR_FAIL;
135 return HDR_NT64;
138 return HDR_FAIL;
141 /***********************************************************************
142 * IMAGEHLP_GetSecurityDirOffset (INTERNAL)
144 * Read a file's PE header, and return the offset and size of the
145 * security directory.
147 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle,
148 DWORD *pdwOfs, DWORD *pdwSize )
150 IMAGE_NT_HEADERS32 nt_hdr32;
151 IMAGE_NT_HEADERS64 nt_hdr64;
152 IMAGE_DATA_DIRECTORY *sd;
153 int ret;
155 ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64);
157 if (ret == HDR_NT32)
158 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
159 else if (ret == HDR_NT64)
160 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
161 else
162 return FALSE;
164 TRACE("ret = %d size = %lx addr = %lx\n", ret, sd->Size, sd->VirtualAddress);
166 *pdwSize = sd->Size;
167 *pdwOfs = sd->VirtualAddress;
169 return TRUE;
172 /***********************************************************************
173 * IMAGEHLP_SetSecurityDirOffset (INTERNAL)
175 * Read a file's PE header, and update the offset and size of the
176 * security directory.
178 static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle,
179 DWORD dwOfs, DWORD dwSize)
181 IMAGE_NT_HEADERS32 nt_hdr32;
182 IMAGE_NT_HEADERS64 nt_hdr64;
183 IMAGE_DATA_DIRECTORY *sd;
184 int ret, nt_hdr_size = 0;
185 DWORD pe_offset;
186 void *nt_hdr;
187 DWORD count;
188 BOOL r;
190 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
192 if (ret == HDR_NT32)
194 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
196 nt_hdr = &nt_hdr32;
197 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
199 else if (ret == HDR_NT64)
201 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
203 nt_hdr = &nt_hdr64;
204 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
206 else
207 return FALSE;
209 sd->Size = dwSize;
210 sd->VirtualAddress = dwOfs;
212 TRACE("size = %lx addr = %lx\n", sd->Size, sd->VirtualAddress);
214 /* write the header back again */
215 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
217 if (count == INVALID_SET_FILE_POINTER)
218 return FALSE;
220 count = 0;
222 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
224 if (!r)
225 return FALSE;
227 if (count != nt_hdr_size)
228 return FALSE;
230 return TRUE;
233 /***********************************************************************
234 * IMAGEHLP_GetCertificateOffset (INTERNAL)
236 * Read a file's PE header, and return the offset and size of the
237 * security directory.
239 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num,
240 DWORD *pdwOfs, DWORD *pdwSize )
242 DWORD size, count, offset, len, sd_VirtualAddr;
243 BOOL r;
245 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
246 if( !r )
247 return FALSE;
249 offset = 0;
250 /* take the n'th certificate */
251 while( 1 )
253 /* read the length of the current certificate */
254 count = SetFilePointer( handle, sd_VirtualAddr + offset,
255 NULL, FILE_BEGIN );
256 if( count == INVALID_SET_FILE_POINTER )
257 return FALSE;
258 r = ReadFile( handle, &len, sizeof len, &count, NULL );
259 if( !r )
260 return FALSE;
261 if( count != sizeof len )
262 return FALSE;
264 /* check the certificate is not too big or too small */
265 if( len < sizeof len )
266 return FALSE;
267 if( len > (size-offset) )
268 return FALSE;
269 if( !num-- )
270 break;
272 /* calculate the offset of the next certificate */
273 offset += len;
275 /* padded out to the nearest 8-byte boundary */
276 if( len % 8 )
277 offset += 8 - (len % 8);
279 if( offset >= size )
280 return FALSE;
283 *pdwOfs = sd_VirtualAddr + offset;
284 *pdwSize = len;
286 TRACE("len = %lx addr = %lx\n", len, sd_VirtualAddr + offset);
288 return TRUE;
291 /***********************************************************************
292 * IMAGEHLP_RecalculateChecksum (INTERNAL)
294 * Update the NT header checksum for the specified file.
296 static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle)
298 DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size;
299 IMAGE_NT_HEADERS32 nt_hdr32;
300 IMAGE_NT_HEADERS64 nt_hdr64;
301 LPVOID BaseAddress;
302 HANDLE hMapping;
303 DWORD *CheckSum;
304 void *nt_hdr;
305 int ret;
306 BOOL r;
308 TRACE("handle %p\n", handle);
310 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
312 if (ret == HDR_NT32)
314 CheckSum = &nt_hdr32.OptionalHeader.CheckSum;
316 nt_hdr = &nt_hdr32;
317 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
319 else if (ret == HDR_NT64)
321 CheckSum = &nt_hdr64.OptionalHeader.CheckSum;
323 nt_hdr = &nt_hdr64;
324 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
326 else
327 return FALSE;
329 hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL);
331 if (!hMapping)
332 return FALSE;
334 BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
336 if (!BaseAddress)
338 CloseHandle(hMapping);
339 return FALSE;
342 FileLength = GetFileSize(handle, NULL);
344 *CheckSum = 0;
345 CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum);
347 UnmapViewOfFile(BaseAddress);
348 CloseHandle(hMapping);
350 if (*CheckSum)
352 /* write the header back again */
353 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
355 if (count == INVALID_SET_FILE_POINTER)
356 return FALSE;
358 count = 0;
360 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
362 if (!r)
363 return FALSE;
365 if (count != nt_hdr_size)
366 return FALSE;
368 return TRUE;
371 return FALSE;
374 /***********************************************************************
375 * ImageAddCertificate (IMAGEHLP.@)
377 * Adds the specified certificate to the security directory of
378 * open PE file.
381 BOOL WINAPI ImageAddCertificate(
382 HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index)
384 DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0;
385 WIN_CERTIFICATE hdr;
386 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
387 BOOL r;
389 TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index);
391 r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size);
393 /* If we've already got a security directory, find the end of it */
394 if ((r) && (sd_VirtualAddr != 0))
396 /* Check if the security directory is at the end of the file.
397 If not, we should probably relocate it. */
398 if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size)
400 FIXME("Security directory already present but not located at EOF, not adding certificate\n");
402 SetLastError(ERROR_NOT_SUPPORTED);
403 return FALSE;
406 while (offset < size)
408 /* read the length of the current certificate */
409 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset,
410 NULL, FILE_BEGIN);
412 if (count == INVALID_SET_FILE_POINTER)
413 return FALSE;
415 r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL);
417 if (!r)
418 return FALSE;
420 if (count != cert_hdr_size)
421 return FALSE;
423 /* check the certificate is not too big or too small */
424 if (hdr.dwLength < cert_hdr_size)
425 return FALSE;
427 if (hdr.dwLength > (size-offset))
428 return FALSE;
430 /* next certificate */
431 offset += hdr.dwLength;
433 /* padded out to the nearest 8-byte boundary */
434 if (hdr.dwLength % 8)
435 offset += 8 - (hdr.dwLength % 8);
437 index++;
440 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN);
442 if (count == INVALID_SET_FILE_POINTER)
443 return FALSE;
445 else
447 sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END);
449 if (sd_VirtualAddr == INVALID_SET_FILE_POINTER)
450 return FALSE;
453 /* Write the certificate to the file */
454 r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL);
456 if (!r)
457 return FALSE;
459 /* Pad out if necessary */
460 if (Certificate->dwLength % 8)
462 char null[8];
464 ZeroMemory(null, 8);
465 WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), &count, NULL);
467 size += 8 - (Certificate->dwLength % 8);
470 size += Certificate->dwLength;
472 /* Update the security directory offset and size */
473 if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size))
474 return FALSE;
476 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
477 return FALSE;
479 if(Index)
480 *Index = index;
481 return TRUE;
484 /***********************************************************************
485 * ImageEnumerateCertificates (IMAGEHLP.@)
487 BOOL WINAPI ImageEnumerateCertificates(
488 HANDLE handle, WORD TypeFilter, PDWORD CertificateCount,
489 PDWORD Indices, DWORD IndexCount)
491 DWORD size, count, offset, sd_VirtualAddr, index;
492 WIN_CERTIFICATE hdr;
493 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
494 BOOL r;
496 TRACE("%p %hd %p %p %ld\n",
497 handle, TypeFilter, CertificateCount, Indices, IndexCount);
499 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
500 if( !r )
501 return FALSE;
503 offset = 0;
504 index = 0;
505 *CertificateCount = 0;
506 while( offset < size )
508 /* read the length of the current certificate */
509 count = SetFilePointer( handle, sd_VirtualAddr + offset,
510 NULL, FILE_BEGIN );
511 if( count == INVALID_SET_FILE_POINTER )
512 return FALSE;
513 r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL );
514 if( !r )
515 return FALSE;
516 if( count != cert_hdr_size )
517 return FALSE;
519 TRACE("Size = %08lx id = %08hx\n",
520 hdr.dwLength, hdr.wCertificateType );
522 /* check the certificate is not too big or too small */
523 if( hdr.dwLength < cert_hdr_size )
524 return FALSE;
525 if( hdr.dwLength > (size-offset) )
526 return FALSE;
528 if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
529 (TypeFilter == hdr.wCertificateType) )
531 (*CertificateCount)++;
532 if(Indices && *CertificateCount <= IndexCount)
533 *Indices++ = index;
536 /* next certificate */
537 offset += hdr.dwLength;
539 /* padded out to the nearest 8-byte boundary */
540 if (hdr.dwLength % 8)
541 offset += 8 - (hdr.dwLength % 8);
543 index++;
546 return TRUE;
549 /***********************************************************************
550 * ImageGetCertificateData (IMAGEHLP.@)
552 * FIXME: not sure that I'm dealing with the Index the right way
554 BOOL WINAPI ImageGetCertificateData(
555 HANDLE handle, DWORD Index,
556 LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength)
558 DWORD r, offset, ofs, size, count;
560 TRACE("%p %ld %p %p\n", handle, Index, Certificate, RequiredLength);
562 if( !RequiredLength)
564 SetLastError( ERROR_INVALID_PARAMETER );
565 return FALSE;
568 if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
569 return FALSE;
571 if( *RequiredLength < size )
573 *RequiredLength = size;
574 SetLastError( ERROR_INSUFFICIENT_BUFFER );
575 return FALSE;
578 if( !Certificate )
580 SetLastError( ERROR_INVALID_PARAMETER );
581 return FALSE;
584 *RequiredLength = size;
586 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
587 if( offset == INVALID_SET_FILE_POINTER )
588 return FALSE;
590 r = ReadFile( handle, Certificate, size, &count, NULL );
591 if( !r )
592 return FALSE;
593 if( count != size )
594 return FALSE;
596 TRACE("OK\n");
597 SetLastError( NO_ERROR );
599 return TRUE;
602 /***********************************************************************
603 * ImageGetCertificateHeader (IMAGEHLP.@)
605 BOOL WINAPI ImageGetCertificateHeader(
606 HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert)
608 DWORD r, offset, ofs, size, count;
609 const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate;
611 TRACE("%p %ld %p\n", handle, index, pCert);
613 if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) )
614 return FALSE;
616 if( size < cert_hdr_size )
617 return FALSE;
619 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
620 if( offset == INVALID_SET_FILE_POINTER )
621 return FALSE;
623 r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL );
624 if( !r )
625 return FALSE;
626 if( count != cert_hdr_size )
627 return FALSE;
629 TRACE("OK\n");
631 return TRUE;
634 /* Finds the section named section in the array of IMAGE_SECTION_HEADERs hdr. If
635 * found, returns the offset to the section. Otherwise returns 0. If the section
636 * is found, optionally returns the size of the section (in size) and the base
637 * address of the section (in base.)
639 static DWORD IMAGEHLP_GetSectionOffset( IMAGE_SECTION_HEADER *hdr,
640 DWORD num_sections, LPCSTR section, PDWORD size, PDWORD base )
642 DWORD i, offset = 0;
644 for( i = 0; !offset && i < num_sections; i++, hdr++ )
646 if( !memcmp( hdr->Name, section, strlen(section) ) )
648 offset = hdr->PointerToRawData;
649 if( size )
650 *size = hdr->SizeOfRawData;
651 if( base )
652 *base = hdr->VirtualAddress;
655 return offset;
658 /* Calls DigestFunction e bytes at offset offset from the file mapped at map.
659 * Returns the return value of DigestFunction, or FALSE if the data is not available.
661 static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size,
662 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
664 if( offset + size > fileSize )
666 SetLastError(ERROR_INVALID_PARAMETER);
667 return FALSE;
669 return DigestFunction( DigestHandle, map + offset, size );
672 /* Finds the section named section among the IMAGE_SECTION_HEADERs in
673 * section_headers and calls DigestFunction for this section. Returns
674 * the return value from DigestFunction, or FALSE if the data could not be read.
676 static BOOL IMAGEHLP_ReportSection( IMAGE_SECTION_HEADER *section_headers,
677 DWORD num_sections, LPCSTR section, BYTE *map, DWORD fileSize,
678 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
680 DWORD offset, size = 0;
682 offset = IMAGEHLP_GetSectionOffset( section_headers, num_sections, section,
683 &size, NULL );
684 if( !offset )
685 return FALSE;
686 return IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize,
687 DigestFunction, DigestHandle );
690 /* Calls DigestFunction for all sections with the IMAGE_SCN_CNT_CODE flag set.
691 * Returns the return value from * DigestFunction, or FALSE if a section could not be read.
693 static BOOL IMAGEHLP_ReportCodeSections( IMAGE_SECTION_HEADER *hdr, DWORD num_sections,
694 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
696 DWORD i;
697 BOOL ret = TRUE;
699 for( i = 0; ret && i < num_sections; i++, hdr++ )
701 if( hdr->Characteristics & IMAGE_SCN_CNT_CODE )
702 ret = IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData,
703 hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle );
705 return ret;
708 /* Reports the import section from the file FileHandle. If
709 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set in DigestLevel, reports the entire
710 * import section.
711 * FIXME: if it's not set, the function currently fails.
713 static BOOL IMAGEHLP_ReportImportSection( IMAGE_SECTION_HEADER *hdr,
714 DWORD num_sections, BYTE *map, DWORD fileSize, DWORD DigestLevel,
715 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
717 BOOL ret = FALSE;
718 DWORD offset, size, base;
720 /* Get import data */
721 offset = IMAGEHLP_GetSectionOffset( hdr, num_sections, ".idata", &size,
722 &base );
723 if( !offset )
724 return FALSE;
726 /* If CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set, the entire
727 * section is reported. Otherwise, the debug info section is
728 * decoded and reported piecemeal. See tests. However, I haven't been
729 * able to figure out how the native implementation decides which values
730 * to report. Either it's buggy or my understanding is flawed.
732 if( DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO )
733 ret = IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize,
734 DigestFunction, DigestHandle );
735 else
737 FIXME("not supported except for CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO\n");
738 SetLastError(ERROR_INVALID_PARAMETER);
739 ret = FALSE;
742 return ret;
745 /***********************************************************************
746 * ImageGetDigestStream (IMAGEHLP.@)
748 * Gets a stream of bytes from a PE file over which a hash might be computed to
749 * verify that the image has not changed. Useful for creating a certificate to
750 * be added to the file with ImageAddCertificate.
752 * PARAMS
753 * FileHandle [In] File for which to return a stream.
754 * DigestLevel [In] Flags to control which portions of the file to return.
755 * 0 is allowed, as is any combination of:
756 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: reports the entire
757 * import section rather than selected portions of it.
758 * CERT_PE_IMAGE_DIGEST_DEBUG_INFO: reports the debug section.
759 * CERT_PE_IMAGE_DIGEST_RESOURCES: reports the resources
760 section.
761 * DigestFunction [In] Callback function.
762 * DigestHandle [In] Handle passed as first parameter to DigestFunction.
764 * RETURNS
765 * TRUE if successful.
766 * FALSE if unsuccessful. GetLastError returns more about the error.
768 * NOTES
769 * Only supports 32-bit PE files, not tested with any other format.
770 * Reports data in the following order:
771 * 1. The file headers are reported first
772 * 2. Any code sections are reported next.
773 * 3. The data (".data" and ".rdata") sections are reported next.
774 * 4. The import section is reported next.
775 * 5. If CERT_PE_IMAGE_DIGEST_DEBUG_INFO is set in DigestLevel, the debug section is
776 * reported next.
777 * 6. If CERT_PE_IMAGE_DIGEST_RESOURCES is set in DigestLevel, the resources section
778 * is reported next.
780 * BUGS
781 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO must be specified, returns an error if not.
783 BOOL WINAPI ImageGetDigestStream(
784 HANDLE FileHandle, DWORD DigestLevel,
785 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle)
787 DWORD error = 0;
788 BOOL ret = FALSE;
789 DWORD offset, size, num_sections, fileSize;
790 HANDLE hMap = INVALID_HANDLE_VALUE;
791 BYTE *map = NULL;
792 IMAGE_DOS_HEADER *dos_hdr;
793 IMAGE_NT_HEADERS *nt_hdr;
794 IMAGE_SECTION_HEADER *section_headers;
796 TRACE("(%p, %ld, %p, %p)\n", FileHandle, DigestLevel, DigestFunction,
797 DigestHandle);
799 /* Get the file size */
800 if( !FileHandle )
801 goto invalid_parameter;
802 fileSize = GetFileSize( FileHandle, NULL );
803 if(fileSize == INVALID_FILE_SIZE )
804 goto invalid_parameter;
806 /* map file */
807 hMap = CreateFileMappingW( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL );
808 if( hMap == INVALID_HANDLE_VALUE )
809 goto invalid_parameter;
810 map = MapViewOfFile( hMap, FILE_MAP_COPY, 0, 0, 0 );
811 if( !map )
812 goto invalid_parameter;
814 /* Read the file header */
815 if( fileSize < sizeof(IMAGE_DOS_HEADER) )
816 goto invalid_parameter;
817 dos_hdr = (IMAGE_DOS_HEADER *)map;
819 if( dos_hdr->e_magic != IMAGE_DOS_SIGNATURE )
820 goto invalid_parameter;
821 offset = dos_hdr->e_lfanew;
822 if( !offset || offset > fileSize )
823 goto invalid_parameter;
824 ret = DigestFunction( DigestHandle, map, offset );
825 if( !ret )
826 goto end;
828 /* Read the NT header */
829 if( offset + sizeof(IMAGE_NT_HEADERS) > fileSize )
830 goto invalid_parameter;
831 nt_hdr = (IMAGE_NT_HEADERS *)(map + offset);
832 if( nt_hdr->Signature != IMAGE_NT_SIGNATURE )
833 goto invalid_parameter;
834 /* It's clear why the checksum is cleared, but why only these size headers?
836 nt_hdr->OptionalHeader.SizeOfInitializedData = 0;
837 nt_hdr->OptionalHeader.SizeOfImage = 0;
838 nt_hdr->OptionalHeader.CheckSum = 0;
839 size = sizeof(nt_hdr->Signature) + sizeof(nt_hdr->FileHeader) +
840 nt_hdr->FileHeader.SizeOfOptionalHeader;
841 ret = DigestFunction( DigestHandle, map + offset, size );
842 if( !ret )
843 goto end;
845 /* Read the section headers */
846 offset += size;
847 num_sections = nt_hdr->FileHeader.NumberOfSections;
848 size = num_sections * sizeof(IMAGE_SECTION_HEADER);
849 if( offset + size > fileSize )
850 goto invalid_parameter;
851 ret = DigestFunction( DigestHandle, map + offset, size );
852 if( !ret )
853 goto end;
855 section_headers = (IMAGE_SECTION_HEADER *)(map + offset);
856 IMAGEHLP_ReportCodeSections( section_headers, num_sections,
857 map, fileSize, DigestFunction, DigestHandle );
858 IMAGEHLP_ReportSection( section_headers, num_sections, ".data",
859 map, fileSize, DigestFunction, DigestHandle );
860 IMAGEHLP_ReportSection( section_headers, num_sections, ".rdata",
861 map, fileSize, DigestFunction, DigestHandle );
862 IMAGEHLP_ReportImportSection( section_headers, num_sections,
863 map, fileSize, DigestLevel, DigestFunction, DigestHandle );
864 if( DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO )
865 IMAGEHLP_ReportSection( section_headers, num_sections, ".debug",
866 map, fileSize, DigestFunction, DigestHandle );
867 if( DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES )
868 IMAGEHLP_ReportSection( section_headers, num_sections, ".rsrc",
869 map, fileSize, DigestFunction, DigestHandle );
871 end:
872 if( map )
873 UnmapViewOfFile( map );
874 if( hMap != INVALID_HANDLE_VALUE )
875 CloseHandle( hMap );
876 if( error )
877 SetLastError(error);
878 return ret;
880 invalid_parameter:
881 error = ERROR_INVALID_PARAMETER;
882 goto end;
885 /***********************************************************************
886 * ImageRemoveCertificate (IMAGEHLP.@)
888 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index)
890 DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0;
891 DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0;
892 LPVOID cert_data;
893 BOOL r;
895 TRACE("(%p, %ld)\n", FileHandle, Index);
897 r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0);
899 if ((!r) || (count == 0))
900 return FALSE;
902 if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) ||
903 (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size)))
904 return FALSE;
906 /* Ignore any padding we have, too */
907 if (cert_size % 8)
908 cert_size_padded = cert_size + (8 - (cert_size % 8));
909 else
910 cert_size_padded = cert_size;
912 data_size = size - (offset - sd_VirtualAddr) - cert_size_padded;
914 if (data_size == 0)
916 ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN);
918 if (ret == INVALID_SET_FILE_POINTER)
919 return FALSE;
921 else
923 cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
925 if (!cert_data)
926 return FALSE;
928 ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN);
930 if (ret == INVALID_SET_FILE_POINTER)
931 goto error;
933 /* Read any subsequent certificates */
934 r = ReadFile(FileHandle, cert_data, data_size, &count, NULL);
936 if ((!r) || (count != data_size))
937 goto error;
939 SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
941 /* Write them one index back */
942 r = WriteFile(FileHandle, cert_data, data_size, &count, NULL);
944 if ((!r) || (count != data_size))
945 goto error;
947 HeapFree(GetProcessHeap(), 0, cert_data);
950 /* If security directory is at end of file, trim the file */
951 if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size)
952 SetEndOfFile(FileHandle);
954 if (count == 1)
955 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0);
956 else
957 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded);
959 if (!r)
960 return FALSE;
962 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
963 return FALSE;
965 return TRUE;
967 error:
968 HeapFree(GetProcessHeap(), 0, cert_data);
969 return FALSE;