读源码笔记--文件过滤驱动FileSpy第1篇 -- DriverEntry

2024-09-07 15:08

本文主要是介绍读源码笔记--文件过滤驱动FileSpy第1篇 -- DriverEntry,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天只读FileSpy的DriverEntry,位于源文件:filespy.c。

//
// 全局变量.
//

ULONG gFileSpyDebugLevel = DEFAULT_FILESPY_DEBUG_LEVEL;
#if WINVER >= 0x0501
ULONG gFileSpyAttachMode = FILESPY_ATTACH_ALL_VOLUMES;
#else
ULONG gFileSpyAttachMode = FILESPY_ATTACH_ON_DEMAND;
#endif

 

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath)

{

    UNICODE_STRING nameString;
    NTSTATUS status;
    PFAST_IO_DISPATCH fastIoDispatch;
    ULONG i;
    UNICODE_STRING linkString;

 

#if WINVER >= 0x0501

//第一步,获取动态函数。

 

//目的只有一个,兼容Windows的之前的版本。原因是:有些Windows后面版本出现的函数,在出现之前的Windows操作系统中是没有。

//如果直接使用该函数,在该函数出现之前的Windows操作系统中,将直接导致驱动加载失败。

 

//这里面包括如下动态加载的函数:

// 1.FsRtlRegisterFileSystemFilterCallbacks:注册一些通知回调函数,当下层文件驱动执行某些操作的时候调用。2K SP4和XP以后可用。

// 2.IoAttachDeviceToDeviceStackSafe:绑定目标设备对象。2K SP4和XP以后可用。

// 3.IoEnumerateDeviceObjectList:枚举驱动的设备对象链。2K SP4和XP以后可用。

// 4.IoGetLowerDeviceObject:获取当前驱动的下一层的设备对象。2K SP4和XP以后可用。

// 5.IoGetDeviceAttachmentBaseRef:获取文件系统驱动或设备驱动栈底的设备对象。2K SP4和XP以后可用。

// 6.IoGetDiskDeviceObject:获取与给定文件系统卷设备相关的磁盘设备对象。2K SP4和XP以后可用。

// 7.IoGetAttachedDeviceReference:获取驱动栈顶的设备对象,并将该设备对象的引用计数增1。2K 和XP以后可用。

// 8.RtlGetVersion:获取操作系统版本。

SpyLoadDynamicFunctions();

 

// 获取操作系统版本,调用的是RtlGetVersion或PsGetVersion。

SpyGetCurrentVersion();

#endif

 

// 从注册表中获取FileSpy指定的参数。

// 根据RegistryPath在注册表中的路径,

// 1.查询“MaxRecords”

//                数据结构体为:KEY_VALUE_PARTIAL_INFORMATION,其下的Data成员的内容放于全局变量:gMaxRecordsToAllocate中

// 2.查询“MaxNames”

//                 数据结构体为:KEY_VALUE_PARTIAL_INFORMATION,其下的Data成员的内容放于全局变量:gMaxNamesToAllocate中

// 3.查询“DebugFlags”

//                 数据结构体为:KEY_VALUE_PARTIAL_INFORMATION,其下的Data成员的内容放于全局变量:gFileSpyDebugLevel中

// 4.查询“AttachMode”

//                 数据结构体为:KEY_VALUE_PARTIAL_INFORMATION,其下的Data成员的内容放于全局变量:gFileSpyAttachMode中

SpyReadDriverParameters( RegistryPath );

 

// #ifndef FlagOn
// #define FlagOn(_F,_SF)        ((_F) & (_SF))
// #endif

if (FlagOn(gFileSpyDebugLevel,   SPYDEBUG_BREAK_ON_DRIVER_ENTRY)) {

        DbgBreakPoint();
    }

 

//

// 将DriverEntry的参数:DriverObject,保存到全局变量:gFileSpyDriverObject

//

gFileSpyDriverObject = DriverObject;

 

//

// 初始化一个Lookaside的内存池。

//

ExInitializePagedLookasideList( &gFileSpyNameBufferLookasideList,
                                    NULL,
                                    NULL,
                                    0,
                                    FILESPY_LOOKASIDE_SIZE,
                                    FILESPY_NAME_BUFFER_TAG,
                                    0 );

 

 

#if DBG && WINVER >= 0x0501

//

// 判断操作系统版本,设置卸载例程。

//

    if (IS_WINDOWSXP_OR_LATER()) {

        ASSERT( NULL != gSpyDynamicFunctions.EnumerateDeviceObjectList );

        gFileSpyDriverObject->DriverUnload = DriverUnload;
    }
#endif

//

// 初始化名称,并调用IoCreateDevice创建设备。

// 这里的#define                  FILESPY_FULLDEVICE_NAME1                L"\\FileSystem\\Filters\\FileSpy"

// 因为是CDO,所以不需要设备拓展。

//

RtlInitUnicodeString( &nameString, FILESPY_FULLDEVICE_NAME1 );

status = IoCreateDevice( DriverObject,
                             0,                 //  has no device extension
                             &nameString,
                             FILE_DEVICE_DISK_FILE_SYSTEM,
                             FILE_DEVICE_SECURE_OPEN,
                             FALSE,
                             &gControlDeviceObject);

    if (STATUS_OBJECT_PATH_NOT_FOUND == status) {

        //

        // 如果第一次创建失败,错误代码为:STATUS_OBJECT_PATH_NOT_FOUND,说明不存在这个路径。再次创建,路径为:

        // #define           FILESPY_FULLDEVICE_NAME2        L"\\FileSystem\\FileSpyCDO"

        // 因为这是一个我们自己使用的CDO,所以不需要设备拓展。该设备,主要用来与我们自己的应用层通信使用 和

        // 修改整个驱动的内部配置的。

        //

        RtlInitUnicodeString( &nameString, FILESPY_FULLDEVICE_NAME2 );

        status = IoCreateDevice( DriverObject,
                                 0,             //  has no device extension
                                 &nameString,
                                 FILE_DEVICE_DISK_FILE_SYSTEM,
                                 FILE_DEVICE_SECURE_OPEN,
                                 FALSE,
                                 &gControlDeviceObject);

        if (!NT_SUCCESS( status )) {

            SPY_LOG_PRINT( SPYDEBUG_ERROR,
                           ("FileSpy!DriverEntry: Error creating FileSpy control device \"%wZ\", error: %x\n",
                           &nameString,
                           status) );

            return status;
        }

    } else if (!NT_SUCCESS( status )) {

        //

       // 调用失败,直接返回。

       //

        SPY_LOG_PRINT( SPYDEBUG_ERROR,
                       ("FileSpy!DriverEntry: Error creating FileSpy control device \"%wZ\", error: %x\n",
                       &nameString,
                       status) );

        return status;

    }

//

// 创建符号链接,如果失败,删除符号链接,再创建一次,如果再次失败,删除设备,返回。

//

RtlInitUnicodeString( &linkString, FILESPY_DOSDEVICE_NAME );
    status = IoCreateSymbolicLink( &linkString, &nameString );

    if (!NT_SUCCESS(status)) {

        //
        //  Remove the existing symbol link and try and create it again.
        //  If this fails then quit.
        //

        IoDeleteSymbolicLink( &linkString );
        status = IoCreateSymbolicLink( &linkString, &nameString );

        if (!NT_SUCCESS(status)) {

            SPY_LOG_PRINT( SPYDEBUG_ERROR,
                       ("FileSpy!DriverEntry: IoCreateSymbolicLink failed\n") );

            IoDeleteDevice(gControlDeviceObject);
            return status;
        }
    }

//

// 初始化派遣例程,这里只设置IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_FILE_SYSTEM_CONTROL。

// IRP_MJ_FILE_SYSTEM_CONTROL,是文件系统控制设备对象(CDO),在一个新的存储介质被系统发现并在文件系统中生成一个卷的

// 这个过程开始时,收到的一个IRP,这个时候的次功能号为IRP_MN_MOUNT。只要过滤驱动生成了一个设备,并且绑定了文件系统的控制

// 设备对象(CDO),过滤驱动就一定能得到这样一个IRP。

//

for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {

        DriverObject->MajorFunction[i] = SpyDispatch;
    }

    DriverObject->MajorFunction[IRP_MJ_CREATE] = SpyCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = SpyClose;
    DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SpyFsControl;

//

// 设置FAST I/O的派遣例程。每个驱动对象都有FAST I/O派遣例程,只是多数设备驱动是不调用这写快速I/O分发函数的。但是文件系统必须

// 要设置,如果不设置上层依然会调用FAST I/O这些例程,而且会导致蓝屏。它是独立于普通IRP的另外的接口。

// 最简单的FAST I/O分发函数的写法是:直接返回FALSE就可以了。

//

// FLAST I/O 的例程空间需要自己开辟。该空间的释放,在DriverUnload里面。

//

fastIoDispatch = ExAllocatePoolWithTag( NonPagedPool,
                                            sizeof( FAST_IO_DISPATCH ),
                                            FILESPY_POOL_TAG );

    if (!fastIoDispatch) {

        IoDeleteDevice( gControlDeviceObject );
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlZeroMemory( fastIoDispatch, sizeof( FAST_IO_DISPATCH ) );
    fastIoDispatch->SizeOfFastIoDispatch = sizeof( FAST_IO_DISPATCH );
    fastIoDispatch->FastIoCheckIfPossible = SpyFastIoCheckIfPossible;
    fastIoDispatch->FastIoRead = SpyFastIoRead;
    fastIoDispatch->FastIoWrite = SpyFastIoWrite;
    fastIoDispatch->FastIoQueryBasicInfo = SpyFastIoQueryBasicInfo;
    fastIoDispatch->FastIoQueryStandardInfo = SpyFastIoQueryStandardInfo;
    fastIoDispatch->FastIoLock = SpyFastIoLock;
    fastIoDispatch->FastIoUnlockSingle = SpyFastIoUnlockSingle;
    fastIoDispatch->FastIoUnlockAll = SpyFastIoUnlockAll;
    fastIoDispatch->FastIoUnlockAllByKey = SpyFastIoUnlockAllByKey;
    fastIoDispatch->FastIoDeviceControl = SpyFastIoDeviceControl;
    fastIoDispatch->FastIoDetachDevice = SpyFastIoDetachDevice;
    fastIoDispatch->FastIoQueryNetworkOpenInfo = SpyFastIoQueryNetworkOpenInfo;
    fastIoDispatch->MdlRead = SpyFastIoMdlRead;
    fastIoDispatch->MdlReadComplete = SpyFastIoMdlReadComplete;
    fastIoDispatch->PrepareMdlWrite = SpyFastIoPrepareMdlWrite;
    fastIoDispatch->MdlWriteComplete = SpyFastIoMdlWriteComplete;
    fastIoDispatch->FastIoReadCompressed = SpyFastIoReadCompressed;
    fastIoDispatch->FastIoWriteCompressed = SpyFastIoWriteCompressed;
    fastIoDispatch->MdlReadCompleteCompressed = SpyFastIoMdlReadCompleteCompressed;
    fastIoDispatch->MdlWriteCompleteCompressed = SpyFastIoMdlWriteCompleteCompressed;
    fastIoDispatch->FastIoQueryOpen = SpyFastIoQueryOpen;

    DriverObject->FastIoDispatch = fastIoDispatch;

//

// 设置通知回调。FsRtlRegisterFileSystemFilterCallbacks函数注册需通知回调函数,这些回调函数将在文件系统的相关操作之前被调用

//

#if WINVER >= 0x0501

    {
        FS_FILTER_CALLBACKS fsFilterCallbacks;

        if (IS_WINDOWSXP_OR_LATER()) {

            ASSERT( NULL != gSpyDynamicFunctions.RegisterFileSystemFilterCallbacks );

            //
            //  This version of the OS exports
            //  FsRtlRegisterFileSystemFilterCallbacks, therefore it must
            //  support the FsFilter callbacks interface.  We will register to
            //  receive callbacks for these operations.
            //

            //
            //  Setup the callbacks for the operations we receive through
            //  the FsFilter interface.
            //

            fsFilterCallbacks.SizeOfFsFilterCallbacks = sizeof( FS_FILTER_CALLBACKS );
            fsFilterCallbacks.PreAcquireForSectionSynchronization = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostAcquireForSectionSynchronization = SpyPostFsFilterOperation;
            fsFilterCallbacks.PreReleaseForSectionSynchronization = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostReleaseForSectionSynchronization = SpyPostFsFilterOperation;
            fsFilterCallbacks.PreAcquireForCcFlush = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostAcquireForCcFlush = SpyPostFsFilterOperation;
            fsFilterCallbacks.PreReleaseForCcFlush = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostReleaseForCcFlush = SpyPostFsFilterOperation;
            fsFilterCallbacks.PreAcquireForModifiedPageWriter = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostAcquireForModifiedPageWriter = SpyPostFsFilterOperation;
            fsFilterCallbacks.PreReleaseForModifiedPageWriter = SpyPreFsFilterOperation;
            fsFilterCallbacks.PostReleaseForModifiedPageWriter = SpyPostFsFilterOperation;

            status = (gSpyDynamicFunctions.RegisterFileSystemFilterCallbacks)( DriverObject,
                                                                              &fsFilterCallbacks );

            if (!NT_SUCCESS( status )) {

                DriverObject->FastIoDispatch = NULL;
                ExFreePoolWithTag( fastIoDispatch, FILESPY_POOL_TAG );
                IoDeleteDevice( gControlDeviceObject );
                return status;
            }
        }
    }
#endif

//

// 初始化全局变量。链表,锁等

//

 ExInitializeFastMutex( &gSpyDeviceExtensionListLock );
    InitializeListHead( &gSpyDeviceExtensionList );

    KeInitializeSpinLock( &gControlDeviceStateLock );

    InitializeListHead( &gOutputBufferList );

    KeInitializeSpinLock( &gOutputBufferLock );
    KeInitializeSpinLock( &gLogSequenceLock );

    ExInitializeFastMutex( &gSpyAttachLock );

#ifndef MEMORY_DBG

    //
    //  When we aren't debugging our memory usage, we want to allocate
    //  memory from a look-aside list for better performance.  Unfortunately,
    //  we cannot benefit from the memory debugging help of the Driver
    //  Verifier if we allocate memory from a look-aside list.
    //

    ExInitializeNPagedLookasideList( &gFreeBufferList,
                                     NULL/*ExAllocatePoolWithTag*/,
                                     NULL/*ExFreePool*/,
                                     0,
                                     RECORD_SIZE,
                                     FILESPY_LOGRECORD_TAG,
                                     100 );
#endif

//

// 初始化名称环境。SpyInitNamingEnvironment位于:fspyHash.c中。初始化:gHashTable和gHashLockTable这2个全局变量。

// 初始化内部字符串,存于全局变量:gVolumeString、gOverrunString、gPagingIoString

//

SpyInitNamingEnvironment();

RtlInitUnicodeString(&gVolumeString, L"VOLUME");
RtlInitUnicodeString(&gOverrunString, L"......");
RtlInitUnicodeString(&gPagingIoString, L"Paging IO");

//

// IoRegisterFsRegistrationChange 注册文件系统变动回调。当系统中有任何文件系统被激活或被注销时,注册过的回调函数就会被调用。

//

// 注:这里的文件系统激活和卷的挂载是2回事。文件系统,比如NTFS、FAT32等,如果系统中一个NTFS的磁盘卷都没有采用这种文件

// 系统,那么这时的操作系统时没有加载NTFS文件系统的驱动,换言之,NTFS处于未激活状态。当任何一个卷采用了NTFS这种文件

// 系统,则NTFS被加载了,此时就叫NTFS被激活,以后再有卷采用NTFS文件系统挂载时,都不能说是文件系统的激活。

//

// 2K SP4和XP及以后的OS,会枚举所有已经存在的文件系统(除了RAM文件系统)。而2K SP4以前的,不会枚举已经在过滤驱动加载之前

// 就已经挂载上了的文件系统。

//

if (gFileSpyAttachMode == FILESPY_ATTACH_ALL_VOLUMES) {

        status = IoRegisterFsRegistrationChange( DriverObject,  SpyFsNotification );

        if (!NT_SUCCESS( status )) {

            SPY_LOG_PRINT( SPYDEBUG_ERROR,
                           ("FileSpy!DriverEntry: Error registering FS change notification, status=%08x\n",
                            status) );

            DriverObject->FastIoDispatch = NULL;
            ExFreePoolWithTag( fastIoDispatch, FILESPY_POOL_TAG );
            IoDeleteDevice( gControlDeviceObject );
            return status;
        }
    }

 

#if WINVER >= 0x0600

//

// 根据filespy创建资源管理器。SpyCreateKtmResourceManager位于:fspyTx.c中

//

status = SpyCreateKtmResourceManager();

if (!NT_SUCCESS( status )) {

        SPY_LOG_PRINT( SPYDEBUG_ERROR,
                       ("FileSpy!DriverEntry: Error creating Ktm resource manager, status=%08x\n",
                        status) );

        return status;
    }

//

// 下面就比较简单了,就不提了。

//

    //
    //  Initialize the lookaside list for the transaction context data.
    //  We will create a transaction context for each enlistment we create.
    //  The context data will be freed when the KTM callback routine
    //  receives appropriate notifications.
    //

    ExInitializeNPagedLookasideList( &gTransactionList,
                                     NULL,
                                     NULL,
                                     0,
                                     sizeof( FILESPY_TRANSACTION_CONTEXT ),
                                     FILESPY_TRANSACTION_TAG,
                                     0 );

#endif


    //
    //  Clear the initializing flag on the control device object since we
    //  have now successfully initialized everything.
    //

    ClearFlag( gControlDeviceObject->Flags, DO_DEVICE_INITIALIZING );

    return STATUS_SUCCESS;

 

 

}

这篇关于读源码笔记--文件过滤驱动FileSpy第1篇 -- DriverEntry的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145398

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

java streamfilter list 过滤的实现

《javastreamfilterlist过滤的实现》JavaStreamAPI中的filter方法是过滤List集合中元素的一个强大工具,可以轻松地根据自定义条件筛选出符合要求的元素,本文就来... 目录1. 创建一个示例List2. 使用Stream的filter方法进行过滤3. 自定义过滤条件1. 定

Redis如何实现刷票过滤

《Redis如何实现刷票过滤》:本文主要介绍Redis如何实现刷票过滤问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录引言一、概述二、技术选型三、搭建开发环境四、使用Redis存储数据四、使用SpringBoot开发应用五、 实现同一IP每天刷票不得超过次数六

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步