From 9e463db339d46224dfbbaf86807802daab7298a5 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Mon, 6 Mar 2017 17:30:20 +0100 Subject: [PATCH] wintrust-WinVerifyTrust: Do not use memory mapping. --- patches/patchinstall.sh | 2 +- ...-Verify-image-hash-in-WinVerifyTrust.patch | 168 ++++++++++-------- 2 files changed, 99 insertions(+), 71 deletions(-) diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 3fd53bd3..6cd894e5 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -9039,7 +9039,7 @@ if test "$enable_wintrust_WinVerifyTrust" -eq 1; then ( printf '%s\n' '+ { "Mark Jansen", "wintrust/tests: Add tests for WinVerifyTrust.", 2 },'; printf '%s\n' '+ { "Sebastian Lackner", "wintrust/tests: Add some additional tests.", 1 },'; - printf '%s\n' '+ { "Mark Jansen", "wintrust: Verify image hash in WinVerifyTrust.", 1 },'; + printf '%s\n' '+ { "Mark Jansen", "wintrust: Verify image hash in WinVerifyTrust.", 2 },'; ) >> "$patchlist" fi diff --git a/patches/wintrust-WinVerifyTrust/0003-wintrust-Verify-image-hash-in-WinVerifyTrust.patch b/patches/wintrust-WinVerifyTrust/0003-wintrust-Verify-image-hash-in-WinVerifyTrust.patch index c5f5e7d8..bd81191b 100644 --- a/patches/wintrust-WinVerifyTrust/0003-wintrust-Verify-image-hash-in-WinVerifyTrust.patch +++ b/patches/wintrust-WinVerifyTrust/0003-wintrust-Verify-image-hash-in-WinVerifyTrust.patch @@ -1,16 +1,19 @@ -From 108397c3d5e227ac2d83740a7f437fa275f1e65d Mon Sep 17 00:00:00 2001 +From 34d2916d1616b418395c6f543ba9cd362a82d7ab Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sat, 2 Apr 2016 02:57:47 +0200 -Subject: wintrust: Verify image hash in WinVerifyTrust. +Subject: wintrust: Verify image hash in WinVerifyTrust. (v2) Includes various improvements by Sebastian Lackner . + +Changes in v2: +* Do not use memory mapping (based on a patch by Mark Jansen). --- - dlls/wintrust/softpub.c | 169 ++++++++++++++++++++++++++++++++++++++++++ + dlls/wintrust/softpub.c | 194 ++++++++++++++++++++++++++++++++++++++++++ dlls/wintrust/tests/softpub.c | 8 +- - 2 files changed, 173 insertions(+), 4 deletions(-) + 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/dlls/wintrust/softpub.c b/dlls/wintrust/softpub.c -index 4e8582e..bb2fbd4 100644 +index 4e8582e2183..35c0d7b5abb 100644 --- a/dlls/wintrust/softpub.c +++ b/dlls/wintrust/softpub.c @@ -1,5 +1,6 @@ @@ -28,84 +31,123 @@ index 4e8582e..bb2fbd4 100644 #include "wintrust.h" #include "mssip.h" #include "softpub.h" -@@ -208,6 +210,170 @@ static DWORD SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data, HANDLE file, +@@ -208,6 +210,195 @@ static DWORD SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data, HANDLE file, return err; } +/* See https://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt + * for details about the hashing. + */ -+static BOOL SOFTPUB_HashPEFile(BYTE *file, LARGE_INTEGER *size, HCRYPTHASH hash) ++static BOOL SOFTPUB_HashPEFile(HANDLE file, HCRYPTHASH hash) +{ -+ IMAGE_DOS_HEADER *dosheader = (IMAGE_DOS_HEADER *)file; -+ IMAGE_NT_HEADERS *ntheader; -+ IMAGE_DATA_DIRECTORY *security_dir; -+ DWORD *checksum; ++ DWORD pos, checksum, security_dir; ++ IMAGE_DOS_HEADER dos_header; ++ union ++ { ++ IMAGE_NT_HEADERS32 nt32; ++ IMAGE_NT_HEADERS64 nt64; ++ } nt_header; ++ IMAGE_DATA_DIRECTORY secdir; ++ LARGE_INTEGER file_size; ++ DWORD bytes_read; ++ BYTE buffer[1024]; ++ BOOL ret; + -+ if (sizeof(dosheader) > size->QuadPart) ++ if (!GetFileSizeEx(file, &file_size)) + return FALSE; + -+ if (dosheader->e_magic != IMAGE_DOS_SIGNATURE) ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ ret = ReadFile(file, &dos_header, sizeof(dos_header), &bytes_read, NULL); ++ if (!ret || bytes_read != sizeof(dos_header)) ++ return FALSE; ++ ++ if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) + { -+ ERR("Unrecognized IMAGE_DOS_HEADER magic %04x\n", dosheader->e_magic); ++ ERR("Unrecognized IMAGE_DOS_HEADER magic %04x\n", dos_header.e_magic); ++ return FALSE; ++ } ++ if (dos_header.e_lfanew >= 256 * 1024 * 1024) /* see RtlImageNtHeaderEx */ ++ return FALSE; ++ if (dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader.MajorLinkerVersion) > file_size.QuadPart) ++ return FALSE; ++ ++ SetFilePointer(file, dos_header.e_lfanew, NULL, FILE_BEGIN); ++ ret = ReadFile(file, &nt_header, sizeof(nt_header), &bytes_read, NULL); ++ if (!ret || bytes_read < FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.Magic) + ++ sizeof(nt_header.nt32.OptionalHeader.Magic)) ++ return FALSE; ++ ++ if (nt_header.nt32.Signature != IMAGE_NT_SIGNATURE) ++ { ++ ERR("Unrecognized IMAGE_NT_HEADERS signature %08x\n", nt_header.nt32.Signature); + return FALSE; + } + -+ if (dosheader->e_lfanew >= 256 * 1024 * 1024) /* see RtlImageNtHeaderEx */ -+ return FALSE; -+ if (dosheader->e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader.MajorLinkerVersion) > size->QuadPart) -+ return FALSE; -+ -+ ntheader = (IMAGE_NT_HEADERS *)(file + dosheader->e_lfanew); -+ if (ntheader->Signature != IMAGE_NT_SIGNATURE) ++ if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { -+ ERR("Unrecognized IMAGE_NT_HEADERS signature %08x\n", ntheader->Signature); -+ return FALSE; -+ } -+ -+ if (ntheader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) -+ { -+ IMAGE_NT_HEADERS32 *nt32 = (IMAGE_NT_HEADERS32 *)ntheader; -+ if (dosheader->e_lfanew + sizeof(nt32) > size->QuadPart) ++ if (bytes_read < sizeof(nt_header.nt32)) + return FALSE; + -+ checksum = &nt32->OptionalHeader.CheckSum; -+ security_dir = &nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; ++ checksum = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum); ++ security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); ++ secdir = nt_header.nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; + } -+ else if (ntheader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) ++ else if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { -+ IMAGE_NT_HEADERS64 *nt64 = (IMAGE_NT_HEADERS64 *)ntheader; -+ if (dosheader->e_lfanew + sizeof(nt64) > size->QuadPart) ++ if (bytes_read < sizeof(nt_header.nt64)) + return FALSE; + -+ checksum = &nt64->OptionalHeader.CheckSum; -+ security_dir = &nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; ++ checksum = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum); ++ security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); ++ secdir = nt_header.nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + else + { -+ ERR("Unrecognized OptionalHeader magic %04x\n", ntheader->OptionalHeader.Magic); ++ ERR("Unrecognized OptionalHeader magic %04x\n", nt_header.nt32.OptionalHeader.Magic); + return FALSE; + } + -+ if (security_dir->VirtualAddress < (BYTE *)(security_dir + 1) - file) ++ if (secdir.VirtualAddress < security_dir + sizeof(IMAGE_DATA_DIRECTORY)) + return FALSE; -+ if (security_dir->VirtualAddress > size->QuadPart) ++ if (secdir.VirtualAddress > file_size.QuadPart) + return FALSE; -+ if (security_dir->VirtualAddress + security_dir->Size != size->QuadPart) ++ if (secdir.VirtualAddress + secdir.Size != file_size.QuadPart) + return FALSE; + + /* Hash until checksum. */ -+ if (!CryptHashData(hash, file, (BYTE *)checksum - file, 0)) -+ return FALSE; ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ for (pos = 0; pos < checksum; pos += bytes_read) ++ { ++ ret = ReadFile(file, buffer, min(sizeof(buffer), checksum - pos), &bytes_read, NULL); ++ if (!ret || !bytes_read) ++ return FALSE; ++ if (!CryptHashData(hash, buffer, bytes_read, 0)) ++ return FALSE; ++ } + + /* Hash until the DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] entry. */ -+ if (!CryptHashData(hash, (BYTE *)(checksum + 1), (BYTE *)security_dir - (BYTE *)(checksum + 1), 0)) -+ return FALSE; ++ checksum += sizeof(DWORD); ++ SetFilePointer(file, checksum, NULL, FILE_BEGIN); ++ for (pos = checksum; pos < security_dir; pos += bytes_read) ++ { ++ ret = ReadFile(file, buffer, min(sizeof(buffer), security_dir - pos), &bytes_read, NULL); ++ if (!ret || !bytes_read) ++ return FALSE; ++ if (!CryptHashData(hash, buffer, bytes_read, 0)) ++ return FALSE; ++ } + + /* Hash until the end of the file. */ -+ if (!CryptHashData(hash, (BYTE *)(security_dir + 1), -+ file + security_dir->VirtualAddress - (BYTE *)(security_dir + 1), 0)) -+ return FALSE; ++ security_dir += sizeof(IMAGE_DATA_DIRECTORY); ++ SetFilePointer(file, security_dir, NULL, FILE_BEGIN); ++ for (pos = security_dir; pos < secdir.VirtualAddress; pos += bytes_read) ++ { ++ ret = ReadFile(file, buffer, min(sizeof(buffer), secdir.VirtualAddress - pos), &bytes_read, NULL); ++ if (!ret || !bytes_read) ++ return FALSE; ++ if (!CryptHashData(hash, buffer, bytes_read, 0)) ++ return FALSE; ++ } + + return TRUE; +} @@ -114,13 +156,11 @@ index 4e8582e..bb2fbd4 100644 +{ + SPC_INDIRECT_DATA_CONTENT *indirect = (SPC_INDIRECT_DATA_CONTENT *)data->u.pPDSip->psIndirectData; + DWORD err, hash_size, length; -+ BYTE *hash_data, *file_map = NULL; -+ LARGE_INTEGER file_size; ++ BYTE *hash_data; + BOOL release_prov = FALSE; + HCRYPTPROV prov = data->hProv; + HCRYPTHASH hash = 0; + ALG_ID algID; -+ HANDLE map = NULL; + + if (((ULONG_PTR)indirect->Data.pszObjId >> 16) == 0 || + strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID)) @@ -145,15 +185,7 @@ index 4e8582e..bb2fbd4 100644 + goto done; + } + -+ if (!GetFileSizeEx(file, &file_size) || -+ !(map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL)) || -+ !(file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0))) -+ { -+ err = GetLastError(); -+ goto done; -+ } -+ -+ if (!SOFTPUB_HashPEFile(file_map, &file_size, hash)) ++ if (!SOFTPUB_HashPEFile(file, hash)) + { + err = TRUST_E_NOSIGNATURE; + goto done; @@ -184,10 +216,6 @@ index 4e8582e..bb2fbd4 100644 + data->psPfns->pfnFree(hash_data); + +done: -+ if (file_map) -+ UnmapViewOfFile(file_map); -+ if (map) -+ CloseHandle(map); + if (hash) + CryptDestroyHash(hash); + if (release_prov) @@ -199,7 +227,7 @@ index 4e8582e..bb2fbd4 100644 static DWORD SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data) { DWORD err = ERROR_SUCCESS; -@@ -371,6 +537,9 @@ static DWORD SOFTPUB_LoadFileMessage(CRYPT_PROVIDER_DATA *data) +@@ -371,6 +562,9 @@ static DWORD SOFTPUB_LoadFileMessage(CRYPT_PROVIDER_DATA *data) if (err) goto error; err = SOFTPUB_DecodeInnerContent(data); @@ -210,10 +238,10 @@ index 4e8582e..bb2fbd4 100644 error: if (err && data->fOpenedFile && data->pWintrustData->u.pFile) diff --git a/dlls/wintrust/tests/softpub.c b/dlls/wintrust/tests/softpub.c -index a2fa764..526b0eb 100644 +index aa481e407fc..1f872341357 100644 --- a/dlls/wintrust/tests/softpub.c +++ b/dlls/wintrust/tests/softpub.c -@@ -1156,7 +1156,7 @@ static void test_wintrust_digest(void) +@@ -1152,7 +1152,7 @@ static void test_wintrust_digest(void) { {{ SelfSignedFile32, sizeof(SelfSignedFile32) }, { Dummy, sizeof(Dummy) }}, @@ -222,7 +250,7 @@ index a2fa764..526b0eb 100644 }, { {{ Dummy, sizeof(Dummy) }, -@@ -1167,7 +1167,7 @@ static void test_wintrust_digest(void) +@@ -1163,7 +1163,7 @@ static void test_wintrust_digest(void) {{ SelfSignedFile32, 19 }, { Dummy, sizeof(Dummy) }, { SelfSignedFile32 + 19 + sizeof(Dummy), sizeof(SelfSignedFile32) - 19 - sizeof(Dummy) }}, @@ -231,7 +259,7 @@ index a2fa764..526b0eb 100644 }, { {{ SelfSignedFile32, sizeof(IMAGE_DOS_HEADER) }}, -@@ -1186,7 +1186,7 @@ static void test_wintrust_digest(void) +@@ -1182,7 +1182,7 @@ static void test_wintrust_digest(void) { {{ SelfSignedFile64, sizeof(SelfSignedFile64) }, { Dummy, sizeof(Dummy) }}, @@ -240,7 +268,7 @@ index a2fa764..526b0eb 100644 }, { {{ Dummy, sizeof(Dummy) }, -@@ -1197,7 +1197,7 @@ static void test_wintrust_digest(void) +@@ -1193,7 +1193,7 @@ static void test_wintrust_digest(void) {{ SelfSignedFile64, 19 }, { Dummy, sizeof(Dummy) }, { SelfSignedFile64 + 19 + sizeof(Dummy), sizeof(SelfSignedFile64) - 19 - sizeof(Dummy) }}, @@ -250,5 +278,5 @@ index a2fa764..526b0eb 100644 { {{ SelfSignedFile64, sizeof(IMAGE_DOS_HEADER) }}, -- -2.7.1 +2.11.0