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
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
38 * These functions are partially documented at:
39 * http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
46 /***********************************************************************
47 * IMAGEHLP_GetNTHeaders (INTERNAL)
49 * Return the IMAGE_NT_HEADERS for a PE file, after validating magic
50 * numbers and distinguishing between 32-bit and 64-bit files.
52 static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64)
54 IMAGE_DOS_HEADER dos_hdr;
58 TRACE("handle %p\n", handle);
60 if ((!nt32) || (!nt64))
63 /* read the DOS header */
64 count = SetFilePointer(handle, 0, NULL, FILE_BEGIN);
66 if (count == INVALID_SET_FILE_POINTER)
71 r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL);
76 if (count != sizeof dos_hdr)
79 /* verify magic number of 'MZ' */
80 if (dos_hdr.e_magic != 0x5A4D)
83 if (pe_offset != NULL)
84 *pe_offset = dos_hdr.e_lfanew;
86 /* read the PE header */
87 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
89 if (count == INVALID_SET_FILE_POINTER)
94 r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL);
99 if (count != sizeof(IMAGE_NT_HEADERS32))
102 /* verify NT signature */
103 if (nt32->Signature != IMAGE_NT_SIGNATURE)
106 /* check if we have a 32-bit or 64-bit executable */
107 switch (nt32->OptionalHeader.Magic)
109 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
112 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
113 /* Re-read as 64-bit */
115 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
117 if (count == INVALID_SET_FILE_POINTER)
122 r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL);
127 if (count != sizeof(IMAGE_NT_HEADERS64))
130 /* verify NT signature */
131 if (nt64->Signature != IMAGE_NT_SIGNATURE)
140 /***********************************************************************
141 * IMAGEHLP_GetSecurityDirOffset (INTERNAL)
143 * Read a file's PE header, and return the offset and size of the
144 * security directory.
146 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle,
147 DWORD *pdwOfs, DWORD *pdwSize )
149 IMAGE_NT_HEADERS32 nt_hdr32;
150 IMAGE_NT_HEADERS64 nt_hdr64;
151 IMAGE_DATA_DIRECTORY *sd;
154 ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64);
157 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
158 else if (ret == HDR_NT64)
159 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
163 TRACE("ret = %d size = %x addr = %x\n", ret, sd->Size, sd->VirtualAddress);
166 *pdwOfs = sd->VirtualAddress;
171 /***********************************************************************
172 * IMAGEHLP_SetSecurityDirOffset (INTERNAL)
174 * Read a file's PE header, and update the offset and size of the
175 * security directory.
177 static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle,
178 DWORD dwOfs, DWORD dwSize)
180 IMAGE_NT_HEADERS32 nt_hdr32;
181 IMAGE_NT_HEADERS64 nt_hdr64;
182 IMAGE_DATA_DIRECTORY *sd;
183 int ret, nt_hdr_size = 0;
189 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
193 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
196 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
198 else if (ret == HDR_NT64)
200 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
203 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
209 sd->VirtualAddress = dwOfs;
211 TRACE("size = %x addr = %x\n", sd->Size, sd->VirtualAddress);
213 /* write the header back again */
214 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
216 if (count == INVALID_SET_FILE_POINTER)
221 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
226 if (count != nt_hdr_size)
232 /***********************************************************************
233 * IMAGEHLP_GetCertificateOffset (INTERNAL)
235 * Read a file's PE header, and return the offset and size of the
236 * security directory.
238 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num,
239 DWORD *pdwOfs, DWORD *pdwSize )
241 DWORD size, count, offset, len, sd_VirtualAddr;
244 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
249 /* take the n'th certificate */
252 /* read the length of the current certificate */
253 count = SetFilePointer( handle, sd_VirtualAddr + offset,
255 if( count == INVALID_SET_FILE_POINTER )
257 r = ReadFile( handle, &len, sizeof len, &count, NULL );
260 if( count != sizeof len )
263 /* check the certificate is not too big or too small */
264 if( len < sizeof len )
266 if( len > (size-offset) )
271 /* calculate the offset of the next certificate */
274 /* padded out to the nearest 8-byte boundary */
276 offset += 8 - (len % 8);
282 *pdwOfs = sd_VirtualAddr + offset;
285 TRACE("len = %x addr = %x\n", len, sd_VirtualAddr + offset);
290 /***********************************************************************
291 * IMAGEHLP_RecalculateChecksum (INTERNAL)
293 * Update the NT header checksum for the specified file.
295 static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle)
297 DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size;
298 IMAGE_NT_HEADERS32 nt_hdr32;
299 IMAGE_NT_HEADERS64 nt_hdr64;
307 TRACE("handle %p\n", handle);
309 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
313 CheckSum = &nt_hdr32.OptionalHeader.CheckSum;
316 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
318 else if (ret == HDR_NT64)
320 CheckSum = &nt_hdr64.OptionalHeader.CheckSum;
323 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
328 hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL);
333 BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
337 CloseHandle(hMapping);
341 FileLength = GetFileSize(handle, NULL);
344 CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum);
346 UnmapViewOfFile(BaseAddress);
347 CloseHandle(hMapping);
351 /* write the header back again */
352 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
354 if (count == INVALID_SET_FILE_POINTER)
359 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
364 if (count != nt_hdr_size)
373 /***********************************************************************
374 * ImageAddCertificate (IMAGEHLP.@)
376 * Adds the specified certificate to the security directory of
380 BOOL WINAPI ImageAddCertificate(
381 HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index)
383 DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0;
385 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
388 TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index);
390 r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size);
392 /* If we've already got a security directory, find the end of it */
393 if ((r) && (sd_VirtualAddr != 0))
399 /* Check if the security directory is at the end of the file.
400 If not, we should probably relocate it. */
401 if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size)
403 FIXME("Security directory already present but not located at EOF, not adding certificate\n");
405 SetLastError(ERROR_NOT_SUPPORTED);
409 while (offset < size)
411 /* read the length of the current certificate */
412 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset,
415 if (count == INVALID_SET_FILE_POINTER)
418 r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL);
423 if (count != cert_hdr_size)
426 /* check the certificate is not too big or too small */
427 if (hdr.dwLength < cert_hdr_size)
430 if (hdr.dwLength > (size-offset))
433 /* next certificate */
434 offset += hdr.dwLength;
436 /* padded out to the nearest 8-byte boundary */
437 if (hdr.dwLength % 8)
438 offset += 8 - (hdr.dwLength % 8);
443 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN);
445 if (count == INVALID_SET_FILE_POINTER)
450 sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END);
452 if (sd_VirtualAddr == INVALID_SET_FILE_POINTER)
456 /* Write the certificate to the file */
457 r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL);
462 /* Pad out if necessary */
463 if (Certificate->dwLength % 8)
468 WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), NULL, NULL);
470 size += 8 - (Certificate->dwLength % 8);
473 size += Certificate->dwLength;
475 /* Update the security directory offset and size */
476 if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size))
479 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
485 /***********************************************************************
486 * ImageEnumerateCertificates (IMAGEHLP.@)
488 BOOL WINAPI ImageEnumerateCertificates(
489 HANDLE handle, WORD TypeFilter, PDWORD CertificateCount,
490 PDWORD Indices, DWORD IndexCount)
492 DWORD size, count, offset, sd_VirtualAddr, index;
494 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
497 TRACE("%p %hd %p %p %d\n",
498 handle, TypeFilter, CertificateCount, Indices, IndexCount);
500 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
506 *CertificateCount = 0;
507 while( offset < size )
509 /* read the length of the current certificate */
510 count = SetFilePointer( handle, sd_VirtualAddr + offset,
512 if( count == INVALID_SET_FILE_POINTER )
514 r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL );
517 if( count != cert_hdr_size )
520 TRACE("Size = %08x id = %08hx\n",
521 hdr.dwLength, hdr.wCertificateType );
523 /* check the certificate is not too big or too small */
524 if( hdr.dwLength < cert_hdr_size )
526 if( hdr.dwLength > (size-offset) )
529 if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
530 (TypeFilter == hdr.wCertificateType) )
532 (*CertificateCount)++;
533 if(Indices && *CertificateCount <= IndexCount)
537 /* next certificate */
538 offset += hdr.dwLength;
540 /* padded out to the nearest 8-byte boundary */
541 if (hdr.dwLength % 8)
542 offset += 8 - (hdr.dwLength % 8);
550 /***********************************************************************
551 * ImageGetCertificateData (IMAGEHLP.@)
553 * FIXME: not sure that I'm dealing with the Index the right way
555 BOOL WINAPI ImageGetCertificateData(
556 HANDLE handle, DWORD Index,
557 LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength)
559 DWORD r, offset, ofs, size, count;
561 TRACE("%p %d %p %p\n", handle, Index, Certificate, RequiredLength);
565 SetLastError( ERROR_INVALID_PARAMETER );
569 if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
572 if( *RequiredLength < size )
574 *RequiredLength = size;
575 SetLastError( ERROR_INSUFFICIENT_BUFFER );
581 SetLastError( ERROR_INVALID_PARAMETER );
585 *RequiredLength = size;
587 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
588 if( offset == INVALID_SET_FILE_POINTER )
591 r = ReadFile( handle, Certificate, size, &count, NULL );
598 SetLastError( NO_ERROR );
603 /***********************************************************************
604 * ImageGetCertificateHeader (IMAGEHLP.@)
606 BOOL WINAPI ImageGetCertificateHeader(
607 HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert)
609 DWORD r, offset, ofs, size, count;
610 const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate;
612 TRACE("%p %d %p\n", handle, index, pCert);
614 if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) )
617 if( size < cert_hdr_size )
620 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
621 if( offset == INVALID_SET_FILE_POINTER )
624 r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL );
627 if( count != cert_hdr_size )
635 /* Finds the section named section in the array of IMAGE_SECTION_HEADERs hdr. If
636 * found, returns the offset to the section. Otherwise returns 0. If the section
637 * is found, optionally returns the size of the section (in size) and the base
638 * address of the section (in base.)
640 static DWORD IMAGEHLP_GetSectionOffset( IMAGE_SECTION_HEADER *hdr,
641 DWORD num_sections, LPCSTR section, PDWORD size, PDWORD base )
645 for( i = 0; !offset && i < num_sections; i++, hdr++ )
647 if( !memcmp( hdr->Name, section, strlen(section) ) )
649 offset = hdr->PointerToRawData;
651 *size = hdr->SizeOfRawData;
653 *base = hdr->VirtualAddress;
659 /* Calls DigestFunction e bytes at offset offset from the file mapped at map.
660 * Returns the return value of DigestFunction, or FALSE if the data is not available.
662 static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size,
663 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
665 if( offset + size > fileSize )
667 SetLastError(ERROR_INVALID_PARAMETER);
670 return DigestFunction( DigestHandle, map + offset, size );
673 /* Finds the section named section among the IMAGE_SECTION_HEADERs in
674 * section_headers and calls DigestFunction for this section. Returns
675 * the return value from DigestFunction, or FALSE if the data could not be read.
677 static BOOL IMAGEHLP_ReportSection( IMAGE_SECTION_HEADER *section_headers,
678 DWORD num_sections, LPCSTR section, BYTE *map, DWORD fileSize,
679 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
681 DWORD offset, size = 0;
683 offset = IMAGEHLP_GetSectionOffset( section_headers, num_sections, section,
687 return IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize,
688 DigestFunction, DigestHandle );
691 /* Calls DigestFunction for all sections with the IMAGE_SCN_CNT_CODE flag set.
692 * Returns the return value from * DigestFunction, or FALSE if a section could not be read.
694 static BOOL IMAGEHLP_ReportCodeSections( IMAGE_SECTION_HEADER *hdr, DWORD num_sections,
695 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
700 for( i = 0; ret && i < num_sections; i++, hdr++ )
702 if( hdr->Characteristics & IMAGE_SCN_CNT_CODE )
703 ret = IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData,
704 hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle );
709 /* Reports the import section from the file FileHandle. If
710 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set in DigestLevel, reports the entire
712 * FIXME: if it's not set, the function currently fails.
714 static BOOL IMAGEHLP_ReportImportSection( IMAGE_SECTION_HEADER *hdr,
715 DWORD num_sections, BYTE *map, DWORD fileSize, DWORD DigestLevel,
716 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle )
719 DWORD offset, size, base;
721 /* Get import data */
722 offset = IMAGEHLP_GetSectionOffset( hdr, num_sections, ".idata", &size,
727 /* If CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set, the entire
728 * section is reported. Otherwise, the debug info section is
729 * decoded and reported piecemeal. See tests. However, I haven't been
730 * able to figure out how the native implementation decides which values
731 * to report. Either it's buggy or my understanding is flawed.
733 if( DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO )
734 ret = IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize,
735 DigestFunction, DigestHandle );
738 FIXME("not supported except for CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO\n");
739 SetLastError(ERROR_INVALID_PARAMETER);
746 /***********************************************************************
747 * ImageGetDigestStream (IMAGEHLP.@)
749 * Gets a stream of bytes from a PE file overwhich a hash might be computed to
750 * verify that the image has not changed. Useful for creating a certificate to
751 * be added to the file with ImageAddCertificate.
754 * FileHandle [In] File for which to return a stream.
755 * DigestLevel [In] Flags to control which portions of the file to return.
756 * 0 is allowed, as is any combination of:
757 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: reports the entire
758 * import section rather than selected portions of it.
759 * CERT_PE_IMAGE_DIGEST_DEBUG_INFO: reports the debug section.
760 * CERT_PE_IMAGE_DIGEST_RESOURCES: reports the resources
762 * DigestFunction [In] Callback function.
763 * DigestHandle [In] Handle passed as first parameter to DigestFunction.
766 * TRUE if successful.
767 * FALSE if unsuccessful. GetLastError returns more about the error.
770 * Only supports 32-bit PE files, not tested with any other format.
771 * Reports data in the following order:
772 * 1. The file headers are reported first
773 * 2. Any code sections are reported next.
774 * 3. The data (".data" and ".rdata") sections are reported next.
775 * 4. The import section is reported next.
776 * 5. If CERT_PE_IMAGE_DIGEST_DEBUG_INFO is set in DigestLevel, the debug section is
778 * 6. If CERT_PE_IMAGE_DIGEST_RESOURCES is set in DigestLevel, the resources section
782 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO must be specified, returns an error if not.
784 BOOL WINAPI ImageGetDigestStream(
785 HANDLE FileHandle, DWORD DigestLevel,
786 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle)
790 DWORD offset, size, num_sections, fileSize;
791 HANDLE hMap = INVALID_HANDLE_VALUE;
793 IMAGE_DOS_HEADER *dos_hdr;
794 IMAGE_NT_HEADERS *nt_hdr;
795 IMAGE_SECTION_HEADER *section_headers;
797 TRACE("(%p, %d, %p, %p)\n", FileHandle, DigestLevel, DigestFunction,
800 /* Get the file size */
802 goto invalid_parameter;
803 fileSize = GetFileSize( FileHandle, NULL );
804 if(fileSize == INVALID_FILE_SIZE )
805 goto invalid_parameter;
808 hMap = CreateFileMappingW( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL );
809 if( hMap == INVALID_HANDLE_VALUE )
810 goto invalid_parameter;
811 map = MapViewOfFile( hMap, FILE_MAP_COPY, 0, 0, 0 );
813 goto invalid_parameter;
815 /* Read the file header */
816 if( fileSize < sizeof(IMAGE_DOS_HEADER) )
817 goto invalid_parameter;
818 dos_hdr = (IMAGE_DOS_HEADER *)map;
820 if( dos_hdr->e_magic != IMAGE_DOS_SIGNATURE )
821 goto invalid_parameter;
822 offset = dos_hdr->e_lfanew;
823 if( !offset || offset > fileSize )
824 goto invalid_parameter;
825 ret = DigestFunction( DigestHandle, map, offset );
829 /* Read the NT header */
830 if( offset + sizeof(IMAGE_NT_HEADERS) > fileSize )
831 goto invalid_parameter;
832 nt_hdr = (IMAGE_NT_HEADERS *)(map + offset);
833 if( nt_hdr->Signature != IMAGE_NT_SIGNATURE )
834 goto invalid_parameter;
835 /* It's clear why the checksum is cleared, but why only these size headers?
837 nt_hdr->OptionalHeader.SizeOfInitializedData = 0;
838 nt_hdr->OptionalHeader.SizeOfImage = 0;
839 nt_hdr->OptionalHeader.CheckSum = 0;
840 size = sizeof(nt_hdr->Signature) + sizeof(nt_hdr->FileHeader) +
841 nt_hdr->FileHeader.SizeOfOptionalHeader;
842 ret = DigestFunction( DigestHandle, map + offset, size );
846 /* Read the section headers */
848 num_sections = nt_hdr->FileHeader.NumberOfSections;
849 size = num_sections * sizeof(IMAGE_SECTION_HEADER);
850 if( offset + size > fileSize )
851 goto invalid_parameter;
852 ret = DigestFunction( DigestHandle, map + offset, size );
856 section_headers = (IMAGE_SECTION_HEADER *)(map + offset);
857 IMAGEHLP_ReportCodeSections( section_headers, num_sections,
858 map, fileSize, DigestFunction, DigestHandle );
859 IMAGEHLP_ReportSection( section_headers, num_sections, ".data",
860 map, fileSize, DigestFunction, DigestHandle );
861 IMAGEHLP_ReportSection( section_headers, num_sections, ".rdata",
862 map, fileSize, DigestFunction, DigestHandle );
863 IMAGEHLP_ReportImportSection( section_headers, num_sections,
864 map, fileSize, DigestLevel, DigestFunction, DigestHandle );
865 if( DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO )
866 IMAGEHLP_ReportSection( section_headers, num_sections, ".debug",
867 map, fileSize, DigestFunction, DigestHandle );
868 if( DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES )
869 IMAGEHLP_ReportSection( section_headers, num_sections, ".rsrc",
870 map, fileSize, DigestFunction, DigestHandle );
874 UnmapViewOfFile( map );
875 if( hMap != INVALID_HANDLE_VALUE )
882 error = ERROR_INVALID_PARAMETER;
886 /***********************************************************************
887 * ImageRemoveCertificate (IMAGEHLP.@)
889 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index)
891 DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0;
892 DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0;
896 TRACE("(%p, %d)\n", FileHandle, Index);
898 r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0);
900 if ((!r) || (count == 0))
903 if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) ||
904 (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size)))
907 /* Ignore any padding we have, too */
909 cert_size_padded = cert_size + (8 - (cert_size % 8));
911 cert_size_padded = cert_size;
913 data_size = size - (offset - sd_VirtualAddr) - cert_size_padded;
917 ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN);
919 if (ret == INVALID_SET_FILE_POINTER)
924 cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
929 ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN);
931 if (ret == INVALID_SET_FILE_POINTER)
934 /* Read any subsequent certificates */
935 r = ReadFile(FileHandle, cert_data, data_size, &count, NULL);
937 if ((!r) || (count != data_size))
940 SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
942 /* Write them one index back */
943 r = WriteFile(FileHandle, cert_data, data_size, &count, NULL);
945 if ((!r) || (count != data_size))
948 HeapFree(GetProcessHeap(), 0, cert_data);
951 /* If security directory is at end of file, trim the file */
952 if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size)
953 SetEndOfFile(FileHandle);
956 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0);
958 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded);
963 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
969 HeapFree(GetProcessHeap(), 0, cert_data);