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 */
IMAGEHLP_GetNTHeaders(HANDLE handle,DWORD * pe_offset,IMAGE_NT_HEADERS32 * nt32,IMAGE_NT_HEADERS64 * nt64)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 */
IMAGEHLP_GetSecurityDirOffset(HANDLE handle,DWORD * pdwOfs,DWORD * pdwSize)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 */
IMAGEHLP_SetSecurityDirOffset(HANDLE handle,DWORD dwOfs,DWORD dwSize)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 */
IMAGEHLP_GetCertificateOffset(HANDLE handle,DWORD num,DWORD * pdwOfs,DWORD * pdwSize)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 */
IMAGEHLP_RecalculateChecksum(HANDLE handle)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
ImageAddCertificate(HANDLE FileHandle,LPWIN_CERTIFICATE Certificate,PDWORD Index)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 */
ImageEnumerateCertificates(HANDLE handle,WORD TypeFilter,PDWORD CertificateCount,PDWORD Indices,DWORD IndexCount)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 */
ImageGetCertificateData(HANDLE handle,DWORD Index,LPWIN_CERTIFICATE Certificate,PDWORD RequiredLength)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 */
ImageGetCertificateHeader(HANDLE handle,DWORD index,LPWIN_CERTIFICATE pCert)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 */
IMAGEHLP_GetSectionOffset(IMAGE_SECTION_HEADER * hdr,DWORD num_sections,LPCSTR section,PDWORD size,PDWORD base)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 */
IMAGEHLP_ReportSectionFromOffset(DWORD offset,DWORD size,BYTE * map,DWORD fileSize,DIGEST_FUNCTION DigestFunction,DIGEST_HANDLE DigestHandle)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 */
IMAGEHLP_ReportSection(IMAGE_SECTION_HEADER * section_headers,DWORD num_sections,LPCSTR section,BYTE * map,DWORD fileSize,DIGEST_FUNCTION DigestFunction,DIGEST_HANDLE DigestHandle)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 */
IMAGEHLP_ReportCodeSections(IMAGE_SECTION_HEADER * hdr,DWORD num_sections,BYTE * map,DWORD fileSize,DIGEST_FUNCTION DigestFunction,DIGEST_HANDLE DigestHandle)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 */
IMAGEHLP_ReportImportSection(IMAGE_SECTION_HEADER * hdr,DWORD num_sections,BYTE * map,DWORD fileSize,DWORD DigestLevel,DIGEST_FUNCTION DigestFunction,DIGEST_HANDLE DigestHandle)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 */
ImageGetDigestStream(HANDLE FileHandle,DWORD DigestLevel,DIGEST_FUNCTION DigestFunction,DIGEST_HANDLE DigestHandle)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 */
ImageRemoveCertificate(HANDLE FileHandle,DWORD Index)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