📄 bootencryption.cpp
字号:
BootEncryptionStatus BootEncryption::GetStatus ()
{
/* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */
BootEncryptionStatus status;
CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS, NULL, 0, &status, sizeof (status));
return status;
}
void BootEncryption::GetVolumeProperties (VOLUME_PROPERTIES_STRUCT *properties)
{
if (properties == NULL)
throw ParameterIncorrect (SRC_POS);
CallDriver (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES, NULL, 0, properties, sizeof (*properties));
}
bool BootEncryption::SystemDriveContainsPartitionType (byte type)
{
Device device (GetSystemDriveConfiguration().DevicePath, true);
byte mbrBuf[SECTOR_SIZE];
device.SeekAt (0);
device.Read (mbrBuf, sizeof (mbrBuf));
MBR *mbr = reinterpret_cast <MBR *> (mbrBuf);
if (mbr->Signature != 0xaa55)
throw ParameterIncorrect (SRC_POS);
for (size_t i = 0; i < array_capacity (mbr->Partitions); ++i)
{
if (mbr->Partitions[i].Type == type)
return true;
}
return false;
}
bool BootEncryption::SystemDriveContainsExtendedPartition ()
{
return SystemDriveContainsPartitionType (PARTITION_EXTENDED) || SystemDriveContainsPartitionType (PARTITION_XINT13_EXTENDED);
}
bool BootEncryption::SystemDriveIsDynamic ()
{
return SystemDriveContainsPartitionType (PARTITION_LDM);
}
SystemDriveConfiguration BootEncryption::GetSystemDriveConfiguration ()
{
if (DriveConfigValid)
return DriveConfig;
SystemDriveConfiguration config;
string winDir = GetWindowsDirectory();
// Scan all drives
for (int driveNumber = 0; driveNumber < 32; ++driveNumber)
{
bool windowsFound = false;
config.SystemLoaderPresent = false;
PartitionList partitions = GetDrivePartitions (driveNumber);
foreach (const Partition &part, partitions)
{
if (_access ((part.MountPoint + "\\bootmgr").c_str(), 0) == 0 || _access ((part.MountPoint + "\\ntldr").c_str(), 0) == 0)
config.SystemLoaderPresent = true;
if (!windowsFound && !part.MountPoint.empty() && winDir.find (part.MountPoint) == 0)
{
config.SystemPartition = part;
windowsFound = true;
}
}
if (windowsFound)
{
config.DriveNumber = driveNumber;
stringstream ss;
ss << "PhysicalDrive" << driveNumber;
config.DevicePath = ss.str();
config.DrivePartition = partitions.front();
partitions.pop_front();
config.Partitions = partitions;
config.InitialUnallocatedSpace = 0x7fffFFFFffffFFFFull;
config.TotalUnallocatedSpace = config.DrivePartition.Info.PartitionLength.QuadPart;
foreach (const Partition &part, config.Partitions)
{
if (part.Info.StartingOffset.QuadPart < config.InitialUnallocatedSpace)
config.InitialUnallocatedSpace = part.Info.StartingOffset.QuadPart;
config.TotalUnallocatedSpace -= part.Info.PartitionLength.QuadPart;
}
DriveConfig = config;
DriveConfigValid = TRUE;
return DriveConfig;
}
}
throw ParameterIncorrect (SRC_POS);
}
bool BootEncryption::SystemPartitionCoversWholeDrive ()
{
SystemDriveConfiguration config = GetSystemDriveConfiguration();
return config.Partitions.size() == 1
&& config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 64 * BYTES_PER_MB;
}
uint32 BootEncryption::GetChecksum (byte *data, size_t size)
{
uint32 sum = 0;
while (size-- > 0)
{
sum += *data++;
sum = _rotl (sum, 1);
}
return sum;
}
void BootEncryption::GetBootLoader (byte *buffer, size_t bufferSize, bool rescueDisk)
{
if (bufferSize < TC_BOOT_LOADER_AREA_SIZE - HEADER_SIZE)
throw ParameterIncorrect (SRC_POS);
ZeroMemory (buffer, bufferSize);
int ea = 0;
if (GetStatus().DriveMounted)
{
try
{
GetBootEncryptionAlgorithmNameRequest request;
CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME, NULL, 0, &request, sizeof (request));
if (_stricmp (request.BootEncryptionAlgorithmName, "AES") == 0)
ea = AES;
else if (_stricmp (request.BootEncryptionAlgorithmName, "Serpent") == 0)
ea = SERPENT;
else if (_stricmp (request.BootEncryptionAlgorithmName, "Twofish") == 0)
ea = TWOFISH;
}
catch (...)
{
try
{
VOLUME_PROPERTIES_STRUCT properties;
GetVolumeProperties (&properties);
ea = properties.ea;
}
catch (...) { }
}
}
else
{
if (SelectedEncryptionAlgorithmId == 0)
throw ParameterIncorrect (SRC_POS);
ea = SelectedEncryptionAlgorithmId;
}
int bootSectorId = IDR_BOOT_SECTOR;
int bootLoaderId = IDR_BOOT_LOADER;
switch (ea)
{
case AES:
bootSectorId = IDR_BOOT_SECTOR_AES;
bootLoaderId = IDR_BOOT_LOADER_AES;
break;
case SERPENT:
bootSectorId = IDR_BOOT_SECTOR_SERPENT;
bootLoaderId = IDR_BOOT_LOADER_SERPENT;
break;
case TWOFISH:
bootSectorId = IDR_BOOT_SECTOR_TWOFISH;
bootLoaderId = IDR_BOOT_LOADER_TWOFISH;
break;
}
// Boot sector
DWORD size;
byte *bootSecResourceImg = MapResource ("BIN", bootSectorId, &size);
if (!bootSecResourceImg || size != SECTOR_SIZE)
throw ParameterIncorrect (SRC_POS);
memcpy (buffer, bootSecResourceImg, size);
if (rescueDisk)
buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK;
if (nCurrentOS == WIN_VISTA_OR_LATER)
buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER;
// Decompressor
byte *decompressor = MapResource ("BIN", IDR_BOOT_LOADER_DECOMPRESSOR, &size);
if (!decompressor || size > TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * SECTOR_SIZE)
throw ParameterIncorrect (SRC_POS);
memcpy (buffer + SECTOR_SIZE, decompressor, size);
// Compressed boot loader
byte *bootLoader = MapResource ("BIN", bootLoaderId, &size);
if (!bootLoader || size > TC_MAX_BOOT_LOADER_SECTOR_COUNT * SECTOR_SIZE)
throw ParameterIncorrect (SRC_POS);
memcpy (buffer + SECTOR_SIZE + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * SECTOR_SIZE, bootLoader, size);
// Boot loader and decompressor checksum
*(uint16 *) (buffer + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET) = static_cast <uint16> (size);
*(uint32 *) (buffer + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET) = GetChecksum (buffer + SECTOR_SIZE,
TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * SECTOR_SIZE + size);
// Backup of decompressor and boot loader
if (size + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * SECTOR_SIZE <= TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * SECTOR_SIZE)
{
memcpy (buffer + SECTOR_SIZE + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * SECTOR_SIZE,
buffer + SECTOR_SIZE, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * SECTOR_SIZE);
buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE;
}
else if (bootLoaderId != IDR_BOOT_LOADER)
{
throw ParameterIncorrect (SRC_POS);
}
}
void BootEncryption::InstallBootLoader ()
{
byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - HEADER_SIZE];
GetBootLoader (bootLoaderBuf, sizeof (bootLoaderBuf), false);
// Write MBR
Device device (GetSystemDriveConfiguration().DevicePath);
byte mbr[SECTOR_SIZE];
device.SeekAt (0);
device.Read (mbr, sizeof (mbr));
memcpy (mbr, bootLoaderBuf, TC_MAX_MBR_BOOT_CODE_SIZE);
device.SeekAt (0);
device.Write (mbr, sizeof (mbr));
byte mbrVerificationBuf[SECTOR_SIZE];
device.SeekAt (0);
device.Read (mbrVerificationBuf, sizeof (mbr));
if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
throw ErrorException ("ERROR_MBR_PROTECTED");
// Write boot loader
device.SeekAt (SECTOR_SIZE);
device.Write (bootLoaderBuf + SECTOR_SIZE, sizeof (bootLoaderBuf) - SECTOR_SIZE);
}
string BootEncryption::GetSystemLoaderBackupPath ()
{
char pathBuf[MAX_PATH];
throw_sys_if (!SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, pathBuf)));
string path = string (pathBuf) + "\\" TC_APP_NAME;
CreateDirectory (path.c_str(), NULL);
return path + '\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME;
}
#ifndef SETUP
void BootEncryption::CreateRescueIsoImage (bool initialSetup, const string &isoImagePath)
{
BootEncryptionStatus encStatus = GetStatus();
if (encStatus.SetupInProgress)
throw ParameterIncorrect (SRC_POS);
Buffer imageBuf (RescueIsoImageSize);
byte *image = imageBuf.Ptr();
memset (image, 0, RescueIsoImageSize);
// Primary volume descriptor
strcpy ((char *)image + 0x8000, "\001CD001\001");
strcpy ((char *)image + 0x7fff + 41, "TrueCrypt Rescue Disk ");
*(uint32 *) (image + 0x7fff + 81) = RescueIsoImageSize / 2048;
*(uint32 *) (image + 0x7fff + 85) = BE32 (RescueIsoImageSize / 2048);
image[0x7fff + 121] = 1;
image[0x7fff + 124] = 1;
image[0x7fff + 125] = 1;
image[0x7fff + 128] = 1;
image[0x7fff + 130] = 8;
image[0x7fff + 131] = 8;
image[0x7fff + 133] = 10;
image[0x7fff + 140] = 10;
image[0x7fff + 141] = 0x14;
image[0x7fff + 157] = 0x22;
image[0x7fff + 159] = 0x18;
// Boot record volume descriptor
strcpy ((char *)image + 0x8801, "CD001\001EL TORITO SPECIFICATION");
image[0x8800 + 0x47] = 0x19;
// Volume descriptor set terminator
strcpy ((char *)image + 0x9000, "\377CD001\001");
// Path table
image[0xA000 + 0] = 1;
image[0xA000 + 2] = 0x18;
image[0xA000 + 6] = 1;
// Root directory
image[0xc000 + 0] = 0x22;
image[0xc000 + 2] = 0x18;
image[0xc000 + 9] = 0x18;
image[0xc000 + 11] = 0x08;
image[0xc000 + 16] = 0x08;
image[0xc000 + 25] = 0x02;
image[0xc000 + 28] = 0x01;
image[0xc000 + 31] = 0x01;
image[0xc000 + 32] = 0x01;
image[0xc000 + 34] = 0x22;
image[0xc000 + 36] = 0x18;
image[0xc000 + 43] = 0x18;
image[0xc000 + 45] = 0x08;
image[0xc000 + 50] = 0x08;
image[0xc000 + 59] = 0x02;
image[0xc000 + 62] = 0x01;
*(uint32 *) (image + 0xc000 + 65) = 0x010101;
// Validation entry
image[0xc800] = 1;
int offset = 0xc800 + 0x1c;
image[offset++] = 0xaa;
image[offset++] = 0x55;
image[offset++] = 0x55;
image[offset] = 0xaa;
// Initial entry
offset = 0xc820;
image[offset++] = 0x88;
image[offset++] = 2;
image[0xc820 + 6] = 1;
image[0xc820 + 8] = TC_CD_BOOT_LOADER_SECTOR;
// TrueCrypt Boot Loader
GetBootLoader (image + TC_CD_BOOTSECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, true);
// Volume header
if (initialSetup)
{
if (!RescueVolumeHeaderValid)
throw ParameterIncorrect (SRC_POS);
memcpy (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, RescueVolumeHeader, HEADER_SIZE);
}
else
{
Device bootDevice (GetSystemDriveConfiguration().DevicePath, true);
bootDevice.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
bootDevice.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, HEADER_SIZE);
}
// Original system loader
try
{
File sysBakFile (GetSystemLoaderBackupPath(), true);
sysBakFile.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE);
image[TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER;
}
catch (Exception &e)
{
e.Show (ParentWindow);
Warning ("SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK");
}
RescueIsoImage = new byte[RescueIsoImageSize];
if (!RescueIsoImage)
throw bad_alloc();
memcpy (RescueIsoImage, image, RescueIsoImageSize);
if (!isoImagePath.empty())
{
File isoFile (isoImagePath, false, true);
isoFile.Write (image, RescueIsoImageSize);
}
}
#endif
bool BootEncryption::VerifyRescueDisk ()
{
if (!RescueIsoImage)
throw ParameterIncorrect (SRC_POS);
for (char drive = 'Z'; drive >= 'D'; --drive)
{
try
{
string path = "X:";
path[0] = drive;
Device driveDevice (path, true);
size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048;
Buffer buffer ((verifiedSectorCount + 1) * 2048);
DWORD bytesRead = driveDevice.Read (buffer.Ptr(), buffer.Size());
if (bytesRead != buffer.Size())
continue;
if (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0)
return true;
}
catch (...) { }
}
return false;
}
#ifndef SETUP
void BootEncryption::CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5)
{
PCRYPTO_INFO cryptoInfo = NULL;
throw_sys_if (Randinit () != 0);
throw_sys_if (VolumeWriteHeader (TRUE, (char *) VolumeHeader, ea, mode, password, pkcs5, NULL, 0, &cryptoInfo,
volumeSize, 0, encryptedAreaStart, 0, FALSE) != 0);
finally_do_arg (PCRYPTO_INFO*, &cryptoInfo, { crypto_close (*finally_arg); });
// Initial rescue disk assumes encryption of the drive has been completed (EncryptedAreaLength == volumeSize)
memcpy (RescueVolumeHeader, VolumeHeader, sizeof (RescueVolumeHeader));
VolumeReadHeader (TRUE, (char *) RescueVolumeHeader, password, NULL, cryptoInfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -