"Fossies" - the Fresh Open Source Software Archive

Member "src/Boot/Windows/BootMain.cpp" (10 Oct 2018, 31265 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "BootMain.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18_Source_vs_1.19_Source.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include "Crc.h"
   14 #include "Crypto.h"
   15 #include "Password.h"
   16 #include "Volumes.h"
   17 
   18 #include "Platform.h"
   19 #include "Bios.h"
   20 #include "BootConfig.h"
   21 #include "BootMain.h"
   22 #include "BootDefs.h"
   23 #include "BootCommon.h"
   24 #include "BootConsoleIo.h"
   25 #include "BootDebug.h"
   26 #include "BootDiskIo.h"
   27 #include "BootEncryptedIo.h"
   28 #include "BootMemory.h"
   29 #include "BootStrings.h"
   30 #include "IntFilter.h"
   31 
   32 
   33 static void InitScreen ()
   34 {
   35     ClearScreen();
   36 
   37     const char *title =
   38 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   39         " VeraCrypt Boot Loader "
   40 #else
   41         " VeraCrypt Rescue Disk "
   42 #endif
   43         VERSION_STRING "\r\n";
   44 
   45     Print (title);
   46 
   47     PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE);
   48 
   49 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   50     if (CustomUserMessage[0])
   51     {
   52         PrintEndl();
   53         Print (CustomUserMessage);
   54     }
   55 #endif
   56 
   57     PrintEndl (2);
   58 }
   59 
   60 
   61 static void PrintMainMenu ()
   62 {
   63     if (PreventBootMenu)
   64         return;
   65 
   66     Print ("    Keyboard Controls:\r\n");
   67     Print ("    [F5]   Hide/Show Password and PIM\r\n");
   68     Print ("    [Esc]  ");
   69 
   70 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   71 
   72     Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE
   73         ? "Boot Non-Hidden System (Boot Manager)"
   74         : "Skip Authentication (Boot Manager)");
   75 
   76 #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   77 
   78     Print ("Skip Authentication (Boot Manager)");
   79     Print ("\r\n    [F8]   "); Print ("Repair Options");
   80 
   81 #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   82 
   83     PrintEndl (3);
   84 }
   85 
   86 
   87 static bool IsMenuKey (byte scanCode)
   88 {
   89 #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
   90     return scanCode == TC_MENU_KEY_REPAIR;
   91 #else
   92     return false;
   93 #endif
   94 }
   95 
   96 
   97 static bool AskYesNo (const char *message)
   98 {
   99     Print (message);
  100     Print ("? (y/n): ");
  101     while (true)
  102     {
  103         switch (GetKeyboardChar())
  104         {
  105         case 'y':
  106         case 'Y':
  107         case 'z':
  108         case 'Z':
  109             Print ("y\r\n");
  110             return true;
  111 
  112         case 'n':
  113         case 'N':
  114             Print ("n\r\n");
  115             return false;
  116 
  117         default:
  118             Beep();
  119         }
  120     }
  121 }
  122 
  123 
  124 static int AskSelection (const char *options[], size_t optionCount)
  125 {
  126     for (int i = 0; i < optionCount; ++i)
  127     {
  128         Print ("["); Print (i + 1); Print ("]    ");
  129         Print (options[i]);
  130         PrintEndl();
  131     }
  132     Print ("[Esc]  Cancel\r\n\r\n");
  133 
  134     Print ("To select, press 1-9: ");
  135 
  136     char str;
  137 
  138     while (true)
  139     {
  140         if (GetString (&str, 1) == 0)
  141             return 0;
  142 
  143         if (str >= '1' && str <= optionCount + '0')
  144             return str - '0';
  145 
  146         Beep();
  147         PrintBackspace();
  148     }
  149 }
  150 
  151 
  152 static byte AskPassword (Password &password, int& pim)
  153 {
  154     size_t pos = 0;
  155     byte scanCode;
  156     byte asciiCode;
  157     byte hidePassword = 1;
  158 
  159     pim = 0;
  160 
  161     Print ("Enter password");
  162     Print (PreventNormalSystemBoot ? " for hidden system:\r\n" : ": ");
  163 
  164     while (true)
  165     {
  166         asciiCode = GetKeyboardChar (&scanCode);
  167 
  168         switch (scanCode)
  169         {
  170         case TC_BIOS_KEY_ENTER:
  171             password.Length = pos;
  172             Print ("\r");
  173             if (!PreventNormalSystemBoot)
  174                 Print ("Enter password: ");
  175             pos = 0;
  176             while (pos < MAX_PASSWORD)
  177             {
  178                 pos++;
  179                 if (pos < MAX_PASSWORD)
  180                     PrintChar ('*');
  181                 else
  182                     PrintCharAtCursor ('*');
  183             }
  184 
  185             ClearBiosKeystrokeBuffer();
  186             PrintEndl();
  187 
  188             break;
  189 
  190         case TC_BIOS_KEY_BACKSPACE:
  191             if (pos > 0)
  192             {
  193                 if (pos < MAX_PASSWORD)
  194                     PrintBackspace();
  195                 else
  196                     PrintCharAtCursor (' ');
  197 
  198                 --pos;
  199             }
  200             continue;
  201 
  202         case TC_BIOS_KEY_F5:
  203             hidePassword ^= 0x01;
  204             continue;
  205 
  206         default:
  207             if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
  208             {
  209                 burn (password.Text, sizeof (password.Text));
  210                 ClearBiosKeystrokeBuffer();
  211 
  212                 PrintEndl();
  213                 return scanCode;
  214             }
  215         }
  216 
  217         if (TC_BIOS_KEY_ENTER == scanCode)
  218             break;
  219 
  220         if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
  221         {
  222             Beep();
  223             continue;
  224         }
  225 
  226         password.Text[pos++] = asciiCode;
  227         if (hidePassword) asciiCode = '*';
  228         if (pos < MAX_PASSWORD)
  229             PrintChar (asciiCode);
  230         else
  231             PrintCharAtCursor (asciiCode);
  232     }
  233 
  234 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  235     if (PimValueOrHiddenVolumeStartUnitNo.LowPart != -1)
  236     {
  237         pim = (int) PimValueOrHiddenVolumeStartUnitNo.LowPart;
  238         // reset stored PIM value to allow requesting PIM next time in case the stored value is wrong
  239         PimValueOrHiddenVolumeStartUnitNo.LowPart = -1;
  240         return TC_BIOS_KEY_ENTER;
  241     }
  242     else
  243 #endif
  244     {
  245         pos = 0;
  246         Print ("PIM: ");
  247 
  248         while (true)
  249         {
  250             asciiCode = GetKeyboardChar (&scanCode);
  251 
  252             switch (scanCode)
  253             {
  254             case TC_BIOS_KEY_ENTER:
  255                 Print ("\rPIM: ");
  256                 pos =0;
  257                 while (pos < MAX_PIM)
  258                 {
  259                     PrintChar ('*');
  260                     pos++;
  261                 }
  262 
  263                 ClearBiosKeystrokeBuffer();
  264                 PrintEndl();
  265 
  266                 return TC_BIOS_KEY_ENTER;
  267 
  268             case TC_BIOS_KEY_BACKSPACE:
  269                 if (pos > 0)
  270                 {
  271                     if (pos < MAX_PIM)
  272                         PrintBackspace();
  273                     else
  274                         PrintCharAtCursor (' ');
  275 
  276                     --pos;
  277                     pim /= 10;
  278                 }
  279                 continue;
  280 
  281             case TC_BIOS_KEY_F5:
  282                 hidePassword ^= 0x01;
  283                 continue;
  284 
  285             default:
  286                 if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
  287                 {
  288                     burn (password.Text, sizeof (password.Text));
  289                     ClearBiosKeystrokeBuffer();
  290 
  291                     PrintEndl();
  292                     return scanCode;
  293                 }
  294             }
  295 
  296             if (!IsDigit (asciiCode) || pos == MAX_PIM)
  297             {
  298                 Beep();
  299                 continue;
  300             }
  301 
  302             pim = 10*pim + (asciiCode - '0');
  303             pos++;
  304 
  305             if (hidePassword) asciiCode = '*';
  306             if (pos < MAX_PIM)
  307                 PrintChar (asciiCode);
  308             else
  309                 PrintCharAtCursor (asciiCode);
  310         }
  311     }
  312 }
  313 
  314 
  315 static void ExecuteBootSector (byte drive, byte *sectorBuffer)
  316 {
  317     Print ("Booting...\r\n");
  318     CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
  319 
  320     BootStarted = true;
  321 
  322     uint32 addr = 0x7c00;
  323     __asm
  324     {
  325         cli
  326         mov dl, drive   // Boot drive
  327         mov dh, 0
  328         xor ax, ax
  329         mov si, ax
  330         mov ds, ax
  331         mov es, ax
  332         mov ss, ax
  333         mov sp, 0x7c00
  334         sti
  335 
  336         jmp cs:addr
  337     }
  338 }
  339 
  340 
  341 static bool OpenVolume (byte drive, Password &password, int pim, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32, bool skipNormal, bool skipHidden)
  342 {
  343     int volumeType;
  344     bool hiddenVolume;
  345     uint64 headerSec;
  346 
  347     AcquireSectorBuffer();
  348 
  349     for (volumeType = 1; volumeType <= 2; ++volumeType)
  350     {
  351         hiddenVolume = (volumeType == 2);
  352 
  353         if (hiddenVolume)
  354         {
  355             if (skipHidden || PartitionFollowingActive.Drive != drive || PartitionFollowingActive.SectorCount <= ActivePartition.SectorCount)
  356                 continue;
  357 
  358             headerSec = PartitionFollowingActive.StartSector + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE;
  359         }
  360         else
  361         {
  362             if (skipNormal)
  363                 continue;
  364 
  365             headerSec.HighPart = 0;
  366             headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
  367         }
  368 
  369         if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess)
  370             continue;
  371 
  372         if (ReadVolumeHeader (!hiddenVolume, (char *) SectorBuffer, &password, pim, cryptoInfo, nullptr) == ERR_SUCCESS)
  373         {
  374             // Prevent opening a non-system hidden volume
  375             if (hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM))
  376             {
  377                 crypto_close (*cryptoInfo);
  378                 continue;
  379             }
  380 
  381             if (headerSaltCrc32)
  382                 *headerSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE);
  383 
  384             break;
  385         }
  386     }
  387 
  388     ReleaseSectorBuffer();
  389     return volumeType != 3;
  390 }
  391 
  392 
  393 static bool CheckMemoryRequirements ()
  394 {
  395     uint16 codeSeg;
  396     __asm mov codeSeg, cs
  397     if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
  398     {
  399         PrintErrorNoEndl ("BIOS reserved too much memory: ");
  400 
  401         uint16 memFree;
  402         __asm
  403         {
  404             push es
  405             xor ax, ax
  406             mov es, ax
  407             mov ax, es:[0x413]
  408             mov memFree, ax
  409             pop es
  410         }
  411 
  412         Print (memFree);
  413         PrintEndl();
  414         Print (TC_BOOT_STR_UPGRADE_BIOS);
  415 
  416         return false;
  417     }
  418 
  419     return true;
  420 }
  421 
  422 
  423 static bool MountVolume (byte drive, byte &exitKey, bool skipNormal, bool skipHidden)
  424 {
  425     BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
  426     int incorrectPasswordCount = 0, pim = 0;
  427 
  428     EraseMemory (bootArguments, sizeof (*bootArguments));
  429 
  430     // Open volume header
  431     while (true)
  432     {
  433         exitKey = AskPassword (bootArguments->BootPassword, pim);
  434 
  435         if (exitKey != TC_BIOS_KEY_ENTER)
  436             return false;
  437 
  438         Print ("Verifying password...");
  439 
  440         if (OpenVolume (BootDrive, bootArguments->BootPassword, pim, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32, skipNormal, skipHidden))
  441         {
  442             Print ("OK\r\n");
  443             break;
  444         }
  445         if (GetShiftFlags() & TC_BIOS_SHIFTMASK_CAPSLOCK)
  446             Print ("Warning: Caps Lock is on.\r\n");
  447 
  448         Print ("Incorrect password.\r\n\r\n");
  449 
  450         if (++incorrectPasswordCount == 4)
  451         {
  452 #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  453             Print ("If you are sure the password is correct, the key data may be damaged.\r\n"
  454                    "If so, use 'Repair Options' > 'Restore key data'.\r\n\r\n");
  455 #else
  456             Print ("If you are sure the password is correct, the key data may be damaged. Boot your\r\n"
  457                    "VeraCrypt Rescue Disk and select 'Repair Options' > 'Restore key data'.\r\n\r\n");
  458 #endif
  459         }
  460     }
  461 
  462     // Setup boot arguments
  463     bootArguments->BootLoaderVersion = VERSION_NUM;
  464     bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo;
  465     bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo);
  466     bootArguments->Flags = (((uint32)pim) << 16);
  467 
  468     if (BootCryptoInfo->hiddenVolume)
  469         bootArguments->HiddenSystemPartitionStart = PartitionFollowingActive.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
  470 
  471     if (ExtraBootPartitionPresent)
  472         bootArguments->Flags |= TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION;
  473 
  474     TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature);
  475 
  476     // Setup virtual encrypted partition
  477     if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
  478     {
  479         EncryptedVirtualPartition.Drive = BootDrive;
  480 
  481         EncryptedVirtualPartition.StartSector = BootCryptoInfo->EncryptedAreaStart >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
  482 
  483         PimValueOrHiddenVolumeStartUnitNo = EncryptedVirtualPartition.StartSector;
  484         HiddenVolumeStartSector = PartitionFollowingActive.StartSector;
  485         HiddenVolumeStartSector += EncryptedVirtualPartition.StartSector;
  486 
  487         EncryptedVirtualPartition.SectorCount = BootCryptoInfo->EncryptedAreaLength >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
  488 
  489         EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.SectorCount - 1;
  490         EncryptedVirtualPartition.EndSector += EncryptedVirtualPartition.StartSector;
  491     }
  492     else
  493     {
  494         // Drive not encrypted
  495         EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
  496     }
  497 
  498     return true;
  499 }
  500 
  501 
  502 static bool GetSystemPartitions (byte drive)
  503 {
  504     size_t partCount;
  505 
  506     if (!GetActivePartition (drive))
  507         return false;
  508 
  509     // Find partition following the active one
  510     GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
  511 
  512     // If there is an extra boot partition, use the partitions following it.
  513     // The real boot partition is determined in BootEncryptedDrive().
  514     if (ActivePartition.SectorCount.HighPart == 0 && ActivePartition.SectorCount.LowPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE / TC_LB_SIZE
  515         && PartitionFollowingActive.Drive != TC_INVALID_BIOS_DRIVE)
  516     {
  517         ExtraBootPartitionPresent = true;
  518 
  519         ActivePartition = PartitionFollowingActive;
  520         GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
  521     }
  522 
  523     return true;
  524 }
  525 
  526 
  527 static byte BootEncryptedDrive ()
  528 {
  529     BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
  530     byte exitKey;
  531     BootCryptoInfo = NULL;
  532 
  533     if (!GetSystemPartitions (BootDrive))
  534         goto err;
  535 
  536     if (!MountVolume (BootDrive, exitKey, PreventNormalSystemBoot, false))
  537         return exitKey;
  538 
  539     if (!CheckMemoryRequirements ())
  540         goto err;
  541 
  542     if (BootCryptoInfo->hiddenVolume)
  543     {
  544         EncryptedVirtualPartition = ActivePartition;
  545         bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
  546     }
  547 
  548     if (ExtraBootPartitionPresent && !GetActivePartition (BootDrive))
  549         goto err;
  550 
  551     if (ReadWriteMBR (false, ActivePartition.Drive) != BiosResultSuccess)
  552         goto err;
  553 
  554     bootArguments->BootDriveSignature = *(uint32 *) (SectorBuffer + 0x1b8);
  555 
  556     if (!InstallInterruptFilters())
  557         goto err;
  558 
  559     bootArguments->BootArgumentsCrc32 = GetCrc32 ((byte *) bootArguments, (byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments);
  560 
  561     while (true)
  562     {
  563         // Execute boot sector of the active partition
  564         if (ReadSectors (SectorBuffer, ActivePartition.Drive, ActivePartition.StartSector, 1) == BiosResultSuccess)
  565         {
  566             if (*(uint16 *) (SectorBuffer + 510) != 0xaa55)
  567             {
  568                 PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
  569                 GetKeyboardChar();
  570             }
  571 
  572             ExecuteBootSector (ActivePartition.Drive, SectorBuffer);
  573         }
  574 
  575         GetKeyboardChar();
  576     }
  577 
  578 err:
  579     if (BootCryptoInfo)
  580     {
  581         crypto_close (BootCryptoInfo);
  582         BootCryptoInfo = NULL;
  583     }
  584 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  585     PimValueOrHiddenVolumeStartUnitNo.LowPart = -1;
  586 #endif
  587     EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
  588     EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
  589 
  590     byte scanCode;
  591     GetKeyboardChar (&scanCode);
  592     return scanCode;
  593 }
  594 
  595 
  596 static void BootMenu ()
  597 {
  598     BiosResult result;
  599     Partition partitions[16];
  600     Partition bootablePartitions[9];
  601     size_t partitionCount;
  602     size_t bootablePartitionCount = 0;
  603 
  604     for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
  605     {
  606         if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, nullptr, true) == BiosResultSuccess)
  607         {
  608             for (size_t i = 0; i < partitionCount; ++i)
  609             {
  610                 const Partition &partition = partitions[i];
  611                 result = ReadSectors (SectorBuffer, drive, partition.StartSector, 1);
  612 
  613                 if (result == BiosResultSuccess && *(uint16 *) (SectorBuffer + TC_LB_SIZE - 2) == 0xaa55)
  614                 {
  615                     // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
  616                     // NTFS/FAT partitions must have the boot indicator set to be considered bootable.
  617                     if (!partition.Active
  618                         && (*(uint32 *) (SectorBuffer + 3) == 0x5346544e  // 'NTFS'
  619                             || *(uint32 *) (SectorBuffer + 3) == 0x41465845 && SectorBuffer[7] == 'T' // 'exFAT'
  620                             || *(uint16 *) (SectorBuffer + 54) == 0x4146 && SectorBuffer[56] == 'T' // 'FAT'
  621                             || *(uint16 *) (SectorBuffer + 82) == 0x4146 && SectorBuffer[84] == 'T'))
  622                     {
  623                         continue;
  624                     }
  625 
  626                     // Bootable sector found
  627                     if (bootablePartitionCount < array_capacity (bootablePartitions))
  628                         bootablePartitions[bootablePartitionCount++] = partition;
  629                 }
  630             }
  631         }
  632     }
  633 
  634     if (bootablePartitionCount < 1)
  635     {
  636         PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
  637         GetKeyboardChar();
  638         return;
  639     }
  640 
  641     char partChar;
  642     while (true)
  643     {
  644         InitScreen();
  645         Print ("Bootable Partitions:\r\n");
  646         PrintRepeatedChar ('\xC4', 20);
  647         Print ("\r\n");
  648 
  649         for (size_t i = 0; i < bootablePartitionCount; ++i)
  650         {
  651             const Partition &partition = bootablePartitions[i];
  652             Print ("["); Print (i + 1); Print ("]    ");
  653             Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
  654             Print (", Partition: "); Print (partition.Number + 1);
  655             Print (", Size: "); PrintSectorCountInMB (partition.SectorCount); PrintEndl();
  656         }
  657 
  658         if (bootablePartitionCount == 1)
  659         {
  660             // There's only one bootable partition so we'll boot it directly instead of showing boot manager
  661             partChar = '1';
  662         }
  663         else
  664         {
  665             Print ("[Esc]  Cancel\r\n\r\n");
  666             Print ("Press 1-9 to select partition: ");
  667 
  668             if (GetString (&partChar, 1) == 0)
  669                 return;
  670 
  671             PrintEndl();
  672 
  673             if (partChar < '1' || partChar > '0' + bootablePartitionCount)
  674             {
  675                 Beep();
  676                 continue;
  677             }
  678         }
  679 
  680         const Partition &partition = bootablePartitions[partChar - '0' - 1];
  681 
  682         if (ReadSectors (SectorBuffer, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
  683         {
  684             ExecuteBootSector (partition.Drive, SectorBuffer);
  685         }
  686     }
  687 }
  688 
  689 
  690 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  691 
  692 static bool CopySystemPartitionToHiddenVolume (byte drive, byte &exitKey)
  693 {
  694     bool status = false;
  695 
  696     uint64 sectorsRemaining;
  697     uint64 sectorOffset;
  698     sectorOffset.LowPart = 0;
  699     sectorOffset.HighPart = 0;
  700 
  701     int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
  702     int statCount = 0;
  703 
  704     if (!CheckMemoryRequirements ())
  705         goto err;
  706 
  707     if (!GetSystemPartitions (drive))
  708         goto err;
  709 
  710     if (PartitionFollowingActive.Drive == TC_INVALID_BIOS_DRIVE)
  711         TC_THROW_FATAL_EXCEPTION;
  712 
  713     // Check if BIOS can read the last sector of the hidden system
  714     AcquireSectorBuffer();
  715 
  716     if (ReadSectors (SectorBuffer, PartitionFollowingActive.Drive, PartitionFollowingActive.EndSector - (TC_VOLUME_HEADER_GROUP_SIZE / TC_LB_SIZE - 2), 1) != BiosResultSuccess
  717         || GetCrc32 (SectorBuffer, sizeof (SectorBuffer)) != OuterVolumeBackupHeaderCrc)
  718     {
  719         PrintErrorNoEndl ("Your BIOS does not support large drives");
  720         Print (IsLbaSupported (PartitionFollowingActive.Drive) ? " due to a bug" : "\r\n- Enable LBA in BIOS");
  721         PrintEndl();
  722         Print (TC_BOOT_STR_UPGRADE_BIOS);
  723 
  724         ReleaseSectorBuffer();
  725         goto err;
  726     }
  727 
  728     ReleaseSectorBuffer();
  729 
  730     if (!MountVolume (drive, exitKey, true, false))
  731         return false;
  732 
  733     sectorsRemaining = EncryptedVirtualPartition.SectorCount;
  734 
  735     if (!(sectorsRemaining == ActivePartition.SectorCount))
  736         TC_THROW_FATAL_EXCEPTION;
  737 
  738     InitScreen();
  739     Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
  740 
  741     while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
  742     {
  743         if (EscKeyPressed())
  744         {
  745             Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
  746             if (AskYesNo ("Abort"))
  747                 break;
  748         }
  749 
  750         if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
  751             fragmentSectorCount = (int) sectorsRemaining.LowPart;
  752 
  753         if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
  754         {
  755             Print ("To fix bad sectors: 1) Terminate 2) Encrypt and decrypt sys partition 3) Retry\r\n");
  756             crypto_close (BootCryptoInfo);
  757             goto err;
  758         }
  759 
  760         AcquireSectorBuffer();
  761 
  762         for (int i = 0; i < fragmentSectorCount; ++i)
  763         {
  764             CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
  765 
  766             uint64 s = PimValueOrHiddenVolumeStartUnitNo + sectorOffset + i;
  767             EncryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
  768 
  769             CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
  770         }
  771 
  772         ReleaseSectorBuffer();
  773 
  774         if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
  775         {
  776             crypto_close (BootCryptoInfo);
  777             goto err;
  778         }
  779 
  780         sectorsRemaining = sectorsRemaining - fragmentSectorCount;
  781         sectorOffset = sectorOffset + fragmentSectorCount;
  782 
  783         if (!(statCount++ & 0xf))
  784         {
  785             Print ("\rRemaining: ");
  786             PrintSectorCountInMB (sectorsRemaining);
  787         }
  788     }
  789 
  790     crypto_close (BootCryptoInfo);
  791 
  792     if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
  793     {
  794         status = true;
  795         Print ("\rCopying completed.");
  796     }
  797 
  798     PrintEndl (2);
  799     goto ret;
  800 
  801 err:
  802     exitKey = TC_BIOS_KEY_ESC;
  803     GetKeyboardChar();
  804 
  805 ret:
  806     PimValueOrHiddenVolumeStartUnitNo.LowPart = -1;
  807     EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
  808     return status;
  809 }
  810 
  811 
  812 #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  813 
  814 
  815 static void DecryptDrive (byte drive)
  816 {
  817     byte exitKey;
  818     if (!MountVolume (drive, exitKey, false, true))
  819         return;
  820 
  821     BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
  822 
  823     bool headerUpdateRequired = false;
  824     uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
  825     uint64 sector = EncryptedVirtualPartition.EndSector + 1;
  826 
  827     int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
  828     int statCount = 0;
  829 
  830     bool skipBadSectors = false;
  831 
  832     Print ("\r\nUse only if Windows cannot start. Decryption under Windows is much faster\r\n"
  833             "(in VeraCrypt, select 'System' > 'Permanently Decrypt').\r\n\r\n");
  834 
  835     if (!AskYesNo ("Decrypt now"))
  836     {
  837         crypto_close (BootCryptoInfo);
  838         goto ret;
  839     }
  840 
  841     if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
  842     {
  843         // Drive already decrypted
  844         sectorsRemaining.HighPart = 0;
  845         sectorsRemaining.LowPart = 0;
  846     }
  847     else
  848     {
  849         Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
  850             "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
  851     }
  852 
  853     while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
  854     {
  855         if (EscKeyPressed())
  856             break;
  857 
  858         if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
  859             fragmentSectorCount = (int) sectorsRemaining.LowPart;
  860 
  861         sector = sector - fragmentSectorCount;
  862 
  863         if (!(statCount++ & 0xf))
  864         {
  865             Print ("\rRemaining: ");
  866             PrintSectorCountInMB (sectorsRemaining);
  867         }
  868 
  869         if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
  870         {
  871             AcquireSectorBuffer();
  872 
  873             for (int i = 0; i < fragmentSectorCount; ++i)
  874             {
  875                 CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
  876 
  877                 uint64 s = sector + i;
  878                 DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
  879 
  880                 CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
  881             }
  882 
  883             ReleaseSectorBuffer();
  884 
  885             if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
  886                 goto askBadSectorSkip;
  887         }
  888         else if (!skipBadSectors)
  889             goto askBadSectorSkip;
  890 
  891         sectorsRemaining = sectorsRemaining - fragmentSectorCount;
  892         headerUpdateRequired = true;
  893         continue;
  894 
  895 askBadSectorSkip:
  896         if (!AskYesNo ("Skip all bad sectors"))
  897             break;
  898 
  899         skipBadSectors = true;
  900         sector = sector + fragmentSectorCount;
  901         fragmentSectorCount = 1;
  902     }
  903 
  904     crypto_close (BootCryptoInfo);
  905 
  906     if (headerUpdateRequired)
  907     {
  908         Print ("\rUpdating header...");
  909 
  910         AcquireSectorBuffer();
  911         uint64 headerSector;
  912         headerSector.HighPart = 0;
  913         headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
  914 
  915         // Update encrypted area size in volume header
  916 
  917         CRYPTO_INFO *headerCryptoInfo = crypto_open();
  918         while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
  919 
  920         if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, (int) (bootArguments->Flags >> 16), NULL, headerCryptoInfo) == 0)
  921         {
  922             DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
  923 
  924             uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
  925 
  926             for (int i = 7; i >= 0; --i)
  927             {
  928                 SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
  929                 encryptedAreaLength = encryptedAreaLength >> 8;
  930             }
  931 
  932             uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
  933 
  934             for (i = 3; i >= 0; --i)
  935             {
  936                 SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
  937                 headerCrc32 >>= 8;
  938             }
  939 
  940             EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
  941         }
  942 
  943         crypto_close (headerCryptoInfo);
  944 
  945         while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
  946         ReleaseSectorBuffer();
  947 
  948         Print ("Done!\r\n");
  949     }
  950 
  951     if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
  952         Print ("\rDrive decrypted.\r\n");
  953     else
  954         Print ("\r\nDecryption deferred.\r\n");
  955 
  956     GetKeyboardChar();
  957 ret:
  958     EraseMemory (bootArguments, sizeof (*bootArguments));
  959 }
  960 
  961 
  962 static void RepairMenu ()
  963 {
  964     DriveGeometry bootLoaderDriveGeometry;
  965 
  966     if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry, true) != BiosResultSuccess)
  967     {
  968         // Some BIOSes may fail to get the geometry of an emulated floppy drive
  969         bootLoaderDriveGeometry.Cylinders = 80;
  970         bootLoaderDriveGeometry.Heads = 2;
  971         bootLoaderDriveGeometry.Sectors = 18;
  972     }
  973 
  974     while (true)
  975     {
  976         InitScreen();
  977         Print ("Available "); Print ("Repair Options"); Print (":\r\n");
  978         PrintRepeatedChar ('\xC4', 25);
  979         PrintEndl();
  980 
  981         enum
  982         {
  983             RestoreNone = 0,
  984             DecryptVolume,
  985             RestoreTrueCryptLoader,
  986             RestoreVolumeHeader,
  987             RestoreOriginalSystemLoader
  988         };
  989 
  990         static const char *options[] = { "Permanently decrypt system partition/drive", "Restore VeraCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
  991 
  992         int selection = AskSelection (options,
  993             (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
  994 
  995         PrintEndl();
  996 
  997         switch (selection)
  998         {
  999             case RestoreNone:
 1000                 return;
 1001 
 1002             case DecryptVolume:
 1003                 DecryptDrive (BootDrive);
 1004                 continue;
 1005 
 1006             case RestoreOriginalSystemLoader:
 1007                 if (!AskYesNo ("Is the system partition/drive decrypted"))
 1008                 {
 1009                     Print ("Please decrypt it first.\r\n");
 1010                     GetKeyboardChar();
 1011                     continue;
 1012                 }
 1013                 break;
 1014         }
 1015 
 1016         bool writeConfirmed = false;
 1017         BiosResult result;
 1018 
 1019         uint64 sector;
 1020         sector.HighPart = 0;
 1021         ChsAddress chs;
 1022 
 1023         byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
 1024         AcquireSectorBuffer();
 1025 
 1026         for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
 1027             i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
 1028         {
 1029             sector.LowPart = i;
 1030 
 1031             if (selection == RestoreOriginalSystemLoader)
 1032                 sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
 1033             else if (selection == RestoreTrueCryptLoader)
 1034                 sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
 1035 
 1036             // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
 1037             // Therefore, only CHS addressing can be used.
 1038             LbaToChs (bootLoaderDriveGeometry, sector, chs);
 1039             sector.LowPart = i;
 1040 
 1041             if (i == TC_MBR_SECTOR)
 1042             {
 1043                 // Read current partition table
 1044                 result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
 1045                 if (result != BiosResultSuccess)
 1046                     goto err;
 1047 
 1048                 memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
 1049             }
 1050 
 1051             result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
 1052             if (result != BiosResultSuccess)
 1053                 goto err;
 1054 
 1055             if (i == TC_MBR_SECTOR)
 1056             {
 1057                 // Preserve current partition table
 1058                 memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
 1059             }
 1060 
 1061             // Volume header
 1062             if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
 1063             {
 1064                 if (selection == RestoreTrueCryptLoader)
 1065                     continue;
 1066 
 1067                 if (selection == RestoreVolumeHeader)
 1068                 {
 1069                     while (true)
 1070                     {
 1071                         bool validHeaderPresent = false;
 1072                         uint32 masterKeyScheduleCrc;
 1073 
 1074                         Password password;
 1075                         int pim;
 1076                         byte exitKey = AskPassword (password, pim);
 1077 
 1078                         if (exitKey != TC_BIOS_KEY_ENTER)
 1079                             goto abort;
 1080 
 1081                         CRYPTO_INFO *cryptoInfo;
 1082 
 1083                         CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
 1084                         ReleaseSectorBuffer();
 1085 
 1086                         // Restore volume header only if the current one cannot be used
 1087                         if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, pim, &cryptoInfo, nullptr, false, true))
 1088                         {
 1089                             validHeaderPresent = true;
 1090                             masterKeyScheduleCrc = GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks));
 1091                             crypto_close (cryptoInfo);
 1092                         }
 1093 
 1094                         AcquireSectorBuffer();
 1095                         CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
 1096 
 1097                         if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &password, pim, &cryptoInfo, nullptr) == 0)
 1098                         {
 1099                             if (validHeaderPresent)
 1100                             {
 1101                                 if (masterKeyScheduleCrc == GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks)))
 1102                                 {
 1103                                     Print ("Original header preserved.\r\n");
 1104                                     goto err;
 1105                                 }
 1106 
 1107                                 Print ("WARNING: Drive 0 contains a valid header!\r\n");
 1108                             }
 1109 
 1110                             crypto_close (cryptoInfo);
 1111                             break;
 1112                         }
 1113 
 1114                         Print ("Incorrect password.\r\n\r\n");
 1115                     }
 1116                 }
 1117             }
 1118 
 1119             if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
 1120                 goto abort;
 1121             writeConfirmed = true;
 1122 
 1123             if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
 1124                 goto err;
 1125         }
 1126 done:
 1127         switch (selection)
 1128         {
 1129         case RestoreTrueCryptLoader:
 1130             Print ("VeraCrypt Boot Loader");
 1131             break;
 1132 
 1133         case RestoreVolumeHeader:
 1134             Print ("Header");
 1135             break;
 1136 
 1137         case RestoreOriginalSystemLoader:
 1138             Print ("System loader");
 1139             break;
 1140         }
 1141         Print (" restored.\r\n");
 1142 
 1143 err:    GetKeyboardChar();
 1144 abort:  ReleaseSectorBuffer();
 1145     }
 1146 }
 1147 
 1148 #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1149 
 1150 
 1151 #ifndef DEBUG
 1152 extern "C" void _acrtused () { }  // Required by linker
 1153 #endif
 1154 
 1155 
 1156 void main ()
 1157 {
 1158     __asm mov BootLoaderDrive, dl
 1159     __asm mov BootSectorFlags, dh
 1160 
 1161 #ifdef TC_BOOT_TRACING_ENABLED
 1162     InitDebugPort();
 1163 #endif
 1164 
 1165 #ifdef TC_BOOT_STACK_CHECKING_ENABLED
 1166     InitStackChecker();
 1167 #endif
 1168 
 1169 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1170     ReadBootSectorUserConfiguration();
 1171 #elif defined (TC_WINDOWS_BOOT_AES)
 1172     EnableHwEncryption (!(BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION));
 1173 #endif
 1174 
 1175     InitVideoMode();
 1176     InitScreen();
 1177 
 1178     // Determine boot drive
 1179     BootDrive = BootLoaderDrive;
 1180     if (BootDrive < TC_FIRST_BIOS_DRIVE)
 1181         BootDrive = TC_FIRST_BIOS_DRIVE;
 1182 
 1183     // Query boot drive geometry
 1184     if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess)
 1185     {
 1186         BootDrive = TC_FIRST_BIOS_DRIVE;
 1187         if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess)
 1188         {
 1189 #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1190             Print ("- Connect system drive to (SATA) port 1\r\n");
 1191 #endif
 1192             GetKeyboardChar();
 1193         }
 1194         else
 1195             BootDriveGeometryValid = true;
 1196     }
 1197     else
 1198         BootDriveGeometryValid = true;
 1199 
 1200 #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1201 
 1202     // Check whether the user is not using the Rescue Disk to create a hidden system
 1203 
 1204     if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
 1205         && *(uint32 *) (SectorBuffer + 6) == 0x61726556
 1206         && *(uint32 *) (SectorBuffer + 10) == 0x70797243
 1207         && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
 1208     {
 1209         PrintError ("It appears you are creating a hidden OS.");
 1210         if (AskYesNo ("Is this correct"))
 1211         {
 1212             Print ("Please remove the Rescue Disk from the drive and restart.");
 1213             while (true);
 1214         }
 1215     }
 1216 
 1217 #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1218 
 1219 
 1220     // Main menu
 1221 
 1222     while (true)
 1223     {
 1224         byte exitKey;
 1225         InitScreen();
 1226 
 1227 #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1228 
 1229         // Hidden system setup
 1230         byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
 1231 
 1232         if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
 1233         {
 1234             PreventNormalSystemBoot = true;
 1235             PrintMainMenu();
 1236 
 1237             if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
 1238             {
 1239                 if (CopySystemPartitionToHiddenVolume (BootDrive, exitKey))
 1240                 {
 1241                     BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_WIPING;
 1242                     UpdateBootSectorConfiguration (BootLoaderDrive);
 1243                 }
 1244                 else if (exitKey == TC_BIOS_KEY_ESC)
 1245                     goto bootMenu;
 1246                 else
 1247                     continue;
 1248             }
 1249         }
 1250         else
 1251             PrintMainMenu();
 1252 
 1253         exitKey = BootEncryptedDrive();
 1254 
 1255 #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1256 
 1257         PrintMainMenu();
 1258         exitKey = BootEncryptedDrive();
 1259 
 1260         if (exitKey == TC_MENU_KEY_REPAIR)
 1261         {
 1262             RepairMenu();
 1263             continue;
 1264         }
 1265 
 1266 #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
 1267 
 1268 bootMenu:
 1269         if (!PreventBootMenu)
 1270             BootMenu();
 1271     }
 1272 }