Closed voidregreso closed 3 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)?
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
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
´´´
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;
}
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
It is possible https://github.com/msys2/MINGW-packages/discussions/8991