/..

#CONTENT

#TOP

main.cC
// Based off of `sioctl.c` driver example in the WDK

//
// Include files.
//

#include <ntddk.h> // various NT definitions
#include <string.h>
#include "interface.h"



#define DRIVER_FUNC_INSTALL 0x01
#define DRIVER_FUNC_REMOVE 0x02

#define DRIVER_NAME "FileUtilityDriver"

#define NT_DEVICE_NAME L"\\Device\\FileUtility"
#define DOS_DEVICE_NAME L"\\DosDevices\\FileUtility"

#if DBG
#define FILEUTIL_KDPRINT(_x_) \
DbgPrint("FileUtil: ");\
DbgPrint _x_;

#else
#define FILEUTIL_KDPRINT(_x_)
#endif

//
// Device driver routine declarations.
//

DRIVER_INITIALIZE DriverEntry;

_Dispatch_type_(IRP_MJ_CREATE)
_Dispatch_type_(IRP_MJ_CLOSE)
DRIVER_DISPATCH FileUtilityCreateClose;

_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH FileUtilityDeviceControl;

DRIVER_UNLOAD FileUtilityUnloadDriver;

VOID
PrintIrpInfo(
PIRP Irp
);
VOID
PrintChars(
_In_reads_(CountChars) PCHAR BufferAddress,
_In_ size_t CountChars
);

#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( PAGE, FileUtilityCreateClose)
#pragma alloc_text( PAGE, FileUtilityDeviceControl)
#pragma alloc_text( PAGE, FileUtilityUnloadDriver)
#pragma alloc_text( PAGE, PrintIrpInfo)
#pragma alloc_text( PAGE, PrintChars)
#endif // ALLOC_PRAGMA


NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
/*++

Routine Description:
This routine is called by the Operating System to initialize the driver.

It creates the device object, fills in the dispatch entry points and
completes the initialization.

Arguments:
DriverObject - a pointer to the object that represents this device
driver.

RegistryPath - a pointer to our Services key in the registry.

Return Value:
STATUS_SUCCESS if initialized; an error otherwise.

--*/

{
NTSTATUS ntStatus;
UNICODE_STRING ntUnicodeString; // NT Device Name "\Device\FileUtility"
UNICODE_STRING ntWin32NameString; // Win32 Name "\DosDevices\FileUtility"
PDEVICE_OBJECT deviceObject = NULL; // ptr to device object

UNREFERENCED_PARAMETER(RegistryPath);

RtlInitUnicodeString(&ntUnicodeString, NT_DEVICE_NAME);

ntStatus = IoCreateDevice(
DriverObject, // Our Driver Object
0, // We don't use a device extension
&ntUnicodeString, // Device name "\Device\FileUtility"
FILE_DEVICE_UNKNOWN, // Device type
FILE_DEVICE_SECURE_OPEN, // Device characteristics
FALSE, // Not an exclusive device
&deviceObject); // Returned ptr to Device Object

if (!NT_SUCCESS(ntStatus))
{
FILEUTIL_KDPRINT(("Couldn't create the device object\n"));
return ntStatus;
}

//
// Initialize the driver object with this driver's entry points.
//

DriverObject->MajorFunction[IRP_MJ_CREATE] = FileUtilityCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FileUtilityCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileUtilityDeviceControl;
DriverObject->DriverUnload = FileUtilityUnloadDriver;

//
// Initialize a Unicode String containing the Win32 name
// for our device.
//

RtlInitUnicodeString(&ntWin32NameString, DOS_DEVICE_NAME);

//
// Create a symbolic link between our device name and the Win32 name
//

ntStatus = IoCreateSymbolicLink(
&ntWin32NameString, &ntUnicodeString);

if (!NT_SUCCESS(ntStatus))
{
//
// Delete everything that this routine has allocated.
//
FILEUTIL_KDPRINT(("Couldn't create symbolic link\n"));
IoDeleteDevice(deviceObject);
}


return ntStatus;
}


