static inline NTSTATUS access_resource( HMODULE hmod, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **ptr, ULONG *size ) #endif { NTSTATUS status; __TRY { ULONG dirsize; if (!RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &dirsize )) status = STATUS_RESOURCE_DATA_NOT_FOUND; else { if (ptr) { if (is_data_file_module(hmod)) { HMODULE mod = (HMODULE)((ULONG_PTR)hmod & ~1); *ptr = RtlImageRvaToVa( RtlImageNtHeader(mod), mod, entry->OffsetToData, NULL ); } else *ptr = (char *)hmod + entry->OffsetToData; } if (size) *size = entry->Size; status = STATUS_SUCCESS; } } __EXCEPT_PAGE_FAULT { return GetExceptionCode(); } __ENDTRY; return status; }
static NTSTATUS LdrpAccessResource( PVOID BaseAddress, IMAGE_RESOURCE_DATA_ENTRY *entry, void **ptr, ULONG *size ) #endif { NTSTATUS status = STATUS_SUCCESS; _SEH2_TRY { ULONG dirsize; if (!RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &dirsize )) status = STATUS_RESOURCE_DATA_NOT_FOUND; else { if (ptr) { if (is_data_file_module(BaseAddress)) { PVOID mod = (PVOID)((ULONG_PTR)BaseAddress & ~1); *ptr = RtlImageRvaToVa( RtlImageNtHeader(mod), mod, entry->OffsetToData, NULL ); } else *ptr = (char *)BaseAddress + entry->OffsetToData; } if (size) *size = entry->Size; } } _SEH2_EXCEPT(page_fault(_SEH2_GetExceptionCode())) { status = _SEH2_GetExceptionCode(); } _SEH2_END; return status; }
/****************************************************************** * pe_map_section * * Maps a single section into memory from an PE file */ const char* pe_map_section(struct image_section_map* ism) { void* mapping; struct pe_file_map* fmap = &ism->fmap->u.pe; if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections && fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP) { IMAGE_NT_HEADERS* nth; if (fmap->sect[ism->sidx].shdr.Misc.VirtualSize > fmap->sect[ism->sidx].shdr.SizeOfRawData) { FIXME("Section %ld: virtual (0x%x) > raw (0x%x) size - not supported\n", ism->sidx, fmap->sect[ism->sidx].shdr.Misc.VirtualSize, fmap->sect[ism->sidx].shdr.SizeOfRawData); return IMAGE_NO_MAP; } /* FIXME: that's rather drastic, but that will do for now * that's ok if the full file map exists, but we could be less aggressive otherwise and * only map the relevant section */ if ((mapping = pe_map_full(ism->fmap, &nth))) { fmap->sect[ism->sidx].mapped = RtlImageRvaToVa(nth, mapping, fmap->sect[ism->sidx].shdr.VirtualAddress, NULL); return fmap->sect[ism->sidx].mapped; } } return IMAGE_NO_MAP; }
/****************************************************************** * pe_map_directory * * Maps a directory content out of a PE file */ const char* pe_map_directory(struct module* module, int dirno, DWORD* size) { IMAGE_NT_HEADERS* nth; void* mapping; if (module->type != DMT_PE || !module->format_info[DFI_PE]) return NULL; if (dirno >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || !(mapping = pe_map_full(&module->format_info[DFI_PE]->u.pe_info->fmap, &nth))) return NULL; if (size) *size = nth->OptionalHeader.DataDirectory[dirno].Size; return RtlImageRvaToVa(nth, mapping, nth->OptionalHeader.DataDirectory[dirno].VirtualAddress, NULL); }
/****************************************************************** * pe_load_stabs * * look for stabs information in PE header (it's how the mingw compiler provides * its debugging information) */ static BOOL pe_load_stabs(const struct process* pcs, struct module* module, void* mapping, IMAGE_NT_HEADERS* nth) { IMAGE_SECTION_HEADER* section; int i, stabsize = 0, stabstrsize = 0; unsigned int stabs = 0, stabstr = 0; BOOL ret = FALSE; section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { if (!strcasecmp((const char*)section->Name, ".stab")) { stabs = section->VirtualAddress; stabsize = section->SizeOfRawData; } else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) { stabstr = section->VirtualAddress; stabstrsize = section->SizeOfRawData; } } if (stabstrsize && stabsize) { ret = stabs_parse(module, module->module.BaseOfImage - nth->OptionalHeader.ImageBase, RtlImageRvaToVa(nth, mapping, stabs, NULL), stabsize, RtlImageRvaToVa(nth, mapping, stabstr, NULL), stabstrsize); } TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); return ret; }
/****************************************************************** * pe_load_msc_debug_info * * Process MSC debug information in PE file. */ static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module) { struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; BOOL ret = FALSE; const IMAGE_DATA_DIRECTORY* dir; const IMAGE_DEBUG_DIRECTORY*dbg = NULL; int nDbg; void* mapping; IMAGE_NT_HEADERS* nth; if (!(mapping = pe_map_full(fmap, &nth))) return FALSE; /* Read in debug directory */ dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG; nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY); if (!nDbg) goto done; dbg = RtlImageRvaToVa(nth, mapping, dir->VirtualAddress, NULL); /* Parse debug directory */ if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { /* Debug info is stripped to .DBG file */ const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*) ((const char*)mapping + dbg->PointerToRawData); if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC || misc->DataType != IMAGE_DEBUG_MISC_EXENAME) { ERR("-Debug info stripped, but no .DBG file in module %s\n", debugstr_w(module->module.ModuleName)); } else { ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp); } } else { const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); /* Debug info is embedded into PE module */ ret = pe_load_debug_directory(pcs, module, mapping, sectp, nth->FileHeader.NumberOfSections, dbg, nDbg); } done: pe_unmap_full(fmap); return ret; }
/*********************************************************************** * ImageDirectoryEntryToDataEx (DBGHELP.@) * * Search for specified directory in PE image * * PARAMS * * base [in] Image base address * image [in] TRUE - image has been loaded by loader, FALSE - raw file image * dir [in] Target directory index * size [out] Receives directory size * section [out] Receives pointer to section header of section containing directory data * * RETURNS * Success: pointer to directory data * Failure: NULL * */ PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section ) { const IMAGE_NT_HEADERS *nt; DWORD addr; *size = 0; if (section) *section = NULL; if (!(nt = RtlImageNtHeader( base ))) return NULL; if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL; if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL; *size = nt->OptionalHeader.DataDirectory[dir].Size; if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr; return RtlImageRvaToVa( nt, base, addr, section ); }
/*********************************************************************** * pe_load_export_debug_info */ static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module) { struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; unsigned int i; const IMAGE_EXPORT_DIRECTORY* exports; DWORD base = module->module.BaseOfImage; DWORD size; IMAGE_NT_HEADERS* nth; void* mapping; if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE; if (!(mapping = pe_map_full(fmap, &nth))) return FALSE; #if 0 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */ /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */ symt_new_public(module, NULL, module->module.ModuleName, FALSE, base, 1); #endif /* Add entry point */ symt_new_public(module, NULL, "EntryPoint", FALSE, base + nth->OptionalHeader.AddressOfEntryPoint, 1); #if 0 /* FIXME: we'd better store addresses linked to sections rather than absolute values */ IMAGE_SECTION_HEADER* section; /* Add start of sections */ section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { symt_new_public(module, NULL, section->Name, FALSE, RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1); } #endif /* Add exported functions */ if ((exports = RtlImageDirectoryEntryToData(mapping, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size))) { const WORD* ordinals = NULL; const DWORD_PTR* functions = NULL; const DWORD* names = NULL; unsigned int j; char buffer[16]; functions = RtlImageRvaToVa(nth, mapping, exports->AddressOfFunctions, NULL); ordinals = RtlImageRvaToVa(nth, mapping, exports->AddressOfNameOrdinals, NULL); names = RtlImageRvaToVa(nth, mapping, exports->AddressOfNames, NULL); if (functions && ordinals && names) { for (i = 0; i < exports->NumberOfNames; i++) { if (!names[i]) continue; symt_new_public(module, NULL, RtlImageRvaToVa(nth, mapping, names[i], NULL), FALSE, base + functions[ordinals[i]], 1); } for (i = 0; i < exports->NumberOfFunctions; i++) { if (!functions[i]) continue; /* Check if we already added it with a name */ for (j = 0; j < exports->NumberOfNames; j++) if ((ordinals[j] == i) && names[j]) break; if (j < exports->NumberOfNames) continue; snprintf(buffer, sizeof(buffer), "%d", i + exports->Base); symt_new_public(module, NULL, buffer, FALSE, base + (DWORD)functions[i], 1); } } } /* no real debug info, only entry points */ if (module->module.SymType == SymDeferred) module->module.SymType = SymExport; pe_unmap_full(fmap); return TRUE; }
/************************************************************************* * ICO_ExtractIconExW [internal] * * NOTES * nIcons = 0: returns number of Icons in file * * returns * invalid file: -1 * failure:0; * success: number of icons in file (nIcons = 0) or nr of icons retrieved */ static UINT ICO_ExtractIconExW( LPCWSTR lpszExeFileName, HICON * RetPtr, INT nIconIndex, UINT nIcons, UINT cxDesired, UINT cyDesired, UINT *pIconId, UINT flags) { UINT ret = 0; UINT cx1, cx2, cy1, cy2; LPBYTE pData; DWORD sig; HANDLE hFile; UINT16 iconDirCount = 0, iconCount = 0; LPBYTE peimage; HANDLE fmapping; DWORD fsizeh,fsizel; WCHAR szExePath[MAX_PATH]; DWORD dwSearchReturn; TRACE("%s, %d, %d %p 0x%08x\n", debugstr_w(lpszExeFileName), nIconIndex, nIcons, pIconId, flags); dwSearchReturn = SearchPathW(NULL, lpszExeFileName, NULL, sizeof(szExePath) / sizeof(szExePath[0]), szExePath, NULL); if ((dwSearchReturn == 0) || (dwSearchReturn > sizeof(szExePath) / sizeof(szExePath[0]))) { WARN("File %s not found or path too long\n", debugstr_w(lpszExeFileName)); return -1; } hFile = CreateFileW(szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) return ret; fsizel = GetFileSize(hFile,&fsizeh); /* Map the file */ fmapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); CloseHandle(hFile); if (!fmapping) { WARN("CreateFileMapping error %ld\n", GetLastError() ); return 0xFFFFFFFF; } if (!(peimage = MapViewOfFile(fmapping, FILE_MAP_READ, 0, 0, 0))) { WARN("MapViewOfFile error %ld\n", GetLastError() ); CloseHandle(fmapping); return 0xFFFFFFFF; } CloseHandle(fmapping); cx1 = LOWORD(cxDesired); cx2 = HIWORD(cxDesired); cy1 = LOWORD(cyDesired); cy2 = HIWORD(cyDesired); if (pIconId) /* Invalidate first icon identifier */ *pIconId = 0xFFFFFFFF; if (!pIconId) /* if no icon identifier array present use the icon handle array as intermediate storage */ pIconId = (UINT*)RetPtr; sig = USER32_GetResourceTable(peimage, fsizel, &pData); #ifdef WINE /* ico file or NE exe/dll*/ if (sig==IMAGE_OS2_SIGNATURE || sig==1) /* .ICO file */ { BYTE *pCIDir = 0; NE_TYPEINFO *pTInfo = (NE_TYPEINFO*)(pData + 2); NE_NAMEINFO *pIconStorage = NULL; NE_NAMEINFO *pIconDir = NULL; LPicoICONDIR lpiID = NULL; ULONG uSize = 0; TRACE("-- OS2/icon Signature (0x%08x)\n", sig); if (pData == (BYTE*)-1) { pCIDir = ICO_GetIconDirectory(peimage, &lpiID, &uSize); /* check for .ICO file */ if (pCIDir) { iconDirCount = 1; iconCount = lpiID->idCount; TRACE("-- icon found %p 0x%08x 0x%08x 0x%08x\n", pCIDir, uSize, iconDirCount, iconCount); } } else while (pTInfo->type_id && !(pIconStorage && pIconDir)) { if (pTInfo->type_id == NE_RSCTYPE_GROUP_ICON) /* find icon directory and icon repository */ { iconDirCount = pTInfo->count; pIconDir = ((NE_NAMEINFO*)(pTInfo + 1)); TRACE("\tfound directory - %i icon families\n", iconDirCount); } if (pTInfo->type_id == NE_RSCTYPE_ICON) { iconCount = pTInfo->count; pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1)); TRACE("\ttotal icons - %i\n", iconCount); } pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO)); } if ((pIconStorage && pIconDir) || lpiID) /* load resources and create icons */ { if (nIcons == 0) { ret = iconDirCount; if (lpiID) /* *.ico file, deallocate heap pointer*/ HeapFree(GetProcessHeap(), 0, pCIDir); } else if (nIconIndex < iconDirCount) { UINT16 i, icon; if (nIcons > iconDirCount - nIconIndex) nIcons = iconDirCount - nIconIndex; for (i = 0; i < nIcons; i++) { /* .ICO files have only one icon directory */ if (lpiID == NULL) /* not *.ico */ pCIDir = USER32_LoadResource(peimage, pIconDir + i + nIconIndex, *(WORD*)pData, &uSize); pIconId[i] = LookupIconIdFromDirectoryEx(pCIDir, TRUE, cx1, cy1, flags); if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(pCIDir, TRUE, cx2, cy2, flags); } if (lpiID) /* *.ico file, deallocate heap pointer*/ HeapFree(GetProcessHeap(), 0, pCIDir); for (icon = 0; icon < nIcons; icon++) { pCIDir = NULL; if (lpiID) pCIDir = ICO_LoadIcon(peimage, lpiID->idEntries + (int)pIconId[icon], &uSize); else for (i = 0; i < iconCount; i++) if (pIconStorage[i].id == ((int)pIconId[icon] | 0x8000) ) pCIDir = USER32_LoadResource(peimage, pIconStorage + i, *(WORD*)pData, &uSize); if (pCIDir) { RetPtr[icon] = CreateIconFromResourceEx(pCIDir, uSize, TRUE, 0x00030000, cx1, cy1, flags); if (cx2 && cy2) RetPtr[++icon] = CreateIconFromResourceEx(pCIDir, uSize, TRUE, 0x00030000, cx2, cy2, flags); } else RetPtr[icon] = 0; } ret = icon; /* return number of retrieved icons */ } } } #else if (sig == 1 || sig == 2) /* .ICO or .CUR file */ { TRACE("-- icon Signature (0x%08x)\n", sig); if (pData == (BYTE*)-1) { INT cx[2] = {cx1, cx2}, cy[2] = {cy1, cy2}; INT index; for(index = 0; index < 2; index++) { DWORD dataOffset; LPBYTE imageData; POINT hotSpot; LPICONIMAGE entry; dataOffset = get_best_icon_file_offset(peimage, fsizel, cx[index], cy[index], sig == 1, flags, sig == 1 ? NULL : &hotSpot); if (dataOffset) { HICON icon; WORD *cursorData = NULL; imageData = peimage + dataOffset; entry = (LPICONIMAGE)(imageData); if(sig == 2) { /* we need to prepend the bitmap data with hot spots for CreateIconFromResourceEx */ cursorData = HeapAlloc(GetProcessHeap(), 0, entry->icHeader.biSizeImage + 2 * sizeof(WORD)); if(!cursorData) continue; cursorData[0] = hotSpot.x; cursorData[1] = hotSpot.y; memcpy(cursorData + 2, imageData, entry->icHeader.biSizeImage); imageData = (LPBYTE)cursorData; } icon = CreateIconFromResourceEx(imageData, entry->icHeader.biSizeImage, sig == 1, 0x00030000, cx[index], cy[index], flags); if (icon) { RetPtr[index] = icon; iconCount = 1; } if(cursorData != NULL) HeapFree(GetProcessHeap(), 0, cursorData); } } } ret = iconCount; /* return number of retrieved icons */ } #endif /* end ico file */ /* exe/dll */ else if( sig == IMAGE_NT_SIGNATURE ) { BYTE *idata, *igdata; const IMAGE_RESOURCE_DIRECTORY *rootresdir, *iconresdir, *icongroupresdir; const IMAGE_RESOURCE_DATA_ENTRY *idataent, *igdataent; const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent; ULONG size; UINT i; rootresdir = RtlImageDirectoryEntryToData((HMODULE)peimage, FALSE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size); if (!rootresdir) { 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))) { WARN("No Icongroupresourcedirectory!\n"); goto end; /* failure */ } iconDirCount = icongroupresdir->NumberOfNamedEntries + icongroupresdir->NumberOfIdEntries; /* only number of icons requested */ if( !pIconId ) { ret = iconDirCount; goto end; /* success */ } if( nIconIndex < 0 ) { /* search resource id */ int n = 0; int iId = abs(nIconIndex); const IMAGE_RESOURCE_DIRECTORY_ENTRY* xprdeTmp = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1); while(n<iconDirCount && xprdeTmp) { if(xprdeTmp->Id == iId) { nIconIndex = n; break; } n++; xprdeTmp++; } if (nIconIndex < 0) { WARN("resource id %d not found\n", iId); goto end; /* failure */ } } else { /* check nIconIndex to be in range */ if (nIconIndex >= iconDirCount) { WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount); goto end; /* failure */ } } /* assure we don't get too much */ if( nIcons > iconDirCount - nIconIndex ) nIcons = iconDirCount - nIconIndex; /* starting from specified index */ xresent = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1) + nIconIndex; for (i=0; i < nIcons; i++,xresent++) { const IMAGE_RESOURCE_DIRECTORY *resdir; /* go down this resource entry, name */ resdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)rootresdir + xresent->OffsetToDirectory); /* default language (0) */ resdir = find_entry_default(resdir,rootresdir); igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir; /* lookup address in mapped image for virtual address */ igdata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, igdataent->OffsetToData, NULL); if (!igdata) { FIXME("no matching real address for icongroup!\n"); goto end; /* failure */ } pIconId[i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx1, cy1, flags); if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx2, cy2, flags); } if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICON),rootresdir))) { WARN("No Iconresourcedirectory!\n"); goto end; /* failure */ } for (i=0; i<nIcons; i++) { const IMAGE_RESOURCE_DIRECTORY *xresdir; xresdir = find_entry_by_id(iconresdir, LOWORD(pIconId[i]), rootresdir); if( !xresdir ) { WARN("icon entry %d not found\n", LOWORD(pIconId[i])); RetPtr[i]=0; continue; } xresdir = find_entry_default(xresdir, rootresdir); idataent = (const IMAGE_RESOURCE_DATA_ENTRY*)xresdir; idata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, idataent->OffsetToData, NULL); if (!idata) { WARN("no matching real address found for icondata!\n"); RetPtr[i]=0; continue; } RetPtr[i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx1, cy1, flags); if (cx2 && cy2) RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags); } ret = i; /* return number of retrieved icons */ } /* if(sig == IMAGE_NT_SIGNATURE) */ end: UnmapViewOfFile(peimage); /* success */ return ret; }