Vector35 / Vector35/binaryninja-api

ARM64ec PE files default to x86-64 when they should be aarch64

Open
#8,096 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
1.3k
Forks
298
Avg merge
5d 5h
Merged PRs (30d)
19

Description

Version and Platform (required):

  • Binary Ninja Version: 5.3.9409-dev Personal (0c30837b)
  • Edition: Non-Commercial
  • OS: Ubuntu
  • OS Version: Ubuntu 25.10
  • CPU Architecture: AArch64 (AmpereOne A192-32X)

Bug Description:
ARM64ec PE files are AArch64 files with x86-64 compatibility.
The COFF_Header machine field has IMAGE_FILE_MACHINE_AMD64 for compatibility, but one must continue to walking the PE64_Optional_Header in to the loadConfigTableEntry which points to eventually points to the CHPEMetadataPointer so you can get the CHPE metadata (symbol __chpe_metadata).

At this point, once you have confirmed that the CHPEMetadata entry exists, you can confirm that if the COFF header declares itself as AMD64 then it's /actually/ ARM64EC, and if the COFF header declares itself as ARM64 then it's actually ARM64X.

Some visibility in to the exact logic can be see in LLVM's source at llvm-project/llvm/include/llvm/Object/COFF.h in the getMachine() function. Additionally llvm-readobj can dump this information as well llvm-readobj --coff-load-config -r libarm64ecfex.dll as long as LLVM is 21 or newer.

Steps To Reproduce:

  1. Open an arm64ec dll and see it try and disassemble as x86-64
  2. Close that file, open with options and see it defaults to windows-x86_64

Expected Behavior:
I expect when loading a libarm64ecfex.dll file that is Arm64ec, that instead of default disassembling as x86-64, it instead default disassembles as aarch64.

Binary:

  1. https://github.com/FEX-Emu/FEX/actions/runs/24476520323 the wine_dll_artifacts are built from our CI for every commit (but self-deletes after a couple weeks)
  2. You can rip the DLL from our Ubuntu launchpad release builders. https://launchpad.net/~fex-emu/+archive/ubuntu/fex/+sourcepub/18299389/+listing-archive-extra
  1. Or use the direct attached zip. libarm64ecfex.dll.zip
  2. You could technically build an arm64ec binary yourself in msvc or llvm-mingw pretty easily but I don't have a direct example.

Additional Information:
Bonus points for parsing the CPHE config header CodeMap section, as this claims which sections in the COFF file are arm64ec, and which ones are x86-64 helper routines. Then having binja default disassemble those regions correctly with the different architectures.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the attached libarm64ecfex.dll and compare its behavior with llvm-project/llvm/include/llvm/Object/COFF.h, especially the getMachine() logic and CHPE metadata handling. Use llvm-readobj --coff-load-config -r on the sample to inspect the load-config data; done means the file defaults to aarch64 rather than x86-64, with the optional CodeMap behavior evaluated separately.

Written by the indexing model from the issue text.

Assessment

Domain
reverse-engineering
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.