この問題に遭遇している人を見かけることがあるためメモ。
Win32 APIのCopyMemory 関数が使用する.NETのバージョンやプラットフォームの違いで使えない理由は.NET Frameworkでは存在したCopyMemory 関数をP/Invokeした際のフォールバック処理が.NET Coreには存在しないため。
CopyMemory関数は実際にはkernel32.dllには存在せず、アンマネージド (C/C++) の環境ではこの関数は実際にはRtlCopyMemoryという関数へのマクロであり、RtlCopyMemory関数は更にCランタイムライブラリのmemcpy関数へのマクロになっている。
CopyMemory関数のMicrosoft Learnの公式ドキュメントにも以下の記載がある。
This function is defined as the RtlCopyMemory function. Its implementation is provided inline. For more information, see WinBase.h and WinNT.h.
以下の画像は64ビットのkernel32.dllのエクスポート (CopyMemory関数ではなくRtlCopyMemory関数がエクスポートされている)

以下の画像は32ビットのkernel32.dllのエクスポート (CopyMemory関数やRtlCopyMemory関数はエクスポートされていない)

プラットフォームが64ビットの場合はRtlCopyMemory関数のみkernel32.dllからエクスポートされているが、実際には64ビットのntdll.dll(他のRtlXxx関数やOSのネイティブAPI (NtXxx関数/システムコール) が実装されているDLL) からエクスポートされている同名の関数へのスタブ (RtlCopyMemoryStub) である。
以下の画像は64ビットのntdll.dllのRtlCopyMemory関数のエクスポート

.NET FrameworkではCopyMemory 関数をP/Invokeした場合はRtlCopyMemory関数かmemmove関数にフォールバックする仕様となっているが、.NET Coreにはこの特別処理は無い。
以下がこの関数に対応するWindows SDKに含まれるヘッダーファイル内の該当部分。
#define CopyMemory RtlCopyMemory
#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))
ちなみにだが、MoveMemory FillMemory ZeroMemory関数も同様にマクロである。
#define MoveMemory RtlMoveMemory
#define FillMemory RtlFillMemory
#define ZeroMemory RtlZeroMemory
#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length)))
#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length))
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
CopyMemory関数を使用しなくても.NET Framework 4.6 (Coreは1.0) 以降はSystem.BufferクラスのMemoryCopy メソッドが用意されており。
.NET 7以降はSystem.Runtime.InteropServices.NativeMemoryクラスにも同様のメソッドが用意されている。
またSystem.Runtime.CompilerServices.UnsafeクラスのCopyBlock メソッドも同様にコピーに使用できる。
どうしてもCopyMemory関数を使用する必要がある場合は、代わりにCランタイムライブラリ (msvcrt.dll / ucrtbase.dll) のmemcpy 関数の方をP/Invokeした方が良いと思われる。
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
// void*
public static extern IntPtr memcpy(
IntPtr _Dst, // void* (or byte* or byte[])
IntPtr _Src, // void* (or byte* or byte[])
UIntPtr _Size // size_t (UIntPtr = UInt32 (on 32-Bit), UInt64 (on 64-Bit))
);
併せてだが、size_tと定義されているバッファーサイズを受け取るパラメーターをintやuint型として定義している例が見受けられるが、これは間違い (プラットフォームを32ビットに固定する場合を除く)。
理由はsize_t型はコンパイルするプラットフォームでサイズが異なり、32ビットでは32ビット符号なし整数であるunsigned int(マネージド型はuint)型、64ビットでは64ビット符号なし整数であるunsigned __int64(マネージド型はulong)型となるので、マネージド型はUIntPtrかnuint(C# 9+)を使用するのが正しい。
// Definitions of common types
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef unsigned int size_t;
#endif
#if defined(_WIN64)
typedef __int64 LONG_PTR, *PLONG_PTR;
typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
#else
typedef _W64 long LONG_PTR, *PLONG_PTR;
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
#endif
//
// SIZE_T used for counts or ranges which need to span the range of
// of a pointer. SSIZE_T is the signed variation.
//
typedef ULONG_PTR SIZE_T, *PSIZE_T;
typedef LONG_PTR SSIZE_T, *PSSIZE_T;
#ifdef _WIN64
typedef __int64 LONG_PTR;
typedef unsigned __int64 ULONG_PTR;
#else
typedef _W64 long LONG_PTR;
typedef _W64 unsigned long ULONG_PTR;
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif
typedef LONG_PTR SSIZE_T;
typedef ULONG_PTR SIZE_T;
void CopyMemory(
_In_ PVOID Destination,
_In_ const VOID *Source,
_In_ SIZE_T Length // SIZE_Tはsize_tと同じ
);
void* __cdecl memcpy(
_Out_writes_bytes_all_(_Size) void* _Dst,
_In_reads_bytes_(_Size) void const* _Src,
_In_ size_t _Size
);