[PATCH v21 0/2] MR10295: Fix ImageGetDigestStream
ImageGetDigestStream is used to hash the "important" parts of PE files. After rigorous experimentation we discovered these changes were sufficient to get identical hashes (and thereby signatures) on Windows and Wine. -- v21: imagehlp: Fix ImageGetDigestStream. https://gitlab.winehq.org/wine/wine/-/merge_requests/10295
From: Trent Waddington <trent.waddington@tensorworks.com.au> --- dlls/imagehlp/tests/image.c | 343 ++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/dlls/imagehlp/tests/image.c b/dlls/imagehlp/tests/image.c index 4d7a6f5bdfe..f47a6b74e55 100644 --- a/dlls/imagehlp/tests/image.c +++ b/dlls/imagehlp/tests/image.c @@ -223,6 +223,242 @@ bin64 = /* final alignment */ {0} }; + +#define FILE_TEXT_2 0x300 +#define NUM_SECTIONS_2 5 +#define FILE_RELOC 0x600 +#define RVA_RELOC 0x4000 +#define FILE_RSRC 0x800 +#define RVA_RSRC 0x5000 +#define FILE_TOTAL_2 0xA00 +#define RVA_TOTAL_2 0x6000 + +static struct image_with_rsrc_and_reloc +{ + IMAGE_DOS_HEADER dos_header; + char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)]; + IMAGE_NT_HEADERS32 nt_headers; + IMAGE_SECTION_HEADER sections[NUM_SECTIONS_2]; + char __alignment2[FILE_TEXT_2 - FILE_PE_START - sizeof(IMAGE_NT_HEADERS32) - + NUM_SECTIONS_2 * sizeof(IMAGE_SECTION_HEADER)]; + unsigned char text_section[FILE_IDATA-FILE_TEXT_2]; + struct imports idata_section; + char __alignment3[FILE_RELOC - FILE_IDATA - sizeof(struct imports)]; + unsigned char reloc_section[FILE_RSRC-FILE_RELOC]; + unsigned char rsrc_section[FILE_TOTAL_2-FILE_RSRC]; +} +bin_with_rsrc_and_reloc = +{ + /* dos header */ + {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, 0, {0}, FILE_PE_START}, + /* alignment before PE header */ + {0}, + /* nt headers */ + {IMAGE_NT_SIGNATURE, + /* basic headers - 5 sections, no symbols, EXE file */ + {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS_2, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32), + IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE}, + /* optional header */ + {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT_2, + FILE_RELOC-FILE_IDATA + FILE_IDATA-FILE_TEXT_2, 0x400, + RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0, + RVA_TOTAL_2, FILE_TEXT_2, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0, + 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10, + {{0, 0}, + {RVA_IDATA, sizeof(struct imports)}, + {RVA_RSRC, 0x100}, + {0, 0}, + {0, 0}, + {RVA_RELOC, 0x100} + } + } + }, + /* sections */ + { + {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT_2, FILE_TEXT_2, + 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ}, + {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".idata", {sizeof(struct imports)}, RVA_IDATA, FILE_RELOC-FILE_IDATA, FILE_IDATA, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".reloc", {0x100}, RVA_RELOC, FILE_RSRC-FILE_RELOC, FILE_RELOC, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ}, + {".rsrc", {0x100}, RVA_RSRC, FILE_TOTAL_2-FILE_RSRC, FILE_RSRC, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ} + }, + /* alignment before first section */ + {0}, + /* .text section */ + { + 0x31, 0xC0, /* xor eax, eax */ + 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF, + (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */ + 0 + }, + /* .idata section */ + { + { + {{RVA_IDATA + FIELD_OFFSET(struct imports, original_thunks)}, 0, 0, + RVA_IDATA + FIELD_OFFSET(struct imports, dllname), + RVA_IDATA + FIELD_OFFSET(struct imports, thunks) + }, + {{0}, 0, 0, 0, 0} + }, + {{{RVA_IDATA+FIELD_OFFSET(struct imports, ibn)}}, {{0}}}, + {{{RVA_IDATA+FIELD_OFFSET(struct imports, ibn)}}, {{0}}}, + {0,"ExitProcess"}, + "KERNEL32.DLL" + }, + /* .reloc section */ + { + 0 + }, + /* .rsrc section */ + { + 0 + } +}; + +IMAGE_NT_HEADERS32 bin_with_rsrc_and_reloc_nt_headers_zeroed = +{ + IMAGE_NT_SIGNATURE, + /* basic headers - 5 sections, no symbols, EXE file */ + {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS_2, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32), + IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE}, + /* optional header */ + {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT_2, + 0, 0x400, + RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0, + 0, FILE_TEXT_2, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0, + 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10, + {{0, 0}, + {RVA_IDATA, sizeof(struct imports)}, + {0, 0}, /* was RVA_RSRC, 0x100 */ + {0, 0}, + {0, 0}, + {RVA_RELOC, 0x100} + } + } +}; + +IMAGE_SECTION_HEADER bin_with_rsrc_and_reloc_sections_zeroed[NUM_SECTIONS_2] = +{ + {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT_2, FILE_TEXT_2, + 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ}, + {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".idata", {sizeof(struct imports)}, RVA_IDATA, FILE_RELOC-FILE_IDATA, FILE_IDATA, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".reloc", {0x100}, RVA_RELOC, FILE_RSRC-FILE_RELOC, FILE_RELOC, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ}, + {".rsrc", {0}, 0, 0, 0, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ} +}; + +static struct image64_with_rsrc_and_reloc +{ + IMAGE_DOS_HEADER dos_header; + char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)]; + IMAGE_NT_HEADERS64 nt_headers; + IMAGE_SECTION_HEADER sections[NUM_SECTIONS_2]; + char __alignment2[FILE_TEXT_2 - FILE_PE_START - sizeof(IMAGE_NT_HEADERS64) - + NUM_SECTIONS_2 * sizeof(IMAGE_SECTION_HEADER)]; + unsigned char text_section[FILE_IDATA-FILE_TEXT_2]; + struct imports64 idata_section; + char __alignment3[FILE_RELOC - FILE_IDATA - sizeof(struct imports)]; + unsigned char reloc_section[FILE_RSRC-FILE_RELOC]; + unsigned char rsrc_section[FILE_TOTAL_2-FILE_RSRC]; +} +bin64_with_rsrc_and_reloc = +{ + /* dos header */ + {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, 0, {0}, FILE_PE_START}, + /* alignment before PE header */ + {0}, + /* nt headers */ + {IMAGE_NT_SIGNATURE, + /* basic headers - 5 sections, no symbols, EXE file */ + {IMAGE_FILE_MACHINE_AMD64, NUM_SECTIONS_2, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER64), + IMAGE_FILE_EXECUTABLE_IMAGE}, + /* optional header */ + {IMAGE_NT_OPTIONAL_HDR64_MAGIC, 6, 0, FILE_IDATA-FILE_TEXT_2, + FILE_RELOC-FILE_IDATA + FILE_IDATA-FILE_TEXT_2, 0x400, + RVA_TEXT, RVA_TEXT, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 5, 2, 0, + RVA_TOTAL_2, FILE_TEXT_2, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0, + 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10, + {{0, 0}, + {RVA_IDATA, sizeof(struct imports64)}, + {RVA_RSRC, 0x100}, + {0, 0}, + {0, 0}, + {RVA_RELOC, 0x100} + } + } + }, + /* sections */ + { + {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT_2, FILE_TEXT_2, + 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ}, + {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".idata", {sizeof(struct imports)}, RVA_IDATA, FILE_RELOC-FILE_IDATA, FILE_IDATA, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".reloc", {0x100}, RVA_RELOC, FILE_RSRC-FILE_RELOC, FILE_RELOC, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ}, + {".rsrc", {0x100}, RVA_RSRC, FILE_TOTAL_2-FILE_RSRC, FILE_RSRC, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ} + }, + /* alignment before first section */ + {0}, + /* .text section */ + { + 0x31, 0xC0, /* xor eax, eax */ + 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF, + (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */ + 0 + }, + /* .idata section */ + { + { {{RVA_IDATA + FIELD_OFFSET(struct imports64, original_thunks)}, 0, 0, + RVA_IDATA + FIELD_OFFSET(struct imports64, dllname), + RVA_IDATA + FIELD_OFFSET(struct imports64, thunks)}, + {{0}, 0, 0, 0, 0} }, + { {{RVA_IDATA + FIELD_OFFSET(struct imports64, ibn)}}, {{0}} }, + { {{RVA_IDATA + FIELD_OFFSET(struct imports64, ibn)}}, {{0}} }, + { 0, "ExitProcess" }, + "KERNEL32.DLL" + }, + /* .reloc section */ + { + 0 + }, + /* .rsrc section */ + { + 0 + } +}; + +IMAGE_NT_HEADERS64 bin64_with_rsrc_and_reloc_nt_headers_zeroed = +{ + IMAGE_NT_SIGNATURE, + /* basic headers - 5 sections, no symbols, EXE file */ + {IMAGE_FILE_MACHINE_AMD64, NUM_SECTIONS_2, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER64), + IMAGE_FILE_EXECUTABLE_IMAGE}, + /* optional header */ + {IMAGE_NT_OPTIONAL_HDR64_MAGIC, 6, 0, FILE_IDATA-FILE_TEXT_2, + 0, 0x400, + RVA_TEXT, RVA_TEXT, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 5, 2, 0, + 0, FILE_TEXT_2, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0, + 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10, + {{0, 0}, + {RVA_IDATA, sizeof(struct imports64)}, + {0, 0}, /* was RVA_RSRC, 0x100 */ + {0, 0}, + {0, 0}, + {RVA_RELOC, 0x100} + } + } +}; #pragma pack(pop) struct blob @@ -358,6 +594,54 @@ static const struct expected_blob b4[] = { }; static const struct expected_update_accum a4 = { ARRAY_SIZE(b4), b4, FALSE }; +static const struct expected_blob b5[] = { + {FILE_PE_START, &bin_with_rsrc_and_reloc}, + /* with zeroed Checksum/SizeOfInitializedData/SizeOfImage fields */ + {sizeof(bin_with_rsrc_and_reloc.nt_headers), &bin_with_rsrc_and_reloc_nt_headers_zeroed}, + {sizeof(bin_with_rsrc_and_reloc.sections), &bin_with_rsrc_and_reloc_sections_zeroed}, + {FILE_IDATA-FILE_TEXT_2, &bin_with_rsrc_and_reloc.text_section}, + {FILE_RELOC-FILE_IDATA, &bin_with_rsrc_and_reloc.idata_section}, + {FILE_RSRC-FILE_RELOC, &bin_with_rsrc_and_reloc.reloc_section}, + {FILE_TOTAL_2-FILE_RSRC-0x100, &bin_with_rsrc_and_reloc.rsrc_section + 0x100} +}; +static const struct expected_update_accum a5 = { ARRAY_SIZE(b5), b5, FALSE }; + +static const struct expected_blob b6[] = { + {FILE_PE_START, &bin_with_rsrc_and_reloc}, + /* with zeroed Checksum but not SizeOfInitializedData/SizeOfImage fields */ + {sizeof(bin_with_rsrc_and_reloc.nt_headers), &bin_with_rsrc_and_reloc.nt_headers}, + {sizeof(bin_with_rsrc_and_reloc.sections), &bin_with_rsrc_and_reloc.sections}, + {FILE_IDATA-FILE_TEXT_2, &bin_with_rsrc_and_reloc.text_section}, + {FILE_RELOC-FILE_IDATA, &bin_with_rsrc_and_reloc.idata_section}, + {FILE_RSRC-FILE_RELOC, &bin_with_rsrc_and_reloc.reloc_section}, + {FILE_TOTAL_2-FILE_RSRC, &bin_with_rsrc_and_reloc.rsrc_section} +}; +static const struct expected_update_accum a6 = { ARRAY_SIZE(b6), b6, FALSE }; + +static const struct expected_blob b7[] = { + {FILE_PE_START, &bin64_with_rsrc_and_reloc}, + /* with zeroed Checksum/SizeOfInitializedData/SizeOfImage fields */ + {sizeof(bin64_with_rsrc_and_reloc.nt_headers), &bin64_with_rsrc_and_reloc_nt_headers_zeroed}, + {sizeof(bin64_with_rsrc_and_reloc.sections), &bin_with_rsrc_and_reloc_sections_zeroed}, + {FILE_IDATA-FILE_TEXT_2, &bin64_with_rsrc_and_reloc.text_section}, + {FILE_RELOC-FILE_IDATA, &bin64_with_rsrc_and_reloc.idata_section}, + {FILE_RSRC-FILE_RELOC, &bin64_with_rsrc_and_reloc.reloc_section}, + {FILE_TOTAL_2-FILE_RSRC-0x100, &bin64_with_rsrc_and_reloc.rsrc_section + 0x100} +}; +static const struct expected_update_accum a7 = { ARRAY_SIZE(b7), b7, FALSE }; + +static const struct expected_blob b8[] = { + {FILE_PE_START, &bin64_with_rsrc_and_reloc}, + /* with zeroed Checksum but not SizeOfInitializedData/SizeOfImage fields */ + {sizeof(bin64_with_rsrc_and_reloc.nt_headers), &bin64_with_rsrc_and_reloc.nt_headers}, + {sizeof(bin64_with_rsrc_and_reloc.sections), &bin64_with_rsrc_and_reloc.sections}, + {FILE_IDATA-FILE_TEXT_2, &bin64_with_rsrc_and_reloc.text_section}, + {FILE_RELOC-FILE_IDATA, &bin64_with_rsrc_and_reloc.idata_section}, + {FILE_RSRC-FILE_RELOC, &bin64_with_rsrc_and_reloc.reloc_section}, + {FILE_TOTAL_2-FILE_RSRC, &bin64_with_rsrc_and_reloc.rsrc_section} +}; +static const struct expected_update_accum a8 = { ARRAY_SIZE(b8), b8, FALSE }; + /* Creates a test file and returns a handle to it. The file's path is returned * in temp_file, which must be at least MAX_PATH characters in length. */ @@ -449,6 +733,7 @@ static void test_get_digest_stream(void) CloseHandle(file); DeleteFileA(temp_file); + /* 64 bit */ file = create_temp_file(temp_file); if (file == INVALID_HANDLE_VALUE) { @@ -478,6 +763,64 @@ static void test_get_digest_stream(void) free_updates(&accum); CloseHandle(file); DeleteFileA(temp_file); + + /* with rsrc and reloc */ + file = create_temp_file(temp_file); + if (file == INVALID_HANDLE_VALUE) + { + skip("couldn't create temp file\n"); + return; + } + bin_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = 0; + checksum = compute_checksum((const WORD *)&bin_with_rsrc_and_reloc, sizeof(bin_with_rsrc_and_reloc)); + bin_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = checksum; + WriteFile(file, &bin_with_rsrc_and_reloc, sizeof(bin_with_rsrc_and_reloc), &count, NULL); + FlushFileBuffers(file); + + ret = ImageGetDigestStream(file, CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO, + accumulating_stream_output, &accum); + ok(ret, "ImageGetDigestStream failed: %ld\n", GetLastError()); + check_updates("wrsrc flags = CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO", &a5, &accum); + free_updates(&accum); + + bin_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = 0; + + ret = ImageGetDigestStream(file, CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO|CERT_PE_IMAGE_DIGEST_RESOURCES, + accumulating_stream_output, &accum); + ok(ret, "ImageGetDigestStream failed: %ld\n", GetLastError()); + check_updates("wrsrc flags = CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO|CERT_PE_IMAGE_DIGEST_RESOURCES", &a6, &accum); + free_updates(&accum); + CloseHandle(file); + DeleteFileA(temp_file); + + /* 64 bit with rsrc and reloc */ + file = create_temp_file(temp_file); + if (file == INVALID_HANDLE_VALUE) + { + skip("couldn't create temp file\n"); + return; + } + bin64_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = 0; + checksum = compute_checksum((const WORD *)&bin64_with_rsrc_and_reloc, sizeof(bin64_with_rsrc_and_reloc)); + bin64_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = checksum; + WriteFile(file, &bin64_with_rsrc_and_reloc, sizeof(bin64_with_rsrc_and_reloc), &count, NULL); + FlushFileBuffers(file); + + ret = ImageGetDigestStream(file, CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO, + accumulating_stream_output, &accum); + ok(ret, "ImageGetDigestStream failed: %ld\n", GetLastError()); + check_updates("64 wrsrc flags = CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO", &a7, &accum); + free_updates(&accum); + + bin64_with_rsrc_and_reloc.nt_headers.OptionalHeader.CheckSum = 0; + + ret = ImageGetDigestStream(file, CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO|CERT_PE_IMAGE_DIGEST_RESOURCES, + accumulating_stream_output, &accum); + ok(ret, "ImageGetDigestStream failed: %ld\n", GetLastError()); + check_updates("64 wrsrc flags = CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO|CERT_PE_IMAGE_DIGEST_RESOURCES", &a8, &accum); + free_updates(&accum); + CloseHandle(file); + DeleteFileA(temp_file); } static unsigned int got_SysAllocString, got_GetOpenFileNameA, got_SHRegGetIntW; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10295
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
participants (2)
-
Trent Waddington -
Trent Waddington (@trent.waddington)