Add ARM64 cross-compilation support for Windows Meterpreter#794
Add ARM64 cross-compilation support for Windows Meterpreter#794SilentSobs wants to merge 7 commits into
Conversation
- Add aarch64-w64-mingw32.cmake toolchain file for llvm-mingw - Add ARM64 build targets to Makefile (meterpreter-arm64, meterpreter-metsrv-arm64) - Add aarch64 architecture detection in workspace CMakeLists.txt - Add ARM64 source selection in ReflectiveDLLInjection CMakeLists.txt Tested with llvm-mingw 20260311, produces valid PE32+ ARM64 DLL.
|
Helllo @SilentSobs, Thank you for opening this PR. We do support Mingw, but our main compiler (for example what we ship in metasploit-framework) is MSVC, so the first step should be extend the VisualStudio projects to use ARM64 along side what you already did for Mingw. Secondly, Porting Meterpreter to ARM64 not only requires the compiler additions, but mainly includes working on the code-base and looking for wrong architecture assumptions. something like: if(dwMeterpreterArch == ARCH_X64) {
// something x64
else {
// something x32
}I would expect a significant effort ensuring in framework we don't have this assumption also. I made last year a small issue Cheers! |
Add Release, Debug, and r7_release configurations for ARM64 target. Uses v143 toolset (VS2022) as ARM64 requires modern toolchain. Wires GateTrampolineARM64.asm under MARMASM (Microsoft ARM Assembler), excludes x86/x64 trampolines from ARM64 builds and vice versa. fix: use ARMASM64 instead of MASM for GateTrampolineARM64.asm fix: use MARMASM instead of ARMASM for GateTrampolineARM64.asm
Several parts of the metsrv codebase made implicit assumptions about x86/x64 that break on ARM64. This commit addresses all of them: - base_inject.c/h: guard inject_via_remotethread_wow64 with #ifndef _M_ARM64 — WOW64 x86->x64 transition doesn't exist on ARM64 - metapi.c: guard inject_via_remotethread_wow64 function pointer in the inject API table with #ifndef _M_ARM64 - pool_party_ext.h: change _CLIENT_ID guard to also check _WINTERNL_ since newer Windows SDK (10.0.26100.0) already defines it there - common.h: add ws2tcpip.h include to make inet_pton available - metsrv.h: conditionally set _WIN32_WINNT to 0x0600 for ARM64 since ARM64 Windows minimum is Vista, not XP - server_transport_tcp.c: replace deprecated inet_addr/gethostbyname with inet_pton/getaddrinfo, replace WSADuplicateSocketA with W variant - server_pivot_named_pipe.c: rename local AddMandatoryAce to AddMandatoryAce_ to avoid conflict with SDK dllimport declaration - metsrv.vcxproj: set RandomizedBaseAddress=true for ARM64 configs since /DYNAMICBASE:NO is not allowed on ARM64 - metsrv.def: remove NAME directive that conflicted with ARM64 output filename causing linker failure
8e8ffe8 to
b5ad9f0
Compare
| // Minimum Windows Vista for inet_pton and modern APIs | ||
| #ifndef _WIN32_WINNT | ||
| #define _WIN32_WINNT 0x0600 | ||
| #endif | ||
| #include <winsock2.h> | ||
| #include <ws2tcpip.h> |
There was a problem hiding this comment.
this change should be wrapped inside an #ifdef _M_ARM64 otherwise we are breaking compatibility with Windows XP
| * threads (kernel32!CreateThread will return ERROR_NOT_ENOUGH_MEMORY). Because of this we filter out | ||
| * Windows 2003 from this method of injection, however the APC injection method will work on 2003. | ||
| */ | ||
| #ifndef _M_ARM64 |
There was a problem hiding this comment.
I don't think we should remove the function on ARM, just throwing an incompatibility error if the architecture is not X86 or X64
| if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64) | ||
| { | ||
| BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") | ||
| dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64; | ||
|
|
||
| if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS) | ||
| { | ||
| BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") | ||
| } | ||
| } | ||
| } | ||
| else | ||
| else | ||
| #endif // _M_ARM64 |
There was a problem hiding this comment.
This is also incorrect. the handling should be by verifying dwMeterpreterArch and dwDestinationArch rather than using ifdefs
| inject_dll, | ||
| inject_via_apcthread, | ||
| inject_via_remotethread, | ||
| #ifndef _M_ARM64 |
There was a problem hiding this comment.
this one shouldn't be removed
| #ifdef _M_ARM64 | ||
| #define _WIN32_WINNT 0x0600 | ||
| #else | ||
| #define _WIN32_WINNT _WIN32_WINNT_WINXP | ||
| #endif |
| typedef BOOL (WINAPI *PAddMandatoryAce_)(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid); | ||
| static BOOL WINAPI AddMandatoryAce_(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid) |
There was a problem hiding this comment.
What is the reason for this change?
| { | ||
| COMMONMIGRATECONTEXT common; | ||
| WSAPROTOCOL_INFOA info; | ||
| WSAPROTOCOL_INFOW info; |
There was a problem hiding this comment.
Swapping this could harm the XP release builds
There was a problem hiding this comment.
Sorry to necro-comment, but per some recent discussions, dropping XP support may be in scope?
There was a problem hiding this comment.
Hello! From 6.5 we are effectively dropping XP support, I believe this PR will be handled AFTER 6.5 so that should not be a problem anymore
…SDK guards, add PROCESS_ARCH_ARM64
…SDK guards, add PROCESS_ARCH_ARM64
Add MSVC ARM64 platform support to metsrv
This PR adds ARM64 Windows support to
metsrvthe core Meterpreter server DLL. It builds on the groundwork already merged by @xaitax (ARM64 ReflectiveLoader in rapid7/ReflectiveDLLInjection#20 and WinExec payload in rapid7/metasploit-framework#20357) and extends it to the full metsrv DLL.The goal was simple: get
metsrv.ARM64.dllbuilding cleanly with MSVC (Visual Studio 2022, v143 toolset) targeting ARM64 Windows. Took a few iterations to get there ARM64 is stricter than x86/x64 in a few ways that exposed some assumptions baked into the existing codebase.What changed and why
metsrv.vcxprojAdded
Debug|ARM64,Release|ARM64, andr7_release|ARM64configurations. ARM64 requires the modern v143 toolset the existingv141_xpused by other platforms doesn't support it. Assembly is wired through MARMASM (Microsoft ARM Assembler) usingmarmasm.props/marmasm.targetsnot MASM, which is x86 only. x86/x64 trampolines are excluded from ARM64 builds and vice versa.RandomizedBaseAddressis forced totruefor ARM64 configs since/DYNAMICBASE:NOis explicitly rejected by the ARM64 linker.metsrv.defRemoved the
NAME server.dlldirective. This was causing a silent linker failure the ARM64 output filename ismetsrv.ARM64.dlland the mismatched NAME directive was preventing the DLL from being produced at all.base_inject.c/base_inject.h/metapi.cGuarded
inject_via_remotethread_wow64with#ifndef _M_ARM64in both the definition and the declaration. The WOW64 x86→x64 transition mechanism simply doesn't exist on ARM64 there's no 32-bit subsystem to bridge to. Also guarded the function pointer reference in the inject API table inmetapi.cthe same way.pool_party_ext.hChanged the
_CLIENT_IDstruct guard from#ifndef __MINGW32__to#if !defined(__MINGW32__) && !defined(_WINTERNL_). The newer Windows SDK (10.0.26100.0) already defines_CLIENT_IDinwinternl.h, so the local definition was causing a redefinition error.common.hAdded
#include <ws2tcpip.h>after#include <winsock2.h>. Without it,inet_ptonis simply not declared.metsrv.hThe file was doing
#undef _WIN32_WINNTthen hardcoding_WIN32_WINNT_WINXP, which overrode any fix made incommon.h. Added a conditional so ARM64 gets0x0600(Vista) instead ARM64 Windows minimum is 10, but Vista is the minimum needed to getinet_ptonand other modern Winsock APIs without errors.server_transport_tcp.cReplaced
inet_addrwithinet_ptonandgethostbynamewithgetaddrinfo. Also replacedWSADuplicateSocketAwithWSADuplicateSocketWand updated theWSAPROTOCOL_INFOAfield inTCPMIGRATECONTEXTtoWSAPROTOCOL_INFOW. These deprecated ANSI Winsock APIs are hard errors on ARM64 with the newer SDK.server_pivot_named_pipe.cRenamed the local
AddMandatoryAcefunction toAddMandatoryAce_to avoid a conflict with the SDK's dllimport declaration. At_WIN32_WINNT=0x0600the Windows SDK exposesAddMandatoryAceas a dllimport, which conflicts with the existing local static definition.Build output
Tested on Windows 10 x64 with Visual Studio 2022 (v143 toolset, SDK 10.0.26100.0):
Notes
metsrv.vcxprojwas modified other projects in the solution (elevator,stdapietc.) have pre-existingv141_xpissues that are unrelated to this PRstdapi,priv) and the Ruby payload module are follow-on work this PR focuses on getting the core DLL building first