没画完的画

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

关于 TrueCrypt 第4集

Posted on 2008-09-09 21:05 没画完的画 阅读(1608) 评论(2)  编辑 收藏 引用 所属分类: Windows Driver
08.09.05
 
昨天看了下在 应用层 与 驱动 进行通信的方法, 回想一下
1、CreateFile 打开设备
2、DeviceIoControl 发设备发送控制指令
3、CloseHandle 关闭设备
 
今天应该看下在 驱动.sys 需要做哪些东西,才可以在应用层使用 "设备路径" 来访问了
首先写一个不能再简单的驱动先!
 
simpledriver.c
#include <ntddk.h>

#define DEVICE_NAME      L"\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\SimpleDriver_Link"

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
VOID     DriverUnload(IN PDRIVER_OBJECT DriverObject);

#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;

    
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);
}


#pragma code_seg()


sources
TARGETNAME=simpledriver
TARGETPATH
=OBJ
TARGETTYPE
=DRIVER
SOURCES
=simpledriver.c \

makefile
#
# DO NOT EDIT THIS FILE
!!! Edit .\sources. If you want to add a new source
# file to 
this component. This file merely indirects to the real make file
# that 
is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)\makefile.def

为了让 应用层 可以用 DeviceIoControl() 与应用程序通信,我们需要在 DriverEntry() 里设置
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;

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 = %d\n", nIoCtrlCodes));
    
    status 
= Irp->IoStatus.Status; 
    IoCompleteRequest(Irp, IO_NO_INCREMENT); 
    
return status; 
}


应用层的代码为:

#include <windows.h>
#include 
<winioctl.h>
#include 
<stdio.h>
  
BOOL talkWithDriver()
{
    HANDLE hDevice;    
    BOOL bResult;      
    DWORD junk;        
  
    hDevice 
= CreateFile("\\SimpleDriver",  // drive to open
                    0,                // no access to the drive
                    FILE_SHARE_READ | // share mode
                    FILE_SHARE_WRITE,
                    NULL,             
// default security attributes
                    OPEN_EXISTING,    // disposition
                    0,                // file attributes
                    NULL);            // do not copy file attributes
  
    
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
  printf(
"CreateFile Error ErrCode = %d", ::GetLastError());
        
return (FALSE);
    }

  
    bResult 
= DeviceIoControl(hDevice,     // device to be queried
                              IOCTL_DISK_GET_DRIVE_GEOMETRY,     // operation to perform
                              NULL, 0,               // no input buffer
                              NULL, 0,     // output buffer
                              &junk,                 // # bytes returned
                              (LPOVERLAPPED) NULL);  // synchronous I/O
 
 
if ( !bResult )
 
{
  printf(
"CreateFile Error ErrCode = %d", ::GetLastError());
  
return FALSE;
 }

  
    CloseHandle(hDevice);
  
    
return (bResult);
}

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


编译后的驱动 .sys 用 OSRLOADER.exe 工具加载成功
运行应用层的 .exe 时,则显示 CreateFile Error ErrCode = 2

找不到路径

尝试将应用层的CreateFile 的路径改为
\\SimpleDriver
\\\\SimpleDriver
\\\\.\\SimpleDriver
还是显示 CreateFile Error ErrCode = 2

CreateFile 打开失败的原因未知!编译后的驱动 .sys 用 OSRLOADER.exe 工具加载成功
运行应用层的 .exe 时,则显示 CreateFile Error ErrCode = 2

找不到路径

尝试将应用层的CreateFile 的路径改为
\\\\SimpleDriver
\\\\.\\SimpleDriver
\\\\.\\SimpleDriver:
\\SimpleDriver
\\.\\SimpleDriver


结果还是显示 CreateFile Error ErrCode = 2

Google到了一个驱动的例子,按照例子里面的路径修改了一下
sys修改为:
#define DEVICE_NAME      L"\\DosDevices\\SimpleDriver"

