From: Trent Waddington <trent.waddington@tensorworks.com.au> --- dlls/imagehlp/integrity.c | 207 ++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 123 deletions(-) diff --git a/dlls/imagehlp/integrity.c b/dlls/imagehlp/integrity.c index ebad7001548..edde0b15838 100644 --- a/dlls/imagehlp/integrity.c +++ b/dlls/imagehlp/integrity.c @@ -631,30 +631,6 @@ BOOL WINAPI ImageGetCertificateHeader( 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. */ @@ -669,79 +645,6 @@ static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size, 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.@) * @@ -789,8 +692,15 @@ BOOL WINAPI ImageGetDigestStream( HANDLE hMap = INVALID_HANDLE_VALUE; BYTE *map = NULL; IMAGE_DOS_HEADER *dos_hdr; - IMAGE_NT_HEADERS *nt_hdr; + IMAGE_NT_HEADERS32 *nthdr32; + IMAGE_NT_HEADERS64 *nthdr64; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY *DataDirectory; + IMAGE_DATA_DIRECTORY DataDirBackup[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; IMAGE_SECTION_HEADER *section_headers; + IMAGE_SECTION_HEADER rsrc; + int rsrc_i = -1; + int i; TRACE("(%p, %ld, %p, %p)\n", FileHandle, DigestLevel, DigestFunction, DigestHandle); @@ -827,45 +737,96 @@ BOOL WINAPI ImageGetDigestStream( /* 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 ) + nthdr32 = (IMAGE_NT_HEADERS32 *)(map + offset); + if( nthdr32->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; + NumberOfRvaAndSizes = nthdr32->OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = nthdr32->OptionalHeader.DataDirectory; + if( nthdr32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC ) + { + nthdr64 = (IMAGE_NT_HEADERS64 *)nthdr32; + NumberOfRvaAndSizes = nthdr64->OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = nthdr64->OptionalHeader.DataDirectory; + /* NOTE: Fields up to SizeOfStackCommit are the same size/offset, except for ImageBase */ + } + memcpy(DataDirBackup, DataDirectory, sizeof(DataDirBackup)); + + /* Set the IMAGE_FILE_SECURITY_DIRECTORY values to zero as Windows does not include them. */ + if( NumberOfRvaAndSizes > IMAGE_FILE_SECURITY_DIRECTORY ) + { + DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY].Size = 0; + DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY].VirtualAddress = 0; + } + + /* Other zeros */ + nthdr32->OptionalHeader.CheckSum = 0; + if( (DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES) == 0 ) + { + nthdr32->OptionalHeader.SizeOfInitializedData = 0; + nthdr32->OptionalHeader.SizeOfImage = 0; + if( NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE ) + { + DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = 0; + DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = 0; + } + } + + size = sizeof(nthdr32->Signature) + sizeof(nthdr32->FileHeader) + + nthdr32->FileHeader.SizeOfOptionalHeader; ret = DigestFunction( DigestHandle, map + offset, size ); if( !ret ) goto end; + memcpy(DataDirectory, DataDirBackup, NumberOfRvaAndSizes * sizeof(*DataDirectory)); + /* Read the section headers */ offset += size; - num_sections = nt_hdr->FileHeader.NumberOfSections; + num_sections = nthdr32->FileHeader.NumberOfSections; size = num_sections * sizeof(IMAGE_SECTION_HEADER); if( offset + size > fileSize ) goto invalid_parameter; + section_headers = (IMAGE_SECTION_HEADER *)(map + offset); + + /* Zero out some sections */ + for( i = 0; DigestLevel != 0 && (DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES) == 0 && i < num_sections; i++ ) + { + IMAGE_SECTION_HEADER *hdr = §ion_headers[i]; + if( hdr->VirtualAddress == DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress ) + { + rsrc_i = i; + memcpy(&rsrc, hdr, sizeof(rsrc)); + hdr->Misc.VirtualSize = 0; + hdr->VirtualAddress = 0; + hdr->SizeOfRawData = 0; + hdr->PointerToRawData = 0; + } + } + 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 ); + /* Restore zeroed out sections */ + if( rsrc_i != -1 ) + memcpy(§ion_headers[rsrc_i], &rsrc, sizeof(rsrc)); + + for( i = 0; ret && i < num_sections; i++ ) + { + IMAGE_SECTION_HEADER *hdr = §ion_headers[i]; + if( (DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO) == 0 && hdr->VirtualAddress == DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress ) + continue; + if( (DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO) == 0 && hdr->VirtualAddress == DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ) + continue; + if( (DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES) == 0 && hdr->VirtualAddress == DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress ) + { + if( hdr->Misc.VirtualSize < hdr->SizeOfRawData ) + IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData + hdr->Misc.VirtualSize, hdr->SizeOfRawData - hdr->Misc.VirtualSize, map, fileSize, DigestFunction, DigestHandle ); + continue; + } + if (hdr->SizeOfRawData == 0) + continue; + IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData, hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle ); + } end: if( map ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10295