Occasionally when deploying my app* a seemingly random one of the bundled DLLs gets in a strange state. On the instance I'm debugging now it's System.Net.Security.dll (from .NET Core 3.1), but it could be any.
- In Explorer, the DLL shows no version information (version, product name, copyright, etc).
- The .NET app fails to load the library, yielding a BadImageFormatException: assembly manifest not found.
- Resource Hacker does show the version info block.
- When I make a copy of the DLL, the copy works fine. The original and copy are bit-for-bit identical.
- When I make a disk image of the disk and attach it elsewhere, the problematic file is fine.
- When I call GetVersionInfoSizeEx() on the DLL, it fails with error 1813 (
ERROR_RESOURCE_TYPE_NOT_FOUND
). It works fine on the bit-for-bit identical copy.
Since there clearly is nothing wrong with the bits in the file, I'm inclined to suspect corruption in sort of cache or in-memory data structure.
How come the version info cannot be read for this DLL, while it can be read just fine from an identical copy?
I did some digging and found that the resource APIs call LoadLibraryEx() with LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE
. After some hoops we end up in ntdll's private LdrpResGetResourceDirectory() which does some calculations and looks up a field at an offset inside the module:
00007ffd`c4c17f61 0fb74a0e movzx ecx,word ptr [rdx+0Eh]
00007ffd`c4c17f80 6685c9 test cx,cx
00007ffd`c4c17f83 7463 je ntdll!LdrpResGetResourceDirectory+0x408 (00007ffd`c4c17fe8)
rdx
is a pointer to somewhere inside the module. From my reading:
rdx = handle + 0x100 + somestruct.(0x14) - somestruct.(0x0C)
This is where the execution diverges between the problematic original DLL and the bit-for-bit identical copy: cx
is 0 for the bad original but 1 for the good copy.
(I've tried calling LoadLibrary() on the DLL and then dumping the memory to compare it against the original DLL, but I can't make out the forest for the trees in the resulting diff.)
*) A self-contained .NET Core 3.1 application that's deployed to Windows Server 2019 Azure Batch nodes by way of downloading and extracting a zip, then robocopying it to shared/.