WDM 실습 - Kernel 의 Device Extension

2007/11/30 21:44

1. User모드 와 통신
- 객체 : data(상태) - 따로 있어야 한다.
           함수(동작) - 모든 객체가 하나의 함수를 사용해도 된다.
- 드라이버는 하나가 있어도 되지만 실제 장치가 2개이상이 있다면 각 장치마다의 상태를 따로 관리해야 한다.
- 디바이스 Object 는 링크드 리스트로 각 장치의 상태(잉크잔량,종이)등을 저장하고 있다.
- 디바이스 Object는 버퍼하나를 가리키는 포인터를 하나 가지고 있다.( Device Extension ) 디바이스당 하나!!
- 심볼릭 링크를 사용하여 유저모드에서 접근을 가능하게 해준다. CreateFile() 로 접근할 수 있다.
WINOBJ.EXE


- ( WinObj 툴을 사용하여 확인 해볼 수 있다. ) : Global?? 심볼릭 링크..
 
1) Device Object 를 생성 : Device Extension을 정의 해주고 심볼릭 링크를 통해 얻어온다.
2) Unload는 반드시 디바이스 만들기 전에 지정 - 만들다 실패 했을 때 unload가 안되는 상황을 피한다.

예제소스 ~
ex1) 드라이버 소스 심볼릭을 만들어 준다. Device Extension 버퍼에 값을 넣어준다.
[ more.. | less.. ]
#include <ntddk.h>

// Device Object 이름 - UNICODE 사용 "
// \\Device\\원하는 이름" - 반드시 이 규칙대로..
#define DEVICE_NAME    L"\\Device\\WDM2"    // 커널모드로 접근

// Symbolic Link 에 사용할 이름 "\\DosDevice\\원하는 이름"
#define DOS_NAME    L"\\DosDevices\\Simple"    // 유저 모드로 접근

// 보관하고 싶은 것을 구조체로 만든다. 사용자가 정의 가능..
typedef struct _DEVICE_EXTENSION
{
    ULONG data;   

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject)
{
    UNICODE_STRING         ustrDosName;
    PDEVICE_OBJECT         pDeviceObject;
    PDEVICE_EXTENSION     pDeviceExtension;
   
    pDeviceObject      = pDriverObject->DeviceObject;
    pDeviceExtension = pDeviceObject->DeviceExtension;
   
    DbgPrint("[Wdm2] DriverUnload : %d", pDeviceExtension->data );
   
    RtlInitUnicodeString( &ustrDosName, DOS_NAME);

    // Symbolic link 파괴 - 이름만 알면 된다.
    IoDeleteSymbolicLink( &ustrDosName );
    // Device Object 파괴 - Device Object 포인터 전달..
    IoDeleteDevice( pDeviceObject );
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT  pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
   
    // 구조체 이므로 함수를 사용하여 초기화 한다.
    UNICODE_STRING    ustrName;
    UNICODE_STRING     ustrDosName;
   
    // 둘다 디바이스에 접근하기 위해 사용하는 포인터
    PDEVICE_OBJECT         pDeviceObject;    // 원래 있는 구조체
    PDEVICE_EXTENSION     pDeviceExtension;    // 사용자가 만든 구조체
   
    DbgPrint("[WDM2] DriverEntry");
       
    pDriverObject->DriverUnload = DriverUnload;
   
    // 문자열을 초기화 한다. 결국은 strcpy()
    RtlInitUnicodeString( &ustrName, DEVICE_NAME );
    RtlInitUnicodeString( &ustrDosName, DOS_NAME );

    // Device Object 를 장치당 1개씩 만들어야 한다.
    // 하지만 하드웨어와 관련 없는 경우... User와 통신하기 위해 1개만 만든다.
    status = IoCreateDevice( pDriverObject,            // 드라이버 Object( 함수 제공 )
                        sizeof( DEVICE_EXTENSION),    // Device EXTENSION 크기
                        &ustrName,                    // 이름
                        FILE_DEVICE_UNKNOWN,// 종류(마우스,키보드등등), 범용드라이버(UNKNOWN)
                        0,
                        TRUE,                          // H/W 관련..
                        &pDeviceObject);          // 완성된 구조체의 주소가 이리로 온다.

    DbgPrint( "address of DeviceObject : %p", pDeviceObject );
                            
    if ( ! NT_SUCCESS( status ) )
    {
        DbgPrint("[WDM2] Error IoCreateDevice");
        return status;
    }
   
    // 테스트를 위한 코드..
    pDeviceExtension = pDeviceObject->DeviceExtension;
    pDeviceExtension->data = 100;
   
    // User Mode 에서 접근하기 위해 별명(Symbolic link) 를 제공한다.
    // 디바이스 오브젝트의 별명을 하나 준다.
    status = IoCreateSymbolicLink( &ustrDosName, &ustrName);
   
    if ( ! NT_SUCCESS( status ) )
    {
        DbgPrint("[WDM2] Error IoCreateSymbolicLink");

        // 항상 나갈때는 삭제하고 가야한다. 드라이버는 위험하므로 꼭 지키자..
        IoDeleteDevice( pDeviceObject );
    }
    return status;
}


ex2) User Mode 에서 CreateFile 로 접근
[ more.. | less.. ]
#include <windows.h>
#include <stdio.h>
#include <conio.h>

int main() { char buf[1000];
    DWORD len;
    getch(); 
    HANDLE h = CreateFile("\\\\.\\SimpleWDM2",            
                    GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,        // share mode none
                    NULL,    // no security
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL );        // no template

    if (h == INVALID_HANDLE_VALUE) {
        printf("Failed to obtain file handle to device: SimpleWDM2 with Win32 error code: %d\n", GetLastError() );
        return 1;
    }

    getch();
    WriteFile( h, buf, 1000, &len, 0);

    getch();
    ReadFile( h, buf, 1000, &len, 0);

    getch();
    CloseHandle(h);
    getch();
}




Tags

WDM