#include "unlock.h"
#include "scsi_structs.h"
#include "rc4.h"
#include "sha1.h"
#include "utils.h"

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stddef.h>

static uint8_t scsibuffer[2001];
static TRC4Context rc4key;

/* Forward declaration required by C99/MinGW because the partial-handshake
 * probe calls this private helper before its definition below. */
static void LogHexDump(const char* prefix, const uint8_t* data, DWORD length);

// --- State persistence for partial execution ---
static uint8_t restable[261];
static int chalpos[11];
static int k_count = 0;
static bool table_initialized = false;

bool AuthenticateXboxMedia_Partial(HANDLE hDrive, int startStep, int endStep) {
    uint8_t buffer[2048];
    uint8_t cdb[16];
    uint8_t hash[0x2C];
    uint8_t shadigest[20];
    uint8_t shastring[20];
    bool status;

    for (int step = startStep; step <= endStep; step++) {
        memset(cdb, 0, 16);
        memset(buffer, 0, 2048);

        printf("\n[PROBE] Executing Handshake Step %d\n", step);

        switch (step) {
            case 1: // Init Read Capacity
                cdb[0] = 0x25;
                LogHexDump("Sending CDB [Step 1: Init Read Cap]", cdb, 10);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 8, SCSI_DATA_IN, 10)) return false;
                LogHexDump("Received Data [Step 1: Init Read Cap]", buffer, 8);
                break;

            case 2: // Mode Sense (Challenge Request)
                cdb[0] = 0x5A; cdb[2] = 0x3E; cdb[8] = 0x1C;
                LogHexDump("Sending CDB [Step 2: Mode Sense]", cdb, 10);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_IN, 10)) return false;
                LogHexDump("Received Data [Step 2: Mode Sense]", buffer, 28);
                break;

            case 3: // Read DVD Struct 0xAD (Session Data)
                cdb[0] = 0xAD; cdb[2] = 0xFF; cdb[3] = 0x02; cdb[4] = 0xFD;
                cdb[5] = 0xFF; cdb[6] = 0xFE; cdb[8] = 0x06; cdb[9] = 0x64; cdb[11] = 0xC0;
                
                LogHexDump("Sending CDB [Step 3: Read DVD Struct 0xAD]", cdb, 12);
                status = scsi_cmd(hDrive, cdb, 12, buffer, 1636, SCSI_DATA_IN, 15);
                
                // Hitachi 4241N Fallback Logic
                if (!status || buffer[772] != 1) {
                    printf("[!] Standard 0xAD Table Invalid. Attempting Hitachi 0xFD Fallback...\n");
                    memset(cdb, 0, 12);
                    cdb[0] = 0xFD; cdb[1] = 0x01; cdb[8] = 0x06; cdb[9] = 0x64;
                    LogHexDump("Sending CDB [Step 3: Fallback 0xFD]", cdb, 12);
                    if (!scsi_cmd(hDrive, cdb, 12, buffer, 1636, SCSI_DATA_IN, 15)) {
                        printf("[-] Fatal: All table acquisition methods failed.\n");
                        return false;
                    }
                }
                LogHexDump("Received Data [Step 3: Handshake Table]", buffer, 32); // Logging header only

                // --- Crypto Processing ---
                for (int i = 0; i < 0x2C; i++) hash[i] = buffer[0x4A3 + i];
                SHA1_CTX ctx;
                SHA1_Init(&ctx);
                SHA1_Update(&ctx, hash, 0x2C);
                SHA1_Final(shadigest, &ctx);
                memcpy(shastring, shadigest, 7);
                RC4Init(&rc4key, shastring, 7);
                for (int i = 0; i <= 260; i++) restable[i] = buffer[774 + i];
                rc4Decrypt(restable, restable, 0xFD, &rc4key);

                k_count = 0;
                for (int l = 0; l <= 23; l++) {
                    if (restable[l * 11] == 1) {
                        chalpos[k_count] = l;
                        k_count++;
                    }
                }
                table_initialized = (k_count >= 2);
                printf("[+] Crypto Done: %d valid challenges found.\n", k_count);
                break;

            case 4: // Mode Select Chal 1
                cdb[0] = 0x55; cdb[8] = 0x1C;
                buffer[1] = 0x1A; buffer[8] = 0x3E; buffer[9] = 0x12;
                buffer[11] = 0x01; buffer[13] = 0xD1; buffer[14] = 0x01;
                memcpy(&buffer[15], &restable[1 + chalpos[k_count - 2] * 11], 5);
                
                LogHexDump("Sending CDB [Step 4: Mode Select Chal 1]", cdb, 10);
                LogHexDump("Sending Data [Step 4: Mode Select Chal 1]", buffer, 28);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_OUT, 10)) return false;
                break;

            case 5: // Mode Sense Verify 1
                cdb[0] = 0x5A; cdb[2] = 0x3E; cdb[8] = 0x1C;
                LogHexDump("Sending CDB [Step 5: Mode Sense Verify 1]", cdb, 10);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_IN, 10)) return false;
                LogHexDump("Received Data [Step 5: Mode Sense Verify 1]", buffer, 28);
                break;

            case 6: // Mode Select Chal 2
                cdb[0] = 0x55; cdb[8] = 0x1C;
                buffer[1] = 0x1A; buffer[8] = 0x3E; buffer[9] = 0x12; buffer[12] = 0x01;
                memcpy(&buffer[15], &restable[1 + chalpos[k_count - 1] * 11], 5);
                
                LogHexDump("Sending CDB [Step 6: Mode Select Chal 2]", cdb, 10);
                LogHexDump("Sending Data [Step 6: Mode Select Chal 2]", buffer, 28);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_OUT, 10)) return false;
                break;

            case 7: // Mode Sense Verify 2
                cdb[0] = 0x5A; cdb[2] = 0x3E; cdb[8] = 0x1C;
                LogHexDump("Sending CDB [Step 7: Mode Sense Verify 2]", cdb, 10);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_IN, 10)) return false;
                LogHexDump("Received Data [Step 7: Mode Sense Verify 2]", buffer, 28);
                break;

            case 8: // Partition 1 Unlock Command
                if (!table_initialized) { printf("[-] Error: Handshake table not ready.\n"); return false; }
                cdb[0] = 0x55; cdb[8] = 0x1C;
                buffer[1] = 0x1A; buffer[8] = 0x3E; buffer[9] = 0x12;
                buffer[10] = 0x01; buffer[11] = 0x01; buffer[12] = 0x01;
                buffer[13] = 0xD1; buffer[14] = 0x01;
                memcpy(&buffer[15], &restable[1 + chalpos[k_count - 1] * 11], 5);
                
                LogHexDump("Sending CDB [Step 8: Mode Select Part1 Unlock]", cdb, 10);
                LogHexDump("Sending Data [Step 8: Mode Select Part1 Unlock]", buffer, 28);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 28, SCSI_DATA_OUT, 10)) return false;
                printf("[+] Step 8 Complete: Partition Unlocked.\n");
                break;

            case 9: // Sticky Descrambling (Mode 0x31)
                cdb[0] = 0x15; cdb[1] = 0x11; cdb[4] = 0x0C;
                buffer[4] = 0x31; buffer[5] = 0x06; buffer[6] = 0x01;
                
                LogHexDump("Sending CDB [Step 9: Sticky Descrambling]", cdb, 6);
                LogHexDump("Sending Data [Step 9: Sticky Descrambling]", buffer, 12);
                if (!scsi_cmd(hDrive, cdb, 6, buffer, 12, SCSI_DATA_OUT, 10)) return false;
                printf("[+] Step 9 Complete: Descrambling Active.\n");
                break;

            case 10: // Final Verify Capacity
                cdb[0] = 0x25;
                LogHexDump("Sending CDB [Step 10: Final Verify]", cdb, 10);
                if (!scsi_cmd(hDrive, cdb, 10, buffer, 8, SCSI_DATA_IN, 10)) return false;
                LogHexDump("Received Data [Step 10: Final Verify]", buffer, 8);
                break;

            default:
                printf("[-] Invalid Step: %d\n", step);
                return false;
        }
    }
    return true;
}


