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