📄 ntvol.c
字号:
/* The source code contained in this file has been derived from the source code
of Encryption for the Masses 2.02a by Paul Le Roux. Modifications and
additions to that source code contained in this file are Copyright (c) 2004-2005
TrueCrypt Foundation and Copyright (c) 2004 TrueCrypt Team. Unmodified
parts are Copyright (c) 1998-99 Paul Le Roux. This is a TrueCrypt Foundation
release. Please see the file license.txt for full license details. */
#include "TCdefs.h"
#include "crypto.h"
#include "volumes.h"
#include "apidrvr.h"
#include "ntdriver.h"
#include "ntvol.h"
#include "ntrawdv.h"
#include "ntfiledv.h"
#include "cache.h"
//#ifdef _DEBUG
//#define EXTRA_INFO 1
//#endif
#pragma warning( disable : 4127 )
NTSTATUS
TCOpenVolume (PDEVICE_OBJECT DeviceObject,
PEXTENSION Extension,
MOUNT_STRUCT * mount,
PWSTR pwszMountVolume,
BOOL bRawDevice)
{
FILE_STANDARD_INFORMATION FileStandardInfo;
FILE_BASIC_INFORMATION FileBasicInfo;
OBJECT_ATTRIBUTES oaFileAttributes;
UNICODE_STRING FullFileName;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER lDiskLength;
char *readBuffer = 0;
char *readBufferHiddenVol = 0;
NTSTATUS ntStatus = 0;
BOOL bTimeStampValid = FALSE;
Extension->pfoDeviceFile = NULL;
Extension->hDeviceFile = NULL;
RtlInitUnicodeString (&FullFileName, pwszMountVolume);
InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
// If we are opening a device, query its size first
if (bRawDevice)
{
PARTITION_INFORMATION pi;
DISK_GEOMETRY dg;
ntStatus = IoGetDeviceObjectPointer (&FullFileName,
FILE_READ_DATA,
&Extension->pfoDeviceFile,
&Extension->pFsdDevice);
if (!NT_SUCCESS (ntStatus))
{
goto error;
}
DeviceObject->StackSize = (CCHAR) (Extension->pFsdDevice->StackSize + 1);
// Query partition size
ntStatus = TCSendDeviceIoControlRequest (DeviceObject,
Extension, IOCTL_DISK_GET_PARTITION_INFO,
(char *) &pi, sizeof (pi));
if (NT_SUCCESS (ntStatus))
{
lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
}
else
{
// Drive geometry info is used only when IOCTL_DISK_GET_PARTITION_INFO fails
ntStatus = TCSendDeviceIoControlRequest (DeviceObject,
Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY,
(char *) &dg, sizeof (dg));
if (!NT_SUCCESS (ntStatus))
goto error;
lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack *
dg.TracksPerCylinder * dg.BytesPerSector;
}
}
// Open the volume hosting file/device
if (!mount->bMountReadOnly)
{
ntStatus = ZwCreateFile (&Extension->hDeviceFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&oaFileAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_SYSTEM,
mount->bExclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_WRITE_THROUGH |
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
}
/* 26-4-99 NT for some partitions returns this code, it is really a
access denied */
if (ntStatus == 0xc000001b)
{
ntStatus = STATUS_ACCESS_DENIED;
}
if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
{
ntStatus = ZwCreateFile (&Extension->hDeviceFile,
GENERIC_READ | SYNCHRONIZE,
&oaFileAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_SYSTEM,
mount->bExclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_WRITE_THROUGH |
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
Extension->bReadOnly = TRUE;
}
else
Extension->bReadOnly = FALSE;
/* 26-4-99 NT for some partitions returns this code, it is really a
access denied */
if (ntStatus == 0xc000001b)
{
/* Partitions which return this code can still be opened with
FILE_SHARE_READ but this causes NT problems elsewhere in
particular if you do FILE_SHARE_READ NT will die later if
anyone even tries to open the partition (or file for that
matter...) */
ntStatus = STATUS_SHARING_VIOLATION;
}
if (!NT_SUCCESS (ntStatus))
{
goto error;
}
// If we have opened a file, query its size now
if (bRawDevice == FALSE)
{
ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
&IoStatusBlock,
&FileBasicInfo,
sizeof (FileBasicInfo),
FileBasicInformation);
if (NT_SUCCESS (ntStatus))
{
/* Remember the container timestamp. (Used to reset access/modification file date/time
of file-hosted containers upon dismount or after unsuccessful mount attempt to preserve
plausible deniability of hidden volumes.) */
Extension->fileCreationTime = FileBasicInfo.CreationTime;
Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
bTimeStampValid = TRUE;
ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
&IoStatusBlock,
&FileStandardInfo,
sizeof (FileStandardInfo),
FileStandardInformation);
}
if (!NT_SUCCESS (ntStatus))
{
Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
ntStatus);
goto error;
}
lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
{
Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
ntStatus = STATUS_SUCCESS;
goto error;
}
ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
FILE_ALL_ACCESS,
*IoFileObjectType,
KernelMode,
&Extension->pfoDeviceFile,
0);
if (!NT_SUCCESS (ntStatus))
{
goto error;
}
/* Get the FSD device for the file (probably either NTFS or FAT) */
Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
DeviceObject->StackSize = (CCHAR) (Extension->pFsdDevice->StackSize + 1);
}
// Check volume size
if (lDiskLength.QuadPart < MIN_VOLUME_SIZE || lDiskLength.QuadPart > MAX_VOLUME_SIZE)
{
mount->nReturnCode = ERR_VOL_SIZE_WRONG;
ntStatus = STATUS_SUCCESS;
goto error;
}
Extension->DiskLength = lDiskLength.QuadPart;
// Read normal volume header
readBuffer = TCalloc (HEADER_SIZE);
if (readBuffer == NULL)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto error;
}
ntStatus = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL,
&IoStatusBlock, readBuffer, HEADER_SIZE, NULL, NULL);
// Read hidden volume header if needed
if (mountingHiddenVolumesAllowed)
{
LARGE_INTEGER byteOffset;
readBufferHiddenVol = TCalloc (HEADER_SIZE);
if (readBufferHiddenVol == NULL)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto error;
}
byteOffset.QuadPart = lDiskLength.QuadPart - HIDDEN_VOL_HEADER_OFFSET;
ntStatus = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL,
&IoStatusBlock, readBufferHiddenVol, HEADER_SIZE, &byteOffset, NULL);
}
if (!NT_SUCCESS (ntStatus))
{
Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
}
else if (IoStatusBlock.Information != HEADER_SIZE)
{
Dump ("Read didn't read enough data in: %lu / %lu\n", IoStatusBlock.Information, HEADER_SIZE);
ntStatus = STATUS_UNSUCCESSFUL;
}
if (!NT_SUCCESS (ntStatus))
{
goto error;
}
/* Attempt to recognize the volume */
mount->nReturnCode = VolumeReadHeaderCache (
mount->bCache,
readBuffer,
readBufferHiddenVol,
mount->szPassword,
strlen (mount->szPassword),
&Extension->cryptoInfo);
if (mount->nReturnCode == 0)
{
/* Volume header successfully decrypted */
if (Extension->cryptoInfo->hiddenVolume)
{
// Hidden volume setup
// Validate the size of the hidden volume specified in the header
if (Extension->DiskLength < (__int64) Extension->cryptoInfo->hiddenVolumeSize + HIDDEN_VOL_HEADER_OFFSET + HEADER_SIZE
|| Extension->cryptoInfo->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 - Extension->cryptoInfo->hiddenVolumeSize - HIDDEN_VOL_HEADER_OFFSET;
Dump("Hidden volume offset = %I64d", Extension->cryptoInfo->hiddenVolumeOffset);
// Validate the offset
if (Extension->cryptoInfo->hiddenVolumeOffset % SECTOR_SIZE != 0)
{
mount->nReturnCode = ERR_VOL_SIZE_WRONG;
ntStatus = STATUS_SUCCESS;
goto error;
}
// Set volume size
Extension->DiskLength = Extension->cryptoInfo->hiddenVolumeSize;
}
else
{
// Normal (not a hidden) volume
// Set volume size
Extension->DiskLength -= HEADER_SIZE;
}
// Calculate virtual volume geometry
Extension->TracksPerCylinder = 1;
Extension->SectorsPerTrack = 1;
Extension->BytesPerSector = 512;
Extension->NumberOfCylinders = Extension->DiskLength / 512;
Extension->PartitionType = 0;
Extension->bRawDevice = bRawDevice;
if (wcslen (pwszMountVolume) < 64)
wcscpy (Extension->wszVolume, pwszMountVolume);
else
{
memcpy (Extension->wszVolume, pwszMountVolume, 60 * 2);
Extension->wszVolume[60] = (WCHAR) '.';
Extension->wszVolume[61] = (WCHAR) '.';
Extension->wszVolume[62] = (WCHAR) '.';
Extension->wszVolume[63] = (WCHAR) 0;
}
Extension->mountTime = mount->time;
TCfree (readBuffer);
return STATUS_SUCCESS;
}
/* 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 (bTimeStampValid)
{
/* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
RestoreTimeStamp (Extension);
bTimeStampValid = FALSE;
}
/* 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);
if (readBufferHiddenVol != NULL)
TCfree (readBufferHiddenVol);
return ntStatus;
}
void
TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
{
if (DeviceObject); /* Remove compiler warning */
if (Extension->hDeviceFile != NULL)
{
if (Extension->bRawDevice == FALSE)
{
/* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
RestoreTimeStamp (Extension);
}
ZwClose (Extension->hDeviceFile);
}
ObDereferenceObject (Extension->pfoDeviceFile);
crypto_close (Extension->cryptoInfo);
}
/* This rountine can be called at any IRQL so we need to tread carefully. Not
even DbgPrint or KdPrint are called here as the kernel sometimes faults if
they are called at high IRQL */
NTSTATUS
TCCompletion (PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID pUserBuffer)
{
PIO_STACK_LOCATION irpSp;
PEXTENSION Extension;
NTSTATUS ntStatus;
Extension = (PEXTENSION) DeviceObject->DeviceExtension;
/* Check to make sure the DeviceObject passed in is actually ours! */
if (Extension->lMagicNumber != 0xabfeacde)
KeBugCheck ((ULONG) 0xabfeacde);
ASSERT (Extension->nDosDriveNo >= 0 && Extension->nDosDriveNo <= 0x19);
#ifdef USE_KERNEL_MUTEX
KeWaitForMutexObject (&Extension->KernelMutex, Executive, KernelMode,
FALSE, NULL);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -