user32: Fix icon extraction from non-native PE executables.
Hans Leidekker
hans at codeweavers.com
Thu Jun 6 07:03:56 CDT 2013
---
dlls/user32/exticon.c | 202 ++++++++++++++++++++++++++++++++-----------------
1 file changed, 133 insertions(+), 69 deletions(-)
diff --git a/dlls/user32/exticon.c b/dlls/user32/exticon.c
index 5b9d681..e6e97d5 100644
--- a/dlls/user32/exticon.c
+++ b/dlls/user32/exticon.c
@@ -251,6 +251,127 @@ static BYTE * ICO_GetIconDirectory( LPBYTE peimage, LPicoICONDIR* lplpiID, ULONG
return 0;
}
+/* caller must make sure we have a PE image */
+static BOOL get_nt_header( const BYTE *image, const IMAGE_NT_HEADERS32 **nt32, const IMAGE_NT_HEADERS64 **nt64 )
+{
+ const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)image;
+ const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)(image + dos->e_lfanew);
+
+ if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
+ *nt64 = NULL;
+ return TRUE;
+ }
+ else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
+ *nt32 = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static const IMAGE_SECTION_HEADER *get_next_section_header( const BYTE *image, WORD *index )
+{
+ const IMAGE_NT_HEADERS32 *hdr32;
+ const IMAGE_NT_HEADERS64 *hdr64;
+ const IMAGE_SECTION_HEADER *section = NULL;
+
+ if (!get_nt_header( image, &hdr32, &hdr64 )) return NULL;
+ if (hdr32)
+ {
+ if (*index >= hdr32->FileHeader.NumberOfSections) return NULL;
+ section = (const IMAGE_SECTION_HEADER *)((char *)hdr32 + sizeof(DWORD) +
+ sizeof(IMAGE_FILE_HEADER) + hdr32->FileHeader.SizeOfOptionalHeader +
+ *index * sizeof(IMAGE_SECTION_HEADER));
+ }
+ else
+ {
+ if (*index >= hdr64->FileHeader.NumberOfSections) return NULL;
+ section = (const IMAGE_SECTION_HEADER *)((char *)hdr64 + sizeof(DWORD) +
+ sizeof(IMAGE_FILE_HEADER) + hdr64->FileHeader.SizeOfOptionalHeader +
+ *index * sizeof(IMAGE_SECTION_HEADER));
+ }
+ if (section) (*index)++;
+ return section;
+}
+
+static DWORD get_resource_va( const BYTE *image )
+{
+ const IMAGE_NT_HEADERS32 *hdr32;
+ const IMAGE_NT_HEADERS64 *hdr64;
+
+ if (!get_nt_header( image, &hdr32, &hdr64 )) return 0;
+ if (hdr32) return hdr32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+ return hdr64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+}
+
+/* search for the root resource directory in a 32 or 64-bit PE image */
+static const IMAGE_RESOURCE_DIRECTORY *get_resource_root( const BYTE *image, DWORD size )
+{
+ const IMAGE_SECTION_HEADER *section;
+ const IMAGE_RESOURCE_DIRECTORY *root = NULL;
+ DWORD resource_va = get_resource_va( image );
+ WORD index = 0;
+
+ if (!resource_va) return NULL;
+
+ while ((section = get_next_section_header( image, &index )))
+ {
+ if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
+ if (section->PointerToRawData + section->SizeOfRawData > size)
+ {
+ WARN( "section size %u beyond image size %u)\n",
+ section->PointerToRawData + section->SizeOfRawData, size );
+ return NULL;
+ }
+ /* FIXME: doesn't work when the resources are not in a separate section */
+ if (section->VirtualAddress == resource_va)
+ {
+ root = (IMAGE_RESOURCE_DIRECTORY *)(image + section->PointerToRawData);
+ break;
+ }
+ }
+ return root;
+}
+
+static BYTE *get_icon_group_data( BYTE *image, DWORD size, const IMAGE_RESOURCE_DATA_ENTRY *entry )
+{
+ const IMAGE_SECTION_HEADER *section;
+ WORD index = 0;
+
+ while ((section = get_next_section_header( image, &index )))
+ {
+ if (entry->OffsetToData < section->VirtualAddress ||
+ entry->OffsetToData + entry->Size > section->VirtualAddress + section->SizeOfRawData) continue;
+
+ if (entry->OffsetToData - section->VirtualAddress + section->PointerToRawData + entry->Size > size)
+ {
+ WARN( "overflow in PE lookup (size %u, have offset %u)\n", size,
+ entry->OffsetToData - section->VirtualAddress + section->PointerToRawData + entry->Size );
+ return NULL;
+ }
+ return image + entry->OffsetToData - section->VirtualAddress + section->PointerToRawData;
+ }
+ return NULL;
+}
+
+static BYTE *get_icon_data( BYTE *image, DWORD size, const IMAGE_RESOURCE_DATA_ENTRY *entry )
+{
+ const IMAGE_SECTION_HEADER *section;
+ WORD index = 0;
+
+ while ((section = get_next_section_header( image, &index )))
+ {
+ if (entry->OffsetToData < section->VirtualAddress ||
+ entry->OffsetToData + entry->Size > section->VirtualAddress + section->SizeOfRawData) continue;
+
+ return image + entry->OffsetToData - section->VirtualAddress + section->PointerToRawData;
+ }
+ return NULL;
+}
+
/*************************************************************************
* ICO_ExtractIconExW [internal]
*
@@ -420,47 +541,17 @@ static UINT ICO_ExtractIconExW(
/* exe/dll */
else if( sig == IMAGE_NT_SIGNATURE )
{
- LPBYTE idata,igdata;
- PIMAGE_DOS_HEADER dheader;
- PIMAGE_NT_HEADERS pe_header;
- PIMAGE_SECTION_HEADER pe_sections;
- const IMAGE_RESOURCE_DIRECTORY *rootresdir,*iconresdir,*icongroupresdir;
- const IMAGE_RESOURCE_DATA_ENTRY *idataent,*igdataent;
- const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent;
- UINT i, j;
-
- dheader = (PIMAGE_DOS_HEADER)peimage;
- pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew); /* it is a pe header, USER32_GetResourceTable checked that */
- pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER)
- + pe_header->FileHeader.SizeOfOptionalHeader);
- rootresdir = NULL;
-
- /* search for the root resource directory */
- for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
- {
- if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- continue;
- if (fsizel < pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData) {
- FIXME("File %s too short (section is at %d bytes, real size is %d)\n",
- debugstr_w(lpszExeFileName),
- pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData,
- fsizel
- );
- goto end;
- }
- /* FIXME: doesn't work when the resources are not in a separate section */
- if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
- {
- rootresdir = (PIMAGE_RESOURCE_DIRECTORY)(peimage+pe_sections[i].PointerToRawData);
- break;
- }
- }
+ BYTE *idata, *igdata;
+ const IMAGE_RESOURCE_DIRECTORY *rootresdir, *iconresdir, *icongroupresdir;
+ const IMAGE_RESOURCE_DATA_ENTRY *idataent, *igdataent;
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent;
+ UINT i;
- if (!rootresdir)
- {
- WARN("haven't found section for resource directory.\n");
- goto end; /* failure */
- }
+ if (!(rootresdir = get_resource_root( peimage, fsizel )))
+ {
+ WARN("haven't found section for resource directory.\n");
+ goto end;
+ }
/* search for the group icon directory */
if (!(icongroupresdir = find_entry_by_id(rootresdir, LOWORD(RT_GROUP_ICON), rootresdir)))
@@ -529,24 +620,7 @@ static UINT ICO_ExtractIconExW(
igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir;
/* lookup address in mapped image for virtual address */
- igdata = NULL;
-
- for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
- {
- if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
- continue;
- if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
- continue;
-
- if (igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData+igdataent->Size > fsizel) {
- FIXME("overflow in PE lookup (%s has len %d, have offset %d), short file?\n", debugstr_w(lpszExeFileName), fsizel,
- igdataent->OffsetToData - pe_sections[j].VirtualAddress + pe_sections[j].PointerToRawData + igdataent->Size);
- goto end; /* failure */
- }
- igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
- }
-
- if (!igdata)
+ if (!(igdata = get_icon_group_data( peimage, fsizel, igdataent )))
{
FIXME("no matching real address for icongroup!\n");
goto end; /* failure */
@@ -573,18 +647,8 @@ static UINT ICO_ExtractIconExW(
}
xresdir = find_entry_default(xresdir, rootresdir);
idataent = (const IMAGE_RESOURCE_DATA_ENTRY*)xresdir;
- idata = NULL;
- /* map virtual to address in image */
- for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
- {
- if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
- continue;
- if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
- continue;
- idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
- }
- if (!idata)
+ if (!(idata = get_icon_data( peimage, fsizel, idataent)))
{
WARN("no matching real address found for icondata!\n");
RetPtr[i]=0;
--
1.7.10.4
More information about the wine-patches
mailing list