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
);
289 /***********************************************************************
290 * ImageAddCertificate (IMAGEHLP.@)
292 * Adds the specified certificate to the security directory of
296 BOOL WINAPI
ImageAddCertificate(
297 HANDLE FileHandle
, LPWIN_CERTIFICATE Certificate
, PDWORD Index
)
299 DWORD size
= 0, count
= 0, offset
= 0, sd_VirtualAddr
= 0, index
= 0;
301 const size_t cert_hdr_size
= sizeof hdr
- sizeof hdr
.bCertificate
;
304 TRACE("(%p, %p, %p)\n", FileHandle
, Certificate
, Index
);
306 r
= IMAGEHLP_GetSecurityDirOffset(FileHandle
, &sd_VirtualAddr
, &size
);
308 /* If we've already got a security directory, find the end of it */
309 if ((r
) && (sd_VirtualAddr
!= 0))
315 /* Check if the security directory is at the end of the file.
316 If not, we should probably relocate it. */
317 if (GetFileSize(FileHandle
, NULL
) != sd_VirtualAddr
+ size
)
319 FIXME("Security directory already present but not located at EOF, not adding certificate\n");
321 SetLastError(ERROR_NOT_SUPPORTED
);
325 while (offset
< size
)
327 /* read the length of the current certificate */
328 count
= SetFilePointer (FileHandle
, sd_VirtualAddr
+ offset
,
331 if (count
== INVALID_SET_FILE_POINTER
)
334 r
= ReadFile(FileHandle
, &hdr
, cert_hdr_size
, &count
, NULL
);
339 if (count
!= cert_hdr_size
)
342 /* check the certificate is not too big or too small */
343 if (hdr
.dwLength
< cert_hdr_size
)
346 if (hdr
.dwLength
> (size
-offset
))
349 /* next certificate */
350 offset
+= hdr
.dwLength
;
352 /* padded out to the nearest 8-byte boundary */
353 if (hdr
.dwLength
% 8)
354 offset
+= 8 - (hdr
.dwLength
% 8);
359 count
= SetFilePointer (FileHandle
, sd_VirtualAddr
+ offset
, NULL
, FILE_BEGIN
);
361 if (count
== INVALID_SET_FILE_POINTER
)
366 sd_VirtualAddr
= SetFilePointer(FileHandle
, 0, NULL
, FILE_END
);
368 if (sd_VirtualAddr
== INVALID_SET_FILE_POINTER
)
372 /* Write the certificate to the file */
373 r
= WriteFile(FileHandle
, Certificate
, Certificate
->dwLength
, &count
, NULL
);
378 /* Pad out if necessary */
379 if (Certificate
->dwLength
% 8)
384 WriteFile(FileHandle
, null
, 8 - (Certificate
->dwLength
% 8), NULL
, NULL
);
386 size
+= 8 - (Certificate
->dwLength
% 8);
389 size
+= Certificate
->dwLength
;
391 /* Update the security directory offset and size */
392 if (!IMAGEHLP_SetSecurityDirOffset(FileHandle
, sd_VirtualAddr
, size
))
398 /***********************************************************************
399 * ImageEnumerateCertificates (IMAGEHLP.@)
401 BOOL WINAPI
ImageEnumerateCertificates(
402 HANDLE handle
, WORD TypeFilter
, PDWORD CertificateCount
,
403 PDWORD Indices
, DWORD IndexCount
)
405 DWORD size
, count
, offset
, sd_VirtualAddr
, index
;
407 const size_t cert_hdr_size
= sizeof hdr
- sizeof hdr
.bCertificate
;
410 TRACE("%p %hd %p %p %d\n",
411 handle
, TypeFilter
, CertificateCount
, Indices
, IndexCount
);
413 r
= IMAGEHLP_GetSecurityDirOffset( handle
, &sd_VirtualAddr
, &size
);
419 *CertificateCount
= 0;
420 while( offset
< size
)
422 /* read the length of the current certificate */
423 count
= SetFilePointer( handle
, sd_VirtualAddr
+ offset
,
425 if( count
== INVALID_SET_FILE_POINTER
)
427 r
= ReadFile( handle
, &hdr
, cert_hdr_size
, &count
, NULL
);
430 if( count
!= cert_hdr_size
)
433 TRACE("Size = %08x id = %08hx\n",
434 hdr
.dwLength
, hdr
.wCertificateType
);
436 /* check the certificate is not too big or too small */
437 if( hdr
.dwLength
< cert_hdr_size
)
439 if( hdr
.dwLength
> (size
-offset
) )
442 if( (TypeFilter
== CERT_SECTION_TYPE_ANY
) ||
443 (TypeFilter
== hdr
.wCertificateType
) )
445 (*CertificateCount
)++;
446 if(Indices
&& *CertificateCount
<= IndexCount
)
450 /* next certificate */
451 offset
+= hdr
.dwLength
;
453 /* padded out to the nearest 8-byte boundary */
454 if (hdr
.dwLength
% 8)
455 offset
+= 8 - (hdr
.dwLength
% 8);
463 /***********************************************************************
464 * ImageGetCertificateData (IMAGEHLP.@)
466 * FIXME: not sure that I'm dealing with the Index the right way
468 BOOL WINAPI
ImageGetCertificateData(
469 HANDLE handle
, DWORD Index
,
470 LPWIN_CERTIFICATE Certificate
, PDWORD RequiredLength
)
472 DWORD r
, offset
, ofs
, size
, count
;
474 TRACE("%p %d %p %p\n", handle
, Index
, Certificate
, RequiredLength
);
478 SetLastError( ERROR_INVALID_PARAMETER
);
482 if( !IMAGEHLP_GetCertificateOffset( handle
, Index
, &ofs
, &size
) )
485 if( *RequiredLength
< size
)
487 *RequiredLength
= size
;
488 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
494 SetLastError( ERROR_INVALID_PARAMETER
);
498 *RequiredLength
= size
;
500 offset
= SetFilePointer( handle
, ofs
, NULL
, FILE_BEGIN
);
501 if( offset
== INVALID_SET_FILE_POINTER
)
504 r
= ReadFile( handle
, Certificate
, size
, &count
, NULL
);
511 SetLastError( NO_ERROR
);
516 /***********************************************************************
517 * ImageGetCertificateHeader (IMAGEHLP.@)
519 BOOL WINAPI
ImageGetCertificateHeader(
520 HANDLE handle
, DWORD index
, LPWIN_CERTIFICATE pCert
)
522 DWORD r
, offset
, ofs
, size
, count
;
523 const size_t cert_hdr_size
= sizeof *pCert
- sizeof pCert
->bCertificate
;
525 TRACE("%p %d %p\n", handle
, index
, pCert
);
527 if( !IMAGEHLP_GetCertificateOffset( handle
, index
, &ofs
, &size
) )
530 if( size
< cert_hdr_size
)
533 offset
= SetFilePointer( handle
, ofs
, NULL
, FILE_BEGIN
);
534 if( offset
== INVALID_SET_FILE_POINTER
)
537 r
= ReadFile( handle
, pCert
, cert_hdr_size
, &count
, NULL
);
540 if( count
!= cert_hdr_size
)
548 /***********************************************************************
549 * ImageGetDigestStream (IMAGEHLP.@)
551 BOOL WINAPI
ImageGetDigestStream(
552 HANDLE FileHandle
, DWORD DigestLevel
,
553 DIGEST_FUNCTION DigestFunction
, DIGEST_HANDLE DigestHandle
)
555 FIXME("(%p, %d, %p, %p): stub\n",
556 FileHandle
, DigestLevel
, DigestFunction
, DigestHandle
558 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
562 /***********************************************************************
563 * ImageRemoveCertificate (IMAGEHLP.@)
565 BOOL WINAPI
ImageRemoveCertificate(HANDLE FileHandle
, DWORD Index
)
567 FIXME("(%p, %d): stub\n", FileHandle
, Index
);
568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);