From: Hans Leidekker hans@codeweavers.com
--- dlls/wintrust/crypt.c | 59 ++++++++++++++++++++++++++++++++--- dlls/wintrust/tests/softpub.c | 34 ++++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/wintrust/crypt.c b/dlls/wintrust/crypt.c index 7321b84eea4..564585f3477 100644 --- a/dlls/wintrust/crypt.c +++ b/dlls/wintrust/crypt.c @@ -214,11 +214,58 @@ HCATINFO WINAPI CryptCATAdminAddCatalog(HCATADMIN catAdmin, PWSTR catalogFile, return ci; }
+static BOOL pe_image_hash( HANDLE file, HCRYPTHASH hash ) +{ + UINT32 size, offset, file_size, header_size, magic, pe32plus, sig_pos; + HANDLE mapping; + BYTE *view; + BOOL ret = FALSE; + + if ((file_size = GetFileSize( file, NULL )) == INVALID_FILE_SIZE || file_size < 64) return FALSE; + + if ((mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL )) == INVALID_HANDLE_VALUE) + return FALSE; + + if (!(view = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ))) goto done; + + header_size = *(UINT32 *)(view + 60); + if (header_size < 44 || header_size > file_size || file_size < header_size + 176 || + memcmp( view + header_size, "PE\0\0", 4 )) goto done; + + magic = *(UINT16 *)(view + header_size + 24); + if (magic == 0x20b) pe32plus = 1; + else if (magic == 0x10b) pe32plus = 0; + else goto done; + + offset = header_size + 88; + if (!CryptHashData( hash, view, offset, 0 )) goto done; + + offset += sizeof(UINT32); /* checksum */ + size = 60 + pe32plus * 16; + if (!CryptHashData( hash, view + offset, size, 0 )) goto done; + + sig_pos = *(UINT32 *)(view + header_size + 152 + pe32plus * 16); + offset += size + 8; + size = sig_pos ? sig_pos - offset : file_size - offset; + if (!CryptHashData( hash, view + offset, size, 0 )) goto done; + ret = TRUE; + + if (!sig_pos && (size = file_size % 8)) + { + static const BYTE pad[7]; + ret = CryptHashData( hash, pad, 8 - size, 0 ); + } + +done: + UnmapViewOfFile( view ); + CloseHandle( mapping ); + return ret; +} + /*********************************************************************** * CryptCATAdminCalcHashFromFileHandle (WINTRUST.@) */ -BOOL WINAPI CryptCATAdminCalcHashFromFileHandle(HANDLE hFile, DWORD* pcbHash, - BYTE* pbHash, DWORD dwFlags ) +BOOL WINAPI CryptCATAdminCalcHashFromFileHandle(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags) { BOOL ret = FALSE;
@@ -262,9 +309,13 @@ BOOL WINAPI CryptCATAdminCalcHashFromFileHandle(HANDLE hFile, DWORD* pcbHash, CryptReleaseContext(prov, 0); return FALSE; } - while ((ret = ReadFile(hFile, buffer, 4096, &bytes_read, NULL)) && bytes_read) + + if (!(ret = pe_image_hash(hFile, hash))) { - CryptHashData(hash, buffer, bytes_read, 0); + while ((ret = ReadFile(hFile, buffer, 4096, &bytes_read, NULL)) && bytes_read) + { + CryptHashData(hash, buffer, bytes_read, 0); + } } if (ret) ret = CryptGetHashParam(hash, HP_HASHVAL, pbHash, pcbHash, 0);
diff --git a/dlls/wintrust/tests/softpub.c b/dlls/wintrust/tests/softpub.c index 46861766621..9654c296a78 100644 --- a/dlls/wintrust/tests/softpub.c +++ b/dlls/wintrust/tests/softpub.c @@ -1892,6 +1892,39 @@ static void test_multiple_signatures(void) DeleteFileW(pathW); }
+static BOOL (WINAPI *pCryptCATAdminCalcHashFromFileHandle)(HANDLE,DWORD*,BYTE*,DWORD); + +static void test_pe_image_hash(void) +{ + static const char expected[] = + {0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0,0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b}; + WCHAR path[MAX_PATH]; + HANDLE file; + BYTE sha1[20]; + DWORD size, count; + HMODULE wintrust = GetModuleHandleA("wintrust.dll"); + BOOL ret; + + pCryptCATAdminCalcHashFromFileHandle = (void *)GetProcAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle"); + if (!pCryptCATAdminCalcHashFromFileHandle) + { + win_skip("hash function missing\n"); + return; + } + + file = create_temp_file(path); + WriteFile(file, &bin, sizeof(bin), &count, NULL); + + size = sizeof(sha1); + memset(sha1, 0, sizeof(sha1)); + ret = pCryptCATAdminCalcHashFromFileHandle(file, &size, sha1, 0); + ok(ret, "got %lu\n", GetLastError()); + ok(!memcmp(sha1, expected, sizeof(sha1)), "wrong hash\n"); + + CloseHandle(file); + DeleteFileW(path); +} + START_TEST(softpub) { InitFunctionPtrs(); @@ -1901,4 +1934,5 @@ START_TEST(softpub) test_wintrust_digest(); test_get_known_usages(); test_multiple_signatures(); + test_pe_image_hash(); }
Is it possible to use some public types for PE structures?
I started out like that but found that it complicates things because of differences between PE32 and PE32+ images. So it's possible but this is simpler.
IMO this can be handled... RtlImageGetNtHeader will do all the DOS+PE validation bits check supported magic values
const IMAGE_DATA_DIRECTORY *dir = (nthdr->Magic == 0x10b) ? ((IMAGE_NT_HEADERS32*)nthdr)->DataDirectory : ((IMAGE_NT_HEADERS64*)nthdr) + IMAGE_DIRECTORY_SECURITY;
and the rest should be transparent
and forgot about RtlImageDirectoryEntryToData