1 /* 2 * IMAGEHLP library 3 * 4 * Copyright 1998 Patrik Stridvall 5 * Copyright 2003 Mike McCormack 6 * Copyright 2009 Owen Rudge for CodeWeavers 7 * Copyright 2010 Juan Lang 8 * Copyright 2010 Andrey Turkin 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25 #include "precomp.h" 26 27 /* 28 * These functions are partially documented at: 29 * http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt 30 */ 31 32 #define HDR_FAIL -1 33 #define HDR_NT32 0 34 #define HDR_NT64 1 35 36 /*********************************************************************** 37 * IMAGEHLP_GetNTHeaders (INTERNAL) 38 * 39 * Return the IMAGE_NT_HEADERS for a PE file, after validating magic 40 * numbers and distinguishing between 32-bit and 64-bit files. 41 */ 42 static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64) 43 { 44 IMAGE_DOS_HEADER dos_hdr; 45 DWORD count; 46 BOOL r; 47 48 TRACE("handle %p\n", handle); 49 50 if ((!nt32) || (!nt64)) 51 return HDR_FAIL; 52 53 /* read the DOS header */ 54 count = SetFilePointer(handle, 0, NULL, FILE_BEGIN); 55 56 if (count == INVALID_SET_FILE_POINTER) 57 return HDR_FAIL; 58 59 count = 0; 60 61 r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL); 62 63 if (!r) 64 return HDR_FAIL; 65 66 if (count != sizeof dos_hdr) 67 return HDR_FAIL; 68 69 /* verify magic number of 'MZ' */ 70 if (dos_hdr.e_magic != IMAGE_DOS_SIGNATURE) 71 return HDR_FAIL; 72 73 if (pe_offset != NULL) 74 *pe_offset = dos_hdr.e_lfanew; 75 76 /* read the PE header */ 77 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN); 78 79 if (count == INVALID_SET_FILE_POINTER) 80 return HDR_FAIL; 81 82 count = 0; 83 84 r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL); 85 86 if (!r) 87 return HDR_FAIL; 88 89 if (count != sizeof(IMAGE_NT_HEADERS32)) 90 return HDR_FAIL; 91 92 /* verify NT signature */ 93 if (nt32->Signature != IMAGE_NT_SIGNATURE) 94 return HDR_FAIL; 95 96 /* check if we have a 32-bit or 64-bit executable */ 97 switch (nt32->OptionalHeader.Magic) 98 { 99 case IMAGE_NT_OPTIONAL_HDR32_MAGIC: 100 return HDR_NT32; 101 102 case IMAGE_NT_OPTIONAL_HDR64_MAGIC: 103 /* Re-read as 64-bit */ 104 105 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN); 106 107 if (count == INVALID_SET_FILE_POINTER) 108 return HDR_FAIL; 109 110 count = 0; 111 112 r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL); 113 114 if (!r) 115 return HDR_FAIL; 116 117 if (count != sizeof(IMAGE_NT_HEADERS64)) 118 return HDR_FAIL; 119 120 /* verify NT signature */ 121 if (nt64->Signature != IMAGE_NT_SIGNATURE) 122 return HDR_FAIL; 123 124 return HDR_NT64; 125 } 126 127 return HDR_FAIL; 128 } 129 130 /*********************************************************************** 131 * IMAGEHLP_GetSecurityDirOffset (INTERNAL) 132 * 133 * Read a file's PE header, and return the offset and size of the 134 * security directory. 135 */ 136 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle, 137 DWORD *pdwOfs, DWORD *pdwSize ) 138 { 139 IMAGE_NT_HEADERS32 nt_hdr32; 140 IMAGE_NT_HEADERS64 nt_hdr64; 141 IMAGE_DATA_DIRECTORY *sd; 142 int ret; 143 144 ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64); 145 146 if (ret == HDR_NT32) 147 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; 148 else if (ret == HDR_NT64) 149 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; 150 else 151 return FALSE; 152 153 TRACE("ret = %d size = %x addr = %x\n", ret, sd->Size, sd->VirtualAddress); 154 155 *pdwSize = sd->Size; 156 *pdwOfs = sd->VirtualAddress; 157 158 return TRUE; 159 } 160 161 /*********************************************************************** 162 * IMAGEHLP_SetSecurityDirOffset (INTERNAL) 163 * 164 * Read a file's PE header, and update the offset and size of the 165 * security directory. 166 */ 167 static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle, 168 DWORD dwOfs, DWORD dwSize) 169 { 170 IMAGE_NT_HEADERS32 nt_hdr32; 171 IMAGE_NT_HEADERS64 nt_hdr64; 172 IMAGE_DATA_DIRECTORY *sd; 173 int ret, nt_hdr_size = 0; 174 DWORD pe_offset; 175 void *nt_hdr; 176 DWORD count; 177 BOOL r; 178 179 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64); 180 181 if (ret == HDR_NT32) 182 { 183 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; 184 185 nt_hdr = &nt_hdr32; 186 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32); 187 } 188 else if (ret == HDR_NT64) 189 { 190 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY]; 191 192 nt_hdr = &nt_hdr64; 193 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64); 194 } 195 else 196 return FALSE; 197 198 sd->Size = dwSize; 199 sd->VirtualAddress = dwOfs; 200 201 TRACE("size = %x addr = %x\n", sd->Size, sd->VirtualAddress); 202 203 /* write the header back again */ 204 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN); 205 206 if (count == INVALID_SET_FILE_POINTER) 207 return FALSE; 208 209 count = 0; 210 211 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL); 212 213 if (!r) 214 return FALSE; 215 216 if (count != nt_hdr_size) 217 return FALSE; 218 219 return TRUE; 220 } 221 222 /*********************************************************************** 223 * IMAGEHLP_GetCertificateOffset (INTERNAL) 224 * 225 * Read a file's PE header, and return the offset and size of the 226 * security directory. 227 */ 228 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num, 229 DWORD *pdwOfs, DWORD *pdwSize ) 230 { 231 DWORD size, count, offset, len, sd_VirtualAddr; 232 BOOL r; 233 234 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size ); 235 if( !r ) 236 return FALSE; 237 238 offset = 0; 239 /* take the n'th certificate */ 240 while( 1 ) 241 { 242 /* read the length of the current certificate */ 243 count = SetFilePointer( handle, sd_VirtualAddr + offset, 244 NULL, FILE_BEGIN ); 245 if( count == INVALID_SET_FILE_POINTER ) 246 return FALSE; 247 r = ReadFile( handle, &len, sizeof len, &count, NULL ); 248 if( !r ) 249 return FALSE; 250 if( count != sizeof len ) 251 return FALSE; 252 253 /* check the certificate is not too big or too small */ 254 if( len < sizeof len ) 255 return FALSE; 256 if( len > (size-offset) ) 257 return FALSE; 258 if( !num-- ) 259 break; 260 261 /* calculate the offset of the next certificate */ 262 offset += len; 263 264 /* padded out to the nearest 8-byte boundary */ 265 if( len % 8 ) 266 offset += 8 - (len % 8); 267 268 if( offset >= size ) 269 return FALSE; 270 } 271 272 *pdwOfs = sd_VirtualAddr + offset; 273 *pdwSize = len; 274 275 TRACE("len = %x addr = %x\n", len, sd_VirtualAddr + offset); 276 277 return TRUE; 278 } 279 280 /*********************************************************************** 281 * IMAGEHLP_RecalculateChecksum (INTERNAL) 282 * 283 * Update the NT header checksum for the specified file. 284 */ 285 static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle) 286 { 287 DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size; 288 IMAGE_NT_HEADERS32 nt_hdr32; 289 IMAGE_NT_HEADERS64 nt_hdr64; 290 LPVOID BaseAddress; 291 HANDLE hMapping; 292 DWORD *CheckSum; 293 void *nt_hdr; 294 int ret; 295 BOOL r; 296 297 TRACE("handle %p\n", handle); 298 299 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64); 300 301 if (ret == HDR_NT32) 302 { 303 CheckSum = &nt_hdr32.OptionalHeader.CheckSum; 304 305 nt_hdr = &nt_hdr32; 306 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32); 307 } 308 else if (ret == HDR_NT64) 309 { 310 CheckSum = &nt_hdr64.OptionalHeader.CheckSum; 311 312 nt_hdr = &nt_hdr64; 313 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64); 314 } 315 else 316 return FALSE; 317 318 hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL); 319 320 if (!hMapping) 321 return FALSE; 322 323 BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); 324 325 if (!BaseAddress) 326 { 327 CloseHandle(hMapping); 328 return FALSE; 329 } 330 331 FileLength = GetFileSize(handle, NULL); 332 333 *CheckSum = 0; 334 CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum); 335 336 UnmapViewOfFile(BaseAddress); 337 CloseHandle(hMapping); 338 339 if (*CheckSum) 340 { 341 /* write the header back again */ 342 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN); 343 344 if (count == INVALID_SET_FILE_POINTER) 345 return FALSE; 346 347 count = 0; 348 349 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL); 350 351 if (!r) 352 return FALSE; 353 354 if (count != nt_hdr_size) 355 return FALSE; 356 357 return TRUE; 358 } 359 360 return FALSE; 361 } 362 363 /*********************************************************************** 364 * ImageAddCertificate (IMAGEHLP.@) 365 * 366 * Adds the specified certificate to the security directory of 367 * open PE file. 368 */ 369 370 BOOL WINAPI ImageAddCertificate( 371 HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index) 372 { 373 DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0; 374 WIN_CERTIFICATE hdr; 375 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate; 376 BOOL r; 377 378 TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index); 379 380 r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size); 381 382 /* If we've already got a security directory, find the end of it */ 383 if ((r) && (sd_VirtualAddr != 0)) 384 { 385 /* Check if the security directory is at the end of the file. 386 If not, we should probably relocate it. */ 387 if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size) 388 { 389 FIXME("Security directory already present but not located at EOF, not adding certificate\n"); 390 391 SetLastError(ERROR_NOT_SUPPORTED); 392 return FALSE; 393 } 394 395 while (offset < size) 396 { 397 /* read the length of the current certificate */ 398 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, 399 NULL, FILE_BEGIN); 400 401 if (count == INVALID_SET_FILE_POINTER) 402 return FALSE; 403 404 r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL); 405 406 if (!r) 407 return FALSE; 408 409 if (count != cert_hdr_size) 410 return FALSE; 411 412 /* check the certificate is not too big or too small */ 413 if (hdr.dwLength < cert_hdr_size) 414 return FALSE; 415 416 if (hdr.dwLength > (size-offset)) 417 return FALSE; 418 419 /* next certificate */ 420 offset += hdr.dwLength; 421 422 /* padded out to the nearest 8-byte boundary */ 423 if (hdr.dwLength % 8) 424 offset += 8 - (hdr.dwLength % 8); 425 426 index++; 427 } 428 429 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN); 430 431 if (count == INVALID_SET_FILE_POINTER) 432 return FALSE; 433 } 434 else 435 { 436 sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END); 437 438 if (sd_VirtualAddr == INVALID_SET_FILE_POINTER) 439 return FALSE; 440 } 441 442 /* Write the certificate to the file */ 443 r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL); 444 445 if (!r) 446 return FALSE; 447 448 /* Pad out if necessary */ 449 if (Certificate->dwLength % 8) 450 { 451 char null[8]; 452 453 ZeroMemory(null, 8); 454 WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), &count, NULL); 455 456 size += 8 - (Certificate->dwLength % 8); 457 } 458 459 size += Certificate->dwLength; 460 461 /* Update the security directory offset and size */ 462 if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size)) 463 return FALSE; 464 465 if (!IMAGEHLP_RecalculateChecksum(FileHandle)) 466 return FALSE; 467 468 if(Index) 469 *Index = index; 470 return TRUE; 471 } 472 473 /*********************************************************************** 474 * ImageEnumerateCertificates (IMAGEHLP.@) 475 */ 476 BOOL WINAPI ImageEnumerateCertificates( 477 HANDLE handle, WORD TypeFilter, PDWORD CertificateCount, 478 PDWORD Indices, DWORD IndexCount) 479 { 480 DWORD size, count, offset, sd_VirtualAddr, index; 481 WIN_CERTIFICATE hdr; 482 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate; 483 BOOL r; 484 485 TRACE("%p %hd %p %p %d\n", 486 handle, TypeFilter, CertificateCount, Indices, IndexCount); 487 488 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size ); 489 if( !r ) 490 return FALSE; 491 492 offset = 0; 493 index = 0; 494 *CertificateCount = 0; 495 while( offset < size ) 496 { 497 /* read the length of the current certificate */ 498 count = SetFilePointer( handle, sd_VirtualAddr + offset, 499 NULL, FILE_BEGIN ); 500 if( count == INVALID_SET_FILE_POINTER ) 501 return FALSE; 502 r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL ); 503 if( !r ) 504 return FALSE; 505 if( count != cert_hdr_size ) 506 return FALSE; 507 508 TRACE("Size = %08x id = %08hx\n", 509 hdr.dwLength, hdr.wCertificateType ); 510 511 /* check the certificate is not too big or too small */ 512 if( hdr.dwLength < cert_hdr_size ) 513 return FALSE; 514 if( hdr.dwLength > (size-offset) ) 515 return FALSE; 516 517 if( (TypeFilter == CERT_SECTION_TYPE_ANY) || 518 (TypeFilter == hdr.wCertificateType) ) 519 { 520 (*CertificateCount)++; 521 if(Indices && *CertificateCount <= IndexCount) 522 *Indices++ = index; 523 } 524 525 /* next certificate */ 526 offset += hdr.dwLength; 527 528 /* padded out to the nearest 8-byte boundary */ 529 if (hdr.dwLength % 8) 530 offset += 8 - (hdr.dwLength % 8); 531 532 index++; 533 } 534 535 return TRUE; 536 } 537 538 /*********************************************************************** 539 * ImageGetCertificateData (IMAGEHLP.@) 540 * 541 * FIXME: not sure that I'm dealing with the Index the right way 542 */ 543 BOOL WINAPI ImageGetCertificateData( 544 HANDLE handle, DWORD Index, 545 LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength) 546 { 547 DWORD r, offset, ofs, size, count; 548 549 TRACE("%p %d %p %p\n", handle, Index, Certificate, RequiredLength); 550 551 if( !RequiredLength) 552 { 553 SetLastError( ERROR_INVALID_PARAMETER ); 554 return FALSE; 555 } 556 557 if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) ) 558 return FALSE; 559 560 if( *RequiredLength < size ) 561 { 562 *RequiredLength = size; 563 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 564 return FALSE; 565 } 566 567 if( !Certificate ) 568 { 569 SetLastError( ERROR_INVALID_PARAMETER ); 570 return FALSE; 571 } 572 573 *RequiredLength = size; 574 575 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN ); 576 if( offset == INVALID_SET_FILE_POINTER ) 577 return FALSE; 578 579 r = ReadFile( handle, Certificate, size, &count, NULL ); 580 if( !r ) 581 return FALSE; 582 if( count != size ) 583 return FALSE; 584 585 TRACE("OK\n"); 586 SetLastError( NO_ERROR ); 587 588 return TRUE; 589 } 590 591 /*********************************************************************** 592 * ImageGetCertificateHeader (IMAGEHLP.@) 593 */ 594 BOOL WINAPI ImageGetCertificateHeader( 595 HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert) 596 { 597 DWORD r, offset, ofs, size, count; 598 const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate; 599 600 TRACE("%p %d %p\n", handle, index, pCert); 601 602 if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) ) 603 return FALSE; 604 605 if( size < cert_hdr_size ) 606 return FALSE; 607 608 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN ); 609 if( offset == INVALID_SET_FILE_POINTER ) 610 return FALSE; 611 612 r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL ); 613 if( !r ) 614 return FALSE; 615 if( count != cert_hdr_size ) 616 return FALSE; 617 618 TRACE("OK\n"); 619 620 return TRUE; 621 } 622 623 /* Finds the section named section in the array of IMAGE_SECTION_HEADERs hdr. If 624 * found, returns the offset to the section. Otherwise returns 0. If the section 625 * is found, optionally returns the size of the section (in size) and the base 626 * address of the section (in base.) 627 */ 628 static DWORD IMAGEHLP_GetSectionOffset( IMAGE_SECTION_HEADER *hdr, 629 DWORD num_sections, LPCSTR section, PDWORD size, PDWORD base ) 630 { 631 DWORD i, offset = 0; 632 633 for( i = 0; !offset && i < num_sections; i++, hdr++ ) 634 { 635 if( !memcmp( hdr->Name, section, strlen(section) ) ) 636 { 637 offset = hdr->PointerToRawData; 638 if( size ) 639 *size = hdr->SizeOfRawData; 640 if( base ) 641 *base = hdr->VirtualAddress; 642 } 643 } 644 return offset; 645 } 646 647 /* Calls DigestFunction e bytes at offset offset from the file mapped at map. 648 * Returns the return value of DigestFunction, or FALSE if the data is not available. 649 */ 650 static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size, 651 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) 652 { 653 if( offset + size > fileSize ) 654 { 655 SetLastError(ERROR_INVALID_PARAMETER); 656 return FALSE; 657 } 658 return DigestFunction( DigestHandle, map + offset, size ); 659 } 660 661 /* Finds the section named section among the IMAGE_SECTION_HEADERs in 662 * section_headers and calls DigestFunction for this section. Returns 663 * the return value from DigestFunction, or FALSE if the data could not be read. 664 */ 665 static BOOL IMAGEHLP_ReportSection( IMAGE_SECTION_HEADER *section_headers, 666 DWORD num_sections, LPCSTR section, BYTE *map, DWORD fileSize, 667 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) 668 { 669 DWORD offset, size = 0; 670 671 offset = IMAGEHLP_GetSectionOffset( section_headers, num_sections, section, 672 &size, NULL ); 673 if( !offset ) 674 return FALSE; 675 return IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, 676 DigestFunction, DigestHandle ); 677 } 678 679 /* Calls DigestFunction for all sections with the IMAGE_SCN_CNT_CODE flag set. 680 * Returns the return value from * DigestFunction, or FALSE if a section could not be read. 681 */ 682 static BOOL IMAGEHLP_ReportCodeSections( IMAGE_SECTION_HEADER *hdr, DWORD num_sections, 683 BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) 684 { 685 DWORD i; 686 BOOL ret = TRUE; 687 688 for( i = 0; ret && i < num_sections; i++, hdr++ ) 689 { 690 if( hdr->Characteristics & IMAGE_SCN_CNT_CODE ) 691 ret = IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData, 692 hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle ); 693 } 694 return ret; 695 } 696 697 /* Reports the import section from the file FileHandle. If 698 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set in DigestLevel, reports the entire 699 * import section. 700 * FIXME: if it's not set, the function currently fails. 701 */ 702 static BOOL IMAGEHLP_ReportImportSection( IMAGE_SECTION_HEADER *hdr, 703 DWORD num_sections, BYTE *map, DWORD fileSize, DWORD DigestLevel, 704 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) 705 { 706 BOOL ret = FALSE; 707 DWORD offset, size, base; 708 709 /* Get import data */ 710 offset = IMAGEHLP_GetSectionOffset( hdr, num_sections, ".idata", &size, 711 &base ); 712 if( !offset ) 713 return FALSE; 714 715 /* If CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set, the entire 716 * section is reported. Otherwise, the debug info section is 717 * decoded and reported piecemeal. See tests. However, I haven't been 718 * able to figure out how the native implementation decides which values 719 * to report. Either it's buggy or my understanding is flawed. 720 */ 721 if( DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO ) 722 ret = IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, 723 DigestFunction, DigestHandle ); 724 else 725 { 726 FIXME("not supported except for CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO\n"); 727 SetLastError(ERROR_INVALID_PARAMETER); 728 ret = FALSE; 729 } 730 731 return ret; 732 } 733 734 /*********************************************************************** 735 * ImageGetDigestStream (IMAGEHLP.@) 736 * 737 * Gets a stream of bytes from a PE file over which a hash might be computed to 738 * verify that the image has not changed. Useful for creating a certificate to 739 * be added to the file with ImageAddCertificate. 740 * 741 * PARAMS 742 * FileHandle [In] File for which to return a stream. 743 * DigestLevel [In] Flags to control which portions of the file to return. 744 * 0 is allowed, as is any combination of: 745 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: reports the entire 746 * import section rather than selected portions of it. 747 * CERT_PE_IMAGE_DIGEST_DEBUG_INFO: reports the debug section. 748 * CERT_PE_IMAGE_DIGEST_RESOURCES: reports the resources 749 section. 750 * DigestFunction [In] Callback function. 751 * DigestHandle [In] Handle passed as first parameter to DigestFunction. 752 * 753 * RETURNS 754 * TRUE if successful. 755 * FALSE if unsuccessful. GetLastError returns more about the error. 756 * 757 * NOTES 758 * Only supports 32-bit PE files, not tested with any other format. 759 * Reports data in the following order: 760 * 1. The file headers are reported first 761 * 2. Any code sections are reported next. 762 * 3. The data (".data" and ".rdata") sections are reported next. 763 * 4. The import section is reported next. 764 * 5. If CERT_PE_IMAGE_DIGEST_DEBUG_INFO is set in DigestLevel, the debug section is 765 * reported next. 766 * 6. If CERT_PE_IMAGE_DIGEST_RESOURCES is set in DigestLevel, the resources section 767 * is reported next. 768 * 769 * BUGS 770 * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO must be specified, returns an error if not. 771 */ 772 BOOL WINAPI ImageGetDigestStream( 773 HANDLE FileHandle, DWORD DigestLevel, 774 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle) 775 { 776 DWORD error = 0; 777 BOOL ret = FALSE; 778 DWORD offset, size, num_sections, fileSize; 779 HANDLE hMap = INVALID_HANDLE_VALUE; 780 BYTE *map = NULL; 781 IMAGE_DOS_HEADER *dos_hdr; 782 IMAGE_NT_HEADERS *nt_hdr; 783 IMAGE_SECTION_HEADER *section_headers; 784 785 TRACE("(%p, %d, %p, %p)\n", FileHandle, DigestLevel, DigestFunction, 786 DigestHandle); 787 788 /* Get the file size */ 789 if( !FileHandle ) 790 goto invalid_parameter; 791 fileSize = GetFileSize( FileHandle, NULL ); 792 if(fileSize == INVALID_FILE_SIZE ) 793 goto invalid_parameter; 794 795 /* map file */ 796 hMap = CreateFileMappingW( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); 797 if( hMap == INVALID_HANDLE_VALUE ) 798 goto invalid_parameter; 799 map = MapViewOfFile( hMap, FILE_MAP_COPY, 0, 0, 0 ); 800 if( !map ) 801 goto invalid_parameter; 802 803 /* Read the file header */ 804 if( fileSize < sizeof(IMAGE_DOS_HEADER) ) 805 goto invalid_parameter; 806 dos_hdr = (IMAGE_DOS_HEADER *)map; 807 808 if( dos_hdr->e_magic != IMAGE_DOS_SIGNATURE ) 809 goto invalid_parameter; 810 offset = dos_hdr->e_lfanew; 811 if( !offset || offset > fileSize ) 812 goto invalid_parameter; 813 ret = DigestFunction( DigestHandle, map, offset ); 814 if( !ret ) 815 goto end; 816 817 /* Read the NT header */ 818 if( offset + sizeof(IMAGE_NT_HEADERS) > fileSize ) 819 goto invalid_parameter; 820 nt_hdr = (IMAGE_NT_HEADERS *)(map + offset); 821 if( nt_hdr->Signature != IMAGE_NT_SIGNATURE ) 822 goto invalid_parameter; 823 /* It's clear why the checksum is cleared, but why only these size headers? 824 */ 825 nt_hdr->OptionalHeader.SizeOfInitializedData = 0; 826 nt_hdr->OptionalHeader.SizeOfImage = 0; 827 nt_hdr->OptionalHeader.CheckSum = 0; 828 size = sizeof(nt_hdr->Signature) + sizeof(nt_hdr->FileHeader) + 829 nt_hdr->FileHeader.SizeOfOptionalHeader; 830 ret = DigestFunction( DigestHandle, map + offset, size ); 831 if( !ret ) 832 goto end; 833 834 /* Read the section headers */ 835 offset += size; 836 num_sections = nt_hdr->FileHeader.NumberOfSections; 837 size = num_sections * sizeof(IMAGE_SECTION_HEADER); 838 if( offset + size > fileSize ) 839 goto invalid_parameter; 840 ret = DigestFunction( DigestHandle, map + offset, size ); 841 if( !ret ) 842 goto end; 843 844 section_headers = (IMAGE_SECTION_HEADER *)(map + offset); 845 IMAGEHLP_ReportCodeSections( section_headers, num_sections, 846 map, fileSize, DigestFunction, DigestHandle ); 847 IMAGEHLP_ReportSection( section_headers, num_sections, ".data", 848 map, fileSize, DigestFunction, DigestHandle ); 849 IMAGEHLP_ReportSection( section_headers, num_sections, ".rdata", 850 map, fileSize, DigestFunction, DigestHandle ); 851 IMAGEHLP_ReportImportSection( section_headers, num_sections, 852 map, fileSize, DigestLevel, DigestFunction, DigestHandle ); 853 if( DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO ) 854 IMAGEHLP_ReportSection( section_headers, num_sections, ".debug", 855 map, fileSize, DigestFunction, DigestHandle ); 856 if( DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES ) 857 IMAGEHLP_ReportSection( section_headers, num_sections, ".rsrc", 858 map, fileSize, DigestFunction, DigestHandle ); 859 860 end: 861 if( map ) 862 UnmapViewOfFile( map ); 863 if( hMap != INVALID_HANDLE_VALUE ) 864 CloseHandle( hMap ); 865 if( error ) 866 SetLastError(error); 867 return ret; 868 869 invalid_parameter: 870 error = ERROR_INVALID_PARAMETER; 871 goto end; 872 } 873 874 /*********************************************************************** 875 * ImageRemoveCertificate (IMAGEHLP.@) 876 */ 877 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index) 878 { 879 DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0; 880 DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0; 881 LPVOID cert_data; 882 BOOL r; 883 884 TRACE("(%p, %d)\n", FileHandle, Index); 885 886 r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0); 887 888 if ((!r) || (count == 0)) 889 return FALSE; 890 891 if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) || 892 (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size))) 893 return FALSE; 894 895 /* Ignore any padding we have, too */ 896 if (cert_size % 8) 897 cert_size_padded = cert_size + (8 - (cert_size % 8)); 898 else 899 cert_size_padded = cert_size; 900 901 data_size = size - (offset - sd_VirtualAddr) - cert_size_padded; 902 903 if (data_size == 0) 904 { 905 ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN); 906 907 if (ret == INVALID_SET_FILE_POINTER) 908 return FALSE; 909 } 910 else 911 { 912 cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size); 913 914 if (!cert_data) 915 return FALSE; 916 917 ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN); 918 919 if (ret == INVALID_SET_FILE_POINTER) 920 goto error; 921 922 /* Read any subsequent certificates */ 923 r = ReadFile(FileHandle, cert_data, data_size, &count, NULL); 924 925 if ((!r) || (count != data_size)) 926 goto error; 927 928 SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN); 929 930 /* Write them one index back */ 931 r = WriteFile(FileHandle, cert_data, data_size, &count, NULL); 932 933 if ((!r) || (count != data_size)) 934 goto error; 935 936 HeapFree(GetProcessHeap(), 0, cert_data); 937 } 938 939 /* If security directory is at end of file, trim the file */ 940 if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size) 941 SetEndOfFile(FileHandle); 942 943 if (count == 1) 944 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0); 945 else 946 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded); 947 948 if (!r) 949 return FALSE; 950 951 if (!IMAGEHLP_RecalculateChecksum(FileHandle)) 952 return FALSE; 953 954 return TRUE; 955 956 error: 957 HeapFree(GetProcessHeap(), 0, cert_data); 958 return FALSE; 959 } 960