Windows 11

Fixing PowerShell on Windows PE for ARM64

In past blog posts, I noted that the ADK for Windows 10 started adding ARM64 builds of Windows PE, but they were missing some key things: no HTA support, and busted .NET Framework/PowerShell support. While the HTA support is likely to never be addressed (given that it’s based on Internet Explorer, which is mostly dead), there was still hope for .NET Framework and PowerShell.

I did notice that in the Windows 11 version of the ADK, the .NET Framework component was at least a more reasonable size (compared to the Windows 10 version that seemed to be mostly empty). So, time to try it out again. I can create a custom Windows PE boot image using the process I described here, and booted my ARM64 device into Windows PE to get to a command prompt, from where I can try to run PowerShell.exe:

And that’s all that happens — PowerShell doesn’t launch successfully. A quick check of the exit code shows a return code of -1073741515, which is hex C0000135, or STATUS_DLL_NOT_FOUND:

OK, PowerShell is having trouble loading a DLL. So all we need to do is figure out what DLL it is missing. Bring on ProcMon for ARM64, which works beautifully on ARM64, so that we can see what it tried to load:

OK, the file is xtajit64.dll. A quick internet search takes me to this documentation page for WOW64, which explains that this file is the x86 software emulator that lets Intel x86/x64 binaries run on ARM64 unchanged. That means PowerShell isn’t 100% native code on ARM64, which isn’t too much of a surprise given that it was x86-only (32-bit) on the original Windows 10 ARM64 releases.

So there are two possibilities at this point: PowerShell will need to be able to run Intel x64 (64-bit) binaries on ARM64, or it will need to be able to run both x64 (64-bit) and x86 (32-bit). Either way, is it possible to make it work without really hacking up Windows PE? It’s certainly worth a try.

A quick search in the full Windows 11 ARM64 OS shows that this file is present in a wow64 OS component:

And surprisingly that component isn’t too big, with just a few files. Trying to increase my odds, I figured I would grab all five of those files and add them to my Windows PE boot image to see what happens. And presto, PowerShell.exe now runs successfully:

That was easier than expected. Scanning through the ProcMon output, I see that the xtajit64.dll was the only one of the five files loaded, so I guess I didn’t really need the other four.

I firmly believe that this would only work with Windows 11 and the Intel x64 (64-bit) emulation support that it includes, building on top of ARM64EC, announced back in June 2021. With ARM64EC, the binaries in this Windows PE ARM64 OS can contain ARM64 “chunks” as well as x64 chunks, with the ability to dynamically translate those x64 chunks using that xtajit64.dll (a “just-in-time” compiler of Intel binary code). This “magic” means that you don’t need three different versions of each binary (ARM64, x64, x86), you just need one; all code doesn’t need to be ported to ARM64 at once (or ever), except for the most performance-sensitive chunks.

Sadly, I guess no one ever bothered to figure out if Windows PE had the necessary pieces to make this “magic” work. I’m not terribly surprised by this, just a little disappointed in the attention to detail when it comes to ARM64 all-up (a rant for a later time).

Categories: Windows 11

Tagged as: , ,