没画完的画

喂马 劈柴 BBQ~
posts - 37, comments - 55, trackbacks - 0, articles - 0
  C++博客 ::  :: 新随笔 :: 联系 :: 聚合  :: 管理

关于 TrueCrypt 第5集

Posted on 2008-09-09 22:28 没画完的画 阅读(1206) 评论(0)  编辑 收藏 引用 所属分类: Windows Driver
08.09.09

终于创建一个设备,并且能与应用层通信

今天打算研究下,filedisk 是如何虚拟出一个分区出来的
首先看下 filedisk 在应用层的实现
 
filedisk 在应用层执行 Mount 时,调用 DeviceIoControl() 向驱动层发送 IOCTL_FILE_DISK_OPEN_FILE 指令
相关代码如下:
 
    if (!DeviceIoControl(
        Device,
        IOCTL_FILE_DISK_OPEN_FILE,
        OpenFileInformation,
        sizeof(OPEN_FILE_INFORMATION) + OpenFileInformation->FileNameLength - 1,
        NULL,
        0,
        &BytesReturned,
        NULL
        ))
    {
        PrintLastError("FileDisk:");
        DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);
        return -1;
    }
 
现在需要来看一下,驱动层在收到 IOCTL_FILE_DISK_OPEN_FILE  指令时,干了哪些事
看了 .sys 的实现,没看出个所以然
 
再次 Google 了一下
1. 创建设备 DriverEntry 创建类型为 FILE_DEVICE_DISK_FILE_SYSTEM 的设备
3. 在IRP_MJ_DEVICE_CONTROL中需要响应几个系统要求的IOCTL:
IOCTL_DISK_GET_DRIVE_GEOMETRY   (需要引入 #include <ntdddisk.h>  头文件 )
IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_IS_WRITABLE
IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_VERIFY
IOCTL_DISK_CHECK_VERIFY
 
接下来,重写 DeviceControl() 处理系统要求的 IOCTL
发现响应上述的IRP也不会显示出一个“虚拟分区”
……
(经过长时间的的折腾……折腾……折腾……)
……
 
找到 DefineDosDevice() API函数
 
DefineDosDevice(0,  "g:",  "c:\\");
这句语句就相当于 Windows 下面的 subst 命令了 
cmd:> subst g: c:\
 
将应用层的代码修改为
 
void mount()
{
    
if (!DefineDosDevice(DDD_RAW_TARGET_PATH, "x:",
        
"\\\\.\\SimpleDriver"
        ))
    
{
        printf(
"DefineDosDevice Error ErrCode = %d", ::GetLastError());
    }

    
else
    
{
        printf(
"DefineDosDevice OK ErrCode = %d", ::GetLastError());
    }

}
  

int main(int argc, char *argv[])
{  
    mount();
    
return 0;
}


虽然显示 DefindDosDevice OK ErrCode = 0
但依然不能在我的电脑里显示分区
查了相关资料,发现
应用层的 DefineDosDevice() 函数相当于 内核的 IoCreateSymbolicLink() 函数
不如试下直接在驱动层创建
于是修改了内核的函数试一下
 
#define DEVICE_NAME               L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME   L"\\x:"
 
加载驱动后,并没有显示设备,用 winobj 查看, 在设备路径的根目录下确实多了 x:
但还是没有显示设备
再修改为:
 
#define DEVICE_NAME      L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\\\.\\x:"
 
加载驱动时,提示“卷标,路径不合法”,用 Winobj查看,设备创建了,显然是 IoCreateSymbolicLink() 创建失败
 
再再修改为:
#define DEVICE_NAME      L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\DosDevices\\x:"
 
创建的符号在设备路径 \Global??\  下面,
 
Description:
Name: \GLOBAL??\x:
Type:  SymbolicLink
To:     \DosDevices\SimpleDriver
Count: 135
 
看到 C: 盘的符号也是在这个目录下面,但为何 X: 盘为何没有在我的电脑中显示?
运行 cmd.exe 输入 X:
可以把路径切换到 X:
但执行 dir 时,显示函数不正确,这显然是没有处理相应的 IRP 的缘故
 
处理了上述的 IRP 依然不显示 X: 盘出来
 
于是 加上
    DriverObject->MajorFunction[IRP_MJ_READ]           = FileDiskReadWrite;
    DriverObject->MajorFunction[IRP_MJ_WRITE]          = FileDiskReadWrite;
试试

#include <ntddk.h>
#include 
<ntdddisk.h>

#define DEVICE_NAME      L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\DosDevices\\X:"

#define SECTOR_SIZE             512

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
VOID     DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

#pragma code_seg(
"INIT")

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{   
    NTSTATUS status 
= STATUS_SUCCESS; 
    UNICODE_STRING uniNameString;
    UNICODE_STRING uniLinkString;
    DEVICE_OBJECT 
*pCDO = NULL;
    
    KdPrint((
"SimpleDriver!DriverEntry \n"));
    
    RtlInitUnicodeString(
&uniNameString, DEVICE_NAME);
    status 
= IoCreateDevice(DriverObject, 0&uniNameString, FILE_DEVICE_DISK_FILE_SYSTEM, 

FILE_DEVICE_SECURE_OPEN, FALSE, 
&pCDO);

    
if!NT_SUCCESS(status) )
        
return status; 
    
    RtlInitUnicodeString(
&uniLinkString, DEVICE_LINK_NAME);
    status 
= IoCreateSymbolicLink(&uniLinkString, &uniNameString);

    
if(!NT_SUCCESS(status))
        
return status;                                          

    DriverObject
->DriverUnload = DriverUnload;
    DriverObject
->MajorFunction[IRP_MJ_CREATE]         = DeviceCreateClose;
    DriverObject
