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
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
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
;
56 TRACE("handle %p\n", handle
);
58 if ((!nt32
) || (!nt64
))
61 /* read the DOS header */
62 count
= SetFilePointer(handle
, 0, NULL
, FILE_BEGIN
);
64 if (count
== INVALID_SET_FILE_POINTER
)
69 r
= ReadFile(handle
, &dos_hdr
, sizeof dos_hdr
, &count
, NULL
);
74 if (count
!= sizeof dos_hdr
)
77 /* verify magic number of 'MZ' */
78 if (dos_hdr
.e_magic
!= 0x5A4D)
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
)
92 r
= ReadFile(handle
, nt32
, sizeof(IMAGE_NT_HEADERS32
), &count
, NULL
);
97 if (count
!= sizeof(IMAGE_NT_HEADERS32
))
100 /* verify NT signature */
101 if (nt32
->Signature
!= IMAGE_NT_SIGNATURE
)
104 /* check if we have a 32-bit or 64-bit executable */
105 switch (nt32
->OptionalHeader
.Magic
)
107 case IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
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
)
120 r
= ReadFile(handle
, nt64
, sizeof(IMAGE_NT_HEADERS64
), &count
, NULL
);
125 if (count
!= sizeof(IMAGE_NT_HEADERS64
))
128 /* verify NT signature */
129 if (nt64
->Signature
!= IMAGE_NT_SIGNATURE
)
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
;
152 ret
= IMAGEHLP_GetNTHeaders(handle
, NULL
, &nt_hdr32
, &nt_hdr64
);
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
];
161 TRACE("ret = %d size = %x addr = %x\n", ret
, sd
->Size
, sd
->VirtualAddress
);
164 *pdwOfs
= sd
->VirtualAddress
;
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;
187 ret
= IMAGEHLP_GetNTHeaders(handle
, &pe_offset
, &nt_hdr32
, &nt_hdr64
);
191 sd
= &nt_hdr32
.OptionalHeader
.DataDirectory
[IMAGE_FILE_SECURITY_DIRECTORY
];
194 nt_hdr_size
= sizeof(IMAGE_NT_HEADERS32
);
196 else if (ret
== HDR_NT64
)
198 sd
= &nt_hdr64
.OptionalHeader
.DataDirectory
[IMAGE_FILE_SECURITY_DIRECTORY
];
201 nt_hdr_size
= sizeof(IMAGE_NT_HEADERS64
);
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
)
219 r
= WriteFile(handle
, nt_hdr
, nt_hdr_size
, &count
, NULL
);
224 if (count
!= nt_hdr_size
)
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
;
242 r
= IMAGEHLP_GetSecurityDirOffset( handle
, &sd_VirtualAddr
, &size
);
247 /* take the n'th certificate */
250 /* read the length of the current certificate */
251 count
= SetFilePointer( handle
, sd_VirtualAddr
+ offset
,
253 if( count
== INVALID_SET_FILE_POINTER
)
255 r
= ReadFile( handle
, &len
, sizeof len
, &count
, NULL
);
258 if( count
!= sizeof len
)
261 /* check the certificate is not too big or too small */
262 if( len
< sizeof len
)
264 if( len
> (size
-offset
) )
269 /* calculate the offset of the next certificate */
272 /* padded out to the nearest 8-byte boundary */
274 offset
+= 8 - (len
% 8);
280 *pdwOfs
= sd_VirtualAddr
+ offset
;
283 TRACE("len = %x addr = %x\n", len
, sd_VirtualAddr
+ offset
);
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
;
305 TRACE("handle %p\n", handle
);
307 ret
= IMAGEHLP_GetNTHeaders(handle
, &pe_offset
, &nt_hdr32
, &nt_hdr64
);
311 CheckSum
= &nt_hdr32
.OptionalHeader
.CheckSum
;
314 nt_hdr_size
= sizeof(IMAGE_NT_HEADERS32
);
316 else if (ret
== HDR_NT64
)
318 CheckSum
= &nt_hdr64
.OptionalHeader
.CheckSum
;
321 nt_hdr_size
= sizeof(IMAGE_NT_HEADERS64
);
326 hMapping
= CreateFileMappingW(handle
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
331 BaseAddress
= MapViewOfFile(hMapping
, FILE_MAP_READ
, 0, 0, 0);
335 CloseHandle(hMapping
);
339 FileLength
= GetFileSize(handle
, NULL
);
342 CheckSumMappedFile(BaseAddress
, FileLength
, &HeaderSum
, CheckSum
);
344 UnmapViewOfFile(BaseAddress
);
345 CloseHandle(hMapping
);
349 /* write the header back again */
350 count
= SetFilePointer(handle
, pe_offset
, NULL
, FILE_BEGIN
);
352 if (count
== INVALID_SET_FILE_POINTER
)
357 r
= WriteFile(handle
, nt_hdr
, nt_hdr_size
, &count
, NULL
);
362 if (count
!= nt_hdr_size
)
371 /***********************************************************************
372 * ImageAddCertificate (IMAGEHLP.@)
374 * Adds the specified certificate to the security directory of
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;
383 const size_t cert_hdr_size
= sizeof hdr
- sizeof hdr
.bCertificate
;
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))
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
);
407 while (offset
< size
)
409 /* read the length of the current certificate */
410 count
= SetFilePointer (FileHandle
, sd_VirtualAddr
+ offset
,
413 if (count
== INVALID_SET_FILE_POINTER
)
416 r
= ReadFile(FileHandle
, &hdr
, cert_hdr_size
, &count
, NULL
);
421 if (count
!= cert_hdr_size
)
424 /* check the certificate is not too big or too small */
425 if (hdr
.dwLength
< cert_hdr_size
)
428 if (hdr
.dwLength
> (size
-offset
))
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);
441 count
= SetFilePointer (FileHandle
, sd_VirtualAddr
+ offset
, NULL
, FILE_BEGIN
);
443 if (count
== INVALID_SET_FILE_POINTER
)
448 sd_VirtualAddr
= SetFilePointer(FileHandle
, 0, NULL
, FILE_END
);
450 if (sd_VirtualAddr
== INVALID_SET_FILE_POINTER
)
454 /* Write the certificate to the file */
455 r
= WriteFile(FileHandle
, Certificate
, Certificate
->dwLength
, &count
, NULL
);
460 /* Pad out if necessary */
461 if (Certificate
->dwLength
% 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
))
477 if (!IMAGEHLP_RecalculateChecksum(FileHandle
))
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
;
492 const size_t cert_hdr_size
= sizeof hdr
- sizeof hdr
.bCertificate
;
495 TRACE("%p %hd %p %p %d\n",
496 handle
, TypeFilter
, CertificateCount
, Indices
, IndexCount
);
498 r
= IMAGEHLP_GetSecurityDirOffset( handle
, &sd_VirtualAddr
, &size
);
504 *CertificateCount
= 0;
505 while( offset
< size
)
507 /* read the length of the current certificate */
508 count
= SetFilePointer( handle
, sd_VirtualAddr
+ offset
,
510 if( count
== INVALID_SET_FILE_POINTER
)
512 r
= ReadFile( handle
, &hdr
, cert_hdr_size
, &count
, NULL
);
515 if( count
!= cert_hdr_size
)
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
)
524 if( hdr
.dwLength
> (size
-offset
) )
527 if( (TypeFilter
== CERT_SECTION_TYPE_ANY
) ||
528 (TypeFilter
== hdr
.wCertificateType
) )
530 (*CertificateCount
)++;
531 if(Indices
&& *CertificateCount
<= IndexCount
)
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);
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
);
563 SetLastError( ERROR_INVALID_PARAMETER
);
567 if( !IMAGEHLP_GetCertificateOffset( handle
, Index
, &ofs
, &size
) )
570 if( *RequiredLength
< size
)
572 *RequiredLength
= size
;
573 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
579 SetLastError( ERROR_INVALID_PARAMETER
);
583 *RequiredLength
= size
;
585 offset
= SetFilePointer( handle
, ofs
, NULL
, FILE_BEGIN
);
586 if( offset
== INVALID_SET_FILE_POINTER
)
589 r
= ReadFile( handle
, Certificate
, size
, &count
, NULL
);
596 SetLastError( NO_ERROR
);
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
) )
615 if( size
< cert_hdr_size
)
618 offset
= SetFilePointer( handle
, ofs
, NULL
, FILE_BEGIN
);
619 if( offset
== INVALID_SET_FILE_POINTER
)
622 r
= ReadFile( handle
, pCert
, cert_hdr_size
, &count
, NULL
);
625 if( count
!= cert_hdr_size
)
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
);
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;
657 TRACE("(%p, %d)\n", FileHandle
, Index
);
659 r
= ImageEnumerateCertificates(FileHandle
, CERT_SECTION_TYPE_ANY
, &count
, NULL
, 0);
661 if ((!r
) || (count
== 0))
664 if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle
, &sd_VirtualAddr
, &size
)) ||
665 (!IMAGEHLP_GetCertificateOffset(FileHandle
, Index
, &offset
, &cert_size
)))
668 /* Ignore any padding we have, too */
670 cert_size_padded
= cert_size
+ (8 - (cert_size
% 8));
672 cert_size_padded
= cert_size
;
674 data_size
= size
- (offset
- sd_VirtualAddr
) - cert_size_padded
;
678 ret
= SetFilePointer(FileHandle
, sd_VirtualAddr
, NULL
, FILE_BEGIN
);
680 if (ret
== INVALID_SET_FILE_POINTER
)
685 cert_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, data_size
);
690 ret
= SetFilePointer(FileHandle
, offset
+ cert_size_padded
, NULL
, FILE_BEGIN
);
692 if (ret
== INVALID_SET_FILE_POINTER
)
695 /* Read any subsequent certificates */
696 r
= ReadFile(FileHandle
, cert_data
, data_size
, &count
, NULL
);
698 if ((!r
) || (count
!= data_size
))
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
))
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
);
717 r
= IMAGEHLP_SetSecurityDirOffset(FileHandle
, 0, 0);
719 r
= IMAGEHLP_SetSecurityDirOffset(FileHandle
, sd_VirtualAddr
, size
- cert_size_padded
);
724 if (!IMAGEHLP_RecalculateChecksum(FileHandle
))
730 HeapFree(GetProcessHeap(), 0, cert_data
);