From cf1d2cdf8859b0809dd626eecad6e5c62b1984af Mon Sep 17 00:00:00 2001 From: Galen Hunt Date: Mon, 24 Jul 2023 13:07:47 -0700 Subject: [PATCH 01/14] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b2f52a2b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Corporation. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 4b8c659f549b0ab21cf649377c7a84eb708f5e68 Mon Sep 17 00:00:00 2001 From: Galen Hunt Date: Mon, 24 Jul 2023 13:10:03 -0700 Subject: [PATCH 02/14] Create SECURITY.md Added required SECURITY.md file. --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..e138ec5d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From 309926adb1fd988f4066ee1ad95f9251c9fe7932 Mon Sep 17 00:00:00 2001 From: rishaw96 Date: Wed, 9 Oct 2024 15:14:43 -0700 Subject: [PATCH 03/14] Fix detours ability to identify OS applied patches. (#318) * Updated detours ability to identify patches applied by OS * add back checksum zeroing * cleanup spacing and stay consistent with logical AND usage --- src/detours.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/detours.cpp b/src/detours.cpp index c1138dca..8db8352a 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -156,6 +156,8 @@ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) { + PBYTE pbCodeOriginal; + if (pbCode == NULL) { return NULL; } @@ -179,6 +181,7 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); pbCode = pbNew; + pbCodeOriginal = pbCode; // First, skip over the import vector if there is one. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] @@ -195,6 +198,23 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); pbCode = pbNew; + + // Patches applied by the OS will jump through an HPAT page to get + // the target function in the patch image. The jump is always performed + // to the target function found at the current instruction pointer + + // PAGE_SIZE - 6 (size of jump). + // If this is an OS patch, we want to detour at the point of the target function + // padding in the base image. Ideally, we would detour at the target function, but + // since it's patched it begins with a short jump (to padding) which isn't long + // enough to hold the detour code bytes. + if (pbCode[0] == 0xff && + pbCode[1] == 0x25 && + *(UNALIGNED INT32 *)&pbCode[2] == (UNALIGNED INT32)(pbCode + 0x1000)) { // jmp [rip+PAGE_SIZE-6] + + DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function. \n", pbCode, pbCodeOriginal)); + pbCode = pbCodeOriginal; + } + } } return pbCode; @@ -369,6 +389,8 @@ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) { + PBYTE pbCodeOriginal; + if (pbCode == NULL) { return NULL; } @@ -392,6 +414,7 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); pbCode = pbNew; + pbCodeOriginal = pbCode; // First, skip over the import vector if there is one. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] @@ -408,6 +431,21 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); pbCode = pbNew; + + // Patches applied by the OS will jump through an HPAT page to get + // the target function in the patch image. The jump is always performed + // to the target function found at the current instruction pointer + + // PAGE_SIZE - 6 (size of jump). + // If this is an OS patch, we want to detour at the point of the target function + // in the base image. Since we need 5 bytes to perform the jump, detour at the + // point of the long jump instead of the short jump at the start of the target. + if (pbCode[0] == 0xff && + pbCode[1] == 0x25 && + *(UNALIGNED INT32 *)&pbCode[2] == 0xFFA) { // jmp [rip+PAGE_SIZE-6] + + DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function. \n", pbCode, pbCodeOriginal)); + pbCode = pbCodeOriginal; + } } } return pbCode; @@ -1151,9 +1189,45 @@ inline void detour_find_jmp_bounds(PBYTE pbCode, *ppUpper = (PDETOUR_TRAMPOLINE)hi; } +inline BOOL detour_is_code_os_patched(PBYTE pbCode) +{ + // Identify whether the provided code pointer is a OS patch jump. + // We can do this by checking if a branch (b ) is present, and if so, + // it must be jumping to an HPAT page containing ldr [PC+PAGE_SIZE-4], br . + ULONG Opcode = fetch_opcode(pbCode); + + if ((Opcode & 0xfc000000) != 0x14000000) { + return FALSE; + } + // The branch must be jumping forward if it's going into the HPAT. + // Check that the sign bit is cleared. + if ((Opcode & 0x2000000) != 0) { + return FALSE; + } + ULONG Delta = (ULONG)((Opcode & 0x1FFFFFF) * 4); + PBYTE BranchTarget = pbCode + Delta; + + // Now inspect the opcodes of the code we jumped to in order to determine if it's HPAT. + ULONG HpatOpcode1 = fetch_opcode(BranchTarget); + ULONG HpatOpcode2 = fetch_opcode(BranchTarget + 4); + + if (HpatOpcode1 != 0x58008010) { // ldr [PC+PAGE_SIZE] + return FALSE; + } + if (HpatOpcode2 != 0xd61f0200) { // br + return FALSE; + } + return TRUE; +} + inline BOOL detour_does_code_end_function(PBYTE pbCode) { ULONG Opcode = fetch_opcode(pbCode); + // When the OS has patched a function entry point, it will incorrectly + // appear as though the function is just a single branch instruction. + if (detour_is_code_os_patched(pbCode)) { + return FALSE; + } if ((Opcode & 0xfffffc1f) == 0xd65f0000 || // br (Opcode & 0xfc000000) == 0x14000000) { // b return TRUE; From c3ffaef25a26dc9788d52da24956bb610d27cff4 Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:18:21 -0700 Subject: [PATCH 04/14] Microsoft mandatory file (#285) Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> From b2bf32a657be1114b173ad28d2d65463ca4c466f Mon Sep 17 00:00:00 2001 From: Filip Wedzicha Date: Wed, 9 Oct 2024 18:19:47 -0400 Subject: [PATCH 05/14] Fix: CI-Build not working due to wrong branch in config (#310) --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 44e7bbd8..f4bdf3ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,12 +7,12 @@ env: # Compile in parallel where possible. CL: /MP -# Triggers the workflow on push or pull request events for the master branch. +# Triggers the workflow on push or pull request events for the main branch. on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: build: From f74982b60e9a8a1b0d9126867c05dfcf96677d7c Mon Sep 17 00:00:00 2001 From: Pedro Miguel Justo <40605312+pmsjt@users.noreply.github.com> Date: Fri, 28 Mar 2025 13:53:47 -0700 Subject: [PATCH 06/14] Work-around an issue in Arm64 (and Arm64EC) in which LR and FP registers may become zeroed when CONTEXT_CONTROL is used without CONTEXT_INTEGER. (#313) Co-authored-by: Pedro Justo (TEIXEIRA) --- src/detours.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/detours.cpp b/src/detours.cpp index 8db8352a..38c71f5c 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -1911,35 +1911,40 @@ LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer) } } - // Update any suspended threads. - for (t = s_pPendingThreads; t != NULL; t = t->pNext) { - CONTEXT cxt; - cxt.ContextFlags = CONTEXT_CONTROL; - #undef DETOURS_EIP +#undef DETOURS_CONTEXT_FLAGS #ifdef DETOURS_X86 #define DETOURS_EIP Eip +#define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL #endif // DETOURS_X86 #ifdef DETOURS_X64 #define DETOURS_EIP Rip +#define DETOURS_CONTEXT_FLAGS (CONTEXT_CONTROL | CONTEXT_INTEGER) #endif // DETOURS_X64 #ifdef DETOURS_IA64 #define DETOURS_EIP StIIP +#define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL #endif // DETOURS_IA64 #ifdef DETOURS_ARM #define DETOURS_EIP Pc +#define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL #endif // DETOURS_ARM #ifdef DETOURS_ARM64 #define DETOURS_EIP Pc +#define DETOURS_CONTEXT_FLAGS (CONTEXT_CONTROL | CONTEXT_INTEGER) #endif // DETOURS_ARM64 typedef ULONG_PTR DETOURS_EIP_TYPE; + // Update any suspended threads. + for (t = s_pPendingThreads; t != NULL; t = t->pNext) { + CONTEXT cxt; + cxt.ContextFlags = DETOURS_CONTEXT_FLAGS; if (GetThreadContext(t->hThread, &cxt)) { for (o = s_pPendingOperations; o != NULL; o = o->pNext) { if (o->fIsRemove) { From 31777ba16820a82509b9f6f1ea4fb15002726e65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:41:45 -0700 Subject: [PATCH 07/14] Dependencies: Bump actions/checkout from 3 to 4 (#300) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4bdf3ee..d1d016c5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Setup build environment variables using vcvarsall.bat. - name: Configure MSCV Compiler for ${{ matrix.arch }} From 14145cd765c8fe6c13068d67f2727896d31e15c6 Mon Sep 17 00:00:00 2001 From: Jeff Bisset <43155345+BissetJ@users.noreply.github.com> Date: Tue, 1 Apr 2025 16:29:57 -0700 Subject: [PATCH 08/14] CI Fixups (#341) * codeql-action and upload-artifact need to be bumped to newer versions. * The artifact names must be unique across jobs, upload-artifact v4 won't merge all the outputs into a single archive like before. --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1d016c5..023946be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: arch: ${{ matrix.arch }} - name: Initialize CodeQL for C++ - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 if: ${{ matrix.os == 'windows-2019' && matrix.conf == 'Debug' }} with: languages: cpp @@ -56,14 +56,14 @@ jobs: if: ${{ matrix.arch == 'x86' || matrix.arch == 'x64' }} - name: Upload artifacts for ${{ matrix.arch }} on ${{ matrix.os }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: artifacts-${{ matrix.os }} + name: artifacts-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.conf }} path: | lib.*/ bin.*/ include/ - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 if: ${{ matrix.os == 'windows-2019' && matrix.conf == 'Debug' }} From 572f1f02f499375b46e4e53300ff11f6a2445bff Mon Sep 17 00:00:00 2001 From: Jeff Bisset <43155345+BissetJ@users.noreply.github.com> Date: Tue, 1 Apr 2025 17:17:13 -0700 Subject: [PATCH 09/14] CI: Disable ARM32 in the CI builds. (#342) The 32-bit ARM builds no longer succeed with the latest platform SDK because 32-bit ARM support has been deprecated and there are no longer libs for things like ws_32. This is why the windows-2022 CI builds are failing for the two 32-bit ARM jobs. 32-bit ARM isn't much of a concern for anybody, I'm just going ahead and disabling it for the CI runs for now. Note that this is not removing 32-bit ARM support from Detours, just (temporarily) from the CI builds. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 023946be..608a42ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [windows-2019, windows-2022] - arch: [x86, x64, x64_arm, x64_arm64] + arch: [x86, x64, x64_arm64] conf: [Release, Debug] steps: From dff734368fc83c2022c90917218e21900e5c6ef4 Mon Sep 17 00:00:00 2001 From: Ratin Gao Date: Wed, 2 Apr 2025 08:20:13 +0800 Subject: [PATCH 10/14] Trivial fixes for commit 309926ad (#323) --- src/detours.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detours.cpp b/src/detours.cpp index 38c71f5c..18a157cb 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -209,9 +209,9 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) // enough to hold the detour code bytes. if (pbCode[0] == 0xff && pbCode[1] == 0x25 && - *(UNALIGNED INT32 *)&pbCode[2] == (UNALIGNED INT32)(pbCode + 0x1000)) { // jmp [rip+PAGE_SIZE-6] + *(UNALIGNED INT32 *)&pbCode[2] == (UNALIGNED INT32)(pbCode + 0x1000)) { // jmp [eip+PAGE_SIZE-6] - DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function. \n", pbCode, pbCodeOriginal)); + DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function.\n", pbCode, pbCodeOriginal)); pbCode = pbCodeOriginal; } @@ -443,7 +443,7 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) pbCode[1] == 0x25 && *(UNALIGNED INT32 *)&pbCode[2] == 0xFFA) { // jmp [rip+PAGE_SIZE-6] - DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function. \n", pbCode, pbCodeOriginal)); + DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function.\n", pbCode, pbCodeOriginal)); pbCode = pbCodeOriginal; } } From 5e2790624b7ee18f1075a575dd12d0004b1225ae Mon Sep 17 00:00:00 2001 From: Shin Jinhyeok <97652090+hakujitsu7@users.noreply.github.com> Date: Wed, 2 Apr 2025 09:22:20 +0900 Subject: [PATCH 11/14] Fix: Correct sizeof usage in `DetourTransactionCommitEx` (#331) Replaced `sizeof(o->pTrampoline)` with `sizeof(*o->pTrampoline)` to correctly calculate the trampoline size when adjusting thread instruction pointers. --- src/detours.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detours.cpp b/src/detours.cpp index 18a157cb..11fa2e1d 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -1950,7 +1950,7 @@ typedef ULONG_PTR DETOURS_EIP_TYPE; if (o->fIsRemove) { if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline && cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline - + sizeof(o->pTrampoline)) + + sizeof(*o->pTrampoline)) ) { cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) From d396f851d27dc407fd6c77cbd885a4d7ecece7d5 Mon Sep 17 00:00:00 2001 From: Jeff Bisset <43155345+BissetJ@users.noreply.github.com> Date: Tue, 1 Apr 2025 18:07:53 -0700 Subject: [PATCH 12/14] CI: Fix CodeQL warnings (#343) Trying to fix the "Resource not accessible by integration" warnings from the CodeQL runs. --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 608a42ce..091438a9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,11 @@ on: pull_request: branches: [ main ] +permissions: + actions: read + contents: read + security-events: write + jobs: build: runs-on: ${{ matrix.os }} From eed910d53fe71d0a693e06a799b51869b732d829 Mon Sep 17 00:00:00 2001 From: Jeff Bisset <43155345+BissetJ@users.noreply.github.com> Date: Wed, 2 Apr 2025 11:34:04 -0700 Subject: [PATCH 13/14] Fix some minor issues in samples found by CodeQL (#345) --- README.md | 2 +- samples/syelog/syelog.cpp | 2 +- samples/traceapi/trcapi.cpp | 2 +- samples/tracebld/trcbld.cpp | 2 +- samples/tryman/tstman.cpp | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 84a4d14f..8fe4043e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ and allows the community to support Detours using open source tools and processe Detours is compatible with the Windows NT family of operating systems: Windows NT, Windows XP, Windows Server 2003, Windows 7, -Windows 8, and Windows 10. It cannot be used by Windows Store apps +Windows 8, Windows 10, and Windows 11. It cannot be used by Windows Store apps because Detours requires APIs not available to those applications. This repo contains the source code for version 4.0.1 of Detours. diff --git a/samples/syelog/syelog.cpp b/samples/syelog/syelog.cpp index 72e02e55..b7e5f09c 100644 --- a/samples/syelog/syelog.cpp +++ b/samples/syelog/syelog.cpp @@ -159,7 +159,7 @@ static PCHAR do_estr(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn) *pszOut++ = '0' + (c % 10); *pszOut++ = ';'; } - else if (c < 1000 && pszOut + 6 <= pszEnd) { + else if (pszOut + 6 <= pszEnd) { *pszOut++ = '&'; *pszOut++ = '#'; *pszOut++ = '0' + ((c / 100) % 10); diff --git a/samples/traceapi/trcapi.cpp b/samples/traceapi/trcapi.cpp index 76c908b1..ff95c73f 100644 --- a/samples/traceapi/trcapi.cpp +++ b/samples/traceapi/trcapi.cpp @@ -352,7 +352,7 @@ BOOL ProcessEnumerate() Syelog(SYELOG_SEVERITY_INFORMATION, "###\n"); LPVOID lpvEnv = Real_GetEnvironmentStrings(); - Syelog(SYELOG_SEVERITY_INFORMATION, "### Env= %08x [%08x %08x]\n", + Syelog(SYELOG_SEVERITY_INFORMATION, "### Env= %p [%p %p]\n", lpvEnv, ((PVOID*)lpvEnv)[0], ((PVOID*)lpvEnv)[1]); return TRUE; diff --git a/samples/tracebld/trcbld.cpp b/samples/tracebld/trcbld.cpp index b246da36..270e17b5 100644 --- a/samples/tracebld/trcbld.cpp +++ b/samples/tracebld/trcbld.cpp @@ -1752,7 +1752,7 @@ static PCHAR do_estr(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn) *pszOut++ = '0' + (c % 10); *pszOut++ = ';'; } - else if (c < 1000 && pszOut + 6 <= pszEnd) { + else if (pszOut + 6 <= pszEnd) { *pszOut++ = '&'; *pszOut++ = '#'; *pszOut++ = '0' + ((c / 100) % 10); diff --git a/samples/tryman/tstman.cpp b/samples/tryman/tstman.cpp index 0ae169b0..0e7a1851 100644 --- a/samples/tryman/tstman.cpp +++ b/samples/tryman/tstman.cpp @@ -164,16 +164,16 @@ void DumpModuleInfo(HMODULE hModule) } if (pinh->FileHeader.Machine == 0x8664) { - StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "x64", pinh->FileHeader.Machine); + StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "x64"); } else if (pinh->FileHeader.Machine == 0x014c) { - StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "x86", pinh->FileHeader.Machine); + StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "x86"); } else if (pinh->FileHeader.Machine == 0x0200) { - StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "i64", pinh->FileHeader.Machine); + StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "i64"); } else if (pinh->FileHeader.Machine == 0x01c0) { - StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "arm", pinh->FileHeader.Machine); + StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "arm"); } else { StringCchPrintfA(szMachine, ARRAYSIZE(szMachine), "%04x", pinh->FileHeader.Machine); From ea6c4ae7f3f1b1772b8a7cda4199230b932f5a50 Mon Sep 17 00:00:00 2001 From: Ben Niu Date: Wed, 2 Apr 2025 14:57:54 -0700 Subject: [PATCH 14/14] Add Arm64EC support (#338) This change adds Arm64EC detours support. It bumps the toolset version to 143 from 142 since 142 does not support Arm64EC officially. It adds a new Arm64EC target. It passes Arm64EC-specific compilation flag /arm64EC and linker flag /machine:arm64x or /machine:arm64ec in right places. --- samples/commem/commem.cpp | 5 +- samples/common.mak | 11 +++ samples/cping/Makefile | 2 + samples/cping/cping.cpp | 4 +- samples/disas/Makefile | 2 +- samples/dtest/dtarge.cpp | 1 + samples/dtest/dtarge.h | 38 ++++---- samples/dtest/dtest.cpp | 2 +- samples/einst/Makefile | 2 +- samples/findfunc/Makefile | 18 ++-- samples/member/member.cpp | 2 +- src/Makefile | 12 ++- src/detours.cpp | 9 ++ src/detours.h | 20 ++-- system.mak | 8 +- tests/test_module_api.cpp | 109 +++++++++++++++++++++- vc/Detours.sln | 8 +- vc/Detours.vcxproj | 186 +++++++++++++++++++++++++++++--------- 18 files changed, 348 insertions(+), 91 deletions(-) diff --git a/samples/commem/commem.cpp b/samples/commem/commem.cpp index 67798438..b713fb6e 100644 --- a/samples/commem/commem.cpp +++ b/samples/commem/commem.cpp @@ -86,7 +86,10 @@ int main(int argc, char **argv) DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - DetourAttach(&(PVOID&)RealIStreamWrite, MineIStreamWrite); + if (DetourAttach(&(PVOID&)RealIStreamWrite, MineIStreamWrite) != NO_ERROR) { + printf("commem: DetourAttach failed.\n"); + return 1; + } DetourTransactionCommit(); printf("commem: Calling Write w/o after attach.\n"); diff --git a/samples/common.mak b/samples/common.mak index 9a909f25..5612f3de 100644 --- a/samples/common.mak +++ b/samples/common.mak @@ -61,6 +61,17 @@ CFLAGS=$(CFLAGS) /D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE CFLAGS=$(CFLAGS) /D_$(DETOURS_TARGET_PROCESSOR:X64=AMD64)_ # redundant with windows.h except for midl proxies +!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" + +ASM=armasm64 + +!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" + +ASM=ml64 +CFLAGS=/arm64EC $(CFLAGS) +LIBFLAGS=$(LIBFLAGS) /machine:arm64x +LINKFLAGS=$(LINKFLAGS) /machine:arm64ec softintrin.lib + !ENDIF DEPS = $(LIBD)\syelog.lib $(LIBD)\detours.lib diff --git a/samples/cping/Makefile b/samples/cping/Makefile index b750a2a2..a4ada9bc 100644 --- a/samples/cping/Makefile +++ b/samples/cping/Makefile @@ -70,6 +70,8 @@ MIDLFLAGS=$(MIDLFLAGS) /x64 MIDLFLAGS=$(MIDLFLAGS) /arm32 !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" MIDLFLAGS=$(MIDLFLAGS) /arm64 +!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" +MIDLFLAGS=$(MIDLFLAGS) /x64 !ENDIF OBJS = \ diff --git a/samples/cping/cping.cpp b/samples/cping/cping.cpp index 43123417..003d9784 100644 --- a/samples/cping/cping.cpp +++ b/samples/cping/cping.cpp @@ -30,7 +30,7 @@ #include #include "iping.h" -// ARM64 ReadTimeStampCounter is a function. +// ARM64/ARM64EC ReadTimeStampCounter is a function. // ARM ReadTimeStampCounter is a declared function but not implemented. // old IA64: ReadTimeStampCounter nonexisant. // new IA64: ReadTimeStampCounter is a macro. @@ -38,7 +38,7 @@ // new x86: ReadTimeStampCounter is a macro. // AMD64: ReadTimeStampCounter is a macro. -#if defined(_ARM64_) || defined(ReadTimeStampCounter) +#if defined(_ARM64_) || defined(_ARM64EC_) || defined(ReadTimeStampCounter) #define GetTimeStamp() ReadTimeStampCounter() #elif defined(_X86_) || defined(_AMD64_) extern "C" diff --git a/samples/disas/Makefile b/samples/disas/Makefile index ecf0f66b..88195cf2 100644 --- a/samples/disas/Makefile +++ b/samples/disas/Makefile @@ -36,7 +36,7 @@ dirs: $(OBJD)\disasm.obj : x86.cpp cl $(CFLAGS) /Fe$@ /FAcs /Fa$(OBJD)\x86.lst \ /Fd$(@R).pdb /Fo$(OBJD)\disasm.obj /c x86.cpp -!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "X64" +!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "X64" || "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" $(OBJD)\disasm.obj : x64.asm $(ASM) $(AFLAGS) /Fo$(OBJD)\disasm.obj /Fl$(OBJD)\x64.lst x64.asm !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "IA64" diff --git a/samples/dtest/dtarge.cpp b/samples/dtest/dtarge.cpp index 2cd45343..42049954 100644 --- a/samples/dtest/dtarge.cpp +++ b/samples/dtest/dtarge.cpp @@ -8,6 +8,7 @@ // #include #include +#include #include "dtarge.h" DWORD_PTR WINAPI Target0() diff --git a/samples/dtest/dtarge.h b/samples/dtest/dtarge.h index 7aa5cd6c..f60317b9 100644 --- a/samples/dtest/dtarge.h +++ b/samples/dtest/dtarge.h @@ -12,49 +12,49 @@ typedef DWORD DWORD_PTR; #endif -DWORD_PTR WINAPI Target0(); -DWORD_PTR WINAPI Target1(DWORD_PTR v1); -DWORD_PTR WINAPI Target2(DWORD_PTR v1, DWORD_PTR v2); -DWORD_PTR WINAPI Target3(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3); -DWORD_PTR WINAPI Target4(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4); -DWORD_PTR WINAPI Target5(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target0(); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target1(DWORD_PTR v1); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target2(DWORD_PTR v1, DWORD_PTR v2); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target3(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target4(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target5(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5); -DWORD_PTR WINAPI Target6(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target6(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6); -DWORD_PTR WINAPI Target7(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target7(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7); -DWORD_PTR WINAPI Target8(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target8(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8); -DWORD_PTR WINAPI Target9(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target9(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9); -DWORD_PTR WINAPI Target10(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target10(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10); -DWORD_PTR WINAPI Target11(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target11(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11); -DWORD_PTR WINAPI Target12(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target12(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11, DWORD_PTR v12); -DWORD_PTR WINAPI Target13(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target13(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11, DWORD_PTR v12, DWORD_PTR v13); -DWORD_PTR WINAPI Target14(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target14(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11, DWORD_PTR v12, DWORD_PTR v13, DWORD_PTR v14); -DWORD_PTR WINAPI Target15(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target15(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11, DWORD_PTR v12, DWORD_PTR v13, DWORD_PTR v14, DWORD_PTR v15); -DWORD_PTR WINAPI Target16(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI Target16(DWORD_PTR v1, DWORD_PTR v2, DWORD_PTR v3, DWORD_PTR v4, DWORD_PTR v5, DWORD_PTR v6, DWORD_PTR v7, DWORD_PTR v8, DWORD_PTR v9, DWORD_PTR v10, DWORD_PTR v11, DWORD_PTR v12, DWORD_PTR v13, DWORD_PTR v14, DWORD_PTR v15, DWORD_PTR v16); -DWORD_PTR WINAPI TargetV(DWORD_PTR v1, ...); -DWORD_PTR WINAPI TargetR(DWORD_PTR v1, ...); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI TargetV(DWORD_PTR v1, ...); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI TargetR(DWORD_PTR v1, ...); // ///////////////////////////////////////////////////////////////// End of File. diff --git a/samples/dtest/dtest.cpp b/samples/dtest/dtest.cpp index f7de56d1..698120fa 100644 --- a/samples/dtest/dtest.cpp +++ b/samples/dtest/dtest.cpp @@ -18,7 +18,7 @@ #include #include "dtarge.h" -DWORD_PTR WINAPI LocalTarget1(DWORD_PTR v1); +DECLSPEC_HYBRID_PATCHABLE DWORD_PTR WINAPI LocalTarget1(DWORD_PTR v1); ////////////////////////////////////////////////////// Multi-Argument Detours. // diff --git a/samples/einst/Makefile b/samples/einst/Makefile index 2821fb7d..24faacc2 100644 --- a/samples/einst/Makefile +++ b/samples/einst/Makefile @@ -12,7 +12,7 @@ # ARM64 does not like base addresses below 4GB. # Append two extra zeros for it. # -!if "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" +!if "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" || "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" EDLL1X_BASE=0x710000000 EDLL2X_BASE=0x720000000 EDLL3X_BASE=0x730000000 diff --git a/samples/findfunc/Makefile b/samples/findfunc/Makefile index 2ea19dc6..ba6befb4 100644 --- a/samples/findfunc/Makefile +++ b/samples/findfunc/Makefile @@ -10,15 +10,15 @@ !include ..\common.mak # ARM64 does not like base addresses below 4GB. -# Append two extra zeros for it. -# -!if "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" -TARGET_BASE=0x190000000 -EXTEND_BASE=0x1a0000000 -!else -TARGET_BASE=0x1900000 -EXTEND_BASE=0x1a00000 -!endif +# Append two extra zeros for it. +# +!if "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" || "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" +TARGET_BASE=0x190000000 +EXTEND_BASE=0x1a0000000 +!else +TARGET_BASE=0x1900000 +EXTEND_BASE=0x1a00000 +!endif LIBS=$(LIBS) kernel32.lib diff --git a/samples/member/member.cpp b/samples/member/member.cpp index 585ef98a..a2a3f78a 100644 --- a/samples/member/member.cpp +++ b/samples/member/member.cpp @@ -40,7 +40,7 @@ class CMember { public: - void Target(void); + DECLSPEC_HYBRID_PATCHABLE void Target(void); }; void CMember::Target(void) diff --git a/src/Makefile b/src/Makefile index 75606c8b..413b30b0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,12 +28,22 @@ CFLAGS=$(CFLAGS) /DWIN32_LEAN_AND_MEAN /D_WIN32_WINNT=0x501 CFLAGS=$(CFLAGS) /wd4163 # intrinsic rdtebex not available; using newer Windows headers with older compiler !ENDIF +!IF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" +CFLAGS=/arm64EC $(CFLAGS) +!ENDIF + !if defined(DETOURS_WIN_7) && defined(DETOURS_CL_17_OR_NEWER) CFLAGS=$(CFLAGS) /D_USING_V110_SDK71_ !elseif defined(DETOURS_ANALYZE) CFLAGS=$(CFLAGS) /analyze !endif +LIBFLAGS=/nologo + +!IF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" +LIBFLAGS=$(LIBFLAGS) /machine:arm64x +!ENDIF + OBJS = \ $(OBJD)\detours.obj \ $(OBJD)\modules.obj \ @@ -90,7 +100,7 @@ $(OBJD)\detours.bsc : $(OBJS) bscmake /v /n /o $@ $(OBJS:.obj=.sbr) $(LIBD)\detours.lib : $(OBJS) - link /lib /out:$@ /nologo $(OBJS) + link /lib $(LIBFLAGS) /out:$@ $(OBJS) $(INCD)\detours.h : detours.h copy detours.h $@ diff --git a/src/detours.cpp b/src/detours.cpp index 11fa2e1d..09b1d379 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -2143,6 +2143,15 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, DETOUR_TRACE((" ppldTarget=%p, code=%p [gp=%p]\n", ppldTarget, pbTarget, pTargetGlobals)); #else // DETOURS_IA64 +#if defined(_M_ARM64EC) + if (RtlIsEcCode(reinterpret_cast(*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)); + DETOUR_BREAK(); + } +#endif pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); pDetour = DetourCodeFromPointer(pDetour, NULL); #endif // !DETOURS_IA64 diff --git a/src/detours.h b/src/detours.h index f3738af0..8e987854 100644 --- a/src/detours.h +++ b/src/detours.h @@ -83,11 +83,15 @@ #undef DETOURS_32BIT #undef DETOURS_64BIT +#ifndef DECLSPEC_HYBRID_PATCHABLE +#define DECLSPEC_HYBRID_PATCHABLE DECLSPEC_CHPE_PATCHABLE +#endif + #if defined(_X86_) #define DETOURS_X86 #define DETOURS_OPTION_BITS 64 -#elif defined(_AMD64_) +#elif defined(_AMD64_) || defined(_ARM64EC_) #define DETOURS_X64 #define DETOURS_OPTION_BITS 32 @@ -102,7 +106,7 @@ #define DETOURS_ARM64 #else -#error Unknown architecture (x86, amd64, ia64, arm, arm64) +#error Unknown architecture (x86, amd64, ia64, arm, arm64, arm64ec) #endif #ifdef _WIN64 @@ -381,10 +385,10 @@ extern const GUID DETOUR_EXE_RESTORE_GUID; extern const GUID DETOUR_EXE_HELPER_GUID; #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! -typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; - -#ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS -#define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 +typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; + +#ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS +#define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 #endif // !DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS /////////////////////////////////////////////////////////// Binary Structures. @@ -594,8 +598,8 @@ PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, _In_ BOOL fLimitReferencesToModule); PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, - _Out_ PDWORD pcbAllocatedSize); -BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode, + _Out_ PDWORD pcbAllocatedSize); +BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode, _In_ PBYTE pbAddress); ///////////////////////////////////////////////////// Loaded Binary Functions. diff --git a/system.mak b/system.mak index 388c0395..40404bc6 100644 --- a/system.mak +++ b/system.mak @@ -52,6 +52,10 @@ DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:x=X) DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:y=Y) DETOURS_TARGET_PROCESSOR=$(DETOURS_TARGET_PROCESSOR:z=Z) +!IF "$(DETOURS_TARGET_PROCESSOR)" == "WIN32" +DETOURS_TARGET_PROCESSOR = X86 +!ENDIF + !IF "$(DETOURS_TARGET_PROCESSOR)" == "AMD64" DETOURS_TARGET_PROCESSOR = X64 !ENDIF @@ -90,7 +94,9 @@ DETOURS_OPTION_BITS=64 !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM" #!MESSAGE Building for 32-bit ARM. !ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64" -#!MESSAGE Building for 64-bit ARM. +#!MESSAGE Building for 64-bit ARM64. +!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64EC" +#!MESSAGE Building for 64-bit ARM64EC. !ELSE !MESSAGE Note: To select the target processor architecture set either !MESSAGE PROCESSOR_ARCHITECTURE or DETOURS_TARGET_PROCESSOR. diff --git a/tests/test_module_api.cpp b/tests/test_module_api.cpp index 3e2928cd..e3f0ca53 100644 --- a/tests/test_module_api.cpp +++ b/tests/test_module_api.cpp @@ -28,6 +28,103 @@ extern "C" int mainCRTStartup(); // void NoopFunction() { } +#include + +#if defined(_ARM64EC_) +inline bool +StdFFSMatch( + unsigned __int64 x64Address, + unsigned __int64 EcAddress + ) +{ + unsigned __int64 FFSpart1; + unsigned short FFSpart2; + unsigned __int64 EcAddr; + int JmpOffset; + + // + // A standard fast-forward sequence follows this pattern + // + // 488bc4 mov rax,rsp + // 48895820 mov qword ptr [rax+20h],rbx + // 55 push rbp + // 5d pop rbp + // e952df1600 jmp ntdll!_swprintf (00000001`80178760) + // + // See https://learn.microsoft.com/en-us/cpp/cpp/hybrid-patchable?view=msvc-170 for details. + // + + if (x64Address % 16 != 0) + { + // + // All standard FFS are 16-byte aligned guaranteed by compiler + // + + return false; + } + + if (RtlIsEcCode(x64Address)) + { + // + // Arm64EC code is never a standard FFS + // + + return false; + } + + __try + { + FFSpart1 = ReadULong64NoFence((ULONG64*)x64Address); + FFSpart2 = ReadUShortNoFence((USHORT*)(x64Address + 8)); + JmpOffset = ReadULongNoFence((ULONG*)(x64Address + 10)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + + if (FFSpart1 == 0x5520588948c48b48 && FFSpart2 == 0xe95d) + { + + EcAddr = (ULONG_PTR)((LONG_PTR)x64Address + 14 + JmpOffset); + if (!RtlIsEcCode(EcAddr)) + { + return false; + } + + if (EcAddress != EcAddr) + { + return false; + } + + return true; + } + + return false; +} +#endif + +bool EquivalentFunctions(void* a, void* b) +{ + if (a == b) + { + return true; + } + + // TODO: Remove Arm64EC-specific FFS matching logic when address taken operator + // inconsistency in Arm64EC MSVC is fixed. + // See https://developercommunity.visualstudio.com/t/Functions-dllimported-from-arm64ec-dlls/10670642 +#if defined(_ARM64EC_) + if (StdFFSMatch(reinterpret_cast(a), reinterpret_cast(b)) || + StdFFSMatch(reinterpret_cast(b), reinterpret_cast(a))) + { + return true; + } +#endif + + return false; +} + TEST_CASE("DetourLoadImageHlp", "[module]") { SECTION("Passing own function, results in own HMODULE") @@ -131,7 +228,7 @@ TEST_CASE("DetourGetEntyPoint", "[module]") auto entry = DetourGetEntryPoint(nullptr); REQUIRE( GetLastError() == NO_ERROR ); - REQUIRE( entry == mainCRTStartup ); + REQUIRE( EquivalentFunctions( entry, mainCRTStartup ) ); } SECTION("Passing nullptr, equals executing image") @@ -147,7 +244,7 @@ TEST_CASE("DetourGetEntyPoint", "[module]") auto entry = DetourGetEntryPoint(reinterpret_cast(&__ImageBase)); REQUIRE( GetLastError() == NO_ERROR ); - REQUIRE( entry == mainCRTStartup ); + REQUIRE( EquivalentFunctions( entry, mainCRTStartup ) ); } SECTION("Corrupt image DOS header magic, results in bad exe format error") @@ -729,9 +826,14 @@ TEST_CASE("DetourRestoreAfterWithEx", "[module]") } // Define the import symbol so that we can get the address of the IAT entry for a static import -#ifdef _X86_ +#pragma warning(push) #pragma warning(disable:4483) // disable warning/error about __identifier() +#if defined(_X86_) #define __imp_SetLastError __identifier("_imp__SetLastError@4") +#elif defined(_ARM64EC_) +// In Arm64EC binaries, __imp_aux_foo points the primary IAT entry +// for foo, and __imp_foo points to the auxiliary IAT entry for foo. +#define __imp_SetLastError __identifier("__imp_aux_SetLastError") #endif extern "C" extern void *__imp_SetLastError; @@ -754,3 +856,4 @@ TEST_CASE("DetourIsFunctionImported", "[module]") } } +#pragma warning(pop) diff --git a/vc/Detours.sln b/vc/Detours.sln index 2bd53476..4bae9dae 100644 --- a/vc/Detours.sln +++ b/vc/Detours.sln @@ -1,7 +1,5 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29519.181 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "Detours.vcxproj", "{37489709-8054-4903-9C49-A79846049FC9}" EndProject @@ -9,10 +7,12 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DebugMDd|ARM = DebugMDd|ARM DebugMDd|ARM64 = DebugMDd|ARM64 + DebugMDd|ARM64EC = DebugMDd|ARM64EC DebugMDd|x64 = DebugMDd|x64 DebugMDd|x86 = DebugMDd|x86 ReleaseMD|ARM = ReleaseMD|ARM ReleaseMD|ARM64 = ReleaseMD|ARM64 + ReleaseMD|ARM64EC = ReleaseMD|ARM64EC ReleaseMD|x64 = ReleaseMD|x64 ReleaseMD|x86 = ReleaseMD|x86 EndGlobalSection @@ -21,6 +21,8 @@ Global {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM.Build.0 = DebugMDd|ARM {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64.ActiveCfg = DebugMDd|ARM64 {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64.Build.0 = DebugMDd|ARM64 + {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64EC.ActiveCfg = DebugMDd|ARM64EC + {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64EC.Build.0 = DebugMDd|ARM64EC {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x64.ActiveCfg = DebugMDd|x64 {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x64.Build.0 = DebugMDd|x64 {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x86.ActiveCfg = DebugMDd|Win32 @@ -29,6 +31,8 @@ Global {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM.Build.0 = ReleaseMD|ARM {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64.ActiveCfg = ReleaseMD|ARM64 {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64.Build.0 = ReleaseMD|ARM64 + {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64EC.ActiveCfg = ReleaseMD|ARM64EC + {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64EC.Build.0 = ReleaseMD|ARM64EC {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x64.ActiveCfg = ReleaseMD|x64 {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x64.Build.0 = ReleaseMD|x64 {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x86.ActiveCfg = ReleaseMD|Win32 diff --git a/vc/Detours.vcxproj b/vc/Detours.vcxproj index 9a3f966f..7cea8720 100644 --- a/vc/Detours.vcxproj +++ b/vc/Detours.vcxproj @@ -9,6 +9,10 @@ DebugMDd ARM64 + + DebugMDd + ARM64EC + DebugMDd Win32 @@ -21,6 +25,10 @@ ReleaseMD ARM64 + + ReleaseMD + ARM64EC + ReleaseMD Win32 @@ -45,49 +53,61 @@ Makefile true - v142 + v143 Unicode Makefile false - v142 + v143 Unicode Makefile true - v142 + v143 + Unicode + + + Makefile + true + v143 Unicode Makefile true - v142 + v143 Unicode Makefile true - v142 + v143 Unicode Makefile false - v142 + v143 + Unicode + + + Makefile + false + v143 Unicode Makefile false - v142 + v143 Unicode Makefile false - v142 + v143 Unicode @@ -104,6 +124,9 @@ + + + @@ -113,6 +136,9 @@ + + + @@ -120,98 +146,122 @@ - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake clean + + + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake clean +nmake + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake clean +nmake + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake clean + + + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake clean @@ -231,7 +281,7 @@ nmake clean - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -255,7 +305,33 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake + + + + + Level4 + Disabled + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + true + ProgramDatabase + + + + + $(OutputPath)$(TargetName).pdb + + + Windows + true + + + + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -281,7 +357,7 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -307,7 +383,7 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -331,7 +407,7 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -357,7 +433,35 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) +cd .. +nmake + + + + + Level4 + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + + + + + $(OutputPath)$(TargetName).pdb + + + Windows + true + true + true + + + + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -385,7 +489,7 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -413,7 +517,7 @@ nmake - SET DETOURS_TARGET_PROCESSOR=$(PlatformTarget) + SET DETOURS_TARGET_PROCESSOR=$(Platform) cd .. nmake @@ -601,4 +705,4 @@ nmake - + \ No newline at end of file