8.4 Windows驱动开发:文件微过滤驱动入门

MiniFilter 微过滤驱动是相对于SFilter传统过滤驱动而言的,传统文件过滤驱动相对来说较为复杂,且接口不清晰并不符合快速开发的需求,为了解决复杂的开发问题,微过滤驱动就此诞生,微过滤驱动在编写时更简单,多数IRP操作都由过滤管理器(FilterManager或Fltmgr)所接管,因为有了兼容层,所以在开发中不需要考虑底层IRP如何派发,更无需要考虑兼容性问题,用户只需要编写对应的回调函数处理请求即可,这极大的提高了文件过滤驱动的开发效率。

接下来将进入正题,讲解微过滤驱动的API定义规范以及具体的使用流程,并最终实现一个简单的过滤功能,首先你必须在VS上做如下配置,依次打开配置菜单,并增加驱动头文件。

  • 配置属性 > 连接器 > 输入> 附加依赖 > fltMgr.lib
  • 配置属性 > C/C++ > 常规 > 设置 关闭所有警告 (警告视为错误关闭)

未过滤驱动的使用非常容易,在使用之前第一件事就是要向过滤管理器宣告我们的微过滤驱动的存在,我们以DriverEntry入口函数为例,首先在入口处需要使用FltRegisterFilter函数注册一个过滤器组件,另外则需要通过FltStartFiltering开启过滤功能,而当我们想要关闭时则需要调用FltUnregisterFilter注销过滤组件,首先来看一下入口处是如何初始化的;

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;

    DbgPrint("Hello lyshark \n");

    // FltRegisterFilter 向过滤管理器注册过滤器
    // 参数1:本驱动驱动对象
    // 参数2:微过滤驱动描述结构
    // 参数3:返回注册成功的微过滤驱动句柄
    status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
    if (NT_SUCCESS(status))
    {
        // 开启过滤
        status = FltStartFiltering(gFilterHandle);
        DbgPrint("[过滤器] 开启监控.. \n");

        if (!NT_SUCCESS(status))
        {
            // 如果启动失败,则取消注册并退出
            FltUnregisterFilter(gFilterHandle);
            DbgPrint("[过滤器] 取消注册.. \n");
        }
    }
    return status;
}

如上代码中我们最需要关注的是FltRegisterFilter函数的第二个参数FilterRegistration它用于宣告注册信息,这个结构内包含了过滤器的所有信息,想要注册成功则我们必须更具要求正确的填写FLT_REGISTRATION微过滤器注册结构,该结构体的微软定义如下所示;

typedef struct _FLT_REGISTRATION {
  USHORT                                      Size;
  USHORT                                      Version;
  FLT_REGISTRATION_FLAGS                      Flags;
  const FLT_CONTEXT_REGISTRATION              *ContextRegistration;
  const FLT_OPERATION_REGISTRATION            *OperationRegistration;
  PFLT_FILTER_UNLOAD_CALLBACK                 FilterUnloadCallback;
  PFLT_INSTANCE_SETUP_CALLBACK                InstanceSetupCallback;
  PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK       InstanceQueryTeardownCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK             InstanceTeardownStartCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK             InstanceTeardownCompleteCallback;
  PFLT_GENERATE_FILE_NAME                     GenerateFileNameCallback;
  PFLT_NORMALIZE_NAME_COMPONENT               NormalizeNameComponentCallback;
  PFLT_NORMALIZE_CONTEXT_CLEANUP              NormalizeContextCleanupCallback;
  PFLT_TRANSACTION_NOTIFICATION_CALLBACK      TransactionNotificationCallback;
  PFLT_NORMALIZE_NAME_COMPONENT_EX            NormalizeNameComponentExCallback;
  PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback;
} FLT_REGISTRATION, *PFLT_REGISTRATION;

当然如上的这些字段并非都要去填充,我们只需要填充自己所需要的部分即可,例如我们代码中只填充了如下这些必要的部分,其他部分可以省略掉,当使用如下结构体注册时,只要实例发生了变化就会根据如下配置路由到不同的函数上面做处理。

