📄 ntvol.c
字号:
if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
{
Dump ("Read didn't read enough data\n");
// If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
// filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
// shorter than the partition). This can happen for example after the user quick-formats a dismounted
// partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
}
/* Attempt to recognize the volume (decrypt the header) */
ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
if ((volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) && mount->bProtectHiddenVolume)
{
mount->nReturnCode = ReadVolumeHeaderWCache (
FALSE,
mount->bCache,
readBuffer,
&mount->ProtectedHidVolPassword,
&tmpCryptoInfo);
}
else
{
mount->nReturnCode = ReadVolumeHeaderWCache (
mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
mount->bCache,
readBuffer,
&mount->VolumePassword,
&Extension->cryptoInfo);
}
ReadVolumeHeaderRecoveryMode = FALSE;
if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
{
/* Volume header successfully decrypted */
Dump ("Volume header decrypted\n");
Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
{
Extension->bReadOnly = mount->bMountReadOnly = TRUE;
HiddenSysLeakProtectionCount++;
}
Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
if (volumeType == TC_VOLUME_TYPE_NORMAL)
{
if (mount->bPartitionInInactiveSysEncScope)
{
if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
|| Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
{
// The partition is not within the key scope of system encryption
mount->nReturnCode = ERR_PASSWORD_WRONG;
ntStatus = STATUS_SUCCESS;
goto error;
}
if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
{
// Partial encryption is not supported for volumes mounted as regular
mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
ntStatus = STATUS_SUCCESS;
goto error;
}
}
else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
{
if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
{
// Non-system in-place encryption process has not been completed on this volume
mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
ntStatus = STATUS_SUCCESS;
goto error;
}
}
}
Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
{
// Prevent mount of a hidden system partition if the system hosted on it is currently running
if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
{
mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
ntStatus = STATUS_SUCCESS;
goto error;
}
}
switch (volumeType)
{
case TC_VOLUME_TYPE_NORMAL:
Extension->cryptoInfo->hiddenVolume = FALSE;
if (mount->bPartitionInInactiveSysEncScope)
{
Extension->cryptoInfo->volDataAreaOffset = 0;
Extension->DiskLength = lDiskLength.QuadPart;
Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
}
else if (Extension->cryptoInfo->LegacyVolume)
{
Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
}
else
{
Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
}
break;
case TC_VOLUME_TYPE_HIDDEN:
case TC_VOLUME_TYPE_HIDDEN_LEGACY:
cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
Extension->cryptoInfo->hiddenVolumeOffset = lDiskLength.QuadPart - cryptoInfoPtr->hiddenVolumeSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
else
Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
// Validate the offset
if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
{
mount->nReturnCode = ERR_VOL_SIZE_WRONG;
ntStatus = STATUS_SUCCESS;
goto error;
}
// If we are supposed to actually mount the hidden volume (not just to protect it)
if (!mount->bProtectHiddenVolume)
{
Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
Extension->cryptoInfo->hiddenVolume = TRUE;
Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
}
else
{
// Hidden volume protection
Extension->cryptoInfo->hiddenVolume = FALSE;
Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
Extension->cryptoInfo->hiddenVolumeProtectedSize += TC_VOLUME_HEADER_SIZE_LEGACY;
Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
}
break;
}
Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
Dump ("Volume data size = %I64d\n", Extension->DiskLength);
Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
if (Extension->DiskLength == 0)
{
Dump ("Incorrect volume size\n");
continue;
}
// If this is a hidden volume, make sure we are supposed to actually
// mount it (i.e. not just to protect it)
if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
{
// Calculate virtual volume geometry
Extension->TracksPerCylinder = 1;
Extension->SectorsPerTrack = 1;
Extension->BytesPerSector = SECTOR_SIZE;
Extension->NumberOfCylinders = Extension->DiskLength / SECTOR_SIZE;
Extension->PartitionType = 0;
Extension->bRawDevice = bRawDevice;
memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
{
/* UNC path */
_snwprintf (Extension->wszVolume,
sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1,
WIDE ("\\??\\\\%s"),
pwszMountVolume + 7);
}
else
{
wcsncpy (Extension->wszVolume, pwszMountVolume, sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1);
}
}
// If we are to protect a hidden volume we cannot exit yet, for we must also
// decrypt the hidden volume header.
if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
{
TCfree (readBuffer);
if (tmpCryptoInfo != NULL)
{
crypto_close (tmpCryptoInfo);
tmpCryptoInfo = NULL;
}
return STATUS_SUCCESS;
}
}
else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
|| mount->nReturnCode != ERR_PASSWORD_WRONG)
{
/* If we are not supposed to protect a hidden volume, the only error that is
tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
If we _are_ supposed to protect a hidden volume, we do not tolerate any error
(both volume headers must be successfully decrypted). */
break;
}
}
/* Failed due to some non-OS reason so we drop through and return NT
SUCCESS then nReturnCode is checked later in user-mode */
if (mount->nReturnCode == ERR_OUTOFMEMORY)
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
else
ntStatus = STATUS_SUCCESS;
error:
if (mount->nReturnCode == ERR_SUCCESS)
mount->nReturnCode = ERR_PASSWORD_WRONG;
if (tmpCryptoInfo != NULL)
{
crypto_close (tmpCryptoInfo);
tmpCryptoInfo = NULL;
}
if (Extension->cryptoInfo)
{
crypto_close (Extension->cryptoInfo);
Extension->cryptoInfo = NULL;
}
if (Extension->bTimeStampValid)
{
/* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
RestoreTimeStamp (Extension);
}
/* Close the hDeviceFile */
if (Extension->hDeviceFile != NULL)
ZwClose (Extension->hDeviceFile);
/* The cryptoInfo pointer is deallocated if the readheader routines
fail so there is no need to deallocate here */
/* Dereference the user-mode file object */
if (Extension->pfoDeviceFile != NULL)
ObDereferenceObject (Extension->pfoDeviceFile);
/* Free the tmp IO buffers */
if (readBuffer != NULL)
TCfree (readBuffer);
return ntStatus;
}
void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
{
if (DeviceObject); /* Remove compiler warning */
if (Extension->hDeviceFile != NULL)
{
if (Extension->bRawDevice == FALSE
&& Extension->bTimeStampValid)
{
/* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
RestoreTimeStamp (Extension);
}
ZwClose (Extension->hDeviceFile);
}
ObDereferenceObject (Extension->pfoDeviceFile);
crypto_close (Extension->cryptoInfo);
}
NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
PEXTENSION Extension,
ULONG IoControlCode,
void *OutputBuffer,
ULONG OutputBufferSize)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS ntStatus;
PIRP Irp;
if (DeviceObject); /* Remove compiler warning */
KeClearEvent (&Extension->keVolumeEvent);
Irp = IoBuildDeviceIoControlRequest (IoControlCode,
Extension->pFsdDevice,
NULL, 0,
OutputBuffer, OutputBufferSize,
FALSE,
&Extension->keVolumeEvent,
&IoStatusBlock);
if (Irp == NULL)
{
Dump ("IRP allocation failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
// Disk device may be used by filesystem driver which needs file object
IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
ntStatus = IoStatusBlock.Status;
}
return ntStatus;
}
NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
PIRP Irp,
NTSTATUS IrpStatus,
ULONG_PTR IrpInformation)
{
Irp->IoStatus.Status = IrpStatus;
Irp->IoStatus.Information = IrpInformation;
if (DeviceObject); /* Remove compiler warning */
#if EXTRA_INFO
if (!NT_SUCCESS (IrpStatus))
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
(ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
}
else
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
(ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
}
#endif
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return IrpStatus;
}
// Restores the container timestamp to preserve plausible deniability of possible hidden volume.
static void RestoreTimeStamp (PEXTENSION Extension)
{
NTSTATUS ntStatus;
FILE_BASIC_INFORMATION FileBasicInfo;
IO_STATUS_BLOCK IoStatusBlock;
if (Extension->hDeviceFile != NULL
&& Extension->bRawDevice == FALSE
&& Extension->bReadOnly == FALSE
&& Extension->bTimeStampValid)
{
ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
&IoStatusBlock,
&FileBasicInfo,
sizeof (FileBasicInfo),
FileBasicInformation);
if (!NT_SUCCESS (ntStatus))
{
Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
ntStatus);
}
else
{
FileBasicInfo.CreationTime = Extension->fileCreationTime;
FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
ntStatus = ZwSetInformationFile(
Extension->hDeviceFile,
&IoStatusBlock,
&FileBasicInfo,
sizeof (FileBasicInfo),
FileBasicInformation);
if (!NT_SUCCESS (ntStatus))
Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -