FreeBASIC  0.91.0
fbportio.c
Go to the documentation of this file.
1 /*
2  * Tiny Windows kernel driver to enable I/O ports access
3  * (currently 32bit only)
4  *
5  * This code (plus the .rc) is compiled into fbportio.sys, the driver binary
6  * that can be put into '%windir%\system32\drivers'. libfb includes the driver
7  * (as an array of bytes in a C module) and writes it back out as a file when
8  * it's needed at runtime.
9  */
10 
11 /*
12  * Many thanks to these useful references:
13  *
14  * http://www.beyondlogic.org/porttalk/porttalk.htm
15  * http://www.codeproject.com/system/kportII.asp
16  * http://www.logix4u.net/inpout32.htm
17  *
18  * This code was written to provide a tiny implementation of the theory described there.
19  */
20 
21 #include <ddk/ntddk.h>
22 #include "../fbportio.h"
23 
24 #define DEVICE_NAME L"\\Device\\fbportio"
25 #define DEVICE_DOS_NAME L"\\DosDevices\\fbportio"
26 #define IOPM_SIZE 0x2000
27 
28 typedef UCHAR IOPM[IOPM_SIZE];
29 
30 static IOPM *IOPM_map = NULL;
31 
32 __declspec(dllimport) NTSTATUS NTAPI PsLookupProcessByProcessId(IN HANDLE, OUT PEPROCESS *);
33 
34 /* some undocumented kernel API calls ;) */
35 __declspec(dllimport) void NTAPI Ke386SetIoAccessMap(int, IOPM *);
36 __declspec(dllimport) void NTAPI Ke386IoSetAccessProcess(PEPROCESS, int);
37 
38 static NTSTATUS STDCALL device_dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
39 {
40  Irp->IoStatus.Information = 0;
41  Irp->IoStatus.Status = STATUS_SUCCESS;
42  IoCompleteRequest(Irp, IO_NO_INCREMENT);
43  return STATUS_SUCCESS;
44 }
45 
46 static NTSTATUS STDCALL device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
47 {
48  PIO_STACK_LOCATION stack;
49  PULONG ldata;
50  PUSHORT sdata;
51  ULONG in_size, out_size;
52  ULONG written_bytes = 0;
53  NTSTATUS status;
54  struct _EPROCESS *process;
55 
56  stack = IoGetCurrentIrpStackLocation(Irp);
57  in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
58  out_size = stack->Parameters.DeviceIoControl.OutputBufferLength;
59  ldata = (PULONG) Irp->AssociatedIrp.SystemBuffer;
60  sdata = (PUSHORT) Irp->AssociatedIrp.SystemBuffer;
61 
62  switch (stack->Parameters.DeviceIoControl.IoControlCode) {
63  case IOCTL_GRANT_IOPM:
64  if (in_size < 4) {
65  status = STATUS_BUFFER_TOO_SMALL;
66  } else {
67  HANDLE pid = (HANDLE) ldata[0];
68  status = PsLookupProcessByProcessId(pid, &process);
69  if (NT_SUCCESS(status)) {
70  /* copy the IOPM bitmap to the process task state segment */
71  Ke386SetIoAccessMap(1, IOPM_map);
72  /* inform the kernel the process has a custom IOPM bitmap */
73  Ke386IoSetAccessProcess(process, 1);
74  status = STATUS_SUCCESS;
75  }
76  }
77  break;
78 
79  case IOCTL_GET_VERSION:
80  if (out_size < 2) {
81  status = STATUS_BUFFER_TOO_SMALL;
82  } else {
83  sdata[0] = FBPORTIO_VERSION;
84  written_bytes = 2;
85  status = STATUS_SUCCESS;
86  }
87  break;
88 
89  default:
90  status = STATUS_UNSUCCESSFUL;
91  break;
92  }
93 
94  Irp->IoStatus.Information = written_bytes;
95  Irp->IoStatus.Status = status;
96  IoCompleteRequest(Irp, IO_NO_INCREMENT);
97 
98  return status;
99 }
100 
101 static VOID STDCALL driver_unload(IN PDRIVER_OBJECT DriverObject)
102 {
103  WCHAR dos_name_buffer[] = DEVICE_DOS_NAME;
104 
105  UNICODE_STRING unicode_dos_name;
106 
107  if (IOPM_map) {
108  MmFreeNonCachedMemory(IOPM_map, sizeof(IOPM));
109  }
110 
111  RtlInitUnicodeString(&unicode_dos_name, dos_name_buffer);
112  IoDeleteSymbolicLink(&unicode_dos_name);
113  IoDeleteDevice(DriverObject->DeviceObject);
114 }
115 
116 NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
117 {
118  PDEVICE_OBJECT device_object;
119  NTSTATUS status;
120  WCHAR name_buffer[] = DEVICE_NAME;
121  WCHAR dos_name_buffer[] = DEVICE_DOS_NAME;
122  UNICODE_STRING unicode_name, unicode_dos_name;
123 
124  IOPM_map = MmAllocateNonCachedMemory(sizeof(IOPM));
125  if (!IOPM_map) {
126  return STATUS_INSUFFICIENT_RESOURCES;
127  }
128 
129  /* clear all bits of the IOPM map, granting access to all ports */
130  RtlZeroMemory(IOPM_map, sizeof(IOPM));
131  RtlInitUnicodeString(&unicode_name, name_buffer);
132  RtlInitUnicodeString(&unicode_dos_name, dos_name_buffer);
133 
134  status = IoCreateDevice(DriverObject, 0, &unicode_name, FILE_DEVICE_UNKNOWN,
135  0, FALSE, &device_object);
136  if (!NT_SUCCESS(status)) {
137  return status;
138  }
139 
140  status = IoCreateSymbolicLink(&unicode_dos_name, &unicode_name);
141  if (!NT_SUCCESS(status)) {
142  return status;
143  }
144 
145  DriverObject->MajorFunction[IRP_MJ_CREATE] = device_dispatch;
146  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = device_control;
147  DriverObject->DriverUnload = driver_unload;
148 
149  return STATUS_SUCCESS;
150 }