WoW64 (Windows 32-bit on Windows 64-bit) is a subsystem within Microsoft Windows that lets Windows run 32-bit programs on 64-bit hardware.

One way to glean what processes are currently running in WoW64 mode is by querying NtQuerySystemInformation and checking whether IsWow64Process returns true or not.

This returns a pointer to a value that is set to TRUE if the process is running under WOW64 on an Intel64, x64, or ARM64 processor.

typedef NTSTATUS(NTAPI* PNtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
    );

BOOL IsProcessWow64(HANDLE hProcess) {
    BOOL bIsWow64 = FALSE;
    FARPROC pIsWow64Process = GetProcAddress(
        GetModuleHandle(TEXT("kernel32")), "IsWow64Process");

    if (pIsWow64Process) {
        ((BOOL(WINAPI*)(HANDLE, PBOOL))pIsWow64Process)(hProcess, &bIsWow64);
    }
    return bIsWow64;
}

With our type definition and the IsProcessWow64 function defined, we can implement the following logic in our main function like so: before doing anything, we pass GetCurrentProcess to our WoW64 check, thus checking whether the current process or environment we’re in is WoW64.

We then get a handle to ntdll, set up a do-while loop and a buffer to store queried process information, and then iterate over them via NextEntryOffset.

If the process is a normal 64-bit process, we simply print “x64,” the process name, and the related PID, like so: [x64] process.exe (PID: 1336).

Similarly, if the process returns true for the WOW64 check, we instead print WOW64, like so: [WOW64] process.exe (PID: 1337).

We iterate over the Windows process list after setting up a pointer to the process information buffer: PSYSTEM_PROCESS_INFORMATION procInfo = (PSYSTEM_PROCESS_INFORMATION)buffer

For each unique process ID we see, we call OpenProcess which takes a “Desired Access” key represented by a DWORD, a BOOLEAN indicating whether or not to inherit the handle – we set this to false – and last, our process ID, represented by a DWORD.

HANDLE OpenProcess(
  [in] DWORD dwDesiredAccess,
  [in] BOOL  bInheritHandle,
  [in] DWORD dwProcessId
);

PROCESS_QUERY_LIMITED_INFORMATION is the desired access we want and what we pass to NtQuerySystemInformation. This way, as a standard user, we won’t get errors if we hit an elevated system process.

Using this method, if we want to enumerate elevated processes, we must run the binary under a user with elevated privileges.

We traverse the process list via NextEntryOffset which is a part of the SYSTEM_PROCESS_INFORMATION structure – we check each process ID against the WoW64 function, and then free our buffer and ntdll handle after completion.

int main() {
    // Check if *this* program is running under WOW64
    if (IsProcessWow64(GetCurrentProcess())) {
        printf("[!] We appear to be running under WOW64 (32-bit on 64-bit Windows)\n\n");
    }
    else {
        printf("[*] We appear to be running as native 64-bit\n\n");
    }

    // Load NtQuerySystemInformation
    HMODULE ntdll = LoadLibraryA("ntdll.dll");
    PNtQuerySystemInformation NtQuerySystemInformation =
        (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");

    ULONG bufferSize = 0;
    NTSTATUS status;
    PVOID buffer = NULL;

    // Query process info
    do {
        if (buffer) free(buffer);
        buffer = malloc(bufferSize);
        status = NtQuerySystemInformation(5, buffer, bufferSize, &bufferSize);
    } while (status == 0xC0000004);  // STATUS_INFO_LENGTH_MISMATCH

    // Iterate processes
    PSYSTEM_PROCESS_INFORMATION procInfo = (PSYSTEM_PROCESS_INFORMATION)buffer;
    while (procInfo->NextEntryOffset) {
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
            (DWORD)(ULONG_PTR)procInfo->UniqueProcessId);

        if (hProcess) {
            BOOL isWow64 = IsProcessWow64(hProcess);
            CloseHandle(hProcess);

            printf("[%s] %.*S (PID: %d)\n",
                isWow64 ? "WOW64" : "x64",
                procInfo->ImageName.Length / 2,
                procInfo->ImageName.Buffer,
                (DWORD)(ULONG_PTR)procInfo->UniqueProcessId);
        }

        procInfo = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)procInfo + procInfo->NextEntryOffset);
    }

    free(buffer);
    FreeLibrary(ntdll);
    return 0;
}

wow64

As seen below, one process is running in WoW64 mode on my vanilla Windows installation:

//snipped
[x64] vshost.exe (PID: 3300)
[WOW64] vcpkgsrv.exe (PID: 7144)
[x64] ServiceHub.Host.dotnet.x64.exe (PID: 7248)

WoW64Search on Github