This extension provides a way to monitor and control process creation and deletion events in the Windows kernel using eBPF. The extension is built on top of eBPF for Windows, following the eBPF Extensions model, and leverages the library files from this repository.
The ntosebpfext extension hooks into the Windows kernel's process notification mechanism using PsSetCreateProcessNotifyRoutineEx, allowing eBPF programs to observe and potentially influence process lifecycle events.
- eBPF for Windows must be installed. Please follow the instructions in the eBPF for Windows - Getting started guide to install the eBPF for Windows components on a test-enabled Windows machine/VM.
After cloning the repository, make sure to initialize the submodules by running the following command from the root of the repository:
.\scripts\initialize_repo.ps1Then, build the ntosebpfext.sln solution from the root of the repository, by running the following command:
msbuild ntosebpfext.sln /p:Configuration=Debug /p:Platform=x64For this extension, the following artifacts will be generated in the x64\Debug (in this case) directory:
ntos_ebpf_ext_export_program_info.exe- A user-mode cmdlet that exports the eBPF program information to the eBPF store.ntosebpfext.sys- The driver that loads the eBPF program and attaches it to the process lifecycle events.process_monitor.sys- The native eBPF program that will be invoked by thentosebpfextextension upon process events, which stores them in ring buffer and LRU hash maps.ntosebpfext_unit.exe- An end-to-end unit test that validates the extension functionality.
To run the end-to-end unit test, you can use the ntosebpfext_unit.exe application as follows:
REM Required only if the eBPF program information is not exported yet
ntos_ebpf_ext_export_program_info.exe
REM Run the test with debugging enabled
ntosebpfext_unit.exe -d yesThis test will perform the following steps:
- Export the eBPF program info to the eBPF store (located in System's registry, under
HKLM\Software\eBPF). - Load & start the
ntosebpfext.sysdriver. - Load and attach the
process_monitor.syseBPF program. - Simulate process creation and deletion events.
- Verify that the eBPF program receives the correct context information.
- Stop and unload all the drivers.
For full end-to-end testing with the user-mode application, see the process_monitor.Tests project which validates the extension functionality using MSTest.
Once the artifacts are generated, to deploy the extension you need to:
-
Export the eBPF program to the system's eBPF store using the
ntos_ebpf_ext_export_program_info.exeapplication:REM Mainly, to clear-out any previous eBPF program information related to this program type. ntos_ebpf_ext_export_program_info.exe --clear ntos_ebpf_ext_export_program_info.exe -
Load and start the
ntosebpfext.syseBPF extension driver which will enable loading eBPF programs of typeprocessand attaching them to the process lifecycle events:sc create ntosebpfext type=kernel start=demand binPath=ntosebpfext.sys sc start ntosebpfext
The simplest way to write an eBPF program that attaches to the process events is to review the process_monitor.c eBPF program provided in the \tools\process_monitor_bpf project. This program stores process events in a ring buffer and maintains LRU hash maps for process image paths and command lines.
The extension provides the following structure for process events, defined in include\ebpf_ntos_hooks.h:
typedef enum _process_operation
{
PROCESS_OPERATION_CREATE, ///< Process creation.
PROCESS_OPERATION_DELETE, ///< Process deletion.
} process_operation_t;
typedef struct _process_md
{
uint8_t* command_start; ///< Pointer to start of the command line as UTF-16 string.
uint8_t* command_end; ///< Pointer to end of the command line as UTF-16 string.
uint64_t process_id; ///< Process ID.
uint64_t parent_process_id; ///< Parent process ID.
uint64_t creating_process_id; ///< Creating process ID.
uint64_t creating_thread_id; ///< Creating thread ID.
uint64_t creation_time; ///< Process creation time (as a FILETIME).
uint64_t exit_time; ///< Process exit time (as a FILETIME). Set only for PROCESS_OPERATION_DELETE.
uint32_t process_exit_code; ///< Process exit status. Set only for PROCESS_OPERATION_DELETE.
process_operation_t operation : 8; ///< Operation to do.
} process_md_t;To write your own eBPF program, you must create your own project (similar to the process_monitor_bpf project) and define a section of type process in your eBPF program. The process section is used by the ntosebpfext extension to attach the eBPF program to the process lifecycle events.
#include "bpf_helpers.h"
#include "ebpf_ntos_hooks.h" // For the process_md_t and process_hook_t definitions.
// Define any eBPF maps that you need here
struct
{
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
// The following line is optional, but is used to verify
// that the ProcessHandler prototype is correct or the compiler
// would complain when the function is actually defined below.
process_hook_t ProcessHandler;
// Define the eBPF program that will be attached to the process events.
SEC("process")
int
ProcessHandler(process_md_t* ctx)
{
// Your eBPF program logic here
// Access process information from ctx
// For example, log to a ring buffer
bpf_ringbuf_output(&events, ctx, sizeof(*ctx), 0);
// Return STATUS_SUCCESS (0) to permit the operation
// Return a failure NTSTATUS value to deny the operation
// Note: For PROCESS_OPERATION_DELETE, the return value is ignored
return 0;
}The extension supports attaching multiple eBPF programs, to which process events will be dispatched.
The ntosebpfext extension provides a custom helper function:
int bpf_process_get_image_path(process_md_t* ctx, uint8_t* path, uint32_t path_length);Description: Retrieves the full image path of the process.
Parameters:
ctx- Process metadata contextpath- Buffer to store the image path (UTF-16 encoded)path_length- Length of the buffer in bytes
Returns:
>= 0- The length of the image path in bytes< 0- A failure occurred
Example usage:
SEC("process")
int
ProcessHandler(process_md_t* ctx)
{
char image_path[1024];
// Get the image path
int len = bpf_process_get_image_path(ctx, (uint8_t*)image_path, sizeof(image_path) - 1);
if (len > 0) {
// Image path retrieved successfully
// Process the image path...
}
return 0;
}The process_md_t structure provides comprehensive information about process events:
-
Process Identifiers:
process_id- The process ID of the process being created or deletedparent_process_id- The parent process IDcreating_process_id- The process ID that is creating this processcreating_thread_id- The thread ID that is creating this process
-
Command Line:
command_start/command_end- Pointers to the command line as a UTF-16 string. The command line can be extracted by reading the memory between these pointers.
-
Timing Information:
creation_time- Process creation time as a FILETIME valueexit_time- Process exit time as a FILETIME value (only valid forPROCESS_OPERATION_DELETE)
-
Exit Information:
process_exit_code- The process exit code (only valid forPROCESS_OPERATION_DELETE)
-
Operation Type:
operation- EitherPROCESS_OPERATION_CREATEorPROCESS_OPERATION_DELETE
eBPF programs attached to the process hook can influence process creation:
-
For
PROCESS_OPERATION_CREATEevents:- Return
STATUS_SUCCESS(0) to permit the process creation - Return a failure NTSTATUS value (e.g.,
STATUS_ACCESS_DENIED = 0xC0000022) to deny the process creation
- Return
-
For
PROCESS_OPERATION_DELETEevents:- The return value is ignored (process deletion cannot be prevented)
The process_monitor example in tools\process_monitor_bpf demonstrates a complete implementation that:
- Captures process creation and deletion events
- Stores event metadata in a ring buffer for user-mode consumption
- Maintains LRU hash maps with process image paths and command lines
- Uses per-CPU scratch space for efficient string handling
The corresponding user-mode application in tools\process_monitor reads events from the ring buffer and displays them in real-time with structured logging.
The ntosebpfext extension uses the Windows kernel's PsSetCreateProcessNotifyRoutineEx API to register for process creation and deletion notifications. When a process event occurs:
- The Windows kernel invokes the extension's notification callback
- The extension constructs a
process_md_tcontext with all relevant information - The context is passed to all attached eBPF programs
- For creation events, if any eBPF program returns a failure status, the process creation is denied
- For deletion events, the eBPF programs are notified but cannot prevent the deletion
- Program Info Provider - Registers the
processprogram type with eBPF for Windows - Hook Provider - Manages the attachment of eBPF programs to process events
- Context Creation/Destruction - Handles the lifecycle of the
process_md_tcontext - Helper Functions - Provides the
bpf_process_get_image_pathhelper
The ntosebpfext extension enables various security and monitoring scenarios:
- Process Monitoring - Real-time tracking of all process creation and deletion events
- Security Policy Enforcement - Blocking specific processes based on image path, command line, or other attributes
- Auditing and Compliance - Logging process lifecycle events for compliance requirements
- Behavioral Analysis - Analyzing process creation patterns for anomaly detection
- Parental Controls - Restricting which applications can be launched
Program Type GUID:
EBPF_PROGRAM_TYPE_PROCESS = {0x22ea7b37, 0x1043, 0x4d0d, {0xb6, 0x0d, 0xca, 0xfa, 0x1c, 0x7b, 0x63, 0x8e}}
Attach Type GUID:
EBPF_ATTACH_TYPE_PROCESS = {0x66e20687, 0x9805, 0x4458, {0xa0, 0xdb, 0x38, 0xe2, 0x20, 0xd3, 0x16, 0x85}}
BPF Program Type:
BPF_PROG_TYPE_PROCESS
BPF Attach Type:
BPF_ATTACH_TYPE_PROCESS
Ensure that:
- eBPF for Windows is installed and running
- The system is in test mode (bcdedit /set testsigning on)
- The driver is properly signed (or test signing is enabled)
- You have administrator privileges
- Verify that the program type information has been exported using
ntos_ebpf_ext_export_program_info.exe - Check that the ntosebpfext.sys driver is loaded and started
- Ensure your eBPF program uses
SEC("process")and the correct context type
- Verify that the eBPF program is successfully attached
- Check that the program logic is correct and doesn't fail early
- Ensure map definitions are correct and maps are accessible from user mode
- Enable debug logging with the
-d yesflag when running test applications