/* * IMAGEHLP library * * Copyright 1998 Patrik Stridvall * Copyright 2003 Mike McCormack * Copyright 2009 Owen Rudge for CodeWeavers * Copyright 2010 Juan Lang * Copyright 2010 Andrey Turkin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "windef.h" #include "winbase.h" #include "winerror.h" #include "winternl.h" #include "winnt.h" #include "imagehlp.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(imagehlp); /* * These functions are partially documented at: * http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt */ #define HDR_FAIL -1 #define HDR_NT32 0 #define HDR_NT64 1 /*********************************************************************** * IMAGEHLP_GetNTHeaders (INTERNAL) * * Return the IMAGE_NT_HEADERS for a PE file, after validating magic * numbers and distinguishing between 32-bit and 64-bit files. */ static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64) { IMAGE_DOS_HEADER dos_hdr; DWORD count; BOOL r; TRACE("handle %p\n", handle); if ((!nt32) || (!nt64)) return HDR_FAIL; /* read the DOS header */ count = SetFilePointer(handle, 0, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return HDR_FAIL; count = 0; r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL); if (!r) return HDR_FAIL; if (count != sizeof dos_hdr) return HDR_FAIL; /* verify magic number of 'MZ' */ if (dos_hdr.e_magic != IMAGE_DOS_SIGNATURE) return HDR_FAIL; if (pe_offset != NULL) *pe_offset = dos_hdr.e_lfanew; /* read the PE header */ count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return HDR_FAIL; count = 0; r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL); if (!r) return HDR_FAIL; if (count != sizeof(IMAGE_NT_HEADERS32)) return HDR_FAIL; /* verify NT signature */ if (nt32->Signature != IMAGE_NT_SIGNATURE) return HDR_FAIL; /* check if we have a 32-bit or 64-bit executable */ switch (nt32->OptionalHeader.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: return HDR_NT32; case IMAGE_NT_OPTIONAL_HDR64_MAGIC: /* Re-read as 64-bit */ count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return HDR_FAIL; count = 0; r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL); if (!r) return HDR_FAIL; if (count != sizeof(IMAGE_NT_HEADERS64)) return HDR_FAIL; /* verify NT signature */ if (nt64->Signature != IMAGE_NT_SIGNATURE) return HDR_FAIL; return HDR_NT64; } return HDR_FAIL; } /*********************************************************************** * IMAGEHLP_GetSecurityDirOffset (INTERNAL) * * Read a file's PE header, and return the offset and size of the * security directory. */ static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle, DWORD *pdwOfs, DWORD *pdwSize ) { IMAGE_NT_HEADERS32 nt_hdr32; IMAGE_NT_HEADERS64 nt_hdr64; IMAGE_DATA_DIRECTORY *sd; int ret; ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64); if (ret == HDR_NT32) sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; else if (ret == HDR_NT64) sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; else return FALSE; TRACE("ret = %d size = %x addr = %x\n", ret, sd->Size, sd->VirtualAddress); *pdwSize = sd->Size; *pdwOfs = sd->VirtualAddress; return TRUE; } /*********************************************************************** * IMAGEHLP_SetSecurityDirOffset (INTERNAL) * * Read a file's PE header, and update the offset and size of the * security directory. */ static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle, DWORD dwOfs, DWORD dwSize) { IMAGE_NT_HEADERS32 nt_hdr32; IMAGE_NT_HEADERS64 nt_hdr64; IMAGE_DATA_DIRECTORY *sd; int ret, nt_hdr_size = 0; DWORD pe_offset; void *nt_hdr; DWORD count; BOOL r; ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64); if (ret == HDR_NT32) { sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; nt_hdr = &nt_hdr32; nt_hdr_size = sizeof(IMAGE_NT_HEADERS32); } else if (ret == HDR_NT64) { sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; nt_hdr = &nt_hdr64; nt_hdr_size = sizeof(IMAGE_NT_HEADERS64); } else return FALSE; sd->Size = dwSize; sd->VirtualAddress = dwOfs; TRACE("size = %x addr = %x\n", sd->Size, sd->VirtualAddress); /* write the header back again */ count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return FALSE; count = 0; r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL); if (!r) return FALSE; if (count != nt_hdr_size) return FALSE; return TRUE; } /*********************************************************************** * IMAGEHLP_GetCertificateOffset (INTERNAL) * * Read a file's PE header, and return the offset and size of the * security directory. */ static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num, DWORD *pdwOfs, DWORD *pdwSize ) { DWORD size, count, offset, len, sd_VirtualAddr; BOOL r; r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size ); if( !r ) return FALSE; offset = 0; /* take the n'th certificate */ while( 1 ) { /* read the length of the current certificate */ count = SetFilePointer( handle, sd_VirtualAddr + offset, NULL, FILE_BEGIN ); if( count == INVALID_SET_FILE_POINTER ) return FALSE; r = ReadFile( handle, &len, sizeof len, &count, NULL ); if( !r ) return FALSE; if( count != sizeof len ) return FALSE; /* check the certificate is not too big or too small */ if( len < sizeof len ) return FALSE; if( len > (size-offset) ) return FALSE; if( !num-- ) break; /* calculate the offset of the next certificate */ offset += len; /* padded out to the nearest 8-byte boundary */ if( len % 8 ) offset += 8 - (len % 8); if( offset >= size ) return FALSE; } *pdwOfs = sd_VirtualAddr + offset; *pdwSize = len; TRACE("len = %x addr = %x\n", len, sd_VirtualAddr + offset); return TRUE; } /*********************************************************************** * IMAGEHLP_RecalculateChecksum (INTERNAL) * * Update the NT header checksum for the specified file. */ static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle) { DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size; IMAGE_NT_HEADERS32 nt_hdr32; IMAGE_NT_HEADERS64 nt_hdr64; LPVOID BaseAddress; HANDLE hMapping; DWORD *CheckSum; void *nt_hdr; int ret; BOOL r; TRACE("handle %p\n", handle); ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64); if (ret == HDR_NT32) { CheckSum = &nt_hdr32.OptionalHeader.CheckSum; nt_hdr = &nt_hdr32; nt_hdr_size = sizeof(IMAGE_NT_HEADERS32); } else if (ret == HDR_NT64) { CheckSum = &nt_hdr64.OptionalHeader.CheckSum; nt_hdr = &nt_hdr64; nt_hdr_size = sizeof(IMAGE_NT_HEADERS64); } else return FALSE; hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL); if (!hMapping) return FALSE; BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); if (!BaseAddress) { CloseHandle(hMapping); return FALSE; } FileLength = GetFileSize(handle, NULL); *CheckSum = 0; CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum); UnmapViewOfFile(BaseAddress); CloseHandle(hMapping); if (*CheckSum) { /* write the header back again */ count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return FALSE; count = 0; r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL); if (!r) return FALSE; if (count != nt_hdr_size) return FALSE; return TRUE; } return FALSE; } /*********************************************************************** * ImageAddCertificate (IMAGEHLP.@) * * Adds the specified certificate to the security directory of * open PE file. */ BOOL WINAPI ImageAddCertificate( HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index) { DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0; WIN_CERTIFICATE hdr; const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate; BOOL r; TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index); r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size); /* If we've already got a security directory, find the end of it */ if ((r) && (sd_VirtualAddr != 0)) { /* Check if the security directory is at the end of the file. If not, we should probably relocate it. */ if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size) { FIXME("Security directory already present but not located at EOF, not adding certificate\n"); SetLastError(ERROR_NOT_SUPPORTED); return FALSE; } while (offset < size) { /* read the length of the current certificate */ count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return FALSE; r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL); if (!r) return FALSE; if (count != cert_hdr_size) return FALSE; /* check the certificate is not too big or too small */ if (hdr.dwLength < cert_hdr_size) return FALSE; if (hdr.dwLength > (size-offset)) return FALSE; /* next certificate */ offset += hdr.dwLength; /* padded out to the nearest 8-byte boundary */ if (hdr.dwLength % 8) offset += 8 - (hdr.dwLength % 8); index++; } count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN); if (count == INVALID_SET_FILE_POINTER) return FALSE; } else { sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END); if (sd_VirtualAddr == INVALID_SET_FILE_POINTER) return FALSE; } /* Write the certificate to the file */ r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL); if (!r) return FALSE; /* Pad out if necessary */ if (Certificate->dwLength % 8) { char null[8]; ZeroMemory(null, 8); WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), &count, NULL); size += 8 - (Certificate->dwLength % 8); } size += Certificate->dwLength; /* Update the security directory offset and size */ if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size)) return FALSE; if (!IMAGEHLP_RecalculateChecksum(FileHandle)) return FALSE; if(Index) *Index = index; return TRUE; } /*********************************************************************** * ImageEnumerateCertificates (IMAGEHLP.@) */ BOOL WINAPI ImageEnumerateCertificates( HANDLE handle, WORD TypeFilter, PDWORD CertificateCount, PDWORD Indices, DWORD IndexCount) { DWORD size, count, offset, sd_VirtualAddr, index; WIN_CERTIFICATE hdr; const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate; BOOL r; TRACE("%p %hd %p %p %d\n", handle, TypeFilter, CertificateCount, Indices, IndexCount); r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size ); if( !r ) return FALSE; offset = 0; index = 0; *CertificateCount = 0; while( offset < size ) { /* read the length of the current certificate */ count = SetFilePointer( handle, sd_VirtualAddr + offset, NULL, FILE_BEGIN ); if( count == INVALID_SET_FILE_POINTER ) return FALSE; r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL ); if( !r ) return FALSE; if( count != cert_hdr_size ) return FALSE; TRACE("Size = %08x id = %08hx\n", hdr.dwLength, hdr.wCertificateType ); /* check the certificate is not too big or too small */ if( hdr.dwLength < cert_hdr_size ) return FALSE; if( hdr.dwLength > (size-offset) ) return FALSE; if( (TypeFilter == CERT_SECTION_TYPE_ANY) || (TypeFilter == hdr.wCertificateType) ) { (*CertificateCount)++; if(Indices && *CertificateCount <= IndexCount) *Indices++ = index; } /* next certificate */ offset += hdr.dwLength; /* padded out to the nearest 8-byte boundary */ if (hdr.dwLength % 8) offset += 8 - (hdr.dwLength % 8); index++; } return TRUE; } /*********************************************************************** * ImageGetCertificateData (IMAGEHLP.@) * * FIXME: not sure that I'm dealing with the Index the right way */ BOOL WINAPI ImageGetCertificateData( HANDLE handle, DWORD Index, LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength) { DWORD r, offset, ofs, size, count; TRACE("%p %d %p %p\n", handle, Index, Certificate, RequiredLength); if( !RequiredLength) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) ) return FALSE; if( *RequiredLength < size ) { *RequiredLength = size; SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } if( !Certificate ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } *RequiredLength = size; offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN ); if( offset == INVALID_SET_FILE_POINTER ) return FALSE; r = ReadFile( handle, Certificate, size, &count, NULL ); if( !r ) return FALSE; if( count != size ) return FALSE; TRACE("OK\n"); SetLastError( NO_ERROR ); return TRUE; } /*********************************************************************** * ImageGetCertificateHeader (IMAGEHLP.@) */ BOOL WINAPI ImageGetCertificateHeader( HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert) { DWORD r, offset, ofs, size, count; const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate; TRACE("%p %d %p\n", handle, index, pCert); if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) ) return FALSE; if( size < cert_hdr_size ) return FALSE; offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN ); if( offset == INVALID_SET_FILE_POINTER ) return FALSE; r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL ); if( !r ) return FALSE; if( count != cert_hdr_size ) return FALSE; TRACE("OK\n"); return TRUE; } /* Finds the section named section in the array of IMAGE_SECTION_HEADERs hdr. If * found, returns the offset to the section. Otherwise returns 0. If the section * is found, optionally returns the size of the section (in size) and the base * address of the section (in base.) */ static DWORD IMAGEHLP_GetSectionOffset( IMAGE_SECTION_HEADER *hdr, DWORD num_sections, LPCSTR section, PDWORD size, PDWORD base ) { DWORD i, offset = 0; for( i = 0; !offset && i < num_sections; i++, hdr++ ) { if( !memcmp( hdr->Name, section, strlen(section) ) ) { offset = hdr->PointerToRawData; if( size ) *size = hdr->SizeOfRawData; if( base ) *base = hdr->VirtualAddress; } } return offset; } /* Calls DigestFunction e bytes at offset offset from the file mapped at map. * Returns the return value of DigestFunction, or FALSE if the data is not available. */ static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size, BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) { if( offset + size > fileSize ) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } return DigestFunction( DigestHandle, map + offset, size ); } /* Finds the section named section among the IMAGE_SECTION_HEADERs in * section_headers and calls DigestFunction for this section. Returns * the return value from DigestFunction, or FALSE if the data could not be read. */ static BOOL IMAGEHLP_ReportSection( IMAGE_SECTION_HEADER *section_headers, DWORD num_sections, LPCSTR section, BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) { DWORD offset, size = 0; offset = IMAGEHLP_GetSectionOffset( section_headers, num_sections, section, &size, NULL ); if( !offset ) return FALSE; return IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, DigestFunction, DigestHandle ); } /* Calls DigestFunction for all sections with the IMAGE_SCN_CNT_CODE flag set. * Returns the return value from * DigestFunction, or FALSE if a section could not be read. */ static BOOL IMAGEHLP_ReportCodeSections( IMAGE_SECTION_HEADER *hdr, DWORD num_sections, BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) { DWORD i; BOOL ret = TRUE; for( i = 0; ret && i < num_sections; i++, hdr++ ) { if( hdr->Characteristics & IMAGE_SCN_CNT_CODE ) ret = IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData, hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle ); } return ret; } /* Reports the import section from the file FileHandle. If * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set in DigestLevel, reports the entire * import section. * FIXME: if it's not set, the function currently fails. */ static BOOL IMAGEHLP_ReportImportSection( IMAGE_SECTION_HEADER *hdr, DWORD num_sections, BYTE *map, DWORD fileSize, DWORD DigestLevel, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) { BOOL ret = FALSE; DWORD offset, size, base; /* Get import data */ offset = IMAGEHLP_GetSectionOffset( hdr, num_sections, ".idata", &size, &base ); if( !offset ) return FALSE; /* If CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set, the entire * section is reported. Otherwise, the debug info section is * decoded and reported piecemeal. See tests. However, I haven't been * able to figure out how the native implementation decides which values * to report. Either it's buggy or my understanding is flawed. */ if( DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO ) ret = IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, DigestFunction, DigestHandle ); else { FIXME("not supported except for CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO\n"); SetLastError(ERROR_INVALID_PARAMETER); ret = FALSE; } return ret; } /*********************************************************************** * ImageGetDigestStream (IMAGEHLP.@) * * Gets a stream of bytes from a PE file over which a hash might be computed to * verify that the image has not changed. Useful for creating a certificate to * be added to the file with ImageAddCertificate. * * PARAMS * FileHandle [In] File for which to return a stream. * DigestLevel [In] Flags to control which portions of the file to return. * 0 is allowed, as is any combination of: * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: reports the entire * import section rather than selected portions of it. * CERT_PE_IMAGE_DIGEST_DEBUG_INFO: reports the debug section. * CERT_PE_IMAGE_DIGEST_RESOURCES: reports the resources section. * DigestFunction [In] Callback function. * DigestHandle [In] Handle passed as first parameter to DigestFunction. * * RETURNS * TRUE if successful. * FALSE if unsuccessful. GetLastError returns more about the error. * * NOTES * Only supports 32-bit PE files, not tested with any other format. * Reports data in the following order: * 1. The file headers are reported first * 2. Any code sections are reported next. * 3. The data (".data" and ".rdata") sections are reported next. * 4. The import section is reported next. * 5. If CERT_PE_IMAGE_DIGEST_DEBUG_INFO is set in DigestLevel, the debug section is * reported next. * 6. If CERT_PE_IMAGE_DIGEST_RESOURCES is set in DigestLevel, the resources section * is reported next. * * BUGS * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO must be specified, returns an error if not. */ BOOL WINAPI ImageGetDigestStream( HANDLE FileHandle, DWORD DigestLevel, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle) { DWORD error = 0; BOOL ret = FALSE; DWORD offset, size, num_sections, fileSize; HANDLE hMap = INVALID_HANDLE_VALUE; BYTE *map = NULL; IMAGE_DOS_HEADER *dos_hdr; IMAGE_NT_HEADERS *nt_hdr; IMAGE_SECTION_HEADER *section_headers; TRACE("(%p, %d, %p, %p)\n", FileHandle, DigestLevel, DigestFunction, DigestHandle); /* Get the file size */ if( !FileHandle ) goto invalid_parameter; fileSize = GetFileSize( FileHandle, NULL ); if(fileSize == INVALID_FILE_SIZE ) goto invalid_parameter; /* map file */ hMap = CreateFileMappingW( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); if( hMap == INVALID_HANDLE_VALUE ) goto invalid_parameter; map = MapViewOfFile( hMap, FILE_MAP_COPY, 0, 0, 0 ); if( !map ) goto invalid_parameter; /* Read the file header */ if( fileSize < sizeof(IMAGE_DOS_HEADER) ) goto invalid_parameter; dos_hdr = (IMAGE_DOS_HEADER *)map; if( dos_hdr->e_magic != IMAGE_DOS_SIGNATURE ) goto invalid_parameter; offset = dos_hdr->e_lfanew; if( !offset || offset > fileSize ) goto invalid_parameter; ret = DigestFunction( DigestHandle, map, offset ); if( !ret ) goto end; /* Read the NT header */ if( offset + sizeof(IMAGE_NT_HEADERS) > fileSize ) goto invalid_parameter; nt_hdr = (IMAGE_NT_HEADERS *)(map + offset); if( nt_hdr->Signature != IMAGE_NT_SIGNATURE ) goto invalid_parameter; /* It's clear why the checksum is cleared, but why only these size headers? */ nt_hdr->OptionalHeader.SizeOfInitializedData = 0; nt_hdr->OptionalHeader.SizeOfImage = 0; nt_hdr->OptionalHeader.CheckSum = 0; size = sizeof(nt_hdr->Signature) + sizeof(nt_hdr->FileHeader) + nt_hdr->FileHeader.SizeOfOptionalHeader; ret = DigestFunction( DigestHandle, map + offset, size ); if( !ret ) goto end; /* Read the section headers */ offset += size; num_sections = nt_hdr->FileHeader.NumberOfSections; size = num_sections * sizeof(IMAGE_SECTION_HEADER); if( offset + size > fileSize ) goto invalid_parameter; ret = DigestFunction( DigestHandle, map + offset, size ); if( !ret ) goto end; section_headers = (IMAGE_SECTION_HEADER *)(map + offset); IMAGEHLP_ReportCodeSections( section_headers, num_sections, map, fileSize, DigestFunction, DigestHandle ); IMAGEHLP_ReportSection( section_headers, num_sections, ".data", map, fileSize, DigestFunction, DigestHandle ); IMAGEHLP_ReportSection( section_headers, num_sections, ".rdata", map, fileSize, DigestFunction, DigestHandle ); IMAGEHLP_ReportImportSection( section_headers, num_sections, map, fileSize, DigestLevel, DigestFunction, DigestHandle ); if( DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO ) IMAGEHLP_ReportSection( section_headers, num_sections, ".debug", map, fileSize, DigestFunction, DigestHandle ); if( DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES ) IMAGEHLP_ReportSection( section_headers, num_sections, ".rsrc", map, fileSize, DigestFunction, DigestHandle ); end: if( map ) UnmapViewOfFile( map ); if( hMap != INVALID_HANDLE_VALUE ) CloseHandle( hMap ); if( error ) SetLastError(error); return ret; invalid_parameter: error = ERROR_INVALID_PARAMETER; goto end; } /*********************************************************************** * ImageRemoveCertificate (IMAGEHLP.@) */ BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index) { DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0; DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0; LPVOID cert_data; BOOL r; TRACE("(%p, %d)\n", FileHandle, Index); r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0); if ((!r) || (count == 0)) return FALSE; if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) || (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size))) return FALSE; /* Ignore any padding we have, too */ if (cert_size % 8) cert_size_padded = cert_size + (8 - (cert_size % 8)); else cert_size_padded = cert_size; data_size = size - (offset - sd_VirtualAddr) - cert_size_padded; if (data_size == 0) { ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN); if (ret == INVALID_SET_FILE_POINTER) return FALSE; } else { cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size); if (!cert_data) return FALSE; ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN); if (ret == INVALID_SET_FILE_POINTER) goto error; /* Read any subsequent certificates */ r = ReadFile(FileHandle, cert_data, data_size, &count, NULL); if ((!r) || (count != data_size)) goto error; SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN); /* Write them one index back */ r = WriteFile(FileHandle, cert_data, data_size, &count, NULL); if ((!r) || (count != data_size)) goto error; HeapFree(GetProcessHeap(), 0, cert_data); } /* If security directory is at end of file, trim the file */ if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size) SetEndOfFile(FileHandle); if (count == 1) r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0); else r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded); if (!r) return FALSE; if (!IMAGEHLP_RecalculateChecksum(FileHandle)) return FALSE; return TRUE; error: HeapFree(GetProcessHeap(), 0, cert_data); return FALSE; }