- Simple project in
Windows 10 x64 architecturecontainskernel driveranduser mode clientfor viewingprocess creation/destruction notificationand preventing program paths if needed. - Feel free to leave a star and fork the repo for a quick start up with Windows Kernel Driver.
- This repo represents our School Project for Course
System ProgramminginRHUST. Therefore, the main goal is to revise & share knowledge with system internals and kernel driver, specifically. - The project is named after the idea of digging inside the
Windows internal system. The default Windows screen is blue, the death screen is also blue and what we do is also diving in this deep Windows ocean. On the other hand, the project name also represents the deep work of students who trying their best to achieve success and be better theiryesterdays. - In this project, we demonstrated a nice solution to monitor process creation in Windows. In details, we registered process creation/destruction notifications via
PsSetCreateProcessNotifyRoutineExin kernel mode. Therefore, we could view all informations about process creation & destruction in real-time. In user mode, we set up a client to print notifications that are from kernel driver to console. Nevertheless, we added up a feature that allow blocking program by path. Client in user mode can prevent any program from running by sending a blacklist to the driver in kernel mode. Then the driver will continuous check if any process creation starts from any path existing in the blacklist. There are 2 important things related to this feature. First, driver needs to compare paths insensitively. Second, driver should consider a mechanism to prevent the case the program changes its name. However, in this project, we only took the first case seriously and considered the second case as unpreventable. Overall, the contributions in this project are as follows:- Kernel Driver regists for process creation/destruction notifications
- User mode Client communicate with kernel driver for logging purpose and send list of blocking program path
- User mode Helper helps user mode client in posting toast notification
- A driver (
deocdrv.sys) set up in kernel mode for retrieving any process creation/destruction notifications and blocking any process creation if its path existed in blacklist.- The driver is written in Cpp and targets
Windows 10. Its main idea is for debugging purpose, but not production!
- The driver is written in Cpp and targets
- An executable (
DOClient.exe) set up in user mode for logging process creation/destruction notifications and sending blocking program path to our kernel driver. The client is written in Cpp.- This Client logs process creation/destruction notifcations in console
- This Client also post a toast notification whenever a program is blocked from running.
- A client helper (
DOClientHelper.exe) set up in user mode for posting toast notification containing information sent from client executable- This client helper is quickly written in Golang.
- Both of these modules are targetting
x64 architectureof Windows.
- Basically, Deep Ocean Solution is divided in 2 main modules which are DODriver and DOClient along with a helper module: DOClientHelper. More details about code has been written inside
Documentfolder. Therefore, we just highlights flows and architecture of this solution. - The root of repository includes a solution file
Deep Ocean Driver.slnwhich helps monitoring multiple projects (in this case is DOClient and DODriver).
- The driver regists
PsSetCreateProcessNotifyRoutineExfor process creation/destruction notifications with functionOnProcessNotify. This makesOnProcessNotifyas a additional routine that system needs to run whenever there is a process creation/destruction notification. In other words,OnProcessNotifywill always receive every process creation/destruction notification sequentially. - Inside
OnProcessNotify, we set up 2 cases corresponding to process creation and process destruction notification.- With process destruction notification, we simply added the notification to a linked list (the head is
ProcNotiItemsHeadand the node type isProcessExitInfo), which later be sent to client mode - With process creation notification, we compared the process path (if there is) with all process paths in blacklist. If the process path exists in the blacklist linked list (the head is
ProgItemsHeadand the node type isProcessMonitorInfo), the driver simply adds the notification to the linked list (the head isProcNotiItemsHeadand the node type isProcessCreateInfo) and marks this notification as blocked
- With process destruction notification, we simply added the notification to a linked list (the head is
- Thanks to the great power of inheritance for struct in Cpp,
ProcessCreateInfoandProcessExitInfocan inherits a same parentItemHeader. Therefore, we could simply added both process creation and destruction notification to a same linkedlist, whose head isProcNotiItemsHead. - To communicate with client user mode, we use 2 main methods:
Direct I/OandBuffered I/O.- We use
direct I/Ofor quickly writing notifications to the same memory that client provides - The buffered I/O is used for receiving commands from cient
- Driver receives
IOCTL_DO_PROGRAM_BLOCKas blocking the program by path. Whenever thisIOCTLcomes, the driver will store it inside the above blacklist linked list. - For
IOCTL_DO_PROGRAM_UNBLOCK, driver will remove the requested program path from the blacklist
- Driver receives
- We use
- In module DOClient, we setup class
KernelGateway(insidekernelgateway.handkernelgateway.cpp) which is responsible for communicating with kernel driver. - As mentioned, to communicate with kernel driver, user mode client are required to support both
Direct I/O(usingReadFileindicates the right handle to Deep Ocean driver device) andBuffered I/O(usingDeviceIoControlindicates the correct handle to driver device and the demanding IOCTL). - To avoid duplicate code, we setup a shared library (
DODriver/drivercommon.h) to help both kernel driver and user mode client unify the same data type and protocol to communicate. - Whenever DOClient receives a process creation notifcation containing blocked status, it will call DOClientHelper for posting toast notification (for better UI)
- This simple module contains a single
main.goto receive arguments and pass it to a simple toast notification - It uses library
argparseandtoast.v1
- Kernel Driver file (
deocdrv.sys) and user mode client (DOClient.exe) should be insidex64\Debug- We ignored to push this path to github repository, but you can simply obtain it by building solution (
Deep Ocean Driver.sln). TheVisual Studiowill generate the binaries and put them in the right folder.
- We ignored to push this path to github repository, but you can simply obtain it by building solution (
- Client Helper binary (
DOClientHelper.exe) should be located inDOClientHelper\Build. - For easy driver installation, we have put a folder named as
Driver Scriptscontaininginstall_driver.cmdfor registeringdeocservice withdeocdrv.sysdriver binary. On the other hand, scriptuninstall_driver.cmdis used to uninstall driver service. - For easy grabbing essential binaries, we create
Binariesfolder containing scriptAutoGetBin.cmd. Click it and all required binaries (deocdrv.sys,DOClient.exe,DOClientHelper.exe,install_driver.cmdanduninstall_driver.cmd)will show up in the same place. What we need to do left is moving those binaries to a virtual machine and test them.- Note that, to utilize the power of this script, location of each binary must be as mentioned above.
- Fortunately, we did keep demo binaries in this folder for fast testing purpose.
- Because binaries are not for production, modules should be installed in a virtual machine (or a real machine if you are rich).
- Turn on debug mode using
bcdedit /debug on - Disable driver signature enforcement using
bcdedit /set loadoptions DDISABLE_INTEGRITY_CHECKS bcdedit.exe /set nointegritychecks on - In the end, restart machine so the above configurations would affect after that.
- Not only the above steps for running services are required, setting port for the machine is also essential to enable debugging.
- Currently,
Microsoftsupports both debugging on real machine and virtual machine. For the sake of simplicity, we only demonstrate the way to enable debugging inVMWare - There are two common types of debugging which are local Kernel Debugging (LKD) and Full Kernel Debugging. LKD cannot help us in setting breakpoints (because when we reach breakpoint, the kernel is paused and LKD also freeze). Hence, we focus on setup 2 machines: 1 machine for setting
WinDbg, 1 virtual machine to run services - In host machine, we can either use
WindDbg preview(recommended) orWinDbg classical.
- Configure
Windbg Preview
- Launch the kernel debugger and select
File/Attach To Kernel. Navigate to theCOMtab and fill as follows:- check
PipeandReconnect - choose
Resetsas 0 - choose
Baud Rateas 115200 - Port as
\\.\pipe\com_1
- check
- After the VMware is setup nicely, we can press OK to start debugging.
- Create pipe and virtual serial connection in VMware
- Edit virtual machine settings, create a serial port with name as
\\.\pipe\com_1. ChooseYield CPU on poll - Denote if the name of created device of
Serial Port 2. The number of 2 may due to the printer is the first one - Start machine, run cmd with Administrators. Input these commands (Remember debugport is 2 if the name of device is
Serial Port 2)> bcdedit /debug on > bcdedit /dbgsettings serial debugport:2 baudrate:115200 /noumex > bcdedit /dbgsettings ------- Result: debugtype Serial debugport 2 baudrate 115200 noumex Yes The operation completed successfully. ------- - Restarting machine is also required.
-
For DODriver and DOClient, developers needs
Visual Studio 2017 / 2019(along withC++ workload),Windows 10 SDK,Windows 10 Driver Kit (WDK)- After installing these prerequisites,
Empty WDM Drivershould appear a project template inVisual Studio
- After installing these prerequisites,
-
For DOClientHelper, Golang is required to be installed (of course :v).
go modmight take place to install the essential libraries.
- For DODriver and DOClient, simply click on
Deep Ocean Driver.slnto open both projects for kernel driver and user mode client.- Choose debug and architecture
x64 - Simply manually build solution or
Ctrl + Shift Bas shortcut - Binaries will be allocated at
x64\Debug
- Choose debug and architecture
- For DOClientHelper, get into
DOClientHelperand build the module using the following command:go build -o Build\DOClientHelper.exe
DODriverinstallation can be automated usinginstall_driver.cmdscript (insideDriver Scriptsfolder). On the other hand, scriptuninstall_driver.cmdis used for uninstallationDOClientcurrently supports logging notifications and add/remove blocking program list- Block notepad:
DOClient.exe -progblock C:\Windows\System32\notepad.exe - Unblock notepad:
DOClient.exe -progunblock C:\Windows\System32\notepad.exe - View informations:
DOClient.exe -procnoti - View usage:
DOClient.exe -h
- Block notepad:
- Windows Kernel Programming Book by Pavel Yosifovich
- https://www.triplefault.io/2017/07/setting-up-kernel-debugging-using.html (for setting up kernel debugging using WinDbg and VMware)
- https://www.osr.com/getting-started-writing-windows-drivers/
- Windows Internals 7th Edition — Part 1
- Windows System Programming 4th Edition
- https://github.com/microsoft/Windows-driver-samples
- http://www.osronline.com/article.cfm%5Earticle=499.htm (Windows Doubly Linked List basic concepts)
- https://osm.hpi.de/research/WRK/2009/07/single_list_entry-containing_record/ (Windows Doubly Linked List essential functions)
- https://www.codeproject.com/Articles/800404/Understanding-LIST-ENTRY-Lists-and-Its-Importance (Windows Linked List and windbg tutorial)
- https://dennisspan.com/analyzing-system-crashes-on-non-persistent-machines/ (analyze system crash on machines)