// Helper function to log hex dumps cleanly to the console
static void LogHexDump(const char* prefix, const uint8_t* data, DWORD length) {
    if (!data || length == 0) return;
    printf("\n--- %s (%lu bytes) ---\n", prefix, length);
    for (DWORD i = 0; i < length; i++) {
        printf("%02X ", data[i]);
        if ((i + 1) % 16 == 0) printf("\n");
    }
    if (length % 16 != 0) printf("\n");
    printf("---------------------------\n");
}

BOOL UnlockDrive(HANDLE AHandle) {
    printf("Structure size: %zu\n", sizeof(SCSI_PASS_THROUGH_DIRECT));
    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER SPTDW;
    DWORD Size = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
    DWORD Returned;
    BOOL Status;
    int i, k, l;
    int chalpos[11];
    uint8_t restable[261];
    uint8_t hash[0x2C];
    uint8_t shadigest[20];
    uint8_t shastring[20];

    // --- STEP 1: INITIAL READ CAPACITY ---
    ZeroMemory(&SPTDW, sizeof(SPTDW));
    ZeroMemory(scsibuffer, sizeof(scsibuffer));
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.SenseInfoLength = 32;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 8; 
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x25;

    LogHexDump("Sending CDB [Step 1: Init Read Cap]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    
    if (Status) {
        LogHexDump("Received Data [Step 1: Init Read Cap]", scsibuffer, SPTDW.Spt.DataTransferLength);
        unsigned int maxLBA = (scsibuffer[0] << 24) |
                              (scsibuffer[1] << 16) | 
                              (scsibuffer[2] << 8)  | 
                               scsibuffer[3];
        printf("Initial Max LBA: %u\n", maxLBA);
        PrintFormattedCapacity(scsibuffer);
    } else {
        printf("Fatal error: Initial capacity read failed (Error %lu).\n", GetLastError());
        return FALSE;
    }

    // --- STEP 2: MODE SENSE (Page 0x3E) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x5A;
    SPTDW.Spt.Cdb[2] = 0x3E;
    SPTDW.Spt.Cdb[8] = 0x1C;
    
    LogHexDump("Sending CDB [Step 2: Mode Sense]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 2 MODE SENSE failed (Error %lu).\n", GetLastError());
        return FALSE;
    }
    LogHexDump("Received Data [Step 2: Mode Sense]", scsibuffer, SPTDW.Spt.DataTransferLength);

    // --- STEP 3: READ DVD STRUCTURE (The Challenge Table) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 12;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 0x664;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0xAD;
    SPTDW.Spt.Cdb[2] = 0xFF; SPTDW.Spt.Cdb[3] = 0x02; SPTDW.Spt.Cdb[4] = 0xFD;
    SPTDW.Spt.Cdb[5] = 0xFF; SPTDW.Spt.Cdb[6] = 0xFE; SPTDW.Spt.Cdb[8] = 0x06;
    SPTDW.Spt.Cdb[9] = 0x64; SPTDW.Spt.Cdb[11] = 0xC0;
    
    LogHexDump("Sending CDB [Step 3: Read DVD Struct 0xAD]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (Status) LogHexDump("Received Data [Step 3: Read DVD Struct 0xAD]", scsibuffer, SPTDW.Spt.DataTransferLength);

    // Fallback Logic for Hitachi 4241N Drives
    if (!Status || scsibuffer[772] != 1 || scsibuffer[773] == 0) {
        printf("8050L Table Invalid. Attempting Hitachi 0xFD Fallback...\n");
        memset(&SPTDW, 0, sizeof(SPTDW));
        memset(scsibuffer, 0, 2000);
        SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
        SPTDW.Spt.CdbLength = 12;
        SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
        SPTDW.Spt.DataTransferLength = 0x664;
        SPTDW.Spt.TimeOutValue = 120;
        SPTDW.Spt.DataBuffer = scsibuffer;
        SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
        
        SPTDW.Spt.Cdb[0] = 0xFD; 
        SPTDW.Spt.Cdb[1] = 0x01; 
        SPTDW.Spt.Cdb[8] = 0x06;
        SPTDW.Spt.Cdb[9] = 0x64;

        LogHexDump("Sending CDB [Step 3: Read DVD Struct Fallback 0xFD]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
        Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
        if (Status) LogHexDump("Received Data [Step 3: Read DVD Struct Fallback 0xFD]", scsibuffer, SPTDW.Spt.DataTransferLength);

        if (!Status || scsibuffer[772] != 1) {
            printf("Fatal error: Invalid host challenge table (Both methods failed).\n");
            return FALSE;
        }
        printf("Success: Acquired Hitachi 0xFD Handshake Table!\n");
    }

    // --- CRYPTO: SHA1 & RC4 ---
    for (i = 0; i < 0x2C; i++) hash[i] = scsibuffer[0x4A3 + i];
    {
        SHA1_CTX ctx;
        SHA1_Init(&ctx);
        SHA1_Update(&ctx, hash, 0x2C);
        SHA1_Final(shadigest, &ctx);
    }
    memcpy(shastring, shadigest, 7);
    RC4Init(&rc4key, shastring, 7);
    for (i = 0; i <= 260; i++) restable[i] = scsibuffer[774 + i];
    rc4Decrypt(restable, restable, 0xFD, &rc4key);

    k = 0;
    for (l = 0; l <= 23; l++) {
        if (restable[l * 11] == 1) {
            chalpos[k] = l;
            k++;
        }
    }

    if (k < 2) {
        printf("Fatal error: Not enough usable challenge entries.\n");
        return FALSE;
    }

    // --- STEP 4: MODE SELECT (First Challenge) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
    scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
    scsibuffer[9] = 0x12;
    scsibuffer[11] = 0x01; scsibuffer[13] = 0xD1; scsibuffer[14] = 0x01;
    memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 2] * 11], 5);
    
    LogHexDump("Sending CDB [Step 4: Mode Select Chal 1]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    LogHexDump("Sending Data [Step 4: Mode Select Chal 1]", scsibuffer, SPTDW.Spt.DataTransferLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 4 first challenge failed (Error %lu).\n", GetLastError());
        return FALSE;
    }

    // --- STEP 5: MODE SENSE (Verify First Challenge) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x5A; SPTDW.Spt.Cdb[2] = 0x3E; SPTDW.Spt.Cdb[8] = 0x1C;
    
    LogHexDump("Sending CDB [Step 5: Mode Sense Verify 1]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 5 first challenge verification failed (Error %lu).\n", GetLastError());
        return FALSE;
    }
    LogHexDump("Received Data [Step 5: Mode Sense Verify 1]", scsibuffer, SPTDW.Spt.DataTransferLength);
    
    // --- STEP 6: MODE SELECT (Second Challenge) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
    scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
    scsibuffer[9] = 0x12;
    scsibuffer[12] = 0x01; // Marker for second challenge
    memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 1] * 11], 5);
    
    LogHexDump("Sending CDB [Step 6: Mode Select Chal 2]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    LogHexDump("Sending Data [Step 6: Mode Select Chal 2]", scsibuffer, SPTDW.Spt.DataTransferLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 6 second challenge failed (Error %lu).\n", GetLastError());
        return FALSE;
    }

    // --- STEP 7: MODE SENSE (Verify Second Challenge) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x5A; SPTDW.Spt.Cdb[2] = 0x3E; SPTDW.Spt.Cdb[8] = 0x1C;
    
    LogHexDump("Sending CDB [Step 7: Mode Sense Verify 2]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 7 second challenge verification failed (Error %lu).\n", GetLastError());
        return FALSE;
    }
    LogHexDump("Received Data [Step 7: Mode Sense Verify 2]", scsibuffer, SPTDW.Spt.DataTransferLength);

    // --- STEP 8: FINAL MODE SELECT (Partition 1 Unlock) ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
    SPTDW.Spt.DataTransferLength = 28;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x55; SPTDW.Spt.Cdb[8] = 0x1C;
    scsibuffer[1] = 0x1A; scsibuffer[8] = 0x3E;
    scsibuffer[9] = 0x12;
    scsibuffer[10] = 0x01; scsibuffer[11] = 0x01; scsibuffer[12] = 0x01;
    scsibuffer[13] = 0xD1; scsibuffer[14] = 0x01;
    memcpy(&scsibuffer[15], &restable[1 + chalpos[k - 1] * 11], 5);
    
    LogHexDump("Sending CDB [Step 8: Mode Select Part1 Unlock]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    LogHexDump("Sending Data [Step 8: Mode Select Part1 Unlock]", scsibuffer, SPTDW.Spt.DataTransferLength);
    
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 8 partition unlock failed (Error %lu).\n", GetLastError());
        return FALSE;
    }
    printf("Partition 1 unlock command completed.\n");

    // --- STEP 9: ENABLE STICKY DESCRAMBLING (Mode 0x31) ---
    printf("Enabling Sticky Descrambling (Mode 0x31)...\n");
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    scsibuffer[4] = 0x31; scsibuffer[5] = 0x06; scsibuffer[6] = 0x01;
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 6;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
    SPTDW.Spt.DataTransferLength = 12;
    SPTDW.Spt.TimeOutValue = 10;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x15; 
    SPTDW.Spt.Cdb[1] = 0x11; 
    SPTDW.Spt.Cdb[4] = 12;
    
    LogHexDump("Sending CDB [Step 9: Sticky Descrambling]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    LogHexDump("Sending Data [Step 9: Sticky Descrambling]", scsibuffer, SPTDW.Spt.DataTransferLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    if (!Status) {
        printf("Fatal error: Step 9 sticky descrambling failed (Error %lu).\n", GetLastError());
        return FALSE;
    }

    // --- STEP 10: FINAL CAPACITY VERIFICATION ---
    memset(&SPTDW, 0, sizeof(SPTDW));
    memset(scsibuffer, 0, 2000);
    SPTDW.Spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    SPTDW.Spt.CdbLength = 10;
    SPTDW.Spt.DataIn = SCSI_IOCTL_DATA_IN;
    SPTDW.Spt.DataTransferLength = 8;
    SPTDW.Spt.TimeOutValue = 120;
    SPTDW.Spt.DataBuffer = scsibuffer;
    SPTDW.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
    SPTDW.Spt.Cdb[0] = 0x25;
    
    LogHexDump("Sending CDB [Step 10: Final Verify]", SPTDW.Spt.Cdb, SPTDW.Spt.CdbLength);
    Status = DeviceIoControl(AHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SPTDW, Size, &SPTDW, Size, &Returned, NULL);
    
    if (!Status) {
        printf("Fatal error: Step 10 final capacity verification failed (Error %lu).\n", GetLastError());
        return FALSE;
    }
    LogHexDump("Received Data [Step 10: Final Verify]", scsibuffer, SPTDW.Spt.DataTransferLength);
    PrintFormattedCapacity(scsibuffer);
    return TRUE;
}
