📄 bootencryption.cpp
字号:
/*
Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
Governed by the TrueCrypt License 2.6 the full text of which is contained
in the file License.txt included in TrueCrypt binary and source code
distribution packages.
*/
#include "Tcdefs.h"
#include "Platform/Finally.h"
#include "Platform/ForEach.h"
#include <Setupapi.h>
#include <devguid.h>
#include <io.h>
#include <shlobj.h>
#include <atlbase.h>
#include "BootEncryption.h"
#include "Boot/Windows/BootCommon.h"
#include "Common/Resource.h"
#include "Crc.h"
#include "Crypto.h"
#include "Dlgcode.h"
#include "Endian.h"
#include "Language.h"
#include "Random.h"
#include "Registry.h"
#include "Volumes.h"
#ifdef VOLFORMAT
#include "Format/FormatCom.h"
#elif defined (TCMOUNT)
#include "Mount/MainCom.h"
#endif
namespace TrueCrypt
{
#if !defined (SETUP)
class Elevator
{
public:
static void AddReference ()
{
++ReferenceCount;
}
static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
{
Elevate();
CComBSTR inputBstr;
if (input && inputBstr.AppendBytes ((const char *) input, inputSize) != S_OK)
throw ParameterIncorrect (SRC_POS);
CComBSTR outputBstr;
if (output && outputBstr.AppendBytes ((const char *) output, outputSize) != S_OK)
throw ParameterIncorrect (SRC_POS);
DWORD result = ElevatedComInstance->CallDriver (ioctl, inputBstr, &outputBstr);
if (output)
memcpy (output, *(void **) &outputBstr, outputSize);
if (result != ERROR_SUCCESS)
{
SetLastError (result);
throw SystemException();
}
}
static void ReadWriteFile (BOOL write, BOOL device, const string &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone)
{
Elevate();
CComBSTR bufferBstr;
if (bufferBstr.AppendBytes ((const char *) buffer, size) != S_OK)
throw ParameterIncorrect (SRC_POS);
DWORD result = ElevatedComInstance->ReadWriteFile (write, device, CComBSTR (filePath.c_str()), &bufferBstr, offset, size, sizeDone);
if (result != ERROR_SUCCESS)
{
SetLastError (result);
throw SystemException();
}
if (!write)
memcpy (buffer, (BYTE *) bufferBstr.m_str, size);
}
static BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
{
Elevate();
return ElevatedComInstance->IsPagingFileActive (checkNonWindowsPartitionsOnly);
}
static void WriteLocalMachineRegistryDwordValue (char *keyPath, char *valueName, DWORD value)
{
Elevate();
DWORD result = ElevatedComInstance->WriteLocalMachineRegistryDwordValue (CComBSTR (keyPath), CComBSTR (valueName), value);
if (result != ERROR_SUCCESS)
{
SetLastError (result);
throw SystemException();
}
}
static void RegisterFilterDriver (bool registerDriver, bool volumeClass)
{
Elevate();
DWORD result = ElevatedComInstance->RegisterFilterDriver (registerDriver ? TRUE : FALSE, volumeClass ? TRUE : FALSE);
if (result != ERROR_SUCCESS)
{
SetLastError (result);
throw SystemException();
}
}
static void Release ()
{
if (--ReferenceCount == 0 && ElevatedComInstance)
{
ElevatedComInstance->Release();
ElevatedComInstance = nullptr;
CoUninitialize ();
}
}
static void SetDriverServiceStartType (DWORD startType)
{
Elevate();
DWORD result = ElevatedComInstance->SetDriverServiceStartType (startType);
if (result != ERROR_SUCCESS)
{
SetLastError (result);
throw SystemException();
}
}
protected:
static void Elevate ()
{
if (IsAdmin())
{
SetLastError (ERROR_ACCESS_DENIED);
throw SystemException();
}
if (!ElevatedComInstance || ElevatedComInstanceThreadId != GetCurrentThreadId())
{
CoInitialize (NULL);
ElevatedComInstance = GetElevatedInstance (GetActiveWindow() ? GetActiveWindow() : MainDlg);
ElevatedComInstanceThreadId = GetCurrentThreadId();
}
}
#if defined (TCMOUNT)
static ITrueCryptMainCom *ElevatedComInstance;
#elif defined (VOLFORMAT)
static ITrueCryptFormatCom *ElevatedComInstance;
#endif
static DWORD ElevatedComInstanceThreadId;
static int ReferenceCount;
};
#if defined (TCMOUNT)
ITrueCryptMainCom *Elevator::ElevatedComInstance;
#elif defined (VOLFORMAT)
ITrueCryptFormatCom *Elevator::ElevatedComInstance;
#endif
DWORD Elevator::ElevatedComInstanceThreadId;
int Elevator::ReferenceCount = 0;
#else // SETUP
class Elevator
{
public:
static void AddReference () { }
static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) { throw ParameterIncorrect (SRC_POS); }
static void ReadWriteFile (BOOL write, BOOL device, const string &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone) { throw ParameterIncorrect (SRC_POS); }
static void RegisterFilterDriver (bool registerDriver, bool volumeClass) { throw ParameterIncorrect (SRC_POS); }
static void Release () { }
static void SetDriverServiceStartType (DWORD startType) { throw ParameterIncorrect (SRC_POS); }
};
#endif // SETUP
File::File (string path, bool readOnly, bool create) : Elevated (false), FileOpen (false)
{
Handle = CreateFile (path.c_str(),
readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
try
{
throw_sys_if (Handle == INVALID_HANDLE_VALUE);
}
catch (SystemException &)
{
if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
Elevated = true;
else
throw;
}
FileOpen = true;
FilePointerPosition = 0;
IsDevice = false;
Path = path;
}
void File::Close ()
{
if (FileOpen)
{
if (!Elevated)
CloseHandle (Handle);
FileOpen = false;
}
}
DWORD File::Read (byte *buffer, DWORD size)
{
DWORD bytesRead;
if (Elevated)
{
DWORD bytesRead;
Elevator::ReadWriteFile (false, IsDevice, Path, buffer, FilePointerPosition, size, &bytesRead);
FilePointerPosition += bytesRead;
return bytesRead;
}
throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL));
return bytesRead;
}
void File::SeekAt (int64 position)
{
FilePointerPosition = position;
if (!Elevated)
{
LARGE_INTEGER pos;
pos.QuadPart = position;
throw_sys_if (!SetFilePointerEx (Handle, pos, NULL, FILE_BEGIN));
}
}
void File::Write (byte *buffer, DWORD size)
{
DWORD bytesWritten;
try
{
if (Elevated)
{
Elevator::ReadWriteFile (true, IsDevice, Path, buffer, FilePointerPosition, size, &bytesWritten);
FilePointerPosition += bytesWritten;
throw_sys_if (bytesWritten != size);
}
else
{
throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size);
}
}
catch (SystemException &e)
{
if (!IsDevice || e.ErrorCode != ERROR_WRITE_PROTECT || !IsHiddenOSRunning())
throw;
BootEncryption bootEnc (NULL);
while (size >= SECTOR_SIZE)
{
bootEnc.WriteBootDriveSector (FilePointerPosition, buffer);
FilePointerPosition += SECTOR_SIZE;
buffer += SECTOR_SIZE;
size -= SECTOR_SIZE;
}
}
}
void Show (HWND parent, const string &str)
{
MessageBox (parent, str.c_str(), NULL, 0);
}
Device::Device (string path, bool readOnly)
{
FileOpen = false;
Elevated = false;
Handle = CreateFile ((string ("\\\\.\\") + path).c_str(),
readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
try
{
throw_sys_if (Handle == INVALID_HANDLE_VALUE);
}
catch (SystemException &)
{
if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
Elevated = true;
else
throw;
}
FileOpen = true;
FilePointerPosition = 0;
IsDevice = true;
Path = path;
}
BootEncryption::BootEncryption (HWND parent)
: DriveConfigValid (false),
ParentWindow (parent),
RealSystemDriveSizeValid (false),
RescueIsoImage (nullptr),
RescueVolumeHeaderValid (false),
SelectedEncryptionAlgorithmId (0),
VolumeHeaderValid (false)
{
Elevator::AddReference();
}
BootEncryption::~BootEncryption ()
{
if (RescueIsoImage)
delete RescueIsoImage;
Elevator::Release();
}
void BootEncryption::CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
{
try
{
DWORD bytesReturned;
throw_sys_if (!DeviceIoControl (hDriver, ioctl, input, inputSize, output, outputSize, &bytesReturned, NULL));
}
catch (SystemException &)
{
if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
Elevator::CallDriver (ioctl, input, inputSize, output, outputSize);
else
throw;
}
}
// Finds the first partition physically located behind the active one and returns its properties
Partition BootEncryption::GetPartitionForHiddenOS ()
{
Partition candidatePartition;
memset (&candidatePartition, 0, sizeof(candidatePartition));
// The user may have modified/added/deleted partitions since the time the partition table was last scanned
InvalidateCachedSysDriveProperties();
SystemDriveConfiguration config = GetSystemDriveConfiguration ();
bool activePartitionFound = false;
bool candidateForHiddenOSFound = false;
if (config.SystemPartition.IsGPT)
throw ParameterIncorrect (SRC_POS); // It is assumed that CheckRequirements() had been called
// Find the first active partition on the system drive
foreach (const Partition &partition, config.Partitions)
{
if (partition.Info.BootIndicator)
{
if (partition.Info.PartitionNumber != config.SystemPartition.Number)
{
throw ErrorException (wstring (GetString ("SYSTEM_PARTITION_NOT_ACTIVE"))
+ GetRemarksOnHiddenOS());
}
activePartitionFound = true;
break;
}
}
/* WARNING: Note that the partition number at the end of a device path (\Device\HarddiskY\PartitionX) must
NOT be used to find the first partition physically located behind the active one. The reason is that the
user may have deleted and created partitions during this session and e.g. the second partition could have
a higer number than the third one. */
// Find the first partition physically located behind the active partition
if (activePartitionFound)
{
int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart;
foreach (const Partition &partition, config.Partitions)
{
if (partition.Info.StartingOffset.QuadPart > config.SystemPartition.Info.StartingOffset.QuadPart
&& partition.Info.StartingOffset.QuadPart < minOffsetFound)
{
minOffsetFound = partition.Info.StartingOffset.QuadPart;
candidatePartition = partition;
candidateForHiddenOSFound = true;
}
}
if (!candidateForHiddenOSFound)
{
throw ErrorException (wstring (GetString ("NO_PARTITION_FOLLOWS_BOOT_PARTITION"))
+ GetRemarksOnHiddenOS());
}
if (config.SystemPartition.Info.PartitionLength.QuadPart > TC_MAX_FAT_FS_SIZE)
{
if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_NTFS)
{
throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS_NTFS"))
+ GetRemarksOnHiddenOS());
}
}
else if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_FAT)
{
throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS"))
+ GetRemarksOnHiddenOS());
}
}
else
{
// No active partition on the system drive
throw ErrorException ("WINDOWS_NOT_ON_BOOT_DRIVE_ERROR");
}
HiddenOSCandidatePartition = candidatePartition;
return candidatePartition;
}
DWORD BootEncryption::GetDriverServiceStartType ()
{
DWORD startType;
throw_sys_if (!ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", "Start", &startType));
return startType;
}
wstring BootEncryption::GetRemarksOnHiddenOS ()
{
return (wstring (L"\n\n")
+ GetString ("TWO_SYSTEMS_IN_ONE_PARTITION_REMARK")
+ L"\n\n"
+ GetString ("FOR_MORE_INFO_ON_PARTITIONS"));
}
void BootEncryption::SetDriverServiceStartType (DWORD startType)
{
if (!IsAdmin() && IsUacSupported())
{
Elevator::SetDriverServiceStartType (startType);
return;
}
BOOL startOnBoot = (startType == SERVICE_BOOT_START);
SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
throw_sys_if (!serviceManager);
finally_do_arg (SC_HANDLE, serviceManager, { CloseServiceHandle (finally_arg); });
SC_HANDLE service = OpenService (serviceManager, "truecrypt", SERVICE_CHANGE_CONFIG);
throw_sys_if (!service);
finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); });
// Windows versions preceding Vista can be installed on FAT filesystem which does not
// support long filenames during boot. Convert the driver path to short form if required.
string driverPath;
if (startOnBoot && nCurrentOS != WIN_VISTA_OR_LATER)
{
char pathBuf[MAX_PATH];
char filesystem[128];
string path (GetWindowsDirectory());
path += "\\drivers\\truecrypt.sys";
if (GetVolumePathName (path.c_str(), pathBuf, sizeof (pathBuf))
&& GetVolumeInformation (pathBuf, NULL, 0, NULL, NULL, NULL, filesystem, sizeof(filesystem))
&& memcmp (filesystem, "FAT", 3) == 0)
{
throw_sys_if (GetShortPathName (path.c_str(), pathBuf, sizeof (pathBuf)) == 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -