查看文章
 
TrueCrypt分析(3)
2010年07月21日 14:44

这里看下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);
}


类别:默认分类||添加到搜藏 |分享到i贴吧|浏览(443)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu