Appcompat: 0x8007000B Bad Image Format - The format of DLL or executable being loaded is invalid
Last week I did some interesting AppCompat work. The customer had a legacy process control application that would only work on Windows 2003. Windows 2003 is out of support by nearly a decade, and the November 2022 Windows update broke those machines' ability to talk to the domain. Oops.
The customer had tried running the app on Win10, but launching it generated a cascade of "0x8007000B Bad Image Format The format of DLL or executable being loaded is invalid error" errors.
I've seen the 0x8007000B Bad Image Format error when trying to run 64-bit code on a 32-bit machine, and I guessed that in this case I had the opposite problem, 64-bit code trying to run a 32-bit library. Digging further in I found the app was written in Visual Basic 8/2008, and interestingly enough it was running on 64-bit mode when we ran it on Win10. That's odd. How can an app that was running on 32-bit Windows 2003 end up running in 64-bit mode?
Here's the bit where I learned something. A normal Windows executable .exe file, aka a PE executable has the "bittidness" of the application set at compile time in the PE header and it can't be changed. For .net applications, that's not the case. They aren't a true PE executable. Instead, they contain .net bytecode that is compiled to machine code at runtime on the target machine. This yields a platform independent executable that can be run on 32-bit, 64-bit, or ARM machines. Unfortunately, that portability only works if all the code is "managed" code that is compiled this way.
That was the problem. The VB code, even though it was a .exe copied from a 32-bit machine, was grinding through the .net runtime compiler and the results were running in 64-bit mode. When that 64-bit executable tried to load the non-managed 32-bit DLL, it failed.
Right, so how do you fix that?
Binging, I found a StackOverflow post that mentioned CorFlags.exe as a tool to view and change the 32/64 bit headers of .net code.
x86 - How to force .NET application to run in 32bit mode - Stack Overflow
Skipping over the bit where I wasted half an hour trying to find CorFlags by downloading and installing various SDKs, it's available as part of the .net 4.8.1 Developer Pack from .NET SDKs downloads for Visual Studio (microsoft.com). Once I installed it, CorFlags.exe was under "c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools"
With the tool in hand, we took a backup of the application folder and changed the binary to run in 32-bit mode with
Corflags Hibachi.exe -32BITREQ+
That fixed it! The app launched and didn't immediately crash. Yeah! During smoke testing we determined that many executables in the same folder needed that option set, so we used a command line for loop to change all the executables in the app folder.
For %i in (*.exe) do Corflags %i -32BITREQ+
With that done all the buttons and knobs seemed to work. We handed it off to the app owner and SME to test it properly.
One last thing popped up as we were closing the books. The customer indicated they had a tool to "build" new screens. Digging into how that worked, the screen builder was programatically generating new VB code and calling the built-in .net vb compiler (vbc.exe) to actually compile a new executable for the new screen. That's an interesting pattern. I cautioned the customer that I wasn't an expert on VB generally, but looking up the Command line options for the VB Compiler vbc.exe (learn.microsoft.com) I shared the option to have it force 32-bit mode at compile time, -platform:x86. The customer said they'd update the compiler batch file and have the app owner test that too. I don't know if that actually worked or not. If it doesn't, they can always change it with CorFlags after the fact.
All things considered, it was a super productive meeting. In a single afternoon we were able to demo several AppCompat tools from the ADK, perform live troubleshooting on the failing app with process monitor/process explorer/etc, find the underlying problem, and fix it. I couldn't be happier with how that turned out.
The end goal was to help the customer get off Windows 2003, and unfortunately that's not done yet. They still have one more app left to fix, and the software vendor is fixing that one. I hope they are able to make it work. If not, maybe I'll get a chance to take a look at it too. Until then, CorFlags is one more shiny new tool in my toolbox.
Elizabeth Greene ©2023