->MajorFunction[IRP_MJ_CLOSE]          = DeviceCreateClose;
    DriverObject
->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
    
    DriverObject
->MajorFunction[IRP_MJ_READ]           = DeviceReadWrite;
    DriverObject
->MajorFunction[IRP_MJ_WRITE]          = DeviceReadWrite;
    
    
return STATUS_SUCCESS;
}


#pragma code_seg(
"PAGE")

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    UNICODE_STRING uniNameString;

    PAGED_CODE();
    
    KdPrint((
"SimpleDriver!DriverUnload \n"));

    RtlInitUnicodeString(
&uniNameString, DEVICE_LINK_NAME);
    IoDeleteSymbolicLink(
&uniNameString);

    IoDeleteDevice(DriverObject
->DeviceObject);
}


NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    PAGED_CODE();

    KdPrint((
"SimpleDriver!DeviceCreateClose \n"));

    Irp
->IoStatus.Status = STATUS_SUCCESS;
    Irp
->IoStatus.Information = FILE_OPENED;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    
return STATUS_SUCCESS;
}


NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS status 
= STATUS_SUCCESS;
    ULONG nIoCtrlCodes 
= 0;  // IO控制码
    PIO_STACK_LOCATION IrpStack = NULL;   //IRP堆栈
        
    KdPrint((
"SimpleDriver!DeviceControl \n"));
    
    
//得到当前调用者的IRP 
    IrpStack = IoGetCurrentIrpStackLocation(Irp);   
    
    nIoCtrlCodes 
= IrpStack->Parameters.DeviceIoControl.IoControlCode;
    
    KdPrint((
"SimpleDriver!DeviceControl IoControlCode = 0x%X\n", nIoCtrlCodes));
    
    
switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )
    
{
        
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
        
{
              PDISK_GEOMETRY  disk_geometry;
            ULONGLONG       length;

            
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof

(DISK_GEOMETRY))
            
{
                Irp
->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
                Irp
->IoStatus.Information = 0;
                
break;
            }


            disk_geometry 
= (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
            
            
// #define SECTOR_SIZE             512
            disk_geometry->Cylinders.QuadPart = 41940668416 / SECTOR_SIZE / 32 / 2;
            disk_geometry
->MediaType = FixedMedia;
            disk_geometry
->TracksPerCylinder = 2;
            disk_geometry
->SectorsPerTrack = 32;
            disk_geometry
->BytesPerSector = SECTOR_SIZE;

            Irp
->IoStatus.Information = sizeof(DISK_GEOMETRY);
            Irp
->IoStatus.Status = STATUS_SUCCESS;
        }

        
break;
        
        
case IOCTL_DISK_GET_PARTITION_INFO:
        
{
              PPARTITION_INFORMATION  partition_information;
            ULONGLONG               length;

            
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof

(PARTITION_INFORMATION))
            
{
                Irp
->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
                Irp
->IoStatus.Information = 0;
                
break;
            }


            partition_information 
= (PPARTITION_INFORMATION) Irp-

>AssociatedIrp.SystemBuffer;

            partition_information
->StartingOffset.QuadPart = 0;
            partition_information
->PartitionLength.QuadPart = 41940668416;
            partition_information
->HiddenSectors = 1;
            partition_information
->PartitionNumber = 0;
            partition_information
->PartitionType = 0;
            partition_information
->BootIndicator = FALSE;
            partition_information
->RecognizedPartition = FALSE;
            partition_information
->RewritePartition = FALSE;

            Irp
->IoStatus.Status = STATUS_SUCCESS;
            Irp
->IoStatus.Information = sizeof(PARTITION_INFORMATION);
        }

        
break;
        
        
case IOCTL_DISK_IS_WRITABLE:
        
{
              Irp
->IoStatus.Status = STATUS_SUCCESS;
            Irp
->IoStatus.Information = 0;
            
break;
        }

        
break;
        
        
case IOCTL_DISK_SET_PARTITION_INFO:
        
{
            
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof

(SET_PARTITION_INFORMATION))
            
{
                  Irp
->IoStatus.Status = STATUS_INVALID_PARAMETER;
                Irp
->IoStatus.Information = 0;
                
break;
            }

            
            Irp
->IoStatus.Status = STATUS_SUCCESS;
            Irp
->IoStatus.Information = 0;

        }

        
break;
                
        
case IOCTL_DISK_VERIFY:
        
{
              PVERIFY_INFORMATION verify_information;

            
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof

(VERIFY_INFORMATION))
            
{
                Irp
->IoStatus.Status = STATUS_INVALID_PARAMETER;
                Irp
->IoStatus.Information = 0;
                
break;
            }


            verify_information 
= (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;

            Irp
->IoStatus.Status = STATUS_SUCCESS;
            Irp
->IoStatus.Information = verify_information->Length;

        }

        
break;
        
        
case IOCTL_DISK_CHECK_VERIFY:
        
{
            Irp
->IoStatus.Information = 0;            
            Irp
->IoStatus.Status = STATUS_SUCCESS;
        }

        
break;        
    }
;
    
    status 
= Irp->IoStatus.Status; 
    IoCompleteRequest(Irp, IO_NO_INCREMENT); 

    
return status; 

}


NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    PIO_STACK_LOCATION  io_stack;

    io_stack 
= IoGetCurrentIrpStackLocation(Irp);

    
if (io_stack->Parameters.Read.Length == 0)
    
{
        Irp
->IoStatus.Status = STATUS_SUCCESS;
        Irp
->IoStatus.Information = 0;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        
return STATUS_SUCCESS;
    }


    IoMarkIrpPending(Irp);

    
return STATUS_PENDING;
}


#pragma code_seg()

还是在我的电脑中没有显示 X: 盘出来
 
5集 终

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理