// 过滤驱动数据结构
CONST FLT_REGISTRATION FilterRegistration =
{
    sizeof(FLT_REGISTRATION),         //  结构大小(默认)
    FLT_REGISTRATION_VERSION,           //  结构版本(默认)
    0,                                  //  过滤器标志
    NULL,                               //  上下文
    Callbacks,                          //  注册回调函数集
    Unload,                             //  驱动卸载函数
    InstanceSetup,                      //  实例安装回调函数
    InstanceQueryTeardown,              //  实例销毁回调函数
    InstanceTeardownStart,              //  实例解除绑定时触发
    InstanceTeardownComplete,           //  实例解绑完成时触发
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};

如上结构中我们最需要注意的是Callbacks字段,该字段是操作回调函数集注册,我们对文件的各种操作的回调事件都会被写入到此处,而此处我们只需要增加我们所需要的回调事件即可,以IRP_MJ_CREATE为例,后面紧跟的是PreOperation事前回调,以及PostOperation事后回调,一般在要进行监控时通常在PreOperation()回调中处理,如果时监视则一般在PostOperation()中处理。

// 回调函数集
CONST FLT_OPERATION_REGISTRATION Callbacks[] =
{
    // 创建时触发 PreOperation(之前回调函数) / PostOperation(之后回调函数)
    { IRP_MJ_CREATE, 0, PreOperation, PostOperation },
    // 读取时触发
    { IRP_MJ_READ, 0, PreOperation, PostOperation },
    // 写入触发
    { IRP_MJ_WRITE, 0, PreOperation, PostOperation },
    // 设置时触发
    { IRP_MJ_SET_INFORMATION, 0, PreOperation, PostOperation },
    // 结束标志
    { IRP_MJ_OPERATION_END }
};

如下完整代码实现了监视当前系统下所有的文件操作,如创建,读取,写入,修改,加载后则会监视系统下所有的文件操作,当然如果是监控则需要在PreOperation事前回调做文章,而如果仅仅只是监视则事前事后都是可以的。

#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>

PFLT_FILTER gFilterHandle;

// ----------------------------------------------------------------------------------------
// 声明部分
// ----------------------------------------------------------------------------------------
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    );

NTSTATUS
InstanceSetup(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_SETUP_FLAGS Flags,
_In_ DEVICE_TYPE VolumeDeviceType,
_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
);

VOID
InstanceTeardownStart(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

VOID
InstanceTeardownComplete(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

NTSTATUS
Unload(
_In_ FLT_FILTER_UNLOAD_FLAGS Flags
);

NTSTATUS
InstanceQueryTeardown(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
);

FLT_PREOP_CALLBACK_STATUS
PreOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
);
FLT_POSTOP_CALLBACK_STATUS
PostOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
);

// ----------------------------------------------------------------------------------------
// 回调函数
// ----------------------------------------------------------------------------------------

// 当实例被安装时触发
NTSTATUS InstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
{
    DbgPrint("[LyShark] 安装 MiniFilter \n");
    return STATUS_SUCCESS;
}

// 当实例被销毁时触发
NTSTATUS InstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
    DbgPrint("[LyShark] 销毁 MiniFilter \n");
    return STATUS_SUCCESS;
}

