📄 ntvol.c
字号:
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions of
this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
by the TrueCrypt License 2.4 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 "Crypto.h"
#include "Volumes.h"
#include "Apidrvr.h"
#include "Ntdriver.h"
#include "Ntvol.h"
#include "Boot/Windows/BootCommon.h"
#include "Cache.h"
#if 0 && _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;
PCRYPTO_INFO cryptoInfoPtr = NULL;
PCRYPTO_INFO tmpCryptoInfo = NULL;
LARGE_INTEGER lDiskLength;
LARGE_INTEGER hiddenVolHeaderOffset;
__int64 partitionStartingOffset;
int volumeType;
char *readBuffer = 0;
NTSTATUS ntStatus = 0;
Extension->pfoDeviceFile = NULL;
Extension->hDeviceFile = NULL;
Extension->bTimeStampValid = FALSE;
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;
PARTITION_INFORMATION_EX pix;
DISK_GEOMETRY dg;
ntStatus = IoGetDeviceObjectPointer (&FullFileName,
FILE_READ_DATA,
&Extension->pfoDeviceFile,
&Extension->pFsdDevice);
if (!NT_SUCCESS (ntStatus))
goto error;
if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg))))
{
lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
mount->BytesPerSector = dg.BytesPerSector;
}
else
lDiskLength.QuadPart = 0;
// Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
{
lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
partitionStartingOffset = pix.StartingOffset.QuadPart;
}
// Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
{
lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
partitionStartingOffset = pi.StartingOffset.QuadPart;
}
if (!mount->bMountReadOnly && TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
{
mount->bMountReadOnly = TRUE;
DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
}
}
if (mount->BytesPerSector == 0)
mount->BytesPerSector = SECTOR_SIZE;
Extension->HostBytesPerSector = mount->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_RANDOM_ACCESS |
FILE_WRITE_THROUGH |
(Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
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 ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_RANDOM_ACCESS |
FILE_WRITE_THROUGH |
(Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
Extension->bReadOnly = TRUE;
DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
}
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))
{
if (mount->bPreserveTimestamp)
{
/* Remember the container timestamp. (Used to reset access/modification file date/time
of file-hosted volumes 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;
Extension->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);
}
// 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;
hiddenVolHeaderOffset.QuadPart = lDiskLength.QuadPart - HIDDEN_VOL_HEADER_OFFSET;
readBuffer = TCalloc (HEADER_SIZE);
if (readBuffer == NULL)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto error;
}
// Go through all volume types (e.g., normal, hidden)
for (volumeType = VOLUME_TYPE_NORMAL;
volumeType < NBR_VOLUME_TYPES;
volumeType++)
{
if (mount->bPartitionInInactiveSysEncScope
&& volumeType != VOLUME_TYPE_NORMAL)
continue;
/* Read the volume header */
if (!mount->bPartitionInInactiveSysEncScope)
{
// Header of a volume that is not within the scope of system encryption
ntStatus = ZwReadFile (Extension->hDeviceFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
readBuffer,
HEADER_SIZE,
volumeType == VOLUME_TYPE_HIDDEN ? &hiddenVolHeaderOffset : NULL,
NULL);
}
else
{
// Header of a partition that is within the scope of system encryption
WCHAR parentDrivePath [47+1] = {0};
HANDLE hParentDeviceFile = NULL;
UNICODE_STRING FullParentPath;
OBJECT_ATTRIBUTES oaParentFileAttributes;
LARGE_INTEGER parentKeyDataOffset;
_snwprintf (parentDrivePath,
sizeof (parentDrivePath) / sizeof (WCHAR) - 1,
WIDE ("\\Device\\Harddisk%d\\Partition0"),
mount->nPartitionInInactiveSysEncScopeDriveNo);
Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
RtlInitUnicodeString (&FullParentPath, parentDrivePath);
InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
ntStatus = ZwCreateFile (&hParentDeviceFile,
GENERIC_READ | SYNCHRONIZE,
&oaParentFileAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_SYSTEM,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_RANDOM_ACCESS |
FILE_WRITE_THROUGH |
(Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS (ntStatus))
{
if (hParentDeviceFile != NULL)
ZwClose (hParentDeviceFile);
Dump ("Cannot open %ls\n", parentDrivePath);
goto error;
}
parentKeyDataOffset.QuadPart = ((volumeType == VOLUME_TYPE_HIDDEN) ? TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET : TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
ntStatus = ZwReadFile (hParentDeviceFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
readBuffer,
HEADER_SIZE,
&parentKeyDataOffset,
NULL);
if (hParentDeviceFile != NULL)
ZwClose (hParentDeviceFile);
}
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -