aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--LICENSE.txt21
-rw-r--r--README.md48
-rw-r--r--add_cert.bat24
-rw-r--r--build_driver.bat103
-rw-r--r--build_drivers.bat8
-rw-r--r--check_ddk.bat23
-rw-r--r--check_env.bat13
-rw-r--r--clean_driver.bat82
-rw-r--r--clean_drivers.bat8
-rw-r--r--setenv.bat20
-rw-r--r--sign.bat29
-rw-r--r--src/nt_path_converter/control_codes.h12
-rw-r--r--src/nt_path_converter/device.c185
-rw-r--r--src/nt_path_converter/device.h13
-rw-r--r--src/nt_path_converter/main.c22
-rw-r--r--src/nt_path_converter/makefile1
-rw-r--r--src/nt_path_converter/nt2dos.c142
-rw-r--r--src/nt_path_converter/nt2dos.h12
-rw-r--r--src/nt_path_converter/sources3
-rw-r--r--src/sysenter/main.c98
-rw-r--r--src/sysenter/makefile1
-rw-r--r--src/sysenter/sources3
-rw-r--r--src/test/device.c200
-rw-r--r--src/test/device.h13
-rw-r--r--src/test/main.c24
-rw-r--r--src/test/makefile1
-rw-r--r--src/test/sources3
28 files changed, 1117 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e7954f5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/bin/
+*.err
+*.log
+*.wrn
+obj*/
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..fbbdd68
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..68a0fd1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+# Windows drivers
+
+This is a collection of drivers for Windows 7, created to amuse and entertain.
+
+## Development
+
+### Prerequisites
+
+The drivers are compiled using the Windows Driver Kit Version 7.1.0.
+
+I've developed a set of batch files to facilitate building the drivers and cleaning after the build.
+The binaries are copied into the "bin" directory under the root directory.
+
+To set up the development environment, start a new `cmd` session, and run
+
+ C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1 fre WIN7 no_oacr
+
+Of course, you may want to modify `setenv.bat` parameters.
+For example, to compile under x86-64, call `setenv.bat` like this:
+
+ C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1 fre x64 WIN7 no_oacr
+
+Then navigate to the root directory and call `setenv.bat`:
+
+ setenv.bat
+
+### Code signing
+
+Driver binaries are signed using the self-verified certificate "Test Certificate" in "Test Certificate Store".
+You can create this certificate using `add_cert.bat` (but first make sure you've set up the development environment).
+To verify it's there, you can use the `certmgr.msc` utility.
+
+Driver binaries are automatically signed during builds, but you can also sign one manually by passing the path to a .sys file to `sign.bat`.
+
+### Build & clean
+
+To build every driver under the "src" directory, call `build_drivers.bat`.
+To build a particular driver, pass the path to the driver source directory to `build_driver.bat`.
+Driver binaries are copied to the "bin" directory.
+
+Cleaning after a driver build includes deleting log and object files in the driver source directory and deleting the binaries from the "bin" directory.
+To clean after every driver in the "src" directory, call `clean_drivers.bat`.
+To clean after a particular driver, pass the path to the driver source directory to `clean_driver.bat`.
+
+## Licensing
+
+This project, including all of the files and their contents, is licensed under the terms of the MIT License.
+See LICENSE.txt for details.
diff --git a/add_cert.bat b/add_cert.bat
new file mode 100644
index 0000000..90f851c
--- /dev/null
+++ b/add_cert.bat
@@ -0,0 +1,24 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+set cert_store=Test Certificate Store
+set cert_name=Test Certificate
+
+echo ============================ CERT INFO ============================
+echo Certificate store: "%cert_store%"
+echo Certificate name: "%cert_name%"
+echo ========================== END CERT INFO ==========================
+echo.
+echo ======================= ADDING CERTIFICATE ========================
+echo makecert.exe -$ individual -r -pe -ss "%cert_store%" -n CN="%cert_name%" "%cert_name%.cer"
+makecert.exe -$ individual -r -pe -ss "%cert_store%" -n CN="%cert_name%" "%cert_name%.cer" >nul || goto :add_cert_failure
+echo certmgr.exe /add "%cert_name%.cer" /s /r localMachine root
+certmgr.exe /add "%cert_name%.cer" /s /r localMachine root >nul || goto :add_cert_failure
+echo del "%cert_name%.cer"
+del "%cert_name%.cer" >nul || goto :add_cert_failure
+echo =================== ADDING CERTIFICATE SUCCESS ====================
+exit /b 0
+
+:add_cert_failure
+echo =================== ADDING CERTIFICATE FAILURE ====================
+exit /b %errorlevel%
diff --git a/build_driver.bat b/build_driver.bat
new file mode 100644
index 0000000..54ee32e
--- /dev/null
+++ b/build_driver.bat
@@ -0,0 +1,103 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+if [%1] == [] (
+ echo Usage: %~0 DRIVER_SRC_ROOT
+ exit /b 1
+)
+
+call check_env.bat || exit /b !errorlevel!
+call check_ddk.bat || exit /b !errorlevel!
+
+set driver_src_root=%~f1
+cd "%driver_src_root%"
+
+for /f %%i in ("%driver_src_root%") do (
+ set driver_name=%%~ni
+ set driver_dist_subdir=%%~dpi
+)
+
+call :make_relative driver_dist_subdir "%src_root%"
+
+set sys_dist_dir=%bin_root%\%target_platform%\%target_configuration%\%driver_dist_subdir%
+set pdb_dist_dir=%bin_root%\%target_platform%\%target_configuration%\%driver_dist_subdir%
+set lib_dist_dir=%lib_root%\%target_platform%\%target_configuration%\%driver_dist_subdir%
+
+echo =========================== DRIVER INFO ===========================
+echo Driver source directory: "%driver_src_root%"
+echo Driver name: "%driver_name%"
+echo ========================= END DRIVER INFO =========================
+echo.
+echo ============================== BUILD ==============================
+set LIBDISTDIR=%lib_dist_dir%
+build.exe /cegwZ
+if %errorlevel% equ 0 (
+ echo ========================== BUILD SUCCESS ==========================
+) else (
+ echo ========================== BUILD FAILURE ==========================
+ exit /b %errorlevel%
+)
+
+if [%_BUILDARCH%] == [x86] (
+ set sys_path=obj%BUILD_ALT_DIR%\i386\%driver_name%.sys
+ set pdb_path=obj%BUILD_ALT_DIR%\i386\%driver_name%.pdb
+ set lib_path=obj%BUILD_ALT_DIR%\i386\%driver_name%.lib
+) else (
+ set sys_path=obj%BUILD_ALT_DIR%\%_BUILDARCH%\%driver_name%.sys
+ set pdb_path=obj%BUILD_ALT_DIR%\%_BUILDARCH%\%driver_name%.pdb
+ set lib_path=obj%BUILD_ALT_DIR%\%_BUILDARCH%\%driver_name%.lib
+)
+
+echo.
+call "%root%\sign.bat" "%sys_path%" || exit /b !errorlevel!
+
+echo.
+echo ============================== DISTR ==============================
+call :distr_copy "%pdb_path%" "%pdb_dist_dir%" || goto :distr_failure
+call :distr_copy "%sys_path%" "%sys_dist_dir%" || goto :distr_failure
+if exist "%lib_path%" (
+ call :distr_copy "%lib_path%" || goto :distr_failure
+)
+echo ========================== DISTR SUCCESS ==========================
+exit /b
+
+:distr_mkdir
+if not exist "%~1\" (
+ echo mkdir "%~1"
+ mkdir "%~1" >nul || exit /b !errorlevel!
+)
+exit /b
+
+:distr_copy
+call :distr_mkdir "%~2" || exit /b !errorlevel!
+echo copy "%~1" "%~2"
+copy "%~1" "%~2" >nul || exit /b !errorlevel!
+exit /b
+
+:distr_failure
+echo ========================== DISTR FAILURE ==========================
+exit /b %errorlevel%
+
+:make_relative
+@setlocal enabledelayedexpansion
+set src=%~1
+if defined %1 set src=!%~1!
+set base=%~2
+if not defined base set base=%cd%
+for /f "tokens=*" %%a in ("%src%") do set src=%%~fa
+for /f "tokens=*" %%a in ("%base%") do set base=%%~fa
+set match=
+set c=
+for /f "tokens=*" %%a in ('echo.%base:\=^&echo.%') do (
+ set sub=!sub!%%a\
+ call set tmp=%%src:!sub!=%%
+ if "!tmp!" neq "!src!" (
+ set match=!sub!
+ ) else (
+ set upper=!upper!..\
+ )
+)
+set src=%upper%!src:%match%=!
+(endlocal
+if defined %1 (set %~1=%src%) else (echo.%src%))
+exit /b
diff --git a/build_drivers.bat b/build_drivers.bat
new file mode 100644
index 0000000..314cb6f
--- /dev/null
+++ b/build_drivers.bat
@@ -0,0 +1,8 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+for /f "delims=" %%i in ('dir /s sources /b') do (
+ set driver_src_root=%%~dpi
+ echo.
+ call build_driver.bat "!driver_src_root:~0,-1!" || exit /b !errorlevel!
+)
diff --git a/check_ddk.bat b/check_ddk.bat
new file mode 100644
index 0000000..d04f8b5
--- /dev/null
+++ b/check_ddk.bat
@@ -0,0 +1,23 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+call check_env.bat || exit /b !errorlevel!
+
+if [%BUILD_ALT_DIR%] == [] goto :ddk_not_set
+if [%_BUILDARCH%] == [] goto :ddk_not_set
+
+if not exist %root%\sign.bat (
+ echo Error: %solution_root%\sign.bat is missing ^(don^'t know how to sign drivers^)
+ exit /b 1
+)
+
+where build.exe >nul || goto :build_not_found
+exit /b 0
+
+:ddk_not_set
+echo Error: either %%BUILD_ALT_DIR%% or %%_BUILDARCH%% are not set ^(perhaps you forgot to set up the WinDDK environment^)
+exit /b 1
+
+:build_not_found
+echo Error: build.exe not found ^(perhaps you forgot to set up the WinDDK environment^)
+exit /b 1
diff --git a/check_env.bat b/check_env.bat
new file mode 100644
index 0000000..15271ec
--- /dev/null
+++ b/check_env.bat
@@ -0,0 +1,13 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+if [%root%] == [] goto :env_not_set
+if [%bin_root%] == [] goto :env_not_set
+if [%lib_root%] == [] goto :env_not_set
+if [%src_root%] == [] goto :env_not_set
+
+exit /b 0
+
+:env_not_set
+echo Error: either %%root%%, %%bin_root%%, %%lib_root%% or %%src_root%% are not set ^(perhaps you forgot to call setenv.bat^)
+exit /b 1
diff --git a/clean_driver.bat b/clean_driver.bat
new file mode 100644
index 0000000..24ddc9a
--- /dev/null
+++ b/clean_driver.bat
@@ -0,0 +1,82 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+if [%1] == [] (
+ echo Usage: %~0 DRIVER_SRC_ROOT
+ exit /b 1
+)
+
+call check_ddk.bat || exit /b !errorlevel!
+call check_env.bat || exit /b !errorlevel!
+
+set driver_src_root=%~f1
+cd "%driver_src_root%"
+
+for /f %%i in ("%driver_src_root%") do (
+ set driver_name=%%~ni
+ set driver_dist_root=%%~dpi
+)
+
+call :make_relative driver_dist_root "%src_root%"
+
+set sys_dist_dir=%bin_root%\%target_platform%\%target_configuration%\%dist_root%
+set pdb_dist_dir=%bin_root%\%target_platform%\%target_configuration%\%dist_root%
+set lib_dist_dir=%lib_root%\%target_platform%\%target_configuration%\%dist_root%
+
+echo =========================== DRIVER INFO ===========================
+echo Driver source directory: "%driver_src_root%"
+echo Driver name: "%driver_name%"
+echo ========================= END DRIVER INFO =========================
+echo.
+echo ============================== CLEAN ==============================
+call :clean_rmdir "obj%BUILD_ALT_DIR%" || goto :clean_failure
+call :clean_del "build%BUILD_ALT_DIR%.err" || goto :clean_failure
+call :clean_del "build%BUILD_ALT_DIR%.log" || goto :clean_failure
+call :clean_del "build%BUILD_ALT_DIR%.wrn" || goto :clean_failure
+call :clean_del "%sys_dist_dir%%driver_name%.sys" || goto :clean_failure
+call :clean_del "%pdb_dist_dir%%driver_name%.pdb" || goto :clean_failure
+call :clean_del "%lib_dist_dir%%driver_name%.lib" || goto :clean_failure
+echo ========================== CLEAN SUCCESS ==========================
+exit /b
+
+:clean_rmdir
+if exist "%~1\" (
+ echo rmdir /s /q "%~1"...
+ rmdir /s /q "%~1" >nul || exit /b !errorlevel!
+)
+exit /b
+
+:clean_del
+if exist "%~1" (
+ echo del "%~1"
+ del "%~1" >nul || exit /b !errorlevel!
+)
+exit /b
+
+:clean_failure
+echo ========================== CLEAN FAILURE ==========================
+exit /b %errorlevel%
+
+:make_relative
+@setlocal enabledelayedexpansion
+set src=%~1
+if defined %1 set src=!%~1!
+set base=%~2
+if not defined base set base=%cd%
+for /f "tokens=*" %%a in ("%src%") do set src=%%~fa
+for /f "tokens=*" %%a in ("%base%") do set base=%%~fa
+set match=
+set c=
+for /f "tokens=*" %%a in ('echo.%base:\=^&echo.%') do (
+ set sub=!sub!%%a\
+ call set tmp=%%src:!sub!=%%
+ if "!tmp!" neq "!src!" (
+ set match=!sub!
+ ) else (
+ set upper=!upper!..\
+ )
+)
+set src=%upper%!src:%match%=!
+(endlocal
+if defined %1 (set %~1=%src%) else (echo.%src%))
+exit /b
diff --git a/clean_drivers.bat b/clean_drivers.bat
new file mode 100644
index 0000000..aaae9ad
--- /dev/null
+++ b/clean_drivers.bat
@@ -0,0 +1,8 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+for /f "delims=" %%i in ('dir /s sources /b') do (
+ set driver_src_root=%%~dpi
+ echo.
+ call clean_driver.bat "!driver_src_root:~0,-1!" || exit /b !errorlevel!
+)
diff --git a/setenv.bat b/setenv.bat
new file mode 100644
index 0000000..72bf356
--- /dev/null
+++ b/setenv.bat
@@ -0,0 +1,20 @@
+@echo off
+
+set root=%~dp0%
+set src_root=%root%src
+set bin_root=%root%bin
+set lib_root=%root%lib
+
+set target_configuration=Release
+
+if [%_BUILDARCH%] == [AMD64] goto :target_platform_x64
+if [%_BUILDARCH%] == [x86] goto :target_platform_x86
+echo Unsupported %%_BUILDARCH%% (supported build architectures: AMD64, x86)
+exit /b -1
+
+:target_platform_x64
+set target_platform=x64
+exit /b 0
+:target_platform_x86
+set target_platform=x86
+exit /b 0
diff --git a/sign.bat b/sign.bat
new file mode 100644
index 0000000..a49bc39
--- /dev/null
+++ b/sign.bat
@@ -0,0 +1,29 @@
+@setlocal enabledelayedexpansion
+@echo off
+
+set cert_store=Test Certificate Store
+set cert_name=Test Certificate
+
+if [%1] == [] (
+ echo Usage: %0 SYS_PATH
+ exit /b 1
+)
+
+set sys_path=%~f1
+
+echo ============================ CERT INFO ============================
+echo Certificate store: "%cert_store%"
+echo Certificate name: "%cert_name%"
+echo ========================== END CERT INFO ==========================
+echo.
+echo ============================= SIGNING =============================
+echo signtool.exe sign /s "%cert_store%" /n "%cert_name%" "%sys_path%"
+signtool.exe sign /s "%cert_store%" /n "%cert_name%" "%sys_path%" >nul || goto :signing_failure
+echo signtool.exe verify /pa "%sys_path%"
+signtool.exe verify /pa "%sys_path%" >nul || goto :signing_failure
+echo ========================= SIGNING SUCCESS =========================
+exit /b 0
+
+:signing_failure
+echo ========================= SIGNING FAILURE =========================
+exit /b %errorlevel%
diff --git a/src/nt_path_converter/control_codes.h b/src/nt_path_converter/control_codes.h
new file mode 100644
index 0000000..b81de84
--- /dev/null
+++ b/src/nt_path_converter/control_codes.h
@@ -0,0 +1,12 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#pragma once
+
+#include <ntddk.h>
+
+#define CONVERT_NT_PATH CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/src/nt_path_converter/device.c b/src/nt_path_converter/device.c
new file mode 100644
index 0000000..90fcc98
--- /dev/null
+++ b/src/nt_path_converter/device.c
@@ -0,0 +1,185 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include "control_codes.h"
+#include "device.h"
+#include "nt2dos.h"
+
+#include <ntddk.h>
+
+static NTSTATUS device_open(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = 0;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ return status;
+}
+
+typedef NTSTATUS (*ioctl_handler)(void *, unsigned long,
+ void *, unsigned long,
+ ULONG_PTR *);
+
+static NTSTATUS handle_convert_nt_path(void *in_buf,
+ unsigned long in_buf_size,
+ void *out_buf,
+ unsigned long out_buf_size,
+ ULONG_PTR *nbwritten)
+{
+ UNICODE_STRING uUnresolved, uResolved;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ RtlInitUnicodeString(&uUnresolved, (WCHAR *) in_buf);
+ status = nt2dos(&uResolved, &uUnresolved);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ *nbwritten = uResolved.Length;
+
+ if (out_buf_size < uResolved.Length)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ goto FREE_RESOLVED;
+ }
+
+ RtlCopyMemory(out_buf, uResolved.Buffer, uResolved.Length);
+
+FREE_RESOLVED:
+ ExFreePool(uResolved.Buffer);
+
+ return status;
+}
+
+static NTSTATUS device_ioctl(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ IO_STACK_LOCATION *io_stack_loc;
+ void* in_buf, *out_buf;
+ unsigned long in_buf_size, out_buf_size;
+ ioctl_handler handler;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = 0;
+ io_stack_loc = IoGetCurrentIrpStackLocation(irp);
+
+ in_buf = out_buf = irp->AssociatedIrp.SystemBuffer;
+ in_buf_size = io_stack_loc->Parameters.DeviceIoControl.InputBufferLength;
+ out_buf_size = io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength;
+
+ switch (io_stack_loc->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case CONVERT_NT_PATH:
+ handler = handle_convert_nt_path;
+ break;
+ default:
+ status = irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ goto complete_request;
+ }
+
+ status = irp->IoStatus.Status = handler(in_buf, in_buf_size,
+ out_buf, out_buf_size,
+ &irp->IoStatus.Information);
+
+complete_request:
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+typedef struct
+{
+ const wchar_t *path;
+ const wchar_t *symlink;
+} device_info;
+
+typedef struct
+{
+ DEVICE_OBJECT *object;
+ UNICODE_STRING path;
+ UNICODE_STRING symlink;
+} device;
+
+#define NUMOF_DEVICES 1
+
+static device_info devices_info[NUMOF_DEVICES] =
+{
+ {
+ L"\\Device\\nt_path_converter",
+ L"\\DosDevices\\nt_path_converter",
+ },
+};
+
+static device devices[NUMOF_DEVICES];
+
+static void destroy_device(int i)
+{
+ IoDeleteSymbolicLink(&devices[i].symlink);
+ IoDeleteDevice(devices[i].object);
+}
+
+void destroy_devices()
+{
+ int i;
+ for (i = 0; i < NUMOF_DEVICES; ++i)
+ destroy_device(i);
+}
+
+static NTSTATUS set_up_device(DRIVER_OBJECT *driver_object, int i)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ RtlInitUnicodeString(&devices[i].path, devices_info[i].path);
+ RtlInitUnicodeString(&devices[i].symlink, devices_info[i].symlink);
+
+ status = IoCreateDevice(driver_object,
+ 0,
+ &devices[i].path,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &devices[i].object);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ devices[i].object->Flags |= DO_BUFFERED_IO;
+ devices[i].object->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ if (!NT_SUCCESS(status = IoCreateSymbolicLink(&devices[i].symlink,
+ &devices[i].path)))
+ goto delete_device;
+
+ return status;
+
+delete_device:
+ IoDeleteDevice(devices[i].object);
+
+ return status;
+}
+
+NTSTATUS set_up_devices(DRIVER_OBJECT *driver_object)
+{
+ int i, j;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ for (i = 0; i < NUMOF_DEVICES; ++i)
+ if (!NT_SUCCESS(status = set_up_device(driver_object, i)))
+ goto destroy_devices;
+
+ driver_object->MajorFunction[IRP_MJ_CREATE] = device_open;
+ driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = device_ioctl;
+
+ return status;
+
+destroy_devices:
+ for (j = 0; j < i; ++j)
+ destroy_device(j);
+
+ return status;
+}
diff --git a/src/nt_path_converter/device.h b/src/nt_path_converter/device.h
new file mode 100644
index 0000000..a5ecc31
--- /dev/null
+++ b/src/nt_path_converter/device.h
@@ -0,0 +1,13 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#pragma once
+
+#include <ntddk.h>
+
+NTSTATUS set_up_devices(DRIVER_OBJECT *);
+void destroy_devices();
diff --git a/src/nt_path_converter/main.c b/src/nt_path_converter/main.c
new file mode 100644
index 0000000..4d969de
--- /dev/null
+++ b/src/nt_path_converter/main.c
@@ -0,0 +1,22 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include "device.h"
+
+#include <ntddk.h>
+
+static void on_driver_unload(DRIVER_OBJECT *driver_object)
+{
+ destroy_devices();
+}
+
+NTSTATUS DriverEntry(DRIVER_OBJECT *driver_object,
+ UNICODE_STRING *registry_path)
+{
+ driver_object->DriverUnload = on_driver_unload;
+ return set_up_devices(driver_object);
+}
diff --git a/src/nt_path_converter/makefile b/src/nt_path_converter/makefile
new file mode 100644
index 0000000..5acbbd2
--- /dev/null
+++ b/src/nt_path_converter/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/nt_path_converter/nt2dos.c b/src/nt_path_converter/nt2dos.c
new file mode 100644
index 0000000..fb0fd80
--- /dev/null
+++ b/src/nt_path_converter/nt2dos.c
@@ -0,0 +1,142 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include <ntifs.h>
+
+#include "nt2dos.h"
+
+static NTSTATUS get_object_name_info(
+ void *object,
+ OBJECT_NAME_INFORMATION **object_name_info)
+{
+ unsigned long nbneeded;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = ObQueryNameString(object, NULL, 0, &nbneeded);
+ if (status != STATUS_INFO_LENGTH_MISMATCH)
+ return status;
+ *object_name_info = ExAllocatePoolWithTag(PagedPool, nbneeded, '1l');
+ if (*object_name_info == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ status = ObQueryNameString(object, *object_name_info, nbneeded, &nbneeded);
+ if (!NT_SUCCESS(status))
+ goto free_object_name_info;
+ return status;
+
+free_object_name_info:
+ ExFreePool(*object_name_info);
+
+ return status;
+}
+
+NTSTATUS nt2dos(UNICODE_STRING *u_resolved, UNICODE_STRING *u_unresolved)
+{
+ IO_STATUS_BLOCK io_status_block;
+ DEVICE_OBJECT *volume_object;
+ FILE_OBJECT *file_object;
+ HANDLE file;
+ OBJECT_ATTRIBUTES file_attrs;
+ OBJECT_NAME_INFORMATION *file_name_info, *volume_name_info;
+ UNICODE_STRING u_dos_name;
+ USHORT u_resolved_size;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ InitializeObjectAttributes(&file_attrs,
+ u_unresolved,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ NULL,
+ NULL);
+
+ status = ZwCreateFile(&file,
+ FILE_READ_ATTRIBUTES,
+ &file_attrs,
+ &io_status_block,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL, 0);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = ObReferenceObjectByHandle(file,
+ FILE_READ_ATTRIBUTES,
+ *IoFileObjectType,
+ KernelMode,
+ &file_object,
+ NULL);
+ if (!NT_SUCCESS(status))
+ goto close_file;
+
+ status = get_object_name_info(file_object, &file_name_info);
+ if (!NT_SUCCESS(status))
+ goto close_file;
+
+ if (file_object->Vpb == NULL)
+ {
+ u_resolved->Buffer = ExAllocatePoolWithTag(
+ PagedPool, file_name_info->Name.Length, '1l');
+ if (u_resolved->Buffer == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto free_file_name_info;
+ }
+
+ RtlInitEmptyUnicodeString(u_resolved,
+ u_resolved->Buffer,
+ file_name_info->Name.Length);
+ RtlCopyUnicodeString(u_resolved, &file_name_info->Name);
+ goto free_file_name_info;
+ }
+
+ volume_object = file_object->Vpb->RealDevice;
+ status = get_object_name_info(volume_object, &volume_name_info);
+
+ if (!NT_SUCCESS(status))
+ goto free_file_name_info;
+
+ status = IoVolumeDeviceToDosName(volume_object, &u_dos_name);
+ if (!NT_SUCCESS(status))
+ goto free_volume_name_info;
+
+ u_resolved_size = file_name_info->Name.Length
+ - volume_name_info->Name.Length
+ + u_dos_name.Length;
+
+ u_resolved->Buffer = ExAllocatePoolWithTag(
+ PagedPool, u_resolved_size, '1l');
+ if (u_resolved->Buffer == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto free_dos_name;
+ }
+
+ RtlInitEmptyUnicodeString(u_resolved, u_resolved->Buffer, u_resolved_size);
+
+ RtlCopyUnicodeString(u_resolved, &u_dos_name);
+ file_name_info->Name.Buffer +=
+ volume_name_info->Name.Length / sizeof(wchar_t);
+ file_name_info->Name.Length -=
+ volume_name_info->Name.Length;
+ RtlUnicodeStringCat(u_resolved, &file_name_info->Name);
+
+free_dos_name:
+ ExFreePool(u_dos_name.Buffer);
+
+free_volume_name_info:
+ ExFreePool(volume_name_info);
+
+free_file_name_info:
+ ExFreePool(file_name_info);
+
+close_file:
+ ZwClose(file);
+
+ return status;
+}
diff --git a/src/nt_path_converter/nt2dos.h b/src/nt_path_converter/nt2dos.h
new file mode 100644
index 0000000..495202d
--- /dev/null
+++ b/src/nt_path_converter/nt2dos.h
@@ -0,0 +1,12 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#pragma once
+
+#include <ntstrsafe.h>
+
+NTSTATUS nt2dos(UNICODE_STRING *resolved, UNICODE_STRING *unresolved);
diff --git a/src/nt_path_converter/sources b/src/nt_path_converter/sources
new file mode 100644
index 0000000..02a42cd
--- /dev/null
+++ b/src/nt_path_converter/sources
@@ -0,0 +1,3 @@
+TARGETTYPE = DRIVER
+TARGETNAME = nt_path_converter
+SOURCES = device.c main.c nt2dos.c
diff --git a/src/sysenter/main.c b/src/sysenter/main.c
new file mode 100644
index 0000000..24d3ac4
--- /dev/null
+++ b/src/sysenter/main.c
@@ -0,0 +1,98 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include <ntddk.h>
+
+static __int64 old_msr_value = 0;
+static void *old_ki_fast_call_entry = NULL;
+
+static void __stdcall log_system_call()
+{
+ static LONG count = 0;
+ static const LONG throttle = 10000;
+
+ LONG n = InterlockedIncrement(&count);
+
+ if (n % throttle == 0)
+ DbgPrint("Another %ld of `sysenter`s (eax=)!\n", throttle);
+}
+
+static void __declspec(naked) new_ki_fast_call_entry()
+{
+ __asm
+ {
+ pushad
+ pushfd
+ mov ecx, 0x23
+ push 0x30
+ pop fs
+ mov ds, cx
+ mov es, cx
+ call log_system_call
+ popfd
+ popad
+ jmp [old_ki_fast_call_entry]
+ }
+}
+
+#define IA32_SYSENTER_EIP 0x176
+
+static void hook_sysenter()
+{
+ /*
+ __asm
+ {
+ mov ecx, IA32_SYSENTER_EIP
+ rdmsr
+ mov old_ki_fast_call_entry, eax
+ mov eax, new_ki_fast_call_entry
+ xor edx, edx
+ wrmsr
+ }
+ */
+
+ old_msr_value = __readmsr(IA32_SYSENTER_EIP);
+ old_ki_fast_call_entry = (void *) old_msr_value;
+ __writemsr(IA32_SYSENTER_EIP, new_ki_fast_call_entry);
+}
+
+static void unhook_sysenter()
+{
+ /*
+ __asm
+ {
+ mov ecx, IA32_SYSENTER_EIP
+ mov eax, old_ki_fast_call_entry
+ xor edx, edx
+ wrmsr
+ }
+ */
+
+ __writemsr(IA32_SYSENTER_EIP, old_msr_value);
+}
+
+static void on_driver_unload(DRIVER_OBJECT *driver_object)
+{
+ KTIMER timer;
+ LARGE_INTEGER time_out;
+
+ unhook_sysenter();
+
+ KeInitializeTimer(&timer);
+ time_out.QuadPart = -30000000; // 3 sec
+ KeSetTimer(&timer, time_out, NULL);
+
+ KeWaitForSingleObject(&timer, Executive, KernelMode, FALSE, NULL);
+}
+
+NTSTATUS DriverEntry(DRIVER_OBJECT *driver_object,
+ UNICODE_STRING *registry_path)
+{
+ driver_object->DriverUnload = on_driver_unload;
+ hook_sysenter();
+ return STATUS_SUCCESS;
+}
diff --git a/src/sysenter/makefile b/src/sysenter/makefile
new file mode 100644
index 0000000..5acbbd2
--- /dev/null
+++ b/src/sysenter/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/sysenter/sources b/src/sysenter/sources
new file mode 100644
index 0000000..2a52870
--- /dev/null
+++ b/src/sysenter/sources
@@ -0,0 +1,3 @@
+TARGETTYPE = DRIVER
+TARGETNAME = sysenter
+SOURCES = main.c
diff --git a/src/test/device.c b/src/test/device.c
new file mode 100644
index 0000000..43ac3bc
--- /dev/null
+++ b/src/test/device.c
@@ -0,0 +1,200 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include "device.h"
+
+#include <ntddk.h>
+
+static NTSTATUS device_open(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = 0;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ return status;
+}
+
+typedef NTSTATUS (*ioctl_handler)(void *, unsigned long,
+ void *, unsigned long,
+ ULONG_PTR *);
+
+static NTSTATUS handle_say_hello(void *in_buf,
+ unsigned long in_buf_size,
+ void *out_buf,
+ unsigned long out_buf_size,
+ ULONG_PTR *nbwritten)
+{
+ DbgPrint("Hello, world!\n");
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS handle_exchange_ints(void *in_buf,
+ unsigned long in_buf_size,
+ void *out_buf,
+ unsigned long out_buf_size,
+ ULONG_PTR *nbwritten)
+{
+ unsigned int read;
+ unsigned int written = 0xdeadbeef;
+
+ if (in_buf_size != sizeof(read))
+ return STATUS_INVALID_BUFFER_SIZE;
+
+ RtlCopyMemory(&read, in_buf, in_buf_size);
+ DbgPrint("%08x\n", read);
+
+ if (out_buf_size < sizeof(written))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ RtlCopyMemory(out_buf, &written, sizeof(written));
+ *nbwritten += sizeof(written);
+
+ return STATUS_SUCCESS;
+}
+
+#define SAY_HELLO CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define EXCHANGE_INTS CTL_CODE(0x8001, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+static NTSTATUS device_ioctl(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ IO_STACK_LOCATION *io_stack_loc;
+ void* in_buf, *out_buf;
+ unsigned long in_buf_size, out_buf_size;
+ ioctl_handler handler;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = 0;
+ io_stack_loc = IoGetCurrentIrpStackLocation(irp);
+
+ in_buf = out_buf = irp->AssociatedIrp.SystemBuffer;
+ in_buf_size = io_stack_loc->Parameters.DeviceIoControl.InputBufferLength;
+ out_buf_size = io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength;
+
+ switch (io_stack_loc->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case SAY_HELLO:
+ handler = handle_say_hello;
+ break;
+ case EXCHANGE_INTS:
+ handler = handle_exchange_ints;
+ break;
+ default:
+ status = irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ goto complete_request;
+ }
+
+ status = irp->IoStatus.Status = handler(in_buf, in_buf_size,
+ out_buf, out_buf_size,
+ &irp->IoStatus.Information);
+
+complete_request:
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+typedef struct
+{
+ const wchar_t *path;
+ const wchar_t *symlink;
+} device_info;
+
+typedef struct
+{
+ DEVICE_OBJECT *object;
+ UNICODE_STRING path;
+ UNICODE_STRING symlink;
+} device;
+
+#define NUMOF_DEVICES 2
+
+static device_info devices_info[NUMOF_DEVICES] =
+{
+ {
+ L"\\Device\\test_device1",
+ L"\\DosDevices\\test_device1",
+ },
+ {
+ L"\\Device\\test_device2",
+ L"\\DosDevices\\test_device2",
+ },
+};
+
+static device devices[NUMOF_DEVICES];
+
+static void destroy_device(int i)
+{
+ IoDeleteSymbolicLink(&devices[i].symlink);
+ IoDeleteDevice(devices[i].object);
+}
+
+void destroy_devices()
+{
+ int i;
+ for (i = 0; i < NUMOF_DEVICES; ++i)
+ destroy_device(i);
+}
+
+static NTSTATUS set_up_device(DRIVER_OBJECT *driver_object, int i)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DbgPrint("Setting up device...\n");
+ DbgPrint("\tPath: %ws\n", devices_info[i].path);
+ DbgPrint("\tSymlink: %ws\n", devices_info[i].symlink);
+
+ RtlInitUnicodeString(&devices[i].path, devices_info[i].path);
+ RtlInitUnicodeString(&devices[i].symlink, devices_info[i].symlink);
+
+ status = IoCreateDevice(driver_object,
+ 0,
+ &devices[i].path,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &devices[i].object);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ devices[i].object->Flags |= DO_BUFFERED_IO;
+ devices[i].object->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ if (!NT_SUCCESS(status = IoCreateSymbolicLink(&devices[i].symlink,
+ &devices[i].path)))
+ goto delete_device;
+
+ return status;
+
+delete_device:
+ IoDeleteDevice(devices[i].object);
+
+ return status;
+}
+
+NTSTATUS set_up_devices(DRIVER_OBJECT *driver_object)
+{
+ int i, j;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ for (i = 0; i < NUMOF_DEVICES; ++i)
+ if (!NT_SUCCESS(status = set_up_device(driver_object, i)))
+ goto destroy_devices;
+
+ driver_object->MajorFunction[IRP_MJ_CREATE] = device_open;
+ driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = device_ioctl;
+
+ return status;
+
+destroy_devices:
+ for (j = 0; j < i; ++j)
+ destroy_device(j);
+
+ return status;
+}
diff --git a/src/test/device.h b/src/test/device.h
new file mode 100644
index 0000000..a5ecc31
--- /dev/null
+++ b/src/test/device.h
@@ -0,0 +1,13 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#pragma once
+
+#include <ntddk.h>
+
+NTSTATUS set_up_devices(DRIVER_OBJECT *);
+void destroy_devices();
diff --git a/src/test/main.c b/src/test/main.c
new file mode 100644
index 0000000..f6b4fbf
--- /dev/null
+++ b/src/test/main.c
@@ -0,0 +1,24 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#include "device.h"
+
+#include <ntddk.h>
+
+VOID on_driver_unload(DRIVER_OBJECT *driver_object)
+{
+ DbgPrint("Unloading test driver...\n");
+ destroy_devices();
+}
+
+NTSTATUS DriverEntry(DRIVER_OBJECT *driver_object,
+ UNICODE_STRING *registry_path)
+{
+ DbgPrint("Loading test driver...\n");
+ driver_object->DriverUnload = on_driver_unload;
+ return set_up_devices(driver_object);
+}
diff --git a/src/test/makefile b/src/test/makefile
new file mode 100644
index 0000000..5acbbd2
--- /dev/null
+++ b/src/test/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/test/sources b/src/test/sources
new file mode 100644
index 0000000..245a1a7
--- /dev/null
+++ b/src/test/sources
@@ -0,0 +1,3 @@
+TARGETTYPE = DRIVER
+TARGETNAME = test
+SOURCES = device.c main.c