// 实例解除绑定时触发
VOID InstanceTeardownStart(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
{
    DbgPrint("[LyShark] 解绑 MiniFilter \n");
    return STATUS_SUCCESS;
}

// 实例解绑完成时触发
VOID InstanceTeardownComplete(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
{
    DbgPrint("[LyShark] 解绑完成 MiniFilter \n");
    return STATUS_SUCCESS;
}

// 驱动关闭时卸载监控
NTSTATUS Unload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
{
    DbgPrint("[LyShark] 卸载 MiniFilter \n");
    FltUnregisterFilter(gFilterHandle);
    return STATUS_SUCCESS;
}

// 回调函数集
CONST FLT_OPERATION_REGISTRATION Callbacks[] =
{
    // 创建时触发 PreOperation(之前回调函数) / PostOperation(之后回调函数)
    { IRP_MJ_CREATE, 0, PreOperation, PostOperation },
    // 读取时触发
    { IRP_MJ_READ, 0, PreOperation, PostOperation },
    // 写入触发
    { IRP_MJ_WRITE, 0, PreOperation, PostOperation },
    // 设置时触发
    { IRP_MJ_SET_INFORMATION, 0, PreOperation, PostOperation },
    // 结束标志
    { IRP_MJ_OPERATION_END }
};

// 过滤驱动数据结构
CONST FLT_REGISTRATION FilterRegistration =
{
    sizeof(FLT_REGISTRATION),           //  结构大小(默认)
    FLT_REGISTRATION_VERSION,           //  结构版本(默认)
    0,                                  //  过滤器标志
    NULL,                               //  上下文
    Callbacks,                          //  注册回调函数集
    Unload,                             //  驱动卸载函数
    InstanceSetup,                      //  实例安装回调函数
    InstanceQueryTeardown,              //  实例销毁回调函数
    InstanceTeardownStart,              //  实例解除绑定时触发
    InstanceTeardownComplete,           //  实例解绑完成时触发
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};

// ----------------------------------------------------------------------------------------
// 功能函数
// ----------------------------------------------------------------------------------------

// 预操作回调函数(在执行过滤操作之前先执行此处)
FLT_PREOP_CALLBACK_STATUS PreOperation(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
{
    NTSTATUS status;

    // 获取文件路径
    UCHAR MajorFunction = Data->Iopb->MajorFunction;
    PFLT_FILE_NAME_INFORMATION lpNameInfo = NULL;

    // 得到文件名相关信息
    status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &lpNameInfo);
    if (NT_SUCCESS(status))
    {
        status = FltParseFileNameInformation(lpNameInfo);
        if (NT_SUCCESS(status))
        {
            // 创建
            if (IRP_MJ_CREATE == MajorFunction)
            {
                DbgPrint("[创建文件时] %wZ", &lpNameInfo->Name);

                // 拒绝创建
                // STATUS_INSUFFICIENT_RESOURCES                 提示不是有效的资源
                // STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY  静默拒绝
                // STATUS_ACCESS_DENIED                          提示访问拒绝
                // return STATUS_ACCESS_DENIED;
                // return FLT_PREOP_COMPLETE;
            }
            // 读取
            else if (IRP_MJ_READ == MajorFunction)
            {
                DbgPrint("[读取文件时] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
            // 文件写入
            else if (IRP_MJ_WRITE == MajorFunction)
            {
                DbgPrint("[写入文件时] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
            // 修改文件信息
            else if (IRP_MJ_SET_INFORMATION == MajorFunction)
            {
                DbgPrint("[修改文件] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
        }
    }
    return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

// 后操作回调函数 (在执行过滤之后运行此处)
FLT_POSTOP_CALLBACK_STATUS PostOperation(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
{
    return FLT_POSTOP_FINISHED_PROCESSING;
}

// ----------------------------------------------------------------------------------------
// 入口函数
// ----------------------------------------------------------------------------------------
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;

    DbgPrint("Hello lyshark \n");

    // FltRegisterFilter 向过滤管理器注册过滤器
    // 参数1:本驱动驱动对象
    // 参数2:微过滤驱动描述结构
    // 参数3:返回注册成功的微过滤驱动句柄
    status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
    if (NT_SUCCESS(status))
    {
        // 开启过滤
        status = FltStartFiltering(gFilterHandle);
        DbgPrint("[过滤器] 开启监控.. \n");

        if (!NT_SUCCESS(status))
        {
            // 如果启动失败,则取消注册并退出
            FltUnregisterFilter(gFilterHandle);
            DbgPrint("[过滤器] 取消注册.. \n");
        }
    }
    return status;
}

过滤驱动的安装方式有多种,可以通过函数注册或者使用INF文件像系统注册驱动,首先以INF为例安装,通过修改INF中的ServiceName以及DriverName并将其改为WinDDK,将文件保存为install.inf鼠标右键选择安装即可。

[Version]
Signature   = "$Windows NT$"     
Class       = "ActivityMonitor"  ;指明了驱动的分组,必须指定.
ClassGuid   = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}  ;GUID 每个分组都有固定的GUID
Provider    = %Msft% ;变量值 从STRING节中可以看到驱动提供者的名称 
DriverVer   = 06/16/2007,1.0.0.1 ;版本号
CatalogFile = passthrough.cat    ;inf对应的cat 文件 可以不需要

[DestinationDirs]
DefaultDestDir          = 12    ;告诉我们驱动拷贝到哪里 13代表拷贝到%windir%
MiniFilter.DriverFiles  = 12            ;%windir%\system32\drivers

[DefaultInstall]
OptionDesc          = %ServiceDescription%
CopyFiles           = MiniFilter.DriverFiles

[DefaultInstall.Services]
AddService          = %ServiceName%,,MiniFilter.Service

[DefaultUninstall]
DelFiles   = MiniFilter.DriverFiles

[DefaultUninstall.Services]
DelService = %ServiceName%,0x200      ;Ensure service is stopped before deleting

[MiniFilter.Service]                 ;服务的一些信息
DisplayName      = %ServiceName%
Description      = %ServiceDescription%
ServiceBinary    = %12%\%DriverName%.sys        ;%windir%\system32\drivers\
Dependencies     = "FltMgr"                     ;服务的依赖
ServiceType      = 2                            ;SERVICE_FILE_SYSTEM_DRIVER
StartType        = 3                            ;SERVICE_DEMAND_START
ErrorControl     = 1                            ;SERVICE_ERROR_NORMAL
LoadOrderGroup   = "FSFilter Activity Monitor"  ;文件过滤分组
AddReg           = MiniFilter.AddRegistry       ;文件过滤注册表需要添加的高度值等信息

[MiniFilter.AddRegistry]
HKR,,"DebugFlags",0x00010001 ,0x0
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%

[MiniFilter.DriverFiles]
%DriverName%.sys

[SourceDisksFiles]
passthrough.sys = 1,,

[SourceDisksNames]
1 = %DiskId1%,,,

[Strings]
Msft                    = "Microsoft Corporation"
ServiceDescription      = "WinDDK Mini-Filter Driver"
ServiceName             = "WinDDK"
DriverName              = "WinDDK"
DiskId1                 = "WinDDK Device Installation Disk"

DefaultInstance         = "WinDDK Instance"
Instance1.Name          = "WinDDK Instance"
Instance1.Altitude      = "370030"
Instance1.Flags         = 0x0              ; Allow all attachments

第二种安装方式则是通过字写驱动加载工具实现,本人更推荐使用此方式安装,此种方式的原理同样是向注册表中写出子健,但同时具备有启动与关闭驱动的功能,比INF安装更灵活易于使用,完整代码如下所示;

#include <Windows.h>
#include <iostream>
#include <winsvc.h>
#include <winioctl.h>

// 安装MiniFinter
BOOL InstallDriver(const char* lpszDriverName, const char* lpszDriverPath, const char* lpszAltitude)
{
    char szTempStr[MAX_PATH];
    HKEY hKey;
    DWORD dwData;
    char szDriverImagePath[MAX_PATH];

    if (NULL == lpszDriverName || NULL == lpszDriverPath)
    {
        return FALSE;
    }

    // 得到完整的驱动路径
    GetFullPathName(lpszDriverPath, MAX_PATH, szDriverImagePath, NULL);

    SC_HANDLE hServiceMgr = NULL; // SCM管理器的句柄
    SC_HANDLE hService = NULL;    // NT驱动程序的服务句柄

    // 打开服务控制管理器
    hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hServiceMgr == NULL)
    {
        // OpenSCManager失败
        CloseServiceHandle(hServiceMgr);
        return FALSE;
    }

    // OpenSCManager成功  

    // 创建驱动所对应的服务
    hService = CreateService(hServiceMgr,
        lpszDriverName,             // 驱动程序的在注册表中的名字
        lpszDriverName,             // 注册表驱动程序的DisplayName 值
        SERVICE_ALL_ACCESS,         // 加载驱动程序的访问权限
        SERVICE_FILE_SYSTEM_DRIVER, // 表示加载的服务是文件系统驱动程序
        SERVICE_DEMAND_START,       // 注册表驱动程序的Start 值
        SERVICE_ERROR_IGNORE,       // 注册表驱动程序的ErrorControl 值
        szDriverImagePath,          // 注册表驱动程序的ImagePath 值
        "FSFilter Activity Monitor",// 注册表驱动程序的Group 值
        NULL,
        "FltMgr",                   // 注册表驱动程序的DependOnService 值
        NULL,
        NULL);

    if (hService == NULL)
    {
        if (GetLastError() == ERROR_SERVICE_EXISTS)
        {
            // 服务创建失败,是由于服务已经创立过
            CloseServiceHandle(hService);       // 服务句柄
            CloseServiceHandle(hServiceMgr);    // SCM句柄
            return TRUE;
        }
        else
        {
            CloseServiceHandle(hService);       // 服务句柄
            CloseServiceHandle(hServiceMgr);    // SCM句柄
            return FALSE;
        }
    }
    CloseServiceHandle(hService);       // 服务句柄
    CloseServiceHandle(hServiceMgr);    // SCM句柄

    //-------------------------------------------------------------------------------------------------------
    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances 子键下的键值项 
    //-------------------------------------------------------------------------------------------------------
    strcpy(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
    strcat(szTempStr, lpszDriverName);
    strcat(szTempStr, "\\Instances");
    if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szTempStr, 0, "", TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的DefaultInstance 值 
    strcpy(szTempStr, lpszDriverName);
    strcat(szTempStr, " Instance");
    if (RegSetValueEx(hKey, "DefaultInstance", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 刷新注册表
    RegFlushKey(hKey);
    RegCloseKey(hKey);

    //-------------------------------------------------------------------------------------------------------
    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance 子键下的键值项 
    //-------------------------------------------------------------------------------------------------------
    strcpy(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
    strcat(szTempStr, lpszDriverName);
    strcat(szTempStr, "\\Instances\\");
    strcat(szTempStr, lpszDriverName);
    strcat(szTempStr, " Instance");
    if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szTempStr, 0, "", TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的Altitude 值
    strcpy(szTempStr, lpszAltitude);
    if (RegSetValueEx(hKey, "Altitude", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的Flags 值
    dwData = 0x0;
    if (RegSetValueEx(hKey, "Flags", 0, REG_DWORD, (CONST BYTE*)&dwData, sizeof(DWORD)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 刷新注册表
    RegFlushKey(hKey);
    RegCloseKey(hKey);
    return TRUE;
}

// 启动驱动
BOOL StartDriver(const char* lpszDriverName)
{
    SC_HANDLE schManager;
    SC_HANDLE schService;
    SERVICE_STATUS svcStatus;

    if (NULL == lpszDriverName)
    {
        return FALSE;
    }

    schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        CloseServiceHandle(schManager);
        return FALSE;
    }
    schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        return FALSE;
    }

    if (!StartService(schService, 0, NULL))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
        {
            // 服务已经开启
            return TRUE;
        }
        return FALSE;
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);

    return TRUE;
}

// 关闭驱动
BOOL StopDriver(const char* lpszDriverName)
{
    SC_HANDLE schManager;
    SC_HANDLE schService;
    SERVICE_STATUS svcStatus;
    bool bStopped = false;

    schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        return FALSE;
    }
    schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schManager);
        return FALSE;
    }
    if (!ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus) && (svcStatus.dwCurrentState != SERVICE_STOPPED))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        return FALSE;
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);

    return TRUE;
}

// 删除驱动
BOOL DeleteDriver(const char* lpszDriverName)
{
    SC_HANDLE schManager;
    SC_HANDLE schService;
    SERVICE_STATUS svcStatus;

    schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        return FALSE;
    }
    schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schManager);
        return FALSE;
    }
    ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus);
    if (!DeleteService(schService))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        return FALSE;
    }
    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);

    return TRUE;
}

int main(int argc, char* argv[])
{
    InstallDriver("minifilter", ".\\WinDDK.sys", "225864");

    while (1)
    {
        char str[20] = "\0";
        printf("请输入命令: ");
        gets(str);

        if (strcmp(str, "start") == 0)
        {
            printf("[*] 启动驱动 \n");
            StartDriver("minifilter");
        }
        if (strcmp(str, "stop") == 0)
        {
            printf("[-] 关闭驱动 \n");
            StopDriver("minifilter");
        }
    }
    return 0;
}

至此分别编译驱动程序,以及应用层下的安装程序,并将两者放入到同一目录下,运行客户端程序lyshark.exe并输入start启动驱动,输入stop则是关闭,启动后会看到如下信息;

这里简单介绍一下如何摘除微过滤驱动回调函数,其实摘除回调的方法有多种,常用的第一种通过向过滤驱动中写出一个返回命令让其不被执行从而实现绕过,另一种是找到回调函数并替换为我们自己的回调,而在自己的回调中什么也不做。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/210265.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

固定Microsoft Edge浏览器的位置设置,避免自动回调至中国

问题描述 在使用Copilot等功能时&#xff0c;需要将Microsoft Edge浏览器的位置设置为国外。但每次重新打开浏览器后&#xff0c;位置设置又自动回调至中国&#xff0c;导致每次均需要手动调整。 原因分析 这个问题的出现是因为每次启动Microsoft Edge时&#xff0c;默认打开…

VT-MRPA1-151-1X/V0/0控制2FRE16模块式模拟放大器

适用于控制带有电气位置反馈的直动式比例减压阀&#xff08;DBETR- 1X 类型&#xff09;或带有电气位置反馈的比例流量控制阀&#xff08;2FRE... 类型&#xff09;&#xff1b;控制值输入 1 0 V&#xff08;差动输入&#xff09;&#xff1b; 可分别调节“上/下”斜坡时间的斜…

RCE绕过

1.[SCTF 2021]rceme 总结下获取disabled_funciton的方式 1.phpinfo() 2.var_dump(ini_get(“disable_functions”)); 3.var_dump(get_cfg_var(“disable_functions”)); 其他的 var_dump(get_cfg_var(“open_basedir”)); var_dump(ini_get_all()); <?php if(isset($_POS…

MMdetection3.0 问题:DETR验证集上AP值全为0.0000

MMdetection3.0 问题&#xff1a;DETR验证集上AP值全为0.0000 条件&#xff1a; 1、选择的是NWPU-VHR-10数据集&#xff0c;其中训练集455张&#xff0c;验证、测试相同均为195张。 2、在Faster-rcnn、YOLOv3模型上均能训练成功&#xff0c;但是在DETR训练时&#xff0c;出现验…

分享89个节日PPT,总有一款适合您

分享89个节日PPT&#xff0c;总有一款适合您 89个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1j6Yj-7UCcUyV4V_S_eGjpQ?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

【计算机毕业设计】java网上服装商城销售系统springboot+jsp

目前互联网上的网上销售系统每天以惊人的速度增加&#xff0c;网上购物越来越成为现代年轻人的首选&#xff0c;足不出门便能选购好自己称心如意的商品。基于Java术及MySQL数据库设计与实现一个网上服装销售系统&#xff0c;要求实现用户管理、服装管理、新闻公告管理、留言管理…

vue项目报错及解决npm run build:prod打包错误

vue项目报错及解决npm run build:prod打包错误 执行dev环境时加载失败了该变量&#xff0c;在package.json文件中 删掉 解决方法&#xff1a; 打包成功&#xff1a;

03-抽象工厂模式-C语言实现

说明&#xff1a; 均由 chatgpt生成&#xff0c;实例可以看出无法运行&#xff0c;仅供参考~ 抽象工厂模式&#xff1a; 代码实现&#xff1a; #include <stdio.h>// 定义抽象产品接口 typedef struct {void (*operation)(); } AbstractProductA;typedef struct {voi…

linux设置权限_setfacl_getfacl

3.2 设置权限ACL&#xff08;access control list&#xff09; 假设&#xff1a;/data所有者与所属组均为root&#xff0c;在不改变所有者的前提下&#xff0c;要求用户tom对该目录有完全访问权限&#xff08;rwx&#xff09;。只能考虑&#xff1a; 方法一&#xff1a;给/dat…

Data Grip的安装和使用

安装&#xff1a; 1.1 双击 exe 文件安装 1.2选择安装目录&#xff0c;点击next 1.3选择安装目录&#xff0c;点击next 1.3 创建快捷方式&#xff0c;安装 1.4点击install 连接&#xff1a; 2.1 创建Project 2.2创建连接 下载驱动&#xff0c;可能时间会比较久一点&#xff0c…

保护您的数据库免受注入攻击:MSSQL注入入门指南

MSSQL注入的入门讲解 一、引言二、MSSQL注入的基础知识2.1、MSSQL数据库的基本原理和结构2.2、常见的SQL语句和操作2.3、MSSQL注入的原理和工作方式 三、MSSQL注入攻击技术3.1、基于错误的注入攻击&#xff1a;利用错误消息和异常信息3.2、基于时间的注入攻击&#xff1a;利用延…

ArkUI组件--image组件

Image&#xff1a;图片显示组件 1.声明Image组件并设置图片的源&#xff1a; Image(src:string|PixelMap|Resource) #src表示源&#xff0c;支持三种格式①string格式&#xff0c;常用来加载网络图片&#xff0c;填写网址。&#xff08;手机端需要申请网络访问权限&#xff1…

【JavaSE学习专栏】第03篇 数组

文章目录 1 数组的定义2 数组声明创建3 数组的初始化4 数组的四个基本特点5 数组边界6 数组的使用7 多维数组8 Arrays类9 冒泡排序9.1 原理9.2 代码实现 10 数组插入算法10.1 问题10.2 分析10.3 代码 11 稀疏矩阵11.1 稀疏数组介绍 1 数组的定义 数组是相同类型数据的有序集合。…

StarRC常见问题整理

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 使用starrc_cmd “错误代码”就能看对应Error或Warnning的解释。如: starrc_cmd SX-2505 1)nxtgrd版本问题 INFORMATION: TCAD_GRD_FILE (nxtgrd file) generate by > 4 years older version…

Flink入门(一)

整体框架 Flink概述Flink上手部署Flink架构DataStream API(算子)Flink中的时间和窗口&#xff1a;窗口就是范围处理函数&#xff1a;底层函数状态管理&#xff1a;容错机制&#xff1a;报错重启后能够从出错的位置继续执行FlinkSQL&#xff1a;功能逐步完善 基于数据流的有状…

【一周安全资讯1202】信安标委发布《网络安全标准实践指南—网络安全产品互联互通 告警信息格式》;网络安全纳入注册会计师考试科目

要闻速览 1、信安标委发布《网络安全标准实践指南—网络安全产品互联互通 告警信息格式》 2、南昌某高校学生个人信息在境外公开出售&#xff0c;警方抓获学校"内鬼" 3、网络安全纳入注册会计师考试科目 4、乌克兰情报机构网攻俄罗斯民航局&#xff0c;称俄民航业正…

前端监控学习笔记

现成的SDK SentryFun Debug 需要监控什么&#xff1f; 错误统计 记录我们代码发布到线上各种奇奇怪怪的错误 行为日志埋点 记录用户行为&#xff0c;比如&#xff1a;分析用户浏览时间比较长的页面有哪些&#xff0c;常常点击的有哪些&#xff0c;可以做 相应的推荐 PV/UV统…

Python----字典练习

相关链接&#xff1a;Python---字典的增、删、改、查操作_python中字典的增删改查-CSDN博客 Python---字典---dict-CSDN博客 Python---引用变量与可变、非可变类型-CSDN博客 重点&#xff1a; 字典中的 key &#xff08;就是键&#xff09;可以是很多数据类型&#xff08;…

LLM:《第 1 部分》只是一个记忆技巧吗?

一、说明 批评者指责大型语言模型&#xff08;LLM&#xff09;仅仅是记忆工具已经变得很流行&#xff0c;他们认为他们对海量数据集的广泛训练几乎没有给真正的创造力留下什么空间。这种观点忽视了LLM背后的数学和经验科学&#xff0c;而正是这些数学和经验科学使KKM超越了基本…

科研者的福利!一个集论文、代码、数据集为一体的网站

Papers with Code 是一个总结了机器学习论文及其代码实现的网站。大多数论文都是有GitHub代码的。这个网站最好的地方就是对机器学习做了任务分类&#xff0c;检索对应的模型非常方便。早在18年Paper With Code创立时就轰动一时&#xff0c;仅创立一年就被Facebook收购。 Pape…