📄 ntvol.c
字号:
if (!NT_SUCCESS (ntStatus))
{
goto error;
}
/* Attempt to recognize the volume (decrypt the header) */
if (volumeType == VOLUME_TYPE_HIDDEN && mount->bProtectHiddenVolume)
{
mount->nReturnCode = VolumeReadHeaderCache (
mount->bPartitionInInactiveSysEncScope,
mount->bCache,
readBuffer,
&mount->ProtectedHidVolPassword,
&tmpCryptoInfo);
}
else
{
mount->nReturnCode = VolumeReadHeaderCache (
mount->bPartitionInInactiveSysEncScope,
mount->bCache,
readBuffer,
&mount->VolumePassword,
&Extension->cryptoInfo);
}
if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
{
/* Volume header successfully decrypted */
Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
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;
}
}
switch (volumeType)
{
case VOLUME_TYPE_NORMAL:
if (!mount->bPartitionInInactiveSysEncScope)
{
// Correct the volume size for this volume type. Later on, this must be undone
// if Extension->DiskLength is used in deriving hidden volume offset
Extension->DiskLength -= HEADER_SIZE;
}
Extension->cryptoInfo->hiddenVolume = FALSE;
Extension->cryptoInfo->volDataAreaOffset = mount->bPartitionInInactiveSysEncScope ? 0 : HEADER_SIZE;
Extension->cryptoInfo->FirstDataUnitNo.Value = mount->bPartitionInInactiveSysEncScope ?
partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE : 0;
break;
case VOLUME_TYPE_HIDDEN:
cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
// Validate the size of the hidden volume specified in the header
if (Extension->DiskLength < (__int64) cryptoInfoPtr->hiddenVolumeSize + HIDDEN_VOL_HEADER_OFFSET + HEADER_SIZE
|| cryptoInfoPtr->hiddenVolumeSize <= 0)
{
mount->nReturnCode = ERR_VOL_SIZE_WRONG;
ntStatus = STATUS_SUCCESS;
goto error;
}
// Determine the offset of the hidden volume
Extension->cryptoInfo->hiddenVolumeOffset = Extension->DiskLength - cryptoInfoPtr->hiddenVolumeSize - HIDDEN_VOL_HEADER_OFFSET;
Dump("Hidden volume size = %I64d", cryptoInfoPtr->hiddenVolumeSize);
Dump("Hidden volume offset = %I64d", Extension->cryptoInfo->hiddenVolumeOffset);
// 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;
Extension->cryptoInfo->FirstDataUnitNo.Value = mount->bPartitionInInactiveSysEncScope ?
(partitionStartingOffset + Extension->cryptoInfo->hiddenVolumeOffset) / ENCRYPTION_DATA_UNIT_SIZE
: 0;
}
else
{
// Hidden volume protection
Extension->cryptoInfo->hiddenVolume = FALSE;
Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
if (!mount->bPartitionInInactiveSysEncScope)
Extension->cryptoInfo->hiddenVolumeOffset += HEADER_SIZE; // Offset was incorrect due to loop processing
Dump("Hidden volume protection active (offset = %I64d)", Extension->cryptoInfo->hiddenVolumeOffset);
}
break;
}
// If this is a hidden volume, make sure we are supposed to actually
// mount it (i.e. not just to protect it)
if (!(volumeType == VOLUME_TYPE_HIDDEN && 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 == VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
{
TCfree (readBuffer);
if (tmpCryptoInfo != NULL)
crypto_close (tmpCryptoInfo);
return STATUS_SUCCESS;
}
}
else if (mount->bProtectHiddenVolume
|| 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 (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,
char *OutputBuffer,
int 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 + -