diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:42:44 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:42:44 -0700 |
| commit | afc20ecb53ad3ade524aceefa30d98a3d84fd479 (patch) | |
| tree | 4fb762f65dc195ccb104a6c1fcce7c40e7693e98 /src/burn/engine/section.cpp | |
| parent | 8e1207c4c5e451ba1a087f0fa11b63964ac35f3c (diff) | |
| parent | af10c45d7b3a44af0b461a557847fe03263dcc10 (diff) | |
| download | wix-afc20ecb53ad3ade524aceefa30d98a3d84fd479.tar.gz wix-afc20ecb53ad3ade524aceefa30d98a3d84fd479.tar.bz2 wix-afc20ecb53ad3ade524aceefa30d98a3d84fd479.zip | |
Merge burn
Diffstat (limited to 'src/burn/engine/section.cpp')
| -rw-r--r-- | src/burn/engine/section.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/src/burn/engine/section.cpp b/src/burn/engine/section.cpp new file mode 100644 index 00000000..3720155c --- /dev/null +++ b/src/burn/engine/section.cpp | |||
| @@ -0,0 +1,399 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | |||
| 6 | // constants | ||
| 7 | |||
| 8 | // If these defaults ever change, be sure to update constants in burn\stub\StubSection.cpp as well. | ||
| 9 | #define BURN_SECTION_NAME ".wixburn" | ||
| 10 | #define BURN_SECTION_MAGIC 0x00f14300 | ||
| 11 | #define BURN_SECTION_VERSION 0x00000002 | ||
| 12 | #define MANIFEST_CABINET_TOKEN L"0" | ||
| 13 | |||
| 14 | // structs | ||
| 15 | typedef struct _BURN_SECTION_HEADER | ||
| 16 | { | ||
| 17 | DWORD dwMagic; | ||
| 18 | DWORD dwVersion; | ||
| 19 | |||
| 20 | GUID guidBundleId; | ||
| 21 | |||
| 22 | DWORD dwStubSize; | ||
| 23 | DWORD dwOriginalChecksum; | ||
| 24 | DWORD dwOriginalSignatureOffset; | ||
| 25 | DWORD dwOriginalSignatureSize; | ||
| 26 | |||
| 27 | DWORD dwFormat; | ||
| 28 | DWORD cContainers; | ||
| 29 | DWORD rgcbContainers[1]; | ||
| 30 | } BURN_SECTION_HEADER; | ||
| 31 | |||
| 32 | static HRESULT VerifySectionMatchesMemoryPEHeader( | ||
| 33 | __in REFGUID pSection | ||
| 34 | ); | ||
| 35 | |||
| 36 | |||
| 37 | extern "C" HRESULT SectionInitialize( | ||
| 38 | __in BURN_SECTION* pSection, | ||
| 39 | __in HANDLE hEngineFile, | ||
| 40 | __in HANDLE hSourceEngineFile | ||
| 41 | ) | ||
| 42 | { | ||
| 43 | HRESULT hr = S_OK; | ||
| 44 | DWORD cbRead = 0; | ||
| 45 | LARGE_INTEGER li = { }; | ||
| 46 | LONGLONG llSize = 0; | ||
| 47 | IMAGE_DOS_HEADER dosHeader = { }; | ||
| 48 | IMAGE_NT_HEADERS ntHeader = { }; | ||
| 49 | DWORD dwChecksumOffset = 0; | ||
| 50 | DWORD dwCertificateTableOffset = 0; | ||
| 51 | DWORD dwSignatureOffset = 0; | ||
| 52 | DWORD cbSignature = 0; | ||
| 53 | IMAGE_SECTION_HEADER sectionHeader = { }; | ||
| 54 | DWORD_PTR dwOriginalChecksumAndSignatureOffset = 0; | ||
| 55 | BURN_SECTION_HEADER* pBurnSectionHeader = NULL; | ||
| 56 | |||
| 57 | pSection->hEngineFile = hEngineFile; | ||
| 58 | ExitOnInvalidHandleWithLastError(pSection->hEngineFile, hr, "Failed to open handle to engine process path."); | ||
| 59 | |||
| 60 | pSection->hSourceEngineFile = INVALID_HANDLE_VALUE == hSourceEngineFile ? hEngineFile : hSourceEngineFile; | ||
| 61 | |||
| 62 | // | ||
| 63 | // First, make sure we have a valid DOS signature. | ||
| 64 | // | ||
| 65 | if (!::SetFilePointerEx(pSection->hEngineFile, li, NULL, FILE_BEGIN)) | ||
| 66 | { | ||
| 67 | ExitWithLastError(hr, "Failed to seek to start of file."); | ||
| 68 | } | ||
| 69 | |||
| 70 | // read DOS header | ||
| 71 | if (!::ReadFile(pSection->hEngineFile, &dosHeader, sizeof(IMAGE_DOS_HEADER), &cbRead, NULL)) | ||
| 72 | { | ||
| 73 | ExitWithLastError(hr, "Failed to read DOS header."); | ||
| 74 | } | ||
| 75 | else if (sizeof(IMAGE_DOS_HEADER) > cbRead || IMAGE_DOS_SIGNATURE != dosHeader.e_magic) | ||
| 76 | { | ||
| 77 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 78 | ExitOnRootFailure(hr, "Failed to find valid DOS image header in buffer."); | ||
| 79 | } | ||
| 80 | |||
| 81 | // | ||
| 82 | // Now, make sure we have a valid NT signature. | ||
| 83 | // | ||
| 84 | |||
| 85 | // seek to new header | ||
| 86 | li.QuadPart = dosHeader.e_lfanew; | ||
| 87 | if (!::SetFilePointerEx(pSection->hEngineFile, li, NULL, FILE_BEGIN)) | ||
| 88 | { | ||
| 89 | ExitWithLastError(hr, "Failed to seek to NT header."); | ||
| 90 | } | ||
| 91 | |||
| 92 | // read NT header | ||
| 93 | if (!::ReadFile(pSection->hEngineFile, &ntHeader, sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER), &cbRead, NULL)) | ||
| 94 | { | ||
| 95 | ExitWithLastError(hr, "Failed to read NT header."); | ||
| 96 | } | ||
| 97 | else if ((sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER)) > cbRead || IMAGE_NT_SIGNATURE != ntHeader.Signature) | ||
| 98 | { | ||
| 99 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 100 | ExitOnRootFailure(hr, "Failed to find valid NT image header in buffer."); | ||
| 101 | } | ||
| 102 | |||
| 103 | // Get the table offsets. | ||
| 104 | dwChecksumOffset = dosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER) + (sizeof(DWORD) * 16); | ||
| 105 | dwCertificateTableOffset = dosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS) - (sizeof(IMAGE_DATA_DIRECTORY) * (IMAGE_NUMBEROF_DIRECTORY_ENTRIES - IMAGE_DIRECTORY_ENTRY_SECURITY)); | ||
| 106 | |||
| 107 | // Seek into the certificate table to get the signature size. | ||
| 108 | li.QuadPart = dwCertificateTableOffset; | ||
| 109 | if (!::SetFilePointerEx(pSection->hEngineFile, li, NULL, FILE_BEGIN)) | ||
| 110 | { | ||
| 111 | ExitWithLastError(hr, "Failed to seek to section info."); | ||
| 112 | } | ||
| 113 | |||
| 114 | if (!::ReadFile(pSection->hEngineFile, &dwSignatureOffset, sizeof(dwSignatureOffset), &cbRead, NULL)) | ||
| 115 | { | ||
| 116 | ExitWithLastError(hr, "Failed to read signature offset."); | ||
| 117 | } | ||
| 118 | |||
| 119 | if (!::ReadFile(pSection->hEngineFile, &cbSignature, sizeof(cbSignature), &cbRead, NULL)) | ||
| 120 | { | ||
| 121 | ExitWithLastError(hr, "Failed to read signature size."); | ||
| 122 | } | ||
| 123 | |||
| 124 | // | ||
| 125 | // Finally, get into the section table and look for the Burn section info. | ||
| 126 | // | ||
| 127 | |||
| 128 | // seek past optional headers | ||
| 129 | li.QuadPart = dosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER) + ntHeader.FileHeader.SizeOfOptionalHeader; | ||
| 130 | if (!::SetFilePointerEx(pSection->hEngineFile, li, NULL, FILE_BEGIN)) | ||
| 131 | { | ||
| 132 | ExitWithLastError(hr, "Failed to seek past optional headers."); | ||
| 133 | } | ||
| 134 | |||
| 135 | // read sections one by one until we find our section | ||
| 136 | for (DWORD i = 0; ; ++i) | ||
| 137 | { | ||
| 138 | // read section | ||
| 139 | if (!::ReadFile(pSection->hEngineFile, §ionHeader, sizeof(IMAGE_SECTION_HEADER), &cbRead, NULL)) | ||
| 140 | { | ||
| 141 | ExitWithLastError(hr, "Failed to read image section header, index: %u", i); | ||
| 142 | } | ||
| 143 | if (sizeof(IMAGE_SECTION_HEADER) > cbRead) | ||
| 144 | { | ||
| 145 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 146 | ExitOnRootFailure(hr, "Failed to read complete image section header, index: %u", i); | ||
| 147 | } | ||
| 148 | |||
| 149 | // compare header name | ||
| 150 | C_ASSERT(sizeof(sectionHeader.Name) == sizeof(BURN_SECTION_NAME) - 1); | ||
| 151 | if (0 == memcmp(sectionHeader.Name, BURN_SECTION_NAME, sizeof(sectionHeader.Name))) | ||
| 152 | { | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | // fail if we hit the end | ||
| 157 | if (i + 1 >= ntHeader.FileHeader.NumberOfSections) | ||
| 158 | { | ||
| 159 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 160 | ExitOnRootFailure(hr, "Failed to find Burn section."); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | // | ||
| 165 | // We've arrived at the section info. | ||
| 166 | // | ||
| 167 | |||
| 168 | // check size of section | ||
| 169 | if (sizeof(BURN_SECTION_HEADER) > sectionHeader.SizeOfRawData) | ||
| 170 | { | ||
| 171 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 172 | ExitOnRootFailure(hr, "Failed to read section info, data to short: %u", sectionHeader.SizeOfRawData); | ||
| 173 | } | ||
| 174 | |||
| 175 | // allocate buffer for section info | ||
| 176 | pBurnSectionHeader = (BURN_SECTION_HEADER*)MemAlloc(sectionHeader.SizeOfRawData, TRUE); | ||
| 177 | ExitOnNull(pBurnSectionHeader, hr, E_OUTOFMEMORY, "Failed to allocate buffer for section info."); | ||
| 178 | |||
| 179 | // seek to section info | ||
| 180 | li.QuadPart = sectionHeader.PointerToRawData; | ||
| 181 | if (!::SetFilePointerEx(pSection->hEngineFile, li, NULL, FILE_BEGIN)) | ||
| 182 | { | ||
| 183 | ExitWithLastError(hr, "Failed to seek to section info."); | ||
| 184 | } | ||
| 185 | |||
| 186 | // Note the location of original checksum and signature information in the burn section header. | ||
| 187 | dwOriginalChecksumAndSignatureOffset = sectionHeader.PointerToRawData + (reinterpret_cast<LPBYTE>(&pBurnSectionHeader->dwOriginalChecksum) - reinterpret_cast<LPBYTE>(pBurnSectionHeader)); | ||
| 188 | |||
| 189 | // read section info | ||
| 190 | if (!::ReadFile(pSection->hEngineFile, pBurnSectionHeader, sectionHeader.SizeOfRawData, &cbRead, NULL)) | ||
| 191 | { | ||
| 192 | ExitWithLastError(hr, "Failed to read section info."); | ||
| 193 | } | ||
| 194 | else if (sectionHeader.SizeOfRawData > cbRead) | ||
| 195 | { | ||
| 196 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 197 | ExitOnRootFailure(hr, "Failed to read complete section info."); | ||
| 198 | } | ||
| 199 | |||
| 200 | // validate version of section info | ||
| 201 | if (BURN_SECTION_VERSION != pBurnSectionHeader->dwVersion) | ||
| 202 | { | ||
| 203 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 204 | ExitOnRootFailure(hr, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion); | ||
| 205 | } | ||
| 206 | |||
| 207 | hr = FileSizeByHandle(pSection->hSourceEngineFile, &llSize); | ||
| 208 | ExitOnFailure(hr, "Failed to get total size of bundle."); | ||
| 209 | |||
| 210 | pSection->cbStub = pBurnSectionHeader->dwStubSize; | ||
| 211 | |||
| 212 | // If there is an original signature use that to determine the engine size. | ||
| 213 | if (pBurnSectionHeader->dwOriginalSignatureOffset) | ||
| 214 | { | ||
| 215 | pSection->cbEngineSize = pBurnSectionHeader->dwOriginalSignatureOffset + pBurnSectionHeader->dwOriginalSignatureSize; | ||
| 216 | } | ||
| 217 | else if (dwSignatureOffset) // if there is a signature, use it. | ||
| 218 | { | ||
| 219 | pSection->cbEngineSize = dwSignatureOffset + cbSignature; | ||
| 220 | } | ||
| 221 | else // just use the stub and UX container as the size of the engine. | ||
| 222 | { | ||
| 223 | pSection->cbEngineSize = pSection->cbStub + pBurnSectionHeader->rgcbContainers[0]; | ||
| 224 | } | ||
| 225 | |||
| 226 | pSection->qwBundleSize = static_cast<DWORD64>(llSize); | ||
| 227 | |||
| 228 | pSection->dwChecksumOffset = dwChecksumOffset; | ||
| 229 | pSection->dwCertificateTableOffset = dwCertificateTableOffset; | ||
| 230 | pSection->dwOriginalChecksumAndSignatureOffset = dwOriginalChecksumAndSignatureOffset; | ||
| 231 | |||
| 232 | pSection->dwOriginalChecksum = pBurnSectionHeader->dwOriginalChecksum; | ||
| 233 | pSection->dwOriginalSignatureOffset = pBurnSectionHeader->dwOriginalSignatureOffset; | ||
| 234 | pSection->dwOriginalSignatureSize = pBurnSectionHeader->dwOriginalSignatureSize; | ||
| 235 | |||
| 236 | pSection->dwFormat = pBurnSectionHeader->dwFormat; | ||
| 237 | pSection->cContainers = pBurnSectionHeader->cContainers; | ||
| 238 | pSection->rgcbContainers = (DWORD*)MemAlloc(sizeof(DWORD) * pSection->cContainers, TRUE); | ||
| 239 | ExitOnNull(pSection->rgcbContainers, hr, E_OUTOFMEMORY, "Failed to allocate memory for container sizes."); | ||
| 240 | |||
| 241 | memcpy(pSection->rgcbContainers, pBurnSectionHeader->rgcbContainers, sizeof(DWORD) * pSection->cContainers); | ||
| 242 | |||
| 243 | // TODO: verify more than just the GUID. | ||
| 244 | hr = VerifySectionMatchesMemoryPEHeader(pBurnSectionHeader->guidBundleId); | ||
| 245 | ExitOnRootFailure(hr, "PE Header from file didn't match PE Header in memory."); | ||
| 246 | |||
| 247 | LExit: | ||
| 248 | ReleaseMem(pBurnSectionHeader); | ||
| 249 | |||
| 250 | return hr; | ||
| 251 | } | ||
| 252 | |||
| 253 | extern "C" void SectionUninitialize( | ||
| 254 | __out BURN_SECTION* pSection | ||
| 255 | ) | ||
| 256 | { | ||
| 257 | ReleaseMem(pSection->rgcbContainers); | ||
| 258 | memset(pSection, 0, sizeof(BURN_SECTION)); | ||
| 259 | } | ||
| 260 | |||
| 261 | extern "C" HRESULT SectionGetAttachedContainerInfo( | ||
| 262 | __in BURN_SECTION* pSection, | ||
| 263 | __in DWORD iContainerIndex, | ||
| 264 | __in DWORD dwExpectedType, | ||
| 265 | __out DWORD64* pqwOffset, | ||
| 266 | __out DWORD64* pqwSize, | ||
| 267 | __out BOOL* pfPresent | ||
| 268 | ) | ||
| 269 | { | ||
| 270 | HRESULT hr = S_OK; | ||
| 271 | |||
| 272 | // validate container info | ||
| 273 | if (iContainerIndex >= pSection->cContainers) | ||
| 274 | { | ||
| 275 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 276 | ExitOnRootFailure(hr, "Failed to find container info, too few elements: %u", pSection->cContainers); | ||
| 277 | } | ||
| 278 | else if (dwExpectedType != pSection->dwFormat) | ||
| 279 | { | ||
| 280 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 281 | ExitOnRootFailure(hr, "Unexpected container format."); | ||
| 282 | } | ||
| 283 | |||
| 284 | // If we are asking for the UX container, find it right after the stub. | ||
| 285 | if (0 == iContainerIndex) | ||
| 286 | { | ||
| 287 | *pqwOffset = pSection->cbStub; | ||
| 288 | } | ||
| 289 | else // attached containers start after the whole engine. | ||
| 290 | { | ||
| 291 | *pqwOffset = pSection->cbEngineSize; | ||
| 292 | for (DWORD i = 1; i < iContainerIndex; ++i) | ||
| 293 | { | ||
| 294 | *pqwOffset += pSection->rgcbContainers[i]; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | *pqwSize = pSection->rgcbContainers[iContainerIndex]; | ||
| 299 | *pfPresent = (*pqwOffset + *pqwSize) <= pSection->qwBundleSize; | ||
| 300 | |||
| 301 | AssertSz(*pfPresent || pSection->qwBundleSize <= *pqwOffset, "An attached container should either be present or completely absent from the bundle. Found a case where the attached container is partially present which is wrong."); | ||
| 302 | |||
| 303 | LExit: | ||
| 304 | return hr; | ||
| 305 | } | ||
| 306 | |||
| 307 | HRESULT VerifySectionMatchesMemoryPEHeader( | ||
| 308 | __in REFGUID pBundleId | ||
| 309 | ) | ||
| 310 | { | ||
| 311 | HRESULT hr = S_OK; | ||
| 312 | BYTE* pbPEHeader = NULL; | ||
| 313 | PIMAGE_DOS_HEADER pDosHeader = NULL; | ||
| 314 | PIMAGE_NT_HEADERS pNtHeader = NULL; | ||
| 315 | PIMAGE_SECTION_HEADER pSections = NULL; | ||
| 316 | PIMAGE_SECTION_HEADER pSectionHeader = NULL; | ||
| 317 | BURN_SECTION_HEADER* pBurnSectionHeader = NULL; | ||
| 318 | |||
| 319 | pbPEHeader = reinterpret_cast<BYTE*>(::GetModuleHandleW(NULL)); | ||
| 320 | ExitOnNullWithLastError(pbPEHeader, hr, "Failed to get module handle to process."); | ||
| 321 | |||
| 322 | // | ||
| 323 | // First, make sure we have a valid DOS signature. | ||
| 324 | // | ||
| 325 | |||
| 326 | pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(pbPEHeader); | ||
| 327 | if (IMAGE_DOS_SIGNATURE != pDosHeader->e_magic) | ||
| 328 | { | ||
| 329 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 330 | ExitOnRootFailure(hr, "Failed to find valid DOS image header in buffer."); | ||
| 331 | } | ||
| 332 | |||
| 333 | // | ||
| 334 | // Now, make sure we have a valid NT signature. | ||
| 335 | // | ||
| 336 | |||
| 337 | pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(pbPEHeader + pDosHeader->e_lfanew); | ||
| 338 | if (IMAGE_NT_SIGNATURE != pNtHeader->Signature) | ||
| 339 | { | ||
| 340 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 341 | ExitOnRootFailure(hr, "Failed to find valid NT image header in buffer."); | ||
| 342 | } | ||
| 343 | |||
| 344 | // | ||
| 345 | // Finally, get into the section table and look for the Burn section info. | ||
| 346 | // | ||
| 347 | |||
| 348 | pSections = reinterpret_cast<PIMAGE_SECTION_HEADER>(pbPEHeader + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER) + pNtHeader->FileHeader.SizeOfOptionalHeader); | ||
| 349 | |||
| 350 | // Read sections one by one until we find our section. | ||
| 351 | for (DWORD i = 0; ; ++i) | ||
| 352 | { | ||
| 353 | pSectionHeader = pSections + i; | ||
| 354 | |||
| 355 | // Compare header name. | ||
| 356 | C_ASSERT(sizeof(pSectionHeader->Name) == sizeof(BURN_SECTION_NAME) - 1); | ||
| 357 | if (0 == memcmp(pSectionHeader->Name, BURN_SECTION_NAME, sizeof(pSectionHeader->Name))) | ||
| 358 | { | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | |||
| 362 | // Fail if we hit the end. | ||
| 363 | if (i + 1 >= pNtHeader->FileHeader.NumberOfSections) | ||
| 364 | { | ||
| 365 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 366 | ExitOnRootFailure(hr, "Failed to find Burn section."); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | // | ||
| 371 | // We've arrived at the section info. | ||
| 372 | // | ||
| 373 | |||
| 374 | // Check size of section. | ||
| 375 | if (sizeof(BURN_SECTION_HEADER) > pSectionHeader->SizeOfRawData) | ||
| 376 | { | ||
| 377 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 378 | ExitOnRootFailure(hr, "Failed to read section info, data to short: %u", pSectionHeader->SizeOfRawData); | ||
| 379 | } | ||
| 380 | |||
| 381 | // Get Burn section info. | ||
| 382 | pBurnSectionHeader = reinterpret_cast<BURN_SECTION_HEADER*>(pbPEHeader + pSectionHeader->VirtualAddress); | ||
| 383 | |||
| 384 | // Validate version of section info. | ||
| 385 | if (BURN_SECTION_VERSION != pBurnSectionHeader->dwVersion) | ||
| 386 | { | ||
| 387 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
| 388 | ExitOnRootFailure(hr, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion); | ||
| 389 | } | ||
| 390 | |||
| 391 | if (!::IsEqualGUID(pBundleId, pBurnSectionHeader->guidBundleId)) | ||
| 392 | { | ||
| 393 | hr = E_INVALIDDATA; | ||
| 394 | ExitOnRootFailure(hr, "Bundle guid didn't match the guid in the PE Header in memory."); | ||
| 395 | } | ||
| 396 | |||
| 397 | LExit: | ||
| 398 | return hr; | ||
| 399 | } | ||