app修改为:
CreateFile("\\\\.\\SimpleDriver"

结果 CreateFile 调用后,GetLastErrorCode 得到的是 1,  (Incorrect function. )
再次 Google 才知道,需要写 IRP_MJ_CREATE 例程,才可以 CreateFile 成功
于是把代码改了一下 

.sys 代码

#include <ntddk.h>

#define DEVICE_NAME      L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\SimpleDriver_Link"

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);

#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;
    

    
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));
    
    status 
= Irp->IoStatus.Status; 
    IoCompleteRequest(Irp, IO_NO_INCREMENT); 

    
return status; 

}


#pragma code_seg()

应用层 exe 代码
#include <windows.h>
#include 
<winioctl.h>
#include 
<stdio.h>
  
BOOL talkWithDriver()
{
    HANDLE hDevice;    
    BOOL bResult;      
    DWORD junk;        
  
    hDevice 
= CreateFile("\\\\.\\SimpleDriver",  // drive to open
                    0,                // no access to the drive
                    FILE_SHARE_READ | // share mode
                    FILE_SHARE_WRITE,
                    NULL,             
// default security attributes
                    OPEN_EXISTING,    // disposition
                    0,                // file attributes
                    NULL);            // do not copy file attributes
  
    
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
        printf(
"\\\\.\\SimpleDriver CreateFile Error ErrCode = %d", ::GetLastError());
        
return (FALSE);
    }

  
    bResult 
= DeviceIoControl(hDevice,     // device to be queried
                              IOCTL_DISK_GET_DRIVE_GEOMETRY,     // operation to perform
                              NULL, 0,               // no input buffer
                              NULL, 0,     // output buffer
                              &junk,                 // # bytes returned
                              (LPOVERLAPPED) NULL);  // synchronous I/O
 
    
if ( !bResult )
    
{
        printf(
"DeviceIoControl Error ErrCode = %d", ::GetLastError());
        
return FALSE;
    }

        

    
if!CloseHandle(hDevice) );
    
{
        printf(
"CloseHandle Error ErrCode = %d", ::GetLastError());
        
return FALSE;
    }


    
return (bResult);
}

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


重新用 OSRLOADER.exe 加载驱动,终于 CreateFile 成功了
Windbg 调试显示

SimpleDriver!DriverEntry
SimpleDriver!DeviceCreateClose
SimpleDriver!DeviceControl
SimpleDriver!DeviceControl IoControlCode = 0x70000
SimpleDriver!DeviceCreateClose
SimpleDriver!DriverUnload

但让我奇怪的是
应用层显示:
CloseHandle Error ErrCode = 0

CloseHandle 返回 FALSE, 但 GetLastError 得到的是 0

1、驱动层与应用层 的设备路径是如何对应的?
     驱动层创建的设备路径是
\\DosDevices\\SimpleDriver
     而对应的应用层的路径是 \\\\.\\SimpleDriver
     为何会跟驱动层的不一致?
--  Thx 网友 Bill Gates

    你完全理解错了device name和symbolic link name的意义。
    用winobj看下你机器上的kernel namespace。

    应用层如果用CreateFile,只能访问到\\??下的路径。如果用ZwCreateFile,可以访问整个命名空间。

2、CloseHandle() 为何会调用失败,而返回的 LastErrorCode 为0 ?
-- 未解决

Feedback

# re: 关于 TrueCrypt 第4集   回复  更多评论   

2008-09-09 16:38 by Bill Gates
你完全理解错了device name和symbolic link name的意义。
用winobj看下你机器上的kernel namespace。

应用层如果用CreateFile,只能访问到\\??下的路径。如果用ZwCreateFile,可以访问整个命名空间。

# re: 关于 TrueCrypt 第4集   回复  更多评论   

2008-09-09 21:07 by 没画完的画
Thx 网友 Bill Gates 的关注与帮助