push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / imagehlp / integrity.c
blob6a13c53bb236eb7867d2b48f75415d98430188fd
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;
289 /***********************************************************************
290 * ImageAddCertificate (IMAGEHLP.@)
292 * Adds the specified certificate to the security directory of
293 * open PE file.
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;
300 WIN_CERTIFICATE hdr;
301 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
302 BOOL r;
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))
311 offset = 0;
312 index = 0;
313 count = 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);
322 return FALSE;
325 while (offset < size)
327 /* read the length of the current certificate */
328 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset,
329 NULL, FILE_BEGIN);
331 if (count == INVALID_SET_FILE_POINTER)
332 return FALSE;
334 r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL);
336 if (!r)
337 return FALSE;
339 if (count != cert_hdr_size)
340 return FALSE;
342 /* check the certificate is not too big or too small */
343 if (hdr.dwLength < cert_hdr_size)
344 return FALSE;
346 if (hdr.dwLength > (size-offset))
347 return FALSE;
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);
356 index++;
359 count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN);
361 if (count == INVALID_SET_FILE_POINTER)
362 return FALSE;
364 else
366 sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END);
368 if (sd_VirtualAddr == INVALID_SET_FILE_POINTER)
369 return FALSE;
372 /* Write the certificate to the file */
373 r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL);
375 if (!r)
376 return FALSE;
378 /* Pad out if necessary */
379 if (Certificate->dwLength % 8)
381 char null[8];
383 ZeroMemory(null, 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))
393 return FALSE;
395 return TRUE;
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;
406 WIN_CERTIFICATE hdr;
407 const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
408 BOOL r;
410 TRACE("%p %hd %p %p %d\n",
411 handle, TypeFilter, CertificateCount, Indices, IndexCount);
413 r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
414 if( !r )
415 return FALSE;
417 offset = 0;
418 index = 0;
419 *CertificateCount = 0;
420 while( offset < size )
422 /* read the length of the current certificate */
423 count = SetFilePointer( handle, sd_VirtualAddr + offset,
424 NULL, FILE_BEGIN );
425 if( count == INVALID_SET_FILE_POINTER )
426 return FALSE;
427 r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL );
428 if( !r )
429 return FALSE;
430 if( count != cert_hdr_size )
431 return FALSE;
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 )
438 return FALSE;
439 if( hdr.dwLength > (size-offset) )
440 return FALSE;
442 if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
443 (TypeFilter == hdr.wCertificateType) )
445 (*CertificateCount)++;
446 if(Indices && *CertificateCount <= IndexCount)
447 *Indices++ = index;
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);
457 index++;
460 return TRUE;
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);
476 if( !RequiredLength)
478 SetLastError( ERROR_INVALID_PARAMETER );
479 return FALSE;
482 if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
483 return FALSE;
485 if( *RequiredLength < size )
487 *RequiredLength = size;
488 SetLastError( ERROR_INSUFFICIENT_BUFFER );
489 return FALSE;
492 if( !Certificate )
494 SetLastError( ERROR_INVALID_PARAMETER );
495 return FALSE;
498 *RequiredLength = size;
500 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
501 if( offset == INVALID_SET_FILE_POINTER )
502 return FALSE;
504 r = ReadFile( handle, Certificate, size, &count, NULL );
505 if( !r )
506 return FALSE;
507 if( count != size )
508 return FALSE;
510 TRACE("OK\n");
511 SetLastError( NO_ERROR );
513 return TRUE;
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 ) )
528 return FALSE;
530 if( size < cert_hdr_size )
531 return FALSE;
533 offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
534 if( offset == INVALID_SET_FILE_POINTER )
535 return FALSE;
537 r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL );
538 if( !r )
539 return FALSE;
540 if( count != cert_hdr_size )
541 return FALSE;
543 TRACE("OK\n");
545 return TRUE;
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);
559 return FALSE;
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);
569 return FALSE;