push 5b1efc32b5a8acb1d5b5e60584746392dd0c436e
[wine/hacks.git] / dlls / imagehlp / integrity.c
blob72bf1552eff9562157005949116c06aee0badc31
1 /*
2 * IMAGEHLP library
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2003 Mike McCormack
6 * Copyright 2009 Owen Rudge for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winternl.h"
29 #include "winnt.h"
30 #include "imagehlp.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
36 * These functions are partially documented at:
37 * http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
40 #define HDR_FAIL -1
41 #define HDR_NT32 0
42 #define HDR_NT64 1
44 /***********************************************************************
45 * IMAGEHLP_GetNTHeaders (INTERNAL)
47 * Return the IMAGE_NT_HEADERS for a PE file, after validating magic
48 * numbers and distinguishing between 32-bit and 64-bit files.
50 static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64)
52 IMAGE_DOS_HEADER dos_hdr;
53 DWORD count;
54 BOOL r;
56 TRACE("handle %p\n", handle);
58 if ((!nt32) || (!nt64))
59 return HDR_FAIL;
61 /* read the DOS header */
62 count = SetFilePointer(handle, 0, NULL, FILE_BEGIN);
64 if (count == INVALID_SET_FILE_POINTER)
65 return HDR_FAIL;
67 count = 0;
69 r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL);
71 if (!r)
72 return HDR_FAIL;
74 if (count != sizeof dos_hdr)
75 return HDR_FAIL;
77 /* verify magic number of 'MZ' */
78 if (dos_hdr.e_magic != 0x5A4D)
79 return HDR_FAIL;
81 if (pe_offset != NULL)
82 *pe_offset = dos_hdr.e_lfanew;
84 /* read the PE header */
85 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
87 if (count == INVALID_SET_FILE_POINTER)
88 return HDR_FAIL;
90 count = 0;
92 r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL);
94 if (!r)
95 return HDR_FAIL;
97 if (count != sizeof(IMAGE_NT_HEADERS32))
98 return HDR_FAIL;
100 /* verify NT signature */
101 if (nt32->Signature != IMAGE_NT_SIGNATURE)
102 return HDR_FAIL;
104 /* check if we have a 32-bit or 64-bit executable */
105 switch (nt32->OptionalHeader.Magic)
107 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
108 return HDR_NT32;
110 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
111 /* Re-read as 64-bit */
113 count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
115 if (count == INVALID_SET_FILE_POINTER)
116 return HDR_FAIL;
118 count = 0;
120 r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL);
122 if (!r)
123 return HDR_FAIL;
125 if (count != sizeof(IMAGE_NT_HEADERS64))
126 return HDR_FAIL;
128 /* verify NT signature */
129 if (nt64->Signature != IMAGE_NT_SIGNATURE)
130 return HDR_FAIL;
132 return HDR_NT64;
135 return HDR_FAIL;
138 /***********************************************************************
139 * IMAGEHLP_GetSecurityDirOffset (INTERNAL)
141 * Read a file's PE header, and return the offset and size of the
142 * security directory.
144 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle,
145 DWORD *pdwOfs, DWORD *pdwSize )
147 IMAGE_NT_HEADERS32 nt_hdr32;
148 IMAGE_NT_HEADERS64 nt_hdr64;
149 IMAGE_DATA_DIRECTORY *sd;
150 int ret;
152 ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64);
154 if (ret == HDR_NT32)
155 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
156 else if (ret == HDR_NT64)
157 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
158 else
159 return FALSE;
161 TRACE("ret = %d size = %x addr = %x\n", ret, sd->Size, sd->VirtualAddress);
163 *pdwSize = sd->Size;
164 *pdwOfs = sd->VirtualAddress;
166 return TRUE;
169 /***********************************************************************
170 * IMAGEHLP_SetSecurityDirOffset (INTERNAL)
172 * Read a file's PE header, and update the offset and size of the
173 * security directory.
175 static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle,
176 DWORD dwOfs, DWORD dwSize)
178 IMAGE_NT_HEADERS32 nt_hdr32;
179 IMAGE_NT_HEADERS64 nt_hdr64;
180 IMAGE_DATA_DIRECTORY *sd;
181 int ret, nt_hdr_size = 0;
182 DWORD pe_offset;
183 void *nt_hdr;
184 DWORD count;
185 BOOL r;
187 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
189 if (ret == HDR_NT32)
191 sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
193 nt_hdr = &nt_hdr32;
194 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
196 else if (ret == HDR_NT64)
198 sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
200 nt_hdr = &nt_hdr64;
201 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
203 else
204 return FALSE;
206 sd->Size = dwSize;
207 sd->VirtualAddress = dwOfs;
209 TRACE("size = %x addr = %x\n", sd->Size, sd->VirtualAddress);
211 /* write the header back again */
212 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
214 if (count == INVALID_SET_FILE_POINTER)
215 return FALSE;
217 count = 0;
219 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
221 if (!r)
222 return FALSE;
224 if (count != nt_hdr_size)
225 return FALSE;
227 return TRUE;
230 /***********************************************************************
231 * IMAGEHLP_GetCertificateOffset (INTERNAL)
233 * Read a file's PE header, and return the offset and size of the
234 * security directory.
236 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num,
237 DWORD *pdwOfs, DWORD *pdwSize )
239 DWORD size, count, offset, len, sd_VirtualAddr;
240 BOOL r;
242 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
243 if( !r )
244 return FALSE;
246 offset = 0;
247 /* take the n'th certificate */
248 while( 1 )
250 /* read the length of the current certificate */
251 count = SetFilePointer( handle, sd_VirtualAddr + offset,
252 NULL, FILE_BEGIN );
253 if( count == INVALID_SET_FILE_POINTER )
254 return FALSE;
255 r = ReadFile( handle, &len, sizeof len, &count, NULL );
256 if( !r )
257 return FALSE;
258 if( count != sizeof len )
259 return FALSE;
261 /* check the certificate is not too big or too small */
262 if( len < sizeof len )
263 return FALSE;
264 if( len > (size-offset) )
265 return FALSE;
266 if( !num-- )
267 break;
269 /* calculate the offset of the next certificate */
270 offset += len;
272 /* padded out to the nearest 8-byte boundary */
273 if( len % 8 )
274 offset += 8 - (len % 8);
276 if( offset >= size )
277 return FALSE;
280 *pdwOfs = sd_VirtualAddr + offset;
281 *pdwSize = len;
283 TRACE("len = %x addr = %x\n", len, sd_VirtualAddr + offset);
285 return TRUE;
288 /***********************************************************************
289 * IMAGEHLP_RecalculateChecksum (INTERNAL)
291 * Update the NT header checksum for the specified file.
293 static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle)
295 DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size;
296 IMAGE_NT_HEADERS32 nt_hdr32;
297 IMAGE_NT_HEADERS64 nt_hdr64;
298 LPVOID BaseAddress;
299 HANDLE hMapping;
300 DWORD *CheckSum;
301 void *nt_hdr;
302 int ret;
303 BOOL r;
305 TRACE("handle %p\n", handle);
307 ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
309 if (ret == HDR_NT32)
311 CheckSum = &nt_hdr32.OptionalHeader.CheckSum;
313 nt_hdr = &nt_hdr32;
314 nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
316 else if (ret == HDR_NT64)
318 CheckSum = &nt_hdr64.OptionalHeader.CheckSum;
320 nt_hdr = &nt_hdr64;
321 nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
323 else
324 return FALSE;
326 hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL);
328 if (!hMapping)
329 return FALSE;
331 BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
333 if (!BaseAddress)
335 CloseHandle(hMapping);
336 return FALSE;
339 FileLength = GetFileSize(handle, NULL);
341 *CheckSum = 0;
342 CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum);
344 UnmapViewOfFile(BaseAddress);
345 CloseHandle(hMapping);
347 if (*CheckSum)
349 /* write the header back again */
350 count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
352 if (count == INVALID_SET_FILE_POINTER)
353 return FALSE;
355 count = 0;
357 r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
359 if (!r)
360 return FALSE;
362 if (count != nt_hdr_size)
363 return FALSE;
365 return TRUE;
368 return FALSE;
371 /***********************************************************************
372 * ImageAddCertificate (IMAGEHLP.@)
374 * Adds the specified certificate to the security directory of
375 * open PE file.
378 BOOL WINAPI ImageAddCertificate(
379 HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index)
381 DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0;
382 WIN_CERTIFICATE hdr;
383 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
384 BOOL r;
386 TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index);
388 r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size);
390 /* If we've already got a security directory, find the end of it */
391 if ((r) && (sd_VirtualAddr != 0))
393 offset = 0;
394 index = 0;
395 count = 0;
397 /* Check if the security directory is at the end of the file.
398 If not, we should probably relocate it. */
399 if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size)
401 FIXME("Security directory already present but not located at EOF, not adding certificate\n");
403 SetLastError(ERROR_NOT_SUPPORTED);
404 return FALSE;
407 while (offset < size)
409 /* read the length of the current certificate */
410 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset,
411 NULL, FILE_BEGIN);
413 if (count == INVALID_SET_FILE_POINTER)
414 return FALSE;
416 r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL);
418 if (!r)
419 return FALSE;
421 if (count != cert_hdr_size)
422 return FALSE;
424 /* check the certificate is not too big or too small */
425 if (hdr.dwLength < cert_hdr_size)
426 return FALSE;
428 if (hdr.dwLength > (size-offset))
429 return FALSE;
431 /* next certificate */
432 offset += hdr.dwLength;
434 /* padded out to the nearest 8-byte boundary */
435 if (hdr.dwLength % 8)
436 offset += 8 - (hdr.dwLength % 8);
438 index++;
441 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN);
443 if (count == INVALID_SET_FILE_POINTER)
444 return FALSE;
446 else
448 sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END);
450 if (sd_VirtualAddr == INVALID_SET_FILE_POINTER)
451 return FALSE;
454 /* Write the certificate to the file */
455 r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL);
457 if (!r)
458 return FALSE;
460 /* Pad out if necessary */
461 if (Certificate->dwLength % 8)
463 char null[8];
465 ZeroMemory(null, 8);
466 WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), NULL, NULL);
468 size += 8 - (Certificate->dwLength % 8);
471 size += Certificate->dwLength;
473 /* Update the security directory offset and size */
474 if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size))
475 return FALSE;
477 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
478 return FALSE;
480 return TRUE;
483 /***********************************************************************
484 * ImageEnumerateCertificates (IMAGEHLP.@)
486 BOOL WINAPI ImageEnumerateCertificates(
487 HANDLE handle, WORD TypeFilter, PDWORD CertificateCount,
488 PDWORD Indices, DWORD IndexCount)
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;
495 TRACE("%p %hd %p %p %d\n",
496 handle, TypeFilter, CertificateCount, Indices, IndexCount);
498 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
499 if( !r )
500 return FALSE;
502 offset = 0;
503 index = 0;
504 *CertificateCount = 0;
505 while( offset < size )
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;
518 TRACE("Size = %08x id = %08hx\n",
519 hdr.dwLength, hdr.wCertificateType );
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;
527 if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
528 (TypeFilter == hdr.wCertificateType) )
530 (*CertificateCount)++;
531 if(Indices && *CertificateCount <= IndexCount)
532 *Indices++ = index;
535 /* next certificate */
536 offset += hdr.dwLength;
538 /* padded out to the nearest 8-byte boundary */
539 if (hdr.dwLength % 8)
540 offset += 8 - (hdr.dwLength % 8);
542 index++;
545 return TRUE;
548 /***********************************************************************
549 * ImageGetCertificateData (IMAGEHLP.@)
551 * FIXME: not sure that I'm dealing with the Index the right way
553 BOOL WINAPI ImageGetCertificateData(
554 HANDLE handle, DWORD Index,
555 LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength)
557 DWORD r, offset, ofs, size, count;
559 TRACE("%p %d %p %p\n", handle, Index, Certificate, RequiredLength);
561 if( !RequiredLength)
563 SetLastError( ERROR_INVALID_PARAMETER );
564 return FALSE;
567 if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
568 return FALSE;
570 if( *RequiredLength < size )
572 *RequiredLength = size;
573 SetLastError( ERROR_INSUFFICIENT_BUFFER );
574 return FALSE;
577 if( !Certificate )
579 SetLastError( ERROR_INVALID_PARAMETER );
580 return FALSE;
583 *RequiredLength = size;
585 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
586 if( offset == INVALID_SET_FILE_POINTER )
587 return FALSE;
589 r = ReadFile( handle, Certificate, size, &count, NULL );
590 if( !r )
591 return FALSE;
592 if( count != size )
593 return FALSE;
595 TRACE("OK\n");
596 SetLastError( NO_ERROR );
598 return TRUE;
601 /***********************************************************************
602 * ImageGetCertificateHeader (IMAGEHLP.@)
604 BOOL WINAPI ImageGetCertificateHeader(
605 HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert)
607 DWORD r, offset, ofs, size, count;
608 const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate;
610 TRACE("%p %d %p\n", handle, index, pCert);
612 if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) )
613 return FALSE;
615 if( size < cert_hdr_size )
616 return FALSE;
618 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
619 if( offset == INVALID_SET_FILE_POINTER )
620 return FALSE;
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;
628 TRACE("OK\n");
630 return TRUE;
633 /***********************************************************************
634 * ImageGetDigestStream (IMAGEHLP.@)
636 BOOL WINAPI ImageGetDigestStream(
637 HANDLE FileHandle, DWORD DigestLevel,
638 DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle)
640 FIXME("(%p, %d, %p, %p): stub\n",
641 FileHandle, DigestLevel, DigestFunction, DigestHandle
643 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
644 return FALSE;
647 /***********************************************************************
648 * ImageRemoveCertificate (IMAGEHLP.@)
650 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index)
652 DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0;
653 DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0;
654 LPVOID cert_data;
655 BOOL r;
657 TRACE("(%p, %d)\n", FileHandle, Index);
659 r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0);
661 if ((!r) || (count == 0))
662 return FALSE;
664 if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) ||
665 (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size)))
666 return FALSE;
668 /* Ignore any padding we have, too */
669 if (cert_size % 8)
670 cert_size_padded = cert_size + (8 - (cert_size % 8));
671 else
672 cert_size_padded = cert_size;
674 data_size = size - (offset - sd_VirtualAddr) - cert_size_padded;
676 if (data_size == 0)
678 ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN);
680 if (ret == INVALID_SET_FILE_POINTER)
681 return FALSE;
683 else
685 cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
687 if (!cert_data)
688 return FALSE;
690 ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN);
692 if (ret == INVALID_SET_FILE_POINTER)
693 goto error;
695 /* Read any subsequent certificates */
696 r = ReadFile(FileHandle, cert_data, data_size, &count, NULL);
698 if ((!r) || (count != data_size))
699 goto error;
701 SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
703 /* Write them one index back */
704 r = WriteFile(FileHandle, cert_data, data_size, &count, NULL);
706 if ((!r) || (count != data_size))
707 goto error;
709 HeapFree(GetProcessHeap(), 0, cert_data);
712 /* If security directory is at end of file, trim the file */
713 if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size)
714 SetEndOfFile(FileHandle);
716 if (count == 1)
717 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0);
718 else
719 r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded);
721 if (!r)
722 return FALSE;
724 if (!IMAGEHLP_RecalculateChecksum(FileHandle))
725 return FALSE;
727 return TRUE;
729 error:
730 HeapFree(GetProcessHeap(), 0, cert_data);
731 return FALSE;