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