Skip to content

Deny instrumentation of arm64 native code by x86 and x64 detours.#385

Open
ashedel wants to merge 2 commits into
mainfrom
user/ashedel/arm64ec-detection
Open

Deny instrumentation of arm64 native code by x86 and x64 detours.#385
ashedel wants to merge 2 commits into
mainfrom
user/ashedel/arm64ec-detection

Conversation

@ashedel

@ashedel ashedel commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

This change adds the logic to deny writing over the native arm64 code when running x64/x86 detours in EC emulation mode.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because no GitHub Actions runner was available. Make sure your repository has a runner available to run Copilot's review, or add a copilot-setup-steps.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds a guard in DetourAttachEx to prevent x86/x64 detours from patching ARM64EC/native targets on ARM64 Windows (EC emulation scenario), avoiding illegal-instruction crashes.

Changes:

  • Introduces ARM64EC/ARM64 detection helpers for x86/x64 builds.
  • Blocks DetourAttachEx when the target pointer is determined to be ARM64EC/ARM64 and returns an error.
  • Minor formatting cleanup in ARM64 indirect jump generation code.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/detours.cpp
Comment on lines +132 to +153
typedef UCHAR (NTAPI *PFN_RtlIsEcCode)(ULONG64);
static PFN_RtlIsEcCode pfnRtlIsEcCode = NULL;
static BOOL s_fInitialized = FALSE;

if (!s_fInitialized) {
s_fInitialized = TRUE;

typedef BOOL (WINAPI *PFN_IsWow64Process2)(HANDLE, USHORT*, USHORT*);
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
if (hKernel32) {
PFN_IsWow64Process2 pfnIsWow64 = (PFN_IsWow64Process2)
GetProcAddress(hKernel32, "IsWow64Process2");
if (pfnIsWow64) {
USHORT processMachine = 0, nativeMachine = 0;
if (pfnIsWow64(GetCurrentProcess(), &processMachine, &nativeMachine) &&
(nativeMachine == 0xAA64)) { //IMAGE_FILE_MACHINE_ARM64
#if defined(DETOURS_X86)
pfnRtlIsEcCode = &detour_rtl_is_ec_code;
#else
pfnRtlIsEcCode = (PFN_RtlIsEcCode)
GetProcAddress(hKernel32, "RtlIsEcCode");
#endif
Comment thread src/detours.cpp
Comment on lines +133 to +140
static PFN_RtlIsEcCode pfnRtlIsEcCode = NULL;
static BOOL s_fInitialized = FALSE;

if (!s_fInitialized) {
s_fInitialized = TRUE;

typedef BOOL (WINAPI *PFN_IsWow64Process2)(HANDLE, USHORT*, USHORT*);
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
Comment thread src/detours.cpp
Comment on lines +2254 to +2260
#if defined(DETOURS_X64) || defined(DETOURS_X86)
if (detour_is_arm64ec_code((ULONG64)*ppPointer)) {
DETOUR_TRACE(("*ppPointer is an Arm64EC address (ppPointer=%p). "
"An Arm64EC address cannot be legitimately detoured with an x64 jmp. "
"Mark the target function with __declspec(hybrid_patchable) to make it detour-able. "
"We still allow an Arm64EC function to be detoured with an x64 jmp to make it easy (crash) to debug.\n", ppPointer));
"Mark the target function with __declspec(hybrid_patchable) to make it detour-able.\n",
*ppPointer));
error = ERROR_INVALID_BLOCK;
Comment thread src/detours.cpp
Comment on lines +127 to +133
static BOOL detour_is_arm64ec_code(ULONG64 Address)
{
#if defined(_M_ARM64EC)
return RtlIsEcCode(Address);
#else
typedef UCHAR (NTAPI *PFN_RtlIsEcCode)(ULONG64);
static PFN_RtlIsEcCode pfnRtlIsEcCode = NULL;
Comment thread src/detours.cpp
Comment on lines +76 to +77
static UCHAR NTAPI detour_rtl_is_ec_code(ULONG64 Address)
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants