这里看下EncryptedIoQueueStart的处理
//创建3个线程来处理读写。
NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
{
NTSTATUS status;
EncryptedIoQueueBuffer *buffer;
int i;
queue->StartPending = TRUE;
queue->ThreadExitRequested = FALSE;
queue->OutstandingIoCount = 0;
queue->IoThreadPendingRequestCount = 0;
queue->FirstPoolBuffer = NULL;
KeInitializeMutex (&queue->BufferPoolMutex, 0);
KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE);
KeInitializeEvent (&queue->PoolBufferFreeEvent, SynchronizationEvent, FALSE);
KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE);
queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
if (!queue->FragmentBufferA)
goto noMemory;
queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
if (!queue->FragmentBufferB)
goto noMemory;
KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE);
KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE);
queue->ReadAheadBufferValid = FALSE;
queue->ReadAheadBuffer = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
if (!queue->ReadAheadBuffer)
goto noMemory;
// Preallocate buffers
for (i = 0; i < TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT; ++i)
{
if (i < TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT && !GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem)))
goto noMemory;
if (!GetPoolBuffer (queue, sizeof (EncryptedIoRequest)))
goto noMemory;
}
for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
{
buffer->InUse = FALSE;
}
// Main thread
InitializeListHead (&queue->MainThreadQueue);
KeInitializeSpinLock (&queue->MainThreadQueueLock);
KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
status = TCStartThread (MainThreadProc, queue, &queue->MainThread);
if (!NT_SUCCESS (status))
goto err;
// IO thread
InitializeListHead (&queue->IoThreadQueue);
KeInitializeSpinLock (&queue->IoThreadQueueLock);
KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
status = TCStartThread (IoThreadProc, queue, &queue->IoThread);
if (!NT_SUCCESS (status))
{
queue->ThreadExitRequested = TRUE;
TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
goto err;
}
// Completion thread
InitializeListHead (&queue->CompletionThreadQueue);
KeInitializeSpinLock (&queue->CompletionThreadQueueLock);
KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread);
if (!NT_SUCCESS (status))
{
queue->ThreadExitRequested = TRUE;
TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
goto err;
}
#ifdef TC_TRACE_IO_QUEUE
GetElapsedTimeInit (&queue->LastPerformanceCounter);
#endif
queue->StopPending = FALSE;
queue->StartPending = FALSE;
Dump ("Queue started\n");
return STATUS_SUCCESS;
noMemory:
status = STATUS_INSUFFICIENT_RESOURCES;
err:
if (queue->FragmentBufferA)
TCfree (queue->FragmentBufferA);
if (queue->FragmentBufferB)
TCfree (queue->FragmentBufferB);
FreePoolBuffers (queue);
queue->StartPending = FALSE;
return status;
}
到这里顺一下流程。
收到挂载通知后,驱动生成一个设备对象
然后创建一个线程处理卷的挂载,
线程中创建了3个线程
这里以MainThreadProc为例,来看看这个线程都做了什么
static VOID MainThreadProc (PVOID threadArg)
{
EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
PLIST_ENTRY listEntry;
EncryptedIoQueueItem *item;
LARGE_INTEGER fragmentOffset;
ULONG dataRemaining;
PUCHAR activeFragmentBuffer = queue->FragmentBufferA;
PUCHAR dataBuffer;
EncryptedIoRequest *request;
uint64 intersectStart;
uint32 intersectLength;
if (IsEncryptionThreadPoolRunning())
KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY); //设置优先级为低
while (!queue->ThreadExitRequested) //没有收到退出请求
{
if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL))) // EncryptedIoQueueAddIrp中设置这个事件 收到读写的时候
continue;
while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock))) // 从队列头取出一个数据
{
PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
if (queue->Suspended) //如果队列是暂停状态等待
KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL);
item = GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem));
item->Queue = queue;
item->OriginalIrp = irp;
item->Status = STATUS_SUCCESS;
IoSetCancelRoutine (irp, NULL); //设置了取消例程
if (irp->Cancel)
{
CompleteOriginalIrp (item, STATUS_CANCELLED, 0);
continue;
}
switch (irpSp->MajorFunction)
{
case IRP_MJ_READ:
item->Write = FALSE;
item->OriginalOffset = irpSp->Parameters.Read.ByteOffset;
item->OriginalLength = irpSp->Parameters.Read.Length;
break;
case IRP_MJ_WRITE:
item->Write = TRUE;
item->OriginalOffset = irpSp->Parameters.Write.ByteOffset;
item->OriginalLength = irpSp->Parameters.Write.Length;
break;
default:
CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
continue;
}
#ifdef TC_TRACE_IO_QUEUE
item->OriginalIrpOffset = item->OriginalOffset;
#endif
// Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices
if (queue->IsFilterDevice
&& !item->Write
&& item->OriginalLength > 0
&& (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0
&& (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
{
byte *buffer;
ULONG alignedLength = item->OriginalLength + ENCRYPTION_DATA_UNIT_SIZE;
LARGE_INTEGER alignedOffset;
alignedOffset.QuadPart = item->OriginalOffset.QuadPart & ~((LONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1);
buffer = TCalloc (alignedLength);
if (!buffer)
{
CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
continue;
}
item->Status = TCReadDevice (queue->LowerDeviceObject, buffer, alignedOffset, alignedLength);
if (NT_SUCCESS (item->Status))
{
UINT64_STRUCT dataUnit;
dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
if (!dataBuffer)
{
TCfree (buffer);
CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
continue;
}
if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1)
{
GetIntersection (alignedOffset.QuadPart, alignedLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
if (intersectLength > 0)
{
dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
DecryptDataUnits (buffer + (intersectStart - alignedOffset.QuadPart), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
}
}
memcpy (dataBuffer, buffer + (item->OriginalOffset.LowPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)), item->OriginalLength);
}
TCfree (buffer);
CompleteOriginalIrp (item, item->Status, NT_SUCCESS (item->Status) ? item->OriginalLength : 0);
continue;
}
// Validate offset and length
if (item->OriginalLength == 0
|| (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
|| (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
|| (!queue->IsFilterDevice && item->OriginalOffset.QuadPart + item->OriginalLength > queue->VirtualDeviceLength))
{
CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
continue;
}
#ifdef TC_TRACE_IO_QUEUE
Dump ("Q %I64d [%I64d] %c len=%d\n", item->OriginalOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), item->Write ? 'W' : 'R', item->OriginalLength);
#endif
if (!queue->IsFilterDevice)
{
// 校准偏移
if (queue->CryptoInfo->hiddenVolume)
item->OriginalOffset.QuadPart += queue->CryptoInfo->hiddenVolumeOffset;
else
item->OriginalOffset.QuadPart += queue->CryptoInfo->volDataAreaOffset;
// Hidden volume protection
if (item->Write && queue->CryptoInfo->bProtectHiddenVolume)
{
// If there has already been a write operation denied in order to protect the
// hidden volume (since the volume mount time)
if (queue->CryptoInfo->bHiddenVolProtectionAction)
{
// Do not allow writing to this volume anymore. This is to fake a complete volume
// or system failure (otherwise certain kinds of inconsistency within the file
// system could indicate that this volume has used hidden volume protection).
CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
continue;
}
// Verify that no byte is going to be written to the hidden volume area
if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart,
(unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1,
queue->CryptoInfo->hiddenVolumeOffset,
(unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1))
{
Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1);
queue->CryptoInfo->bHiddenVolProtectionAction = TRUE;
// Deny this write operation to prevent the hidden volume from being overwritten
CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
continue;
}
}
}
else if (item->Write
&& RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE - 1))
{
// Prevent inappropriately designed software from damaging important data that may be out of sync with the backup on the Rescue Disk (such as the end of the encrypted area).
Dump ("Preventing write to the system encryption key data area\n");
CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
continue;
}
else if (item->Write && IsHiddenSystemRunning()
&& (RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, SECTOR_SIZE, TC_BOOT_LOADER_AREA_SECTOR_COUNT * SECTOR_SIZE - 1)
|| RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, GetBootDriveLength(), _I64_MAX)))
{
Dump ("Preventing write to boot loader or host protected area\n");
CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
continue;
}
//前几个条件都进不去,直接到这里
dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
if (dataBuffer == NULL)
{
CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
continue;
}
// Divide data block to fragments to enable efficient overlapping of encryption and IO operations
//分割数据块成几个部分,以便更快的加密和io
dataRemaining = item->OriginalLength;
fragmentOffset = item->OriginalOffset;
while (dataRemaining > 0)
{
BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; //256*1024
ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; //如果大于256*1024 就用256*1024
分成几块操作
activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA);
InterlockedIncrement (&queue->IoThreadPendingRequestCount);
// Create IO request
request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest));
request->Item = item;
request->CompleteOriginalIrp = isLastFragment;
request->Offset = fragmentOffset;
request->Data = activeFragmentBuffer;
request->OrigDataBufferFragment = dataBuffer;
request->Length = dataFragmentLength;
if (queue->IsFilterDevice)
{
if (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1)
{
request->EncryptedLength = 0;
}
else
{
// Get intersection of data fragment with encrypted area
GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart;
request->EncryptedLength = intersectLength;
}
}
else
{
request->EncryptedOffset = 0;
request->EncryptedLength = dataFragmentLength;
}
//等待queue->FragmentBufferAFreeEvent被设置 在IoThreadProc中被设置
AcquireFragmentBuffer (queue, activeFragmentBuffer);
if (item->Write)
{
// Encrypt data 加密数据部分
memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength);
if (request->EncryptedLength > 0)
{
UINT64_STRUCT dataUnit;
ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
else if (queue->RemapEncryptedArea)
dataUnit.Value += queue->RemappedAreaDataUnitOffset;
EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
/*
void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci)
#ifndef TC_WINDOWS_BOOT
{
EncryptionThreadPoolDoWork (EncryptDataUnitsWork, buf, structUnitNo, nbrUnits, ci);
}
*/
}
}
// Queue IO request
ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
if (isLastFragment)
break;
dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
}
}
}
PsTerminateSystemThread (STATUS_SUCCESS);
}