1. CreateFile(), WriteFile(), ReadFile(), CloseHandle() 를 Dispatch
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\WDM3"
#define DOS_NAME L"\\DosDevices\\SimpleWDM3"
// non-paged pool
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pDeviceObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
/**********************************************************
* Dispatch Routine
**********************************************************/
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) // 사용자가 전달한 인자가 있다...
{
DbgPrint("[WDM3] CreateFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM3] CloseHandle() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM3] ReadFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM3] WriteFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING ustrDosName;
PDEVICE_OBJECT pDeviceObject;
pDeviceObject = pDriverObject->DeviceObject;
DbgPrint("[WDM3] DriverUnload");
RtlInitUnicodeString( &ustrDosName, DOS_NAME);
IoDeleteSymbolicLink( &ustrDosName );
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("[WDM3] DriverEntry");
RtlInitUnicodeString( &ustrName, DEVICE_NAME );
RtlInitUnicodeString( &ustrDosName, DOS_NAME );
// Unload는 반드시 디바이스 만들기 전에 지정 - 만들다 실패 했을 때 unload가 안되는 상황을 피한다.
pDriverObject->DriverUnload = DriverUnload;
status = IoCreateDevice( pDriverObject,
sizeof( DEVICE_EXTENSION),
&ustrName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObject);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM3] Error IoCreateDevice");
return status;
}
status = IoCreateSymbolicLink( &ustrDosName, &ustrName);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM3] Error IoCreateSymbolicLink");
IoDeleteDevice( pDeviceObject );
}
pDeviceObject->Flags |= DO_BUFFERED_IO;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
return status;
}
2. Bufferd I/O 를 사용한 Dispatch
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\WDM3_1"
#define DOS_NAME L"\\DosDevices\\SimpleWDM3_1"
#define MAX_BUF 256
typedef struct _DEVICE_EXTENSION
{
ULONG ulSize;
char strBuffer[MAX_BUF];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
/**********************************************************
* Dispatch Routine
**********************************************************/
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM3_1] CreateFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM3_1] CloseHandle() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
PDEVICE_EXTENSION pDevExt = pDevObj->DeviceExtension;
PIO_STACK_LOCATION pIo = IoGetCurrentIrpStackLocation(pIrp);
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
ULONG ulSize = pIo->Parameters.Read.Length;
DbgPrint("[WDM3_1] ReadFile() is Called");
// 작은 버퍼를 보낸경우.
if ( ulSize < pDevExt->ulSize )
{
pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
pIrp->IoStatus.Information = ulSize;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return 0;
}
RtlCopyMemory( pBuffer, pDevExt->strBuffer, pDevExt->ulSize );
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = pDevExt->ulSize;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
PDEVICE_EXTENSION pDevExt = pDevObj->DeviceExtension;
// IRP 구조체안에 있는 IO_STACK_LOCATIONI 의 주소를 구한다.
PIO_STACK_LOCATION pIo = IoGetCurrentIrpStackLocation(pIrp);
// 사용자가 전달한 버퍼의 복사본의 주소.
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
// 버퍼의 크기.
ULONG ulSize = pIo->Parameters.Write.Length;
DbgPrint("[WDM3_1] WriteFile : %s", pBuffer);
if ( ulSize > MAX_BUF ) ulSize = MAX_BUF;
RtlZeroMemory( pDevExt->strBuffer, 0);
RtlCopyMemory( pDevExt->strBuffer, pBuffer, ulSize );
pDevExt->ulSize = ulSize;
pIrp->IoStatus.Status = STATUS_SUCCESS; // 성공.. WriteFile(,&len)이 TRUE 리턴.
pIrp->IoStatus.Information = ulSize; // 실제 성공한 크기.
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING ustrDosName;
PDEVICE_OBJECT pDeviceObject;
pDeviceObject = pDriverObject->DeviceObject;
DbgPrint("[WDM3_1] DriverUnload");
RtlInitUnicodeString( &ustrDosName, DOS_NAME);
IoDeleteSymbolicLink( &ustrDosName );
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;
DbgPrint("[WDM3_1] DriverEntry");
RtlInitUnicodeString( &ustrName, DEVICE_NAME );
RtlInitUnicodeString( &ustrDosName, DOS_NAME );
// Dispatch Routine
pDriverObject->DriverUnload = DriverUnload;
status = IoCreateDevice( pDriverObject,
sizeof( DEVICE_EXTENSION),
&ustrName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObject);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM3_1] Error IoCreateDevice");
return status;
}
status = IoCreateSymbolicLink( &ustrDosName, &ustrName);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM3_1] Error IoCreateSymbolicLink");
IoDeleteDevice( pDeviceObject );
}
// DeviceObject 안에 버퍼 전달 방식을 지정한다.
pDeviceObject->Flags |= DO_BUFFERED_IO;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
return status;
}
3. DeviceIoControl 을 사용한 Dispatch
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\WDM4"
#define DOS_NAME L"\\DosDevices\\SimpleWDM4"
#define MAX_BUF 256
typedef struct _DEVICE_EXTENSION
{
ULONG ulSize;
char strBuffer[MAX_BUF];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// IOCTL Code - DeviceIoControl..
#define IOCTL_TEST_CODE CTL_CODE( FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
/**********************************************************
* Dispatch Routine
**********************************************************/
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM4] CreateFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM4] CloseHandle() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
NTSTATUS DispatchDeviceIoControl( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
PIO_STACK_LOCATION pIoStk = IoGetCurrentIrpStackLocation( pIrp );
ULONG ctlCode = pIoStk->Parameters.DeviceIoControl.IoControlCode;
ULONG inSize = pIoStk->Parameters.DeviceIoControl.InputBufferLength;
ULONG outSize = pIoStk->Parameters.DeviceIoControl.OutputBufferLength;
// 복사된 버퍼는 한개 이다. 처음에 input buffer를 복사해 놓고
// 읽어서 사용한 후에
// User에게 보내고 싶은 data역시 이 버퍼에 담아 주면 된다.
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
NTSTATUS status = STATUS_SUCCESS;
ULONG dwSize = 0;
switch( ctlCode )
{
case IOCTL_TEST_CODE:
{
DbgPrint("IOCTL_TEST_CODE : %s", pBuffer);
if ( inSize > outSize )
{
status = STATUS_BUFFER_TOO_SMALL;
dwSize = 0;
}
else
{
dwSize = inSize;
}
}
}
DbgPrint("[WDM4] DeviceIoControl() is Called");
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = dwSize;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//===========================================================
VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING ustrDosName;
PDEVICE_OBJECT pDeviceObject;
pDeviceObject = pDriverObject->DeviceObject;
DbgPrint("[WDM4] DriverUnload");
RtlInitUnicodeString( &ustrDosName, DOS_NAME);
IoDeleteSymbolicLink( &ustrDosName );
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;
DbgPrint("[WDM4] DriverEntry");
RtlInitUnicodeString( &ustrName, DEVICE_NAME );
RtlInitUnicodeString( &ustrDosName, DOS_NAME );
status = IoCreateDevice( pDriverObject,
sizeof( DEVICE_EXTENSION),
&ustrName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObject);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM4] Error IoCreateDevice");
return status;
}
status = IoCreateSymbolicLink( &ustrDosName, &ustrName);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM4] Error IoCreateSymbolicLink");
IoDeleteDevice( pDeviceObject );
}
pDeviceObject->Flags |= DO_BUFFERED_IO;
// Dispatch Routine
pDriverObject->DriverUnload = DriverUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl;
return status;
}
4. IRP_MJ_DEVICE_CONTROL( DispatchDeviceIoControl ) 사용한 Dispatch ( Event )
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\WDM4_1"
#define DOS_NAME L"\\DosDevices\\SimpleWDM4_1"
#define MAX_BUF 256
typedef struct _DEVICE_EXTENSION
{
ULONG ulSize;
char strBuffer[MAX_BUF];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// IOCTL Code
#define IOCTL_START CTL_CODE( FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
PVOID g_pEventObject = 0;
/**********************************************************
* Dispatch Routine
**********************************************************/
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM4] CreateFile() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
DbgPrint("[WDM4] CloseHandle() is Called");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID foo( HANDLE ParentID, HANDLE ProcessID, BOOLEAN b)
{
DbgPrint("foo");
KeSetEvent( g_pEventObject, 0, FALSE ); // 커널에서 Event를 signal 하는 함수..
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
NTSTATUS DispatchDeviceIoControl( IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
PIO_STACK_LOCATION pIoStk = IoGetCurrentIrpStackLocation( pIrp );
ULONG ctlCode = pIoStk->Parameters.DeviceIoControl.IoControlCode;
ULONG inSize = pIoStk->Parameters.DeviceIoControl.InputBufferLength;
ULONG outSize = pIoStk->Parameters.DeviceIoControl.OutputBufferLength;
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
NTSTATUS status = STATUS_SUCCESS;
ULONG dwSize = 0;
OBJECT_HANDLE_INFORMATION objHandleInfo;
HANDLE hEvent;
switch( ctlCode )
{
case IOCTL_START:
{
// User에서 Event를 보낸다고 생각한다.
hEvent = *((HANDLE*)pBuffer);
// Event 핸들을 가지고 KEVENT 구조체의 주소로 변경한다.
status = ObReferenceObjectByHandle( hEvent, GENERIC_ALL,
NULL, KernelMode,
&g_pEventObject, &objHandleInfo);
if ( status != STATUS_SUCCESS)
{
DbgPrint("Error ObReferenceObjectByHandle");
break;
}
// 프로세스가 생성되거나 종료될떄 호출되는 함수..
PsSetCreateProcessNotifyRoutine( foo, FALSE);
}
break;
}
DbgPrint("[WDM4] DeviceIoControl() is Called");
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = dwSize;
IoCompleteRequest( pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//===========================================================
VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING ustrDosName;
PDEVICE_OBJECT pDeviceObject;
pDeviceObject = pDriverObject->DeviceObject;
PsSetCreateProcessNotifyRoutine( foo, TRUE );
if ( g_pEventObject )
ObDereferenceObject( g_pEventObject );
DbgPrint("[WDM4_1] DriverUnload");
RtlInitUnicodeString( &ustrDosName, DOS_NAME);
IoDeleteSymbolicLink( &ustrDosName );
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;
DbgPrint("[WDM4_1] DriverEntry");
RtlInitUnicodeString( &ustrName, DEVICE_NAME );
RtlInitUnicodeString( &ustrDosName, DOS_NAME );
status = IoCreateDevice( pDriverObject,
sizeof( DEVICE_EXTENSION),
&ustrName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObject);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM4_1] Error IoCreateDevice");
return status;
}
status = IoCreateSymbolicLink( &ustrDosName, &ustrName);
if ( ! NT_SUCCESS( status ) )
{
DbgPrint("[WDM4_1] Error IoCreateSymbolicLink");
IoDeleteDevice( pDeviceObject );
}
pDeviceObject->Flags |= DO_BUFFERED_IO;
// Dispatch Routine
pDriverObject->DriverUnload = DriverUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl;
return status;
}