NTSTATUS
FileUtilityCreateClose(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++

Routine Description:

This routine is called by the I/O system when the FILEUTIL is opened or
closed.

No action is performed other than completing the request successfully.

Arguments:

DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.

Irp - a pointer to the I/O Request Packet for this request.

Return Value:

NT status code

--*/

{
UNREFERENCED_PARAMETER(DeviceObject);

PAGED_CODE();

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

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return STATUS_SUCCESS;
}

VOID
FileUtilityUnloadDriver(
_In_ PDRIVER_OBJECT DriverObject
)
/*++

Routine Description:

This routine is called by the I/O system to unload the driver.

Any resources previously allocated must be freed.

Arguments:

DriverObject - a pointer to the object that represents our driver.

Return Value:

None
--*/

{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniWin32NameString;

PAGED_CODE();

//
// Create counted string version of our Win32 device name.
//

RtlInitUnicodeString(&uniWin32NameString, DOS_DEVICE_NAME);


//
// Delete the link from our device name to a name in the Win32 namespace.
//

IoDeleteSymbolicLink(&uniWin32NameString);

if (deviceObject != NULL)
{
IoDeleteDevice(deviceObject);
}



}

NTSTATUS
FileUtilityDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)

/*++

Routine Description:

This routine is called by the I/O system to perform a device I/O
control function.

Arguments:

DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.

Irp - a pointer to the I/O Request Packet for this request.

Return Value:

NT status code

--*/

{
PIO_STACK_LOCATION irpSp;// Pointer to current stack location
NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success
ULONG inBufLength; // Input buffer length
ULONG outBufLength; // Output buffer length


UNREFERENCED_PARAMETER(DeviceObject);

PAGED_CODE();

irpSp = IoGetCurrentIrpStackLocation(Irp);
inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;

// OutputBuffer must be present and point to userspace, size needs to be checked by each handler individually to match the desired struct
if (!Irp->UserBuffer || (INT64)Irp->UserBuffer < 0) {
ntStatus = STATUS_INVALID_PARAMETER;
goto End;
}


// We know that InputBuffer is a file handle for all handlers. Fetch the actual object now
if (inBufLength) {
ntStatus = STATUS_INVALID_PARAMETER;
goto End;
}

HANDLE fileHandle = (HANDLE)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;

PFILE_OBJECT fileObject;
ntStatus = ObReferenceObjectByHandle(fileHandle, FILE_READ_ACCESS, *IoFileObjectType, UserMode, (PVOID*)&fileObject, NULL);
if (!NT_SUCCESS(ntStatus)) goto End;

#define CHECK_AND_CAST_OUTPUT(name, type) \
if (outBufLength != sizeof(type)) { \
ntStatus = STATUS_INFO_LENGTH_MISMATCH; \
ObDereferenceObject(fileHandle); \
goto End; \
} \
type* name = (type*) Irp->UserBuffer; \
memset(name, 0, sizeof(type))

//
// Determine which I/O control code was specified.
//
switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_FILEUTIL_METHOD_GET_ACCESS_INFORMATION: {
CHECK_AND_CAST_OUTPUT(info, FILEUTIL_ACCESS_INFORMATION);

info->ReadAccess = fileObject->ReadAccess;
info->WriteAccess = fileObject->WriteAccess;
info->DeleteAccess = fileObject->DeleteAccess;
ObDereferenceObject(fileObject);
}
case IOCTL_FILEUTIL_METHOD_GET_SHARING_INFORMATION: {
CHECK_AND_CAST_OUTPUT(info, FILEUTIL_SHARING_INFORMATION);
info->SharedRead = fileObject->SharedRead;
info->SharedWrite = fileObject->SharedWrite;
info->SharedDelete = fileObject->SharedDelete;

ObDereferenceObject(fileObject);
break;
}
case IOCTL_FILEUTIL_METHOD_GET_CACHING_INFORMATION: {
CHECK_AND_CAST_OUTPUT(info, FILEUTIL_CACHING_INFORMATION);

info->HasPrivateCache = !!fileObject->PrivateCacheMap;
if (fileObject->SectionObjectPointer) {
info->HasSectionAsData = !!fileObject->SectionObjectPointer->DataSectionObject;
info->HasSharedCache = !!fileObject->SectionObjectPointer->SharedCacheMap;
info->HasSectionAsImage = !!fileObject->SectionObjectPointer->ImageSectionObject;
}
ObDereferenceObject(fileObject);
break;
}
default:

//
// The specified I/O control code is unrecognized by this driver.
//

ntStatus = STATUS_INVALID_DEVICE_REQUEST;
FILEUTIL_KDPRINT(("ERROR: unrecognized IOCTL %x\n",
irpSp->Parameters.DeviceIoControl.IoControlCode));
ObDereferenceObject(fileObject);
break;
}

End:
//
// Finish the I/O operation by simply completing the packet and returning
// the same status as in the packet itself.
//

Irp->IoStatus.Status = ntStatus;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return ntStatus;
}