winsiderss / systeminformer

A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. Brought to you by Winsider Seminars & Solutions, Inc. @ http://www.windows-internals.com
https://systeminformer.sourceforge.io
MIT License
11.04k stars 1.4k forks source link

Is there any possibility to add ARM64 support? #376

Closed voidregreso closed 3 years ago

Biswa96 commented 2 years ago

It is possible https://github.com/msys2/MINGW-packages/discussions/8991

dmex commented 2 years ago

mut M$'s task manager can tel them apart, I wonder how

It's just using IsWow64Process2 @DavidXanatos https://docs.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process2

don't see yet a good way to distinguish x64 from ARM64EC processes

It should be returning IMAGE_FILE_MACHINE_CHPE_X86 (not included in the SDK but rather the WDK ntimage.h)?

DavidXanatos commented 2 years ago

On my raspi 4 for a x64 process it returns ProcessMachine: 0x0000 NativeMachine: 0xaa64 same for ARM64EC and ARM64

IsWow64Process2 seams to work only for 32 bit processes

DavidXanatos commented 2 years ago

To me this decisively looks like x64 on arm64 is not longer WOW but a different interoperability mechanism. Also there is no \Syswow6464 or something folder for x64 and no registry redirection eider.

See: ´´´ NtQuerySystemInformationEx(SystemSupportedProcessorArchitectures2, &handle, sizeof(handle), info, sizeof(info), &length);

x86 on Arm64: Machine: ARM64; KernelMode: 1; UserMode: 1; Native: 1; Process: 0; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 1; WoW64Container: 1 Machine: ARM-Thumb-2; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: x64; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 0

x64 on Arm64: Machine: ARM64; KernelMode: 1; UserMode: 1; Native: 1; Process: 0; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: ARM-Thumb-2; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: x64; KernelMode: 0; UserMode: 1; Native: 0; Process: 1; WoW64Container: 0

Arm64EC on Arm64: Machine: ARM64; KernelMode: 1; UserMode: 1; Native: 1; Process: 0; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: ARM-Thumb-2; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: x64; KernelMode: 0; UserMode: 1; Native: 0; Process: 1; WoW64Container: 0

Arm64: Machine: ARM64; KernelMode: 1; UserMode: 1; Native: 1; Process: 1; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: ARM-Thumb-2; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: x64; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 0

Arm on Arm64: Machine: ARM64; KernelMode: 1; UserMode: 1; Native: 1; Process: 0; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 1 Machine: ARM-Thumb-2; KernelMode: 0; UserMode: 1; Native: 0; Process: 1; WoW64Container: 1 Machine: x64; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 0

x64 on x64: Machine: x64; KernelMode: 1; UserMode: 1; Native: 1; Process: 1; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 0; WoW64Container: 0

x86 on x64: Machine: x64; KernelMode: 1; UserMode: 1; Native: 1; Process: 0; WoW64Container: 0 Machine: x86; KernelMode: 0; UserMode: 1; Native: 0; Process: 1; WoW64Container: 0

´´´

DavidXanatos commented 2 years ago

I have reverse engineered how taskman.exe tells x64 and arm64ec apart and here it is ready to be put into PH:

#ifndef IMAGE_FILE_MACHINE_CHPE_X86
#define IMAGE_FILE_MACHINE_CHPE_X86 0x3A64
#endif
#ifndef IMAGE_FILE_MACHINE_ARM64EC
#define IMAGE_FILE_MACHINE_ARM64EC  0xA641
#endif
#ifndef IMAGE_FILE_MACHINE_ARM64X
#define IMAGE_FILE_MACHINE_ARM64X   0xA64E
#endif

NTSTATUS PhGetProcessMachine(HANDLE hProcess, USHORT* pProcessMachine) // handle requirers PROCESS_QUERY_INFORMATION and PROCESS_VM_READ
{
    NTSTATUS status;

    *pProcessMachine = 0;

    USHORT ProcessMachine;
    USHORT NativeMachine;
    status = RtlWow64GetProcessMachines(hProcess, &ProcessMachine, &NativeMachine);
    if (!NT_SUCCESS(status))
        return status;

    if (ProcessMachine != IMAGE_FILE_MACHINE_UNKNOWN) { // is it a WOW process
        *pProcessMachine = ProcessMachine;
        return status;
    }

    *pProcessMachine = NativeMachine;
    if (NativeMachine != IMAGE_FILE_MACHINE_ARM64)
        return status;

    //
    // check if its a real x64 process or an ARM64EC
    //

    ULONGLONG pebAddress;
    //ULONG_PTR peb32;
    //status = NtQueryInformationProcess(handle, ProcessWow64Information, &peb32, sizeof(ULONG_PTR), NULL);
    //if (!NT_SUCCESS(status))
    //  return;
    //BOOLEAN bIsWow64 = !!peb32;
    //
    //if (bIsWow64)
    //  pebAddress = peb32;
    //else
    {
        PROCESS_BASIC_INFORMATION basicInfo;
        status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &basicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL);
        if (!NT_SUCCESS(status))
            return status;

        pebAddress = (ULONGLONG)basicInfo.PebBaseAddress;
    }

    ULONGLONG ImageBaseAddress;
    status = NtReadVirtualMemory(hProcess, (PVOID)(pebAddress + FIELD_OFFSET(PEB, ImageBaseAddress)), &ImageBaseAddress, sizeof(ImageBaseAddress), NULL);
    if (!NT_SUCCESS(status))
        return status;

    BYTE Buffer[0x1000];
    status = NtReadVirtualMemory(hProcess, (PVOID)ImageBaseAddress, Buffer, sizeof(Buffer), NULL);
    if (!NT_SUCCESS(status))
        return status;

    int peHeadderOffset = *(int*)(Buffer + 0x3C); // 0x3C Pointer to PE Headder

    //char* peSignature = (char*)&Buffer[peHeadderOffset];
    IMAGE_FILE_HEADER* peHeader = (IMAGE_FILE_HEADER*)&Buffer[peHeadderOffset + 4];

    if (peHeader->Machine == IMAGE_FILE_MACHINE_AMD64)
    {
        PIMAGE_OPTIONAL_HEADER64 optHeader = (PIMAGE_OPTIONAL_HEADER64)&Buffer[peHeadderOffset + 24];

        DWORD Offset = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress;
        DWORD Size = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size;
        PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadConfig = (PIMAGE_LOAD_CONFIG_DIRECTORY64) new BYTE[Size];

        if(Size < 0xD0)
            return status;

        status = NtReadVirtualMemory(hProcess, (PVOID)(ImageBaseAddress + Offset), pLoadConfig, Size, NULL);
        if (!NT_SUCCESS(status))
            return status;

        if (pLoadConfig->CHPEMetadataPointer)
            *pProcessMachine = IMAGE_FILE_MACHINE_ARM64EC;
    }
    /*else // seams it also checks for the 32 bit version but I haven't seen that in the wild
    {
        PIMAGE_OPTIONAL_HEADER32 optHeader = (PIMAGE_OPTIONAL_HEADER32)&Buffer[peHeadderOffset + 24];

        DWORD Offset = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress;
        DWORD Size = optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size;
        PIMAGE_LOAD_CONFIG_DIRECTORY32 pLoadConfig = (PIMAGE_LOAD_CONFIG_DIRECTORY32) new BYTE[Size];

        if (Size < 0x84)
            return status;

        status = NtReadVirtualMemory(hProcess, (PVOID)(ImageBaseAddress + Offset), pLoadConfig, Size, NULL);
        if (!NT_SUCCESS(status))
            return status;

        if (pLoadConfig->CHPEMetadataPointer)
            *pProcessMachine = ???
    }*/

    return status;
}
Biswa96 commented 2 years ago

compiler error in arm64 build

processhacker\ProcessHacker\syssccpu.c(1685,12): error C2220: the following warning is treated as an error
processhacker\ProcessHacker\syssccpu.c(1685,12): warning C4013: 'CpuIdEx' undefined; assuming extern returning int