前回の投稿で、WoW64の説明と関連するAPIのテストツールについて説明しました。今回は、各APIの振る舞を各Windows上で確認します。
WoW64に関するテストツールと動作環境
前回の投稿で説明した、WoW64に関連する5つのAPIを確認するテストツールを使って、APIの振る舞いを確認します。このテストツールは、このサイトのツールのページで公開しています。
前回に説明したようにx86 / x64 / ARM32 / ARM64 のCPUアーキテクチャーでビルドしたアプリの各Windowsシステムでの動作可否は以下のようになります。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | 可 (Native) | – | – | – |
64ビットWindows 10 on x64 CPU | 可 | 可 (Native) | – | – |
64ビットWindows 11 on x64 CPU | 可 | 可 (Native) | – | – |
64ビットWindows 10 on ARM64 CPU | 可 | – | 可 | 可 (Native) |
64ビットWindows 11 on ARM64 CPU | 可 | 可 | 可 | 可 (Native) |
「可」の部分のリンクは、実行したアプリのスクリーンショットへのリンクとなります。実行画面を確認したい場合はリンクをクリックしてください。
これらの動作可能なパターンの各APIの挙動を確認します。
GetSystemInfo()
VOID
GetSystemInfo(
_Out_ LPSYSTEM_INFO lpSystemInfo);
GetSystemInfo()は、実行中のプロセスがどのシステム上で動作しているかを確認することができます。WindowsのNativeのシステム情報ではなく、あくまで実行中のプロセスがどのシステム(または、サブシステム)で動作しているかの情報です。WoW64サブシステム上などで動作している場合は、そのサブシステムの情報となります。
lpSystemInfo->wProcessorArchitecture や lpSystemInfo->dwProcessorType でCPUアーキテクチャが確認できます。
実行結果は以下の通りとなりました。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | INTEL (0) INTEL_PENTIUM (586) | – | – | – |
64ビットWindows 10 on x64 CPU | INTEL (0) INTEL_PENTIUM (586) | AMD64 (9) AMD_X8664 (8664) | – | – |
64ビットWindows 11 on x64 CPU | INTEL (0) INTEL_PENTIUM (586) | AMD64 (9) AMD_X8664 (8664) | – | – |
64ビットWindows 10 on ARM64 CPU | INTEL (0) INTEL_PENTIUM (586) | – | ARM (5) unknown (0) | ARM64 (12) unknown (0) |
64ビットWindows 11 on ARM64 CPU | INTEL (0) INTEL_PENTIUM (586) | AMD64 (9) AMD_X8664 (8664) | ARM (5) unknown (0) | ARM64 (12) unknown (0) |
この表では上段の値がlpSystemInfo->wProcessorArchitecture の値で、下段の値がlpSystemInfo->dwProcessorTypeの値となります。
現在実行しているプロセスの情報であるため、Windowsの種類が異なっても、各アプリが取得できる情報は同じとなりました。
これらの振る舞いは、APIリファレンスに記載されている振舞と同じです。
GetNativeSystemInfo()
VOID
GetNativeSystemInfo(
_Out_ LPSYSTEM_INFO lpSystemInfo);
GetNativeSystemInfo()は、Windowsがどのシステム上で動作しているかを確認することができます。プロセスのシステム情報ではなく、Windowsのシステム情報です。実行中のプロセスがWoW64サブシステム上で動作していたとしても、Windowsのシステム情報が取得できます。ただし、完全に系統が異なるCPUアーキテクチャー上のWoW64サブシステム上でアプリが動作している場合(たとえば、ARM64のWindowsシステム上でx86アプリやx64アプリが動作している場合)は、アプリの実行サブシステムと同じ情報が返されます。
lpSystemInfo->wProcessorArchitecture や lpSystemInfo->dwProcessorType でCPUアーキテクチャが確認できます。
実行結果は以下の通りとなりました。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | INTEL (0) INTEL_PENTIUM (586) | – | – | – |
64ビットWindows 10 on x64 CPU | AMD64 (9) AMD_X8664 (8664) | AMD64 (9) AMD_X8664 (8664) | – | – |
64ビットWindows 11 on x64 CPU | AMD64 (9) AMD_X8664 (8664) | AMD64 (9) AMD_X8664 (8664) | – | – |
64ビットWindows 10 on ARM64 CPU | INTEL (0) INTEL_PENTIUM (586) | – | ARM64 (12) unknown (0) | ARM64 (12) unknown (0) |
64ビットWindows 11 on ARM64 CPU | AMD64 (9) INTEL_PENTIUM (586) | AMD64 (9) AMD_X8664 (8664) | ARM64 (12) unknown (0) | ARM64 (12) unknown (0) |
この表では上段の値がlpSystemInfo->wProcessorArchitecture の値で、下段の値がlpSystemInfo->dwProcessorTypeの値となります。
プロセスの実行をホストしているWindowsの情報であるため、アプリの種類が異なっても、各アプリが取得できる情報は、WindowsのCPUアーキテクチャーがアプリのCPUアーキテクチャーが同系の場合は同じとなりました。CPUアーキテクチャーが異なる場合は、アプリのCPUアーキテクチャーと同じ値が取得できます。
これらの振る舞いは、APIリファレンスに記載されている振舞と同じです。
IsWow64Process()
BOOL
IsWow64Process(
_In_ HANDLE hProcess,
_Out_ PBOOL Wow64Process);
IsWow64Process()は、実行中のプロセスが、WoW64サブシステム上で動作しているかを確認することができます。ただし、系統が異なるCPUアーキテクチャー上のWoW64サブシステム上でアプリが動作している場合(たとえば、ARM64のWindowsシステム上でx86アプリやx64アプリが動作している場合)は、FALSEが返ります。
そのため、Windowsとアプリで系統が異なるCPUアーキテクチャーの場合は、WoW64サブシステム上で動作しているかどうかは、正しく判定できません。
実行結果は以下の通りとなりました。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | FALSE | – | – | – |
64ビットWindows 10 on x64 CPU | TRUE | FALSE | – | – |
64ビットWindows 11 on x64 CPU | TRUE | FALSE | – | – |
64ビットWindows 10 on ARM64 CPU | FALSE | – | FALSE | FALSE |
64ビットWindows 11 on ARM64 CPU | TRUE | FALSE | TRUE | FALSE |
各環境上での挙動は、ほぼAPIリファレンスと同じです。
IsWow64Process() の Parameters (Microsoftのサイトより、2022/06/12時点の情報)
[out] PBOOL Wow64Process
A pointer to a value that is set to TRUE if the process is running under WOW64 on an Intel64 or x64 processor. If the process is running under 32-bit Windows, the value is set to FALSE. If the process is a 32-bit application running under 64-bit Windows 10 on ARM, the value is set to FALSE. If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE.
と書かれています。日本語訳は以下の通り。
[out] PBOOL Wow64Process
値を保存する変数へのポインタ。プロセスがIntel64またはx64プロセッサ上のWOW64で動作している場合、この値はTRUEに設定される。プロセスが32ビットWindowsの下で実行されている場合、この値はFALSEに設定される。プロセスがARM上の64ビットWindows 10で実行されている32ビットアプリの場合、この値はFALSEに設定されます。プロセスが64ビットWindowsの下で実行されている64ビットアプリである場合、この値もFALSEに設定されます。
実行結果は、「64ビットWindows 11 on ARM64 CPU」以外については、APIリファレンス通りとなります。
しかし、Windows 11 on ARM64の挙動がWindows 10 on ARM64の挙動と異なるようです。Windows 11 on ARM64では、アプリがx86かARM32であるかは問わず32ビットアプリの場合は、TRUEが返るようになっています。APIリファレンスにはWindows 11での挙動が記載されていないため、この値がAPI仕様として正常な値なのかどうかは、わかりません。
推論すると、本当のNativeのシステムのアーキテクチャーと比較した結果を返しているのではなく、GetNativeSystemInfo()
の結果のシステムのアーキテクチャーに対して、アプリのアーキテクチャーと比較した結果を返しているのかもしれません。この考えであれば、上記のようにWindows 11 on ARM64の「x32アプリ」の挙動が説明可能となります。ただ、この場合でもWindows 11 on ARM64の「ARM32アプリ」の挙動は説明できません。
やはり、APIリファレンスが更新されないと正しいところはわからないようです。
IsWow64Process2()
BOOL
IsWow64Process2(
_In_ HANDLE hProcess,
_Out_ USHORT* pProcessMachine,
_Out_opt_ USHORT* pNativeMachine);
IsWow64Process2()は、IsWow64Process()の機能を改善し、IsWow64Process()を置き換えるために設計されています。実行中のプロセスが、どのWoW64サブシステム上で動作しているかとWindowsがどのシステムで動作しているかを確認することができます。
WoW64サブシステム上で動作している場合は、サブシステムの情報がpProcessMachineに得られます。WoW64サブシステム上で動作していないときは、0x0000 (UNKNOWN) が得られます。
Windowsのシステム情報は、WoW64サブシステム上で動作しているかどうかにかかわらず、pNativeMachineに得られます。
GetNativeSystemInfo()とは異なり、Windowsとアプリで系統が異なるCPUアーキテクチャであっても正しい情報が取得できます。
実行結果は以下の通りとなりました。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | 0x0000 (UNKNOWN) 0x014c (I386) | – | – | – |
64ビットWindows 10 on x64 CPU | 0x014c (I386) 0x8664 (AMD64) | 0x0000 (UNKNOWN) 0x8664 (AMD64) | – | – |
64ビットWindows 11 on x64 CPU | 0x014c (I386) 0x8664 (AMD64) | 0x0000 (UNKNOWN) 0x8664 (AMD64) | – | – |
64ビットWindows 10 on ARM64 CPU | 0x014c (I386) 0xaa64 (ARM64) | – | 0x01c4 (ARMNT) 0xaa64 (ARM64) | 0x0000 (UNKNOWN) 0xaa64 (ARM64) |
64ビットWindows 11 on ARM64 CPU | 0x014c (I386) 0xaa64 (ARM64) | 0x0000 (UNKNOWN) 0xaa64 (ARM64) | 0x01c4 (ARMNT) 0xaa64 (ARM64) | 0x0000 (UNKNOWN) 0xaa64 (ARM64) |
この表では上段の値がpProcessMachineの値で、下段の値がpNativeMachineの値となります。
この結果から分かることは、pProcessMachineの値は、「Nativeアプリ」および「x64アプリ on ARM64」では0x0000 (UNKNOWN)の値が設定されており、「それ以外のアプリ」では0x0000 (UNKNOWN)以外の値が設定されています。「x64アプリ on ARM64」以外のエミュレーション実行されているものはすべてWoW64サブシステムで動作していることを表す値となっています。
結果として、このAPIは、一部の例外を除き、どのCPUアーキテクチャーでビルドしたアプリであったとしても、また、どのWindowsシステム上で実行されたとしても、プロセスの情報とシステムの情報を一番正しく返すAPIであることがわかります。一部の例外はx64アプリ on ARM64となります。
IsWow64GuestMachineSupported()
HRESULT
IsWow64GuestMachineSupported(
_In_ USHORT WowGuestMachine,
_Out_ BOOL* MachineIsSupported);
IsWow64GuestMachineSupported()は、実行中のプロセスの動作環境に関係なく、WindowsのWoW64サブシステムがどのCPUアーキテクチャーをサポートしているかを確認することができます。
WowGuestMachineで指定したゲストマシン(アプリのアーキテクチャ)のWoW64サブシステム上での実行(エミュレーション実行)がサポートされているかどうかが、MachineIsSupportedに得られます。
実行結果は以下の通りとなりました。
x86アプリ | x64アプリ | ARM32アプリ | ARM64アプリ | |
---|---|---|---|---|
32ビットWindows 10 on x64 CPU | none | – | – | – |
64ビットWindows 10 on x64 CPU | 0x014c (I386) | 0x014c (I386) | – | – |
64ビットWindows 11 on x64 CPU | 0x014c (I386) | 0x014c (I386) | – | – |
64ビットWindows 10 on ARM64 CPU | 0x014c (I386) 0x01c4 (ARMNT) | – | 0x014c (I386) 0x01c4 (ARMNT) | 0x014c (I386) 0x01c4 (ARMNT) |
64ビットWindows 11 on ARM64 CPU | 0x014c (I386) 0x01c4 (ARMNT) | 0x014c (I386) 0x01c4 (ARMNT) | 0x014c (I386) 0x01c4 (ARMNT) | 0x014c (I386) 0x01c4 (ARMNT) |
このAPIが返す値は、実行中のプロセスのアーキテクチャには依存しない情報なので、同じWindowsであれば、すべてのアプリで同じ値となります。実際に、表の横方向の値は同じ値になっています。
ただし、気になる点が一つあります。Windows 11 on ARM64では、x64アプリもエミュレーション実行できるにもかかわらず、このAPIでは、x64アプリのWoW64サブシステムでの実行はサポートしていないとの振る舞いをすることです。
これは、仕様なのかバグなのかはよくわかりません。
以上、今回の投稿では、WoW64に関連するAPIを、各CPUアーキテクチャーでビルドしたアプリを使い、各CPUアーキテクチャーのWindows上での振る舞いを確認しました。
一部、仕様なのかバグなのかわからない挙動もありましたが、現時点(2022/06/12)での挙動はわかりました。
>WoW64サブシステム上で動作していないときは、0x0000 (UNKNOWN) が得られます。
>この結果から分かることは、pProcessMachineの値は、Nativeアプリ以外はすべて0x0000 (UNKNOWN)以外の値が設定されており、エミュレーション実行されているものはすべてWoW64サブシステムで動作していることを表す値となっています。
投稿内に記載されている検証結果の表をちゃんと見てますか?
x64 on ARM64がUNKNOWNになっています。つまり検証結果はx64 on ARM64がWoW64ではないことを表しています。
実際そのとおりなのでWow64 APIのIsWow64GuestMachineSupported()ではなくGetMachineTypeAttributes()を使用する必要があります。
Windows Internals 7th part2にも”However emulating AMD64 code in ARM systems is not performed through WoW64.”と書かれています。
ご指摘ありがとうございます。
たしかに、検証結果の表と文章が一致していませんでした。
検証していた時にはUnknownになっていることに気づいていたのですが、文章を書くときにその件を忘れてしまっていました。
文章を訂正させていただきました。