diff options
author | David Wrighton <davidwr@microsoft.com> | 2019-03-25 16:04:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-25 16:04:26 -0700 |
commit | 36c34ed6724416f212aa81eb8596f0bfed59d3f1 (patch) | |
tree | cb3fa26ca6042d58b363d876b304c88865bd15a4 /src/utilcode | |
parent | 32df0e741befb3cc815927c37cb29dd039e62158 (diff) | |
download | coreclr-36c34ed6724416f212aa81eb8596f0bfed59d3f1.tar.gz coreclr-36c34ed6724416f212aa81eb8596f0bfed59d3f1.tar.bz2 coreclr-36c34ed6724416f212aa81eb8596f0bfed59d3f1.zip |
Replace Win32 resource reading logic with cross platform implementation (#23363)
* FindResource direct implementation in PEDecoder
* Fixup bugs identified in resource reading
Diffstat (limited to 'src/utilcode')
-rw-r--r-- | src/utilcode/pedecoder.cpp | 145 |
1 files changed, 130 insertions, 15 deletions
diff --git a/src/utilcode/pedecoder.cpp b/src/utilcode/pedecoder.cpp index 794540a97b..7324f6e9fa 100644 --- a/src/utilcode/pedecoder.cpp +++ b/src/utilcode/pedecoder.cpp @@ -1790,7 +1790,96 @@ void PEDecoder::LayoutILOnly(void *base, BOOL allowFullPE) const #endif // #ifndef DACCESS_COMPILE -#ifndef FEATURE_PAL +DWORD PEDecoder::ReadResourceDictionary(DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pIsDictionary) const +{ + *pIsDictionary = FALSE; + + if (!CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY))) + { + return 0; + } + + IMAGE_RESOURCE_DIRECTORY *pResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)GetRvaData(rva); + + if (pResourceDirectory->MajorVersion != 4) + return 0; + + if (pResourceDirectory->MinorVersion != 0) + return 0; + + // Check to see if entire resource dictionary is accessible + if (!CheckRva(rva + sizeof(IMAGE_RESOURCE_DIRECTORY), + (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * pResourceDirectory->NumberOfNamedEntries) + + (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * pResourceDirectory->NumberOfIdEntries))) + { + return 0; + } + + IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY)); + + // A fast implementation of resource lookup uses a binary search, but our needs are simple, and a linear search + // is easier to prove correct, so do that instead. + DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries; + + for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++) + { + BOOL foundEntry = FALSE; + + if (((UINT_PTR)name) <= 0xFFFF) + { + // name is id + if (pDirectoryEntries[iEntry].Name == (DWORD)name) + foundEntry = TRUE; + } + else + { + // name is string + DWORD entryName = pDirectoryEntries[iEntry].Name; + if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING)) + continue; + + DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection; + + if (!CheckRva(entryNameRva, sizeof(WORD))) + return 0; + + size_t entryNameLen = *(WORD*)GetRvaData(entryNameRva); + if (wcslen(name) != entryNameLen) + continue; + + if (!CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen)))) + return 0; + + if (memcmp((WCHAR*)GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0) + foundEntry = TRUE; + } + + if (!foundEntry) + continue; + + *pIsDictionary = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY); + DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY; + DWORD dataRva = rvaOfResourceSection + offsetToData; + return dataRva; + } + + return 0; +} + +DWORD PEDecoder::ReadResourceDataEntry(DWORD rva, COUNT_T *pSize) const +{ + *pSize = 0; + + if (!CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) + { + return 0; + } + + IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)GetRvaData(rva); + *pSize = pDataEntry->Size; + return pDataEntry->OffsetToData; +} + void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize /*=NULL*/) const { CONTRACTL { @@ -1800,31 +1889,57 @@ void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSiz GC_NOTRIGGER; } CONTRACTL_END; - if (pSize != NULL) - *pSize = 0; + COUNT_T sizeUnused = 0; // Use this variable if pSize is null + if (pSize == NULL) + pSize = &sizeUnused; + + *pSize = 0; + + if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE)) + return NULL; + + COUNT_T resourceDataSize = 0; + IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE); - HMODULE hModule = (HMODULE) dac_cast<TADDR>(GetBase()); + if (pDir->VirtualAddress == 0) + return NULL; - // Use the Win32 functions to decode the resources + BOOL isDictionary = FALSE; + DWORD nameTableRva = ReadResourceDictionary(pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDictionary); - HRSRC hResource = WszFindResourceEx(hModule, lpType, lpName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); - if (!hResource) + if (!isDictionary) + return NULL; + + if (nameTableRva == 0) return NULL; - HGLOBAL hLoadedResource = ::LoadResource(hModule, hResource); - if (!hLoadedResource) + DWORD languageTableRva = ReadResourceDictionary(pDir->VirtualAddress, nameTableRva, lpName, &isDictionary); + if (!isDictionary) return NULL; - PVOID pResource = ::LockResource(hLoadedResource); - if (!pResource) + if (languageTableRva == 0) return NULL; - if (pSize != NULL) - *pSize = ::SizeofResource(hModule, hResource); + // This api is designed to find resources with LANGID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) + // This translates to LANGID 0 as the initial lookup point, which is sufficient for the needs of this api at this time + // (FindResource in the Windows api implements a large number of fallback paths which this api does not implement) + + DWORD resourceDataEntryRva = ReadResourceDictionary(pDir->VirtualAddress, languageTableRva, 0, &isDictionary); + if (isDictionary) // This must not be a resource dictionary itself + return NULL; + + if (resourceDataEntryRva == 0) + return NULL; + + DWORD resourceDataRva = ReadResourceDataEntry(resourceDataEntryRva, pSize); + if (!CheckRva(resourceDataRva, *pSize)) + { + *pSize = 0; + return NULL; + } - return pResource; + return (void*)GetRvaData(resourceDataRva); } -#endif // FEATURE_PAL BOOL PEDecoder::HasNativeHeader() const { |