Author: cwittich Date: Sun Feb 27 18:49:27 2011 New Revision: 50923
URL: http://svn.reactos.org/svn/reactos?rev=50923&view=rev Log: [imagehlp] -partial winesync
Modified: trunk/reactos/dll/win32/imagehlp/integrity.c
Modified: trunk/reactos/dll/win32/imagehlp/integrity.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/imagehlp/integrit... ============================================================================== --- trunk/reactos/dll/win32/imagehlp/integrity.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/imagehlp/integrity.c [iso-8859-1] Sun Feb 27 18:49:27 2011 @@ -4,6 +4,8 @@ * Copyright 1998 Patrik Stridvall * Copyright 2003 Mike McCormack * Copyright 2009 Owen Rudge for CodeWeavers + * Copyright 2010 Juan Lang + * Copyright 2010 Andrey Turkin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -461,9 +463,10 @@ if (Certificate->dwLength % 8) { char null[8]; + DWORD dwBytesWritten;
ZeroMemory(null, 8); - WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), NULL, NULL); + WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), &dwBytesWritten, NULL);
size += 8 - (Certificate->dwLength % 8); } @@ -630,18 +633,255 @@ return TRUE; }
+/* Finds the section named section in the array of IMAGE_SECTION_HEADERs hdr. If + * found, returns the offset to the section. Otherwise returns 0. If the section + * is found, optionally returns the size of the section (in size) and the base + * address of the section (in base.) + */ +static DWORD IMAGEHLP_GetSectionOffset( IMAGE_SECTION_HEADER *hdr, + DWORD num_sections, LPCSTR section, PDWORD size, PDWORD base ) +{ + DWORD i, offset = 0; + + for( i = 0; !offset && i < num_sections; i++, hdr++ ) + { + if( !memcmp( hdr->Name, section, strlen(section) ) ) + { + offset = hdr->PointerToRawData; + if( size ) + *size = hdr->SizeOfRawData; + if( base ) + *base = hdr->VirtualAddress; + } + } + return offset; +} + +/* Calls DigestFunction e bytes at offset offset from the file mapped at map. + * Returns the return value of DigestFunction, or FALSE if the data is not available. + */ +static BOOL IMAGEHLP_ReportSectionFromOffset( DWORD offset, DWORD size, + BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) +{ + if( offset + size > fileSize ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return DigestFunction( DigestHandle, map + offset, size ); +} + +/* Finds the section named section among the IMAGE_SECTION_HEADERs in + * section_headers and calls DigestFunction for this section. Returns + * the return value from DigestFunction, or FALSE if the data could not be read. + */ +static BOOL IMAGEHLP_ReportSection( IMAGE_SECTION_HEADER *section_headers, + DWORD num_sections, LPCSTR section, BYTE *map, DWORD fileSize, + DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) +{ + DWORD offset, size = 0; + + offset = IMAGEHLP_GetSectionOffset( section_headers, num_sections, section, + &size, NULL ); + if( !offset ) + return FALSE; + return IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, + DigestFunction, DigestHandle ); +} + +/* Calls DigestFunction for all sections with the IMAGE_SCN_CNT_CODE flag set. + * Returns the return value from * DigestFunction, or FALSE if a section could not be read. + */ +static BOOL IMAGEHLP_ReportCodeSections( IMAGE_SECTION_HEADER *hdr, DWORD num_sections, + BYTE *map, DWORD fileSize, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) +{ + DWORD i; + BOOL ret = TRUE; + + for( i = 0; ret && i < num_sections; i++, hdr++ ) + { + if( hdr->Characteristics & IMAGE_SCN_CNT_CODE ) + ret = IMAGEHLP_ReportSectionFromOffset( hdr->PointerToRawData, + hdr->SizeOfRawData, map, fileSize, DigestFunction, DigestHandle ); + } + return ret; +} + +/* Reports the import section from the file FileHandle. If + * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set in DigestLevel, reports the entire + * import section. + * FIXME: if it's not set, the function currently fails. + */ +static BOOL IMAGEHLP_ReportImportSection( IMAGE_SECTION_HEADER *hdr, + DWORD num_sections, BYTE *map, DWORD fileSize, DWORD DigestLevel, + DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle ) +{ + BOOL ret = FALSE; + DWORD offset, size, base; + + /* Get import data */ + offset = IMAGEHLP_GetSectionOffset( hdr, num_sections, ".idata", &size, + &base ); + if( !offset ) + return FALSE; + + /* If CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO is set, the entire + * section is reported. Otherwise, the debug info section is + * decoded and reported piecemeal. See tests. However, I haven't been + * able to figure out how the native implementation decides which values + * to report. Either it's buggy or my understanding is flawed. + */ + if( DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO ) + ret = IMAGEHLP_ReportSectionFromOffset( offset, size, map, fileSize, + DigestFunction, DigestHandle ); + else + { + FIXME("not supported except for CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO\n"); + SetLastError(ERROR_INVALID_PARAMETER); + ret = FALSE; + } + + return ret; +} + /*********************************************************************** * ImageGetDigestStream (IMAGEHLP.@) + * + * Gets a stream of bytes from a PE file overwhich a hash might be computed to + * verify that the image has not changed. Useful for creating a certificate to + * be added to the file with ImageAddCertificate. + * + * PARAMS + * FileHandle [In] File for which to return a stream. + * DigestLevel [In] Flags to control which portions of the file to return. + * 0 is allowed, as is any combination of: + * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: reports the entire + * import section rather than selected portions of it. + * CERT_PE_IMAGE_DIGEST_DEBUG_INFO: reports the debug section. + * CERT_PE_IMAGE_DIGEST_RESOURCES: reports the resources + section. + * DigestFunction [In] Callback function. + * DigestHandle [In] Handle passed as first parameter to DigestFunction. + * + * RETURNS + * TRUE if successful. + * FALSE if unsuccessful. GetLastError returns more about the error. + * + * NOTES + * Only supports 32-bit PE files, not tested with any other format. + * Reports data in the following order: + * 1. The file headers are reported first + * 2. Any code sections are reported next. + * 3. The data (".data" and ".rdata") sections are reported next. + * 4. The import section is reported next. + * 5. If CERT_PE_IMAGE_DIGEST_DEBUG_INFO is set in DigestLevel, the debug section is + * reported next. + * 6. If CERT_PE_IMAGE_DIGEST_RESOURCES is set in DigestLevel, the resources section + * is reported next. + * + * BUGS + * CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO must be specified, returns an error if not. */ BOOL WINAPI ImageGetDigestStream( HANDLE FileHandle, DWORD DigestLevel, DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle) { - FIXME("(%p, %d, %p, %p): stub\n", - FileHandle, DigestLevel, DigestFunction, DigestHandle - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + DWORD error = 0; + BOOL ret = FALSE; + DWORD offset, size, num_sections, fileSize; + HANDLE hMap = INVALID_HANDLE_VALUE; + BYTE *map = NULL; + IMAGE_DOS_HEADER *dos_hdr; + IMAGE_NT_HEADERS *nt_hdr; + IMAGE_SECTION_HEADER *section_headers; + + TRACE("(%p, %d, %p, %p)\n", FileHandle, DigestLevel, DigestFunction, + DigestHandle); + + /* Get the file size */ + if( !FileHandle ) + goto invalid_parameter; + fileSize = GetFileSize( FileHandle, NULL ); + if(fileSize == INVALID_FILE_SIZE ) + goto invalid_parameter; + + /* map file */ + hMap = CreateFileMappingW( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); + if( hMap == INVALID_HANDLE_VALUE ) + goto invalid_parameter; + map = MapViewOfFile( hMap, FILE_MAP_COPY, 0, 0, 0 ); + if( !map ) + goto invalid_parameter; + + /* Read the file header */ + if( fileSize < sizeof(IMAGE_DOS_HEADER) ) + goto invalid_parameter; + dos_hdr = (IMAGE_DOS_HEADER *)map; + + if( dos_hdr->e_magic != IMAGE_DOS_SIGNATURE ) + goto invalid_parameter; + offset = dos_hdr->e_lfanew; + if( !offset || offset > fileSize ) + goto invalid_parameter; + ret = DigestFunction( DigestHandle, map, offset ); + if( !ret ) + goto end; + + /* Read the NT header */ + if( offset + sizeof(IMAGE_NT_HEADERS) > fileSize ) + goto invalid_parameter; + nt_hdr = (IMAGE_NT_HEADERS *)(map + offset); + if( nt_hdr->Signature != IMAGE_NT_SIGNATURE ) + goto invalid_parameter; + /* It's clear why the checksum is cleared, but why only these size headers? + */ + nt_hdr->OptionalHeader.SizeOfInitializedData = 0; + nt_hdr->OptionalHeader.SizeOfImage = 0; + nt_hdr->OptionalHeader.CheckSum = 0; + size = sizeof(nt_hdr->Signature) + sizeof(nt_hdr->FileHeader) + + nt_hdr->FileHeader.SizeOfOptionalHeader; + ret = DigestFunction( DigestHandle, map + offset, size ); + if( !ret ) + goto end; + + /* Read the section headers */ + offset += size; + num_sections = nt_hdr->FileHeader.NumberOfSections; + size = num_sections * sizeof(IMAGE_SECTION_HEADER); + if( offset + size > fileSize ) + goto invalid_parameter; + ret = DigestFunction( DigestHandle, map + offset, size ); + if( !ret ) + goto end; + + section_headers = (IMAGE_SECTION_HEADER *)(map + offset); + IMAGEHLP_ReportCodeSections( section_headers, num_sections, + map, fileSize, DigestFunction, DigestHandle ); + IMAGEHLP_ReportSection( section_headers, num_sections, ".data", + map, fileSize, DigestFunction, DigestHandle ); + IMAGEHLP_ReportSection( section_headers, num_sections, ".rdata", + map, fileSize, DigestFunction, DigestHandle ); + IMAGEHLP_ReportImportSection( section_headers, num_sections, + map, fileSize, DigestLevel, DigestFunction, DigestHandle ); + if( DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO ) + IMAGEHLP_ReportSection( section_headers, num_sections, ".debug", + map, fileSize, DigestFunction, DigestHandle ); + if( DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES ) + IMAGEHLP_ReportSection( section_headers, num_sections, ".rsrc", + map, fileSize, DigestFunction, DigestHandle ); + +end: + if( map ) + UnmapViewOfFile( map ); + if( hMap != INVALID_HANDLE_VALUE ) + CloseHandle( hMap ); + if( error ) + SetLastError(error); + return ret; + +invalid_parameter: + error = ERROR_INVALID_PARAMETER; + goto end; }
/***********************************************************************