2013年10月23日星期三

枚举系统注册的所有的minifilter驱动及其信息

/*
文件名:FltEnumerateFilters.C

微软不建议使用:IoEnumerateRegisteredFiltersList.

功能:enumerates all registered minifilter drivers in the system及其一些信息的显示.
目的:示例一些minifilter的一些枚举函数的用法,理解,区别.

可能要连接fltMgr.lib.
加载的方式可用一般的驱动(nt服务).

参考资料:
http://hi.baidu.com/kernelkit/item/95dab957bf115711aaf6d743
http://www.inreverse.net/?p=1334
http://blogs.msdn.com/b/alexcarp/archive/2009/08/11/issuing-io-in-minifilters-part-1-fltcreatefile.aspx 
http://blogs.msdn.com/b/alexcarp/archive/2009/09/01/issuing-io-in-minifilters-part-2-flt-vs-zw.aspx
http://blogs.msdn.com/b/alexcarp/archive/2009/06/16/filter-manager-concepts-part-3-flt-filter.aspx
http://blogs.msdn.com/b/alexcarp/archive/2009/06/24/filter-manager-concepts-part-4-flt-instance.aspx
等. 

不足之处,敬请指出.
made by correy
made at 2013.10.23
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

个人感觉FltEnumerateInstances和FltEnumerateVolumes差不多.
区别是前者能获取所有的minifilter的所有的实例的信息,后者只获取某个minifilter的所有的卷设备的信息.
相信有转换和联系的函数.

开始以为:FltEnumerateVolumes是获取的一个PFLT_FILTER过滤的卷设备的对象,不是全部的磁盘上的卷.
经测试是:获取本地计算机上的可用的卷.一下是获取不到的:
1.光驱里面没有光盘.
2.虚拟磁盘软件虚拟出来的卷设备.
3.网络映射的盘符.
4.subst命令搞出的驱动器号.
5.软盘没有测试.
这个函数的缺点是第一个参数,而且还不能是0,个人建议是去掉这个参数.
不过在minifilter驱动里面是有这个参数的.
*/

#include <fltKernel.h>

#define TAG 'tset' //test
#define _In_ //WDK8不需要.

void PrintFilterFullInformation(PFLT_FILTER pf)
{
    //另一个思路是使用:FltEnumerateFilterInformation

    NTSTATUS status = STATUS_SUCCESS;
    PVOID  Buffer = 0;
    ULONG  BufferSize = 0;
    ULONG  BytesReturned = 0;
    PFILTER_FULL_INFORMATION pfi = 0;
    UNICODE_STRING FilterName;

    status = FltGetFilterInformation(pf, FilterFullInformation, Buffer, BufferSize, &BytesReturned);
    if (!NT_SUCCESS( status )) 
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return;
        }
    }

    BufferSize = sizeof (PFLT_FILTER) * BytesReturned * 2;//多申请一倍.

    Buffer = (PFLT_FILTER *)ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG);
    if (Buffer == NULL) {
        return;
    }
    RtlZeroMemory(Buffer,BufferSize);

    status = FltGetFilterInformation(pf, FilterFullInformation, Buffer, BufferSize, &BytesReturned);
    if (!NT_SUCCESS( status )) 
    {
        ExFreePoolWithTag(Buffer, TAG);
        return;
    }

    pfi = (PFILTER_FULL_INFORMATION)Buffer;

    FilterName.Buffer = pfi->FilterNameBuffer;
    FilterName.Length = pfi->FilterNameLength;
    FilterName.MaximumLength = pfi->FilterNameLength;//不再加2.

    //DbgPrint("FrameID:%d\n", pfi->FrameID);
    //DbgPrint("NumberOfInstances:%d\n", pfi->NumberOfInstances);
    DbgPrint("FilterName:%wZ\n",&FilterName);

    /*
    打印的内容如下:
    FrameID:0
    NumberOfInstances:5
    FilterName:TFsFlt
    FrameID:0
    NumberOfInstances:6
    FilterName:QQSysMonX64
    FrameID:0
    NumberOfInstances:1
    FilterName:luafv 注释:微软的LUA文件虚拟化筛选器驱动程序.
    */
    
    ExFreePoolWithTag(Buffer, TAG);
}

void PrintVolumeStandardInformation(PFLT_VOLUME pv)
{
    NTSTATUS status = STATUS_SUCCESS;
    PVOID  Buffer = 0;
    ULONG  BufferSize = 0;
    ULONG  BytesReturned = 0;
    PFILTER_VOLUME_STANDARD_INFORMATION pvsi = 0;
    UNICODE_STRING VolumeName;

    status = FltGetVolumeInformation(pv, FilterVolumeStandardInformation, Buffer, BufferSize, &BytesReturned);
    if (!NT_SUCCESS( status )) 
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return;
        }
    }

    BufferSize = sizeof (PFLT_FILTER) * BytesReturned * 2;//多申请一倍.

    Buffer = (PFLT_FILTER *)ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG);
    if (Buffer == NULL) {
        return;
    }
    RtlZeroMemory(Buffer,BufferSize);

    status = FltGetVolumeInformation(pv, FilterVolumeStandardInformation, Buffer, BufferSize, &BytesReturned);
    if (!NT_SUCCESS( status )) 
    {
        ExFreePoolWithTag(Buffer, TAG);
        return;
    }

    pvsi = (PFILTER_VOLUME_STANDARD_INFORMATION)Buffer;

    VolumeName.Buffer = pvsi->FilterVolumeName;
    VolumeName.Length = pvsi->FilterVolumeNameLength;
    VolumeName.MaximumLength = pvsi->FilterVolumeNameLength;//不再加2.

    //DbgPrint("Flags:%d\n", pvsi->Flags);
    //DbgPrint("FrameID:%d\n", pvsi->FrameID);
    DbgPrint("VolumeName:%wZ\n",&VolumeName);

    switch(pvsi->FileSystemType) 
    {
    case FLT_FSTYPE_UNKNOWN:
        DbgPrint("FileSystemType :%ls\n",L"Unknown file system type.");
        break;
    case FLT_FSTYPE_RAW: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\RAW.");
        break;
    case FLT_FSTYPE_NTFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Ntfs.");
        break;
    case FLT_FSTYPE_FAT: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Fat.");
        break;
    case FLT_FSTYPE_CDFS:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Cdfs.");
        break;
    case FLT_FSTYPE_UDFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Udfs.");
        break;
    case FLT_FSTYPE_LANMAN: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\MRxSmb.");
        break;
    case FLT_FSTYPE_WEBDAV: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\MRxDav.");
        break;
    case FLT_FSTYPE_RDPDR:
        DbgPrint("FileSystemType :%ls\n",L"\\Driver\\rdpdr.");
        break;
    case FLT_FSTYPE_NFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\NfsRdr.");
        break;
    case FLT_FSTYPE_MS_NETWARE: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\nwrdr.");
        break;
    case FLT_FSTYPE_NETWARE: 
        DbgPrint("FileSystemType :%ls\n",L"Novell NetWare redirector.");
        break;
    case FLT_FSTYPE_BSUDF:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\BsUDF.");
        break;
    case FLT_FSTYPE_MUP:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Mup.");
        break;
    case FLT_FSTYPE_RSFX: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\RsFxDrv.");
        break;
    case FLT_FSTYPE_ROXIO_UDF1:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\cdudf_xp.");
        break;
    case FLT_FSTYPE_ROXIO_UDF2:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\UdfReadr_xp.");
        break;
    case FLT_FSTYPE_ROXIO_UDF3: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\DVDVRRdr_xp.");
        break;
    case FLT_FSTYPE_TACIT: 
        DbgPrint("FileSystemType :%ls\n",L"\\Device\\TCFSPSE.");
        break;
    case FLT_FSTYPE_FS_REC: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\Fs_rec.");
        break;
    case FLT_FSTYPE_INCD:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\InCDfs.");
        break;
    case FLT_FSTYPE_INCD_FAT: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\InCDFat.");
        break;
    case FLT_FSTYPE_EXFAT: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\exfat.");
        break;
    case FLT_FSTYPE_PSFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\psfs.");
        break;
    case FLT_FSTYPE_GPFS:
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\gpfs.");
        break;
    case FLT_FSTYPE_NPFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\npfs.");
        break;
    case FLT_FSTYPE_MSFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\msfs.");
        break;
    case FLT_FSTYPE_CSVFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\csvfs.");
        break;
    case FLT_FSTYPE_REFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\refs.");
        break;
    case FLT_FSTYPE_OPENAFS: 
        DbgPrint("FileSystemType :%ls\n",L"\\FileSystem\\AFSRedirector.");
        break;
    default: 
        DbgPrint("FileSystemType :%ls\n",L"发生错误!");
        break;
    }

    //这里也要用FltObjectDereference再释放一下?
    FltObjectDereference(pv);

    ExFreePoolWithTag(Buffer, TAG);
}

void EnumerateInstances(PFLT_FILTER pf)
{
    //FltEnumerateInstances
    //FltGetInstanceInformation 这个获取的全是数字,所以放弃使用.
    //FltEnumerateInstanceInformationByFilter 这个获取的全是数字,所以放弃使用.
    //FltEnumerateInstanceInformationByVolume 这个获取的全是数字,所以放弃使用.

    NTSTATUS status = STATUS_SUCCESS;
    PFLT_INSTANCE  * InstanceList = 0;
    ULONG  InstanceListSize = 0;
    ULONG  NumberInstancesReturned = 0;
    ULONG i;

    status = FltEnumerateInstances(0, pf, InstanceList, InstanceListSize, &NumberInstancesReturned);
    if (!NT_SUCCESS( status )) 
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return;
        }
    }

    InstanceListSize = sizeof (PFLT_INSTANCE) * NumberInstancesReturned * 2;//多申请一倍.

    InstanceList = (PFLT_INSTANCE *)ExAllocatePoolWithTag(NonPagedPool, InstanceListSize, TAG);
    if (InstanceList == NULL) {
        return;
    }
    RtlZeroMemory(InstanceList,InstanceListSize);

    status = FltEnumerateInstances(0, pf, InstanceList, InstanceListSize, &NumberInstancesReturned);
    if (!NT_SUCCESS( status )) 
    {
        ExFreePoolWithTag(InstanceList, TAG);
        return;
    }

    for (i = 0; i< NumberInstancesReturned; i++)
    {
        //打印每个实例的信息.
        //相信和卷设备是一样的,转换为卷设备再打印,这里就不打印详细信息的,只打印实例的地址.
        DbgPrint("PFLT_FILTER:%p\tInstances:%p\n", pf, InstanceList[i]);

        FltObjectDereference(InstanceList[i]);
    }

    //这里也要用FltObjectDereference再释放一下?
    FltObjectDereference(pf);

    ExFreePoolWithTag(InstanceList, TAG);
}

void EnumerateVolumes(PFLT_FILTER pf)
{
    //FltEnumerateVolumes这个获取全了,要枚举.
    //FltGetVolumeInformation
    //FltEnumerateVolumeInformation这个不用,是获取单个的,要循环.

    NTSTATUS status = STATUS_SUCCESS;
    PFLT_VOLUME  * VolumeList = 0;
    ULONG  VolumeListSize = 0;
    ULONG  NumberVolumesReturned = 0;
    ULONG i;

    status = FltEnumerateVolumes(pf, VolumeList, VolumeListSize, &NumberVolumesReturned);
    if (!NT_SUCCESS( status )) 
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return;
        }
    }

    VolumeListSize = sizeof (PFLT_VOLUME) * NumberVolumesReturned * 2;//多申请一倍.

    VolumeList = (PFLT_VOLUME  *)ExAllocatePoolWithTag(NonPagedPool, VolumeListSize, TAG);
    if (VolumeList == NULL) {
        return;
    }
    RtlZeroMemory(VolumeList,VolumeListSize);

    status = FltEnumerateVolumes(pf, VolumeList, VolumeListSize, &NumberVolumesReturned);
    if (!NT_SUCCESS( status )) 
    {
        ExFreePoolWithTag(VolumeList, TAG);
        return;
    }

    for (i = 0; i< NumberVolumesReturned; i++)
    {
        //打印每个卷设备的信息.
        PrintVolumeStandardInformation(VolumeList[i]);

        FltObjectDereference(VolumeList[i]);
    }

    //这里也要用FltObjectDereference再释放一下?
    FltObjectDereference(pf);

    ExFreePoolWithTag(VolumeList, TAG);
}

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    /*
    没有此函数是停止不了此驱动的,但是可以删除驱动.
    在别的地方设置一下,如注册表回调保护驱动入口的第二个参数,可以让本驱动删除不了.
    如果这样,就在一个消息中卸载了:恢复回调入口和删除注册表的保护.
    然后应用层再卸载,上面的消息中还可以加密码验证.
    */
}

DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    PFLT_FILTER * FilterList;
    ULONG FilterListSize = 0;
    ULONG NumberFiltersReturned = 0;
    ULONG i;

    UNREFERENCED_PARAMETER( RegistryPath );

    KdBreakPoint();//DbgBreakPoint() 

    DriverObject->DriverUnload = DriverUnload;

    //Because filters can register at any time, two calls to FltEnumerateFilters are not guaranteed to return the same result.
    //确保两次调用FltEnumerateFilters期间不要加载或者卸载minifilter.建议使用rundown机制.
    status = FltEnumerateFilters(0,FilterListSize,&NumberFiltersReturned);
    if (!NT_SUCCESS( status )) //#define STATUS_BUFFER_TOO_SMALL          ((NTSTATUS)0xC0000023L)
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return status;
        }
    }    

    //建议每次成功的调用之后都调用:VOID FltObjectDereference(_Inout_  PVOID FltObject);

    FilterListSize = sizeof (PFLT_FILTER) * NumberFiltersReturned * 2;//多申请一倍.

    FilterList = (PFLT_FILTER *)ExAllocatePoolWithTag(NonPagedPool, FilterListSize, TAG);
    if (FilterList == NULL) {
        return status;
    }
    RtlZeroMemory(FilterList,FilterListSize);

    status = FltEnumerateFilters(FilterList,FilterListSize,&NumberFiltersReturned);
    if (!NT_SUCCESS( status )) 
    {
        ExFreePoolWithTag(FilterList, TAG);
        return status;
    }

    //卸载所有已经注册的minifilter.理论上比抹去未公开的结构好.这里暂时注释掉.
    //for (i = 0;i < NumberFiltersReturned;i++)
    //{
    //    FltUnregisterFilter(FilterList[i]);//有的驱动会永远停止在这里.
    //}

    /*
    在这里可以列举一些minifilter的信息
    甚至每个minifilter过滤的每个卷设备的信息.

    PFLT_FILTER是个为公开的数据结构,各个版本的结构不一.

    0: kd> vertarget
    Windows 7 Kernel Version 7601 (Service Pack 1) MP (2 procs) Free x64
    Built by: 7601.18229.amd64fre.win7sp1_gdr.130801-1533
    Machine Name:
    Kernel base = 0xfffff800`0185f000 PsLoadedModuleList = 0xfffff800`01aa26d0
    Debug session time: Wed Oct 23 16:25:06.039 2013 (UTC + 8:00)
    System Uptime: 0 days 0:04:08.664
    0: kd> dt _FLT_FILTER fffffa80`04306c60
    fltmgr!_FLT_FILTER
    +0x000 Base             : _FLT_OBJECT
    +0x020 Frame            : 0xfffffa80`03f30630 _FLTP_FRAME
    +0x028 Name             : _UNICODE_STRING "TFsFlt"
    +0x038 DefaultAltitude  : _UNICODE_STRING "389700"
    +0x048 Flags            : 2 ( FLTFL_FILTERING_INITIATED )
    +0x050 DriverObject     : 0xfffffa80`042fde70 _DRIVER_OBJECT
    +0x058 InstanceList     : _FLT_RESOURCE_LIST_HEAD
    +0x0d8 VerifierExtension : (null) 
    +0x0e0 VerifiedFiltersLink : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
    +0x0f0 FilterUnload     : 0xfffff880`0245f320     long  +0
    +0x0f8 InstanceSetup    : 0xfffff880`0248d0ec     long  +0
    +0x100 InstanceQueryTeardown : 0xfffff880`0248d118     long  +0
    +0x108 InstanceTeardownStart : (null) 
    +0x110 InstanceTeardownComplete : 0xfffff880`0248d138     void  +0
    +0x118 SupportedContextsListHead : 0xfffffa80`04306890 _ALLOCATE_CONTEXT_HEADER
    +0x120 SupportedContexts : [6] (null) 
    +0x150 PreVolumeMount   : (null) 
    +0x158 PostVolumeMount  : (null) 
    +0x160 GenerateFileName : (null) 
    +0x168 NormalizeNameComponent : (null) 
    +0x170 NormalizeNameComponentEx : (null) 
    +0x178 NormalizeContextCleanup : (null) 
    +0x180 KtmNotification  : (null) 
    +0x188 Operations       : 0xfffffa80`04306ef0 _FLT_OPERATION_REGISTRATION
    +0x190 OldDriverUnload  : (null) 
    +0x198 ActiveOpens      : _FLT_MUTEX_LIST_HEAD
    +0x1e8 ConnectionList   : _FLT_MUTEX_LIST_HEAD
    +0x238 PortList         : _FLT_MUTEX_LIST_HEAD
    +0x288 PortLock         : _EX_PUSH_LOCK   

    再附加两个结构:
    1: kd> dt _FLT_INSTANCE
    fltmgr!_FLT_INSTANCE
    +0x000 Base             : _FLT_OBJECT
    +0x020 OperationRundownRef : Ptr64 _EX_RUNDOWN_REF_CACHE_AWARE
    +0x028 Volume           : Ptr64 _FLT_VOLUME
    +0x030 Filter           : Ptr64 _FLT_FILTER
    +0x038 Flags            : _FLT_INSTANCE_FLAGS
    +0x040 Altitude         : _UNICODE_STRING
    +0x050 Name             : _UNICODE_STRING
    +0x060 FilterLink       : _LIST_ENTRY
    +0x070 ContextLock      : _EX_PUSH_LOCK
    +0x078 Context          : Ptr64 _CONTEXT_NODE
    +0x080 TransactionContexts : _CONTEXT_LIST_CTRL
    +0x088 TrackCompletionNodes : Ptr64 _TRACK_COMPLETION_NODES
    +0x090 CallbackNodes    : [50] Ptr64 _CALLBACK_NODE
    1: kd> dt _FLT_VOLUME
    fltmgr!_FLT_VOLUME
    +0x000 Base             : _FLT_OBJECT
    +0x020 Flags            : _FLT_VOLUME_FLAGS
    +0x024 FileSystemType   : _FLT_FILESYSTEM_TYPE
    +0x028 DeviceObject     : Ptr64 _DEVICE_OBJECT
    +0x030 DiskDeviceObject : Ptr64 _DEVICE_OBJECT
    +0x038 FrameZeroVolume  : Ptr64 _FLT_VOLUME
    +0x040 VolumeInNextFrame : Ptr64 _FLT_VOLUME
    +0x048 Frame            : Ptr64 _FLTP_FRAME
    +0x050 DeviceName       : _UNICODE_STRING
    +0x060 GuidName         : _UNICODE_STRING
    +0x070 CDODeviceName    : _UNICODE_STRING
    +0x080 CDODriverName    : _UNICODE_STRING
    +0x090 InstanceList     : _FLT_RESOURCE_LIST_HEAD
    +0x110 Callbacks        : _CALLBACK_CTRL
    +0x4f8 ContextLock      : _EX_PUSH_LOCK
    +0x500 VolumeContexts   : _CONTEXT_LIST_CTRL
    +0x508 StreamListCtrls  : _FLT_RESOURCE_LIST_HEAD
    +0x588 FileListCtrls    : _FLT_RESOURCE_LIST_HEAD
    +0x608 NameCacheCtrl    : _NAME_CACHE_VOLUME_CTRL
    +0x6b8 MountNotifyLock  : _ERESOURCE
    +0x720 TargetedOpenActiveCount : Int4B
    +0x728 TxVolContextListLock : _EX_PUSH_LOCK
    +0x730 TxVolContexts    : _TREE_ROOT

    不过建议使用:FltEnumerateFilterInformation或者FltGetFilterInformation获取各种信息.
    */

    //打印每个驱动的信息,这里选择FilterFullInformation类型.
    for (i = 0;i < NumberFiltersReturned;i++)
    {
        PrintFilterFullInformation(FilterList[i]);//打印系统的所有的minifilter 驱动.
        EnumerateInstances(FilterList[i]);//枚举每个minifilter驱动的每个过滤设备的实例,里面可以获取更多的信息.
        EnumerateVolumes(FilterList[i]);//枚举每个minifilter驱动的每个卷设备的信息,里面可以获取更多的信息,其实和上面的差不多.

        DbgPrint("\n\n");
    }

    /*
    FltEnumerateFilters adds a rundown reference to each of the opaque filter pointers returned in the array that the FilterList parameter points to. 
    When these pointers are no longer needed, the caller must release them by calling FltObjectDereference on each one. 
    Thus every successful call to FltEnumerateFilters must be matched by a subsequent call to FltObjectDereference for each returned filter pointer. 
    */
    for (i = 0;i < NumberFiltersReturned;i++)
    {
        FltObjectDereference(FilterList[i]);
    }    

    ExFreePoolWithTag(FilterList, TAG);

    return status;
}

/*
效果如下:
0: kd> g
FilterName:TFsFlt
PFLT_FILTER:FFFFFA800433E010 Instances:FFFFFA8004432C60
PFLT_FILTER:FFFFFA800433E010 Instances:FFFFFA8004346C60
PFLT_FILTER:FFFFFA800433E010 Instances:FFFFFA80047D3C60
PFLT_FILTER:FFFFFA800433E010 Instances:FFFFFA80047B9C60
PFLT_FILTER:FFFFFA800433E010 Instances:FFFFFA80040DF7F0
VolumeName:\Device\Mup
FileSystemType :\FileSystem\Mup.
VolumeName:\Device\HarddiskVolume1
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume2
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume5
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume3
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume4
FileSystemType :\FileSystem\Ntfs.


FilterName:QQSysMonX64
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004A9A760
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004A9D760
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004AA0C50
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004AA0170
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004AA34F0
PFLT_FILTER:FFFFFA8004A8B160 Instances:FFFFFA8004AA4C50
VolumeName:\Device\Mup
FileSystemType :\FileSystem\Mup.
VolumeName:\Device\HarddiskVolume1
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume2
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume5
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume3
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume4
FileSystemType :\FileSystem\Ntfs.


FilterName:luafv
PFLT_FILTER:FFFFFA8004A8A010 Instances:FFFFFA8004A8C010
VolumeName:\Device\Mup
FileSystemType :\FileSystem\Mup.
VolumeName:\Device\HarddiskVolume1
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume2
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume5
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume3
FileSystemType :\FileSystem\Ntfs.
VolumeName:\Device\HarddiskVolume4
FileSystemType :\FileSystem\Ntfs.

验证一下:
0: kd> !fltkd.filters

Filter List: fffffa8003e690c0 "Frame 0" 
   FLT_FILTER: fffffa800433e010 "TFsFlt" "389700"
      FLT_INSTANCE: fffffa8004432c60 "TFsFlt Instance" "389700"
      FLT_INSTANCE: fffffa8004346c60 "TFsFlt Instance" "389700"
      FLT_INSTANCE: fffffa80047d3c60 "TFsFlt Instance" "389700"
      FLT_INSTANCE: fffffa80047b9c60 "TFsFlt Instance" "389700"
      FLT_INSTANCE: fffffa80040df7f0 "TFsFlt Instance" "389700"
   FLT_FILTER: fffffa8004a8b160 "QQSysMonX64" "327125"
      FLT_INSTANCE: fffffa8004a9a760 "QQSysMonx64 Instance" "327125"
      FLT_INSTANCE: fffffa8004a9d760 "QQSysMonx64 Instance" "327125"
      FLT_INSTANCE: fffffa8004aa0c50 "QQSysMonx64 Instance" "327125"
      FLT_INSTANCE: fffffa8004aa0170 "QQSysMonx64 Instance" "327125"
      FLT_INSTANCE: fffffa8004aa34f0 "QQSysMonx64 Instance" "327125"
      FLT_INSTANCE: fffffa8004aa4c50 "QQSysMonx64 Instance" "327125"
   FLT_FILTER: fffffa8004a8a010 "luafv" "135000"
      FLT_INSTANCE: fffffa8004a8c010 "luafv" "135000"

0: kd> !fltkd.instance fffffa8004432c60

FLT_INSTANCE: fffffa8004432c60 "TFsFlt Instance" "389700"
   FLT_OBJECT: fffffa8004432c60  [01000000] Instance
      RundownRef               : 0x0000000000000000 (0)
      PointerCount             : 0x00000002 
      PrimaryLink              : [fffffa8004a9d770-fffffa800404d108] 
   OperationRundownRef      : fffffa80044310b0 
Could not read field "Number" of fltmgr!_EX_RUNDOWN_REF_CACHE_AWARE from address: fffffa80044310b0
   Flags                    : [00000000]
   Volume                   : fffffa800404d010 "\Device\HarddiskVolume1"
   Filter                   : fffffa800433e010 "TFsFlt"
   TrackCompletionNodes     : fffffa8004432a20 
   ContextLock              : (fffffa8004432cd0)
   Context                  : fffffa800433a770 
   CallbackNodes            : (fffffa8004432cf0)
   VolumeLink               : [fffffa8004a9d770-fffffa800404d108] 
   FilterLink               : [fffffa8004346cc0-fffffa800433e0d0] 

*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <ntifs.h>
#include <windef.h>

#define TAG 'tset' //test

/*
IoEnumerateRegisteredFiltersList enumerates only file system filter drivers (also called "legacy filters"). 
It does not enumerate minifilters. 
To enumerate both minifilters and legacy filters, or only minifilters, call FltEnumerateFilterInformation.

此代码在Windows 7上测试成功。
不当之处,请指正。

made by correy
made at 2014.07.01
homepage:http://correy.webs.com
*/


VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    PDRIVER_OBJECT * DriverObjectList = 0;//*
    ULONG DriverObjectListSize = 0;
    ULONG ActualNumberDriverObjects = 0;
    ULONG i = 0;

    UNREFERENCED_PARAMETER( RegistryPath );

    KdBreakPoint();

    DriverObject->DriverUnload = DriverUnload;

    //XP下调用此函数没有反应。就是各个参数及返回值依旧是原来的样子。
    status = IoEnumerateRegisteredFiltersList(DriverObjectList, DriverObjectListSize, &ActualNumberDriverObjects);
    if (!NT_SUCCESS( status )) 
    {
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            return status;
        }
    }

    //XP下申请大小为0的内存竟然成功,而且还可以读写。
    DriverObjectListSize = ActualNumberDriverObjects * sizeof(DRIVER_OBJECT);
    DriverObjectList = (PDRIVER_OBJECT *)ExAllocatePoolWithTag(NonPagedPool, DriverObjectListSize, TAG);
    if (DriverObjectList == NULL) {
        return STATUS_UNSUCCESSFUL ;
    }
    RtlZeroMemory(DriverObjectList, DriverObjectListSize);

    //XP下调用此函数仍然没有反应。就是各个参数及返回值依旧是原来的样子。
    status = IoEnumerateRegisteredFiltersList(DriverObjectList, DriverObjectListSize, &ActualNumberDriverObjects);
    if (!NT_SUCCESS( status )) 
    {
        return status;
    }

    for (i = 0;i < ActualNumberDriverObjects;i++)
    {
        DbgPrint("DriverName:%wZ\n",&DriverObjectList[i]->DriverName);
        ObDereferenceObject(DriverObjectList[i]);
    }    

    ExFreePoolWithTag(DriverObjectList, TAG);

    return status;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*WindowsResearchKernel-WRK/WRK-v1.2/base/ntos/io/iomgr/iosubs.c
NTSTATUS
IoEnumerateRegisteredFiltersList(
    IN  PDRIVER_OBJECT  *DriverObjectList,
    IN  ULONG           DriverObjectListSize,
    OUT PULONG          ActualNumberDriverObjects
    )
++

Routine Description:

    This routine retrieves a list of driver objects associated with all of the
    filters which have registered with the system.

Parameters:

    DriverObjectList - Pointer to an array where driver  object lists will be stored.

    DriverObjectListSize - Size in bytes of the DriverObjectList array

    ActualNumberDriverObjects - The actual number of driver objects returned.

ReturnValue:

    If size is not sufficient it will return STATUS_BUFFER_TOO_SMALL.

Notes:

--*//*
{
    PNOTIFICATION_PACKET nPacket;
    PLIST_ENTRY entry;
    ULONG   numListEntries;
    ULONG   numDriverObjects = 0;
    NTSTATUS status = STATUS_SUCCESS;

    //
    //  Lock the list shared
    //

    ExAcquireResourceSharedLite( &IopDatabaseResource, TRUE );

    //
    //  Calculate how many entries can be returned
    //

    numListEntries = DriverObjectListSize / sizeof(PDRIVER_OBJECT);

    //
    //  Calculate how many entries are on the list
    //

    entry = IopFsNotifyChangeQueueHead.Flink;
    while (entry != &IopFsNotifyChangeQueueHead) {

        numDriverObjects++;
        entry = entry->Flink;
    }

    //
    //  Return total number of entries on the list
    //

    *ActualNumberDriverObjects = numDriverObjects;

    //
    //  If we don't have room for all of the entries, tell them about this
    //

    if (numDriverObjects > numListEntries) {
        status = STATUS_BUFFER_TOO_SMALL;
    }

    //
    //  Return what entries we can
    //

    entry = IopFsNotifyChangeQueueHead.Flink;

    while ((numListEntries > 0) && (entry != &IopFsNotifyChangeQueueHead)) {

        nPacket = CONTAINING_RECORD( entry, NOTIFICATION_PACKET, ListEntry );

        ObReferenceObject(nPacket->DriverObject);

        *DriverObjectList = nPacket->DriverObject;
        DriverObjectList++;

        entry = entry->Flink;
        numListEntries--;
    }

    ExReleaseResourceLite( &IopDatabaseResource );

    return status;
}
*/

2013年10月22日星期二

NDIS过滤驱动在绑定的时候获取一些信息

NDIS过滤驱动在绑定的时候获取一些信息.
同理:minifilter的PFLT_INSTANCE_SETUP_CALLBACK也可以获取类似的信息.
     wfp和wsk也应该有.
此文虽然简单,仅仅3行代码,但是自己的所得,无人指导.

VOID PtBindAdapter(OUT PNDIS_STATUS Status, IN  NDIS_HANDLE BindContext, IN  PNDIS_STRING DeviceName, IN  PVOID SystemSpecific1, IN  PVOID SystemSpecific2)
/*++
Routine Description:Called by NDIS to bind to a miniport below.
Arguments:
    Status            - Return status of bind here.
    BindContext        - Can be passed to NdisCompleteBindAdapter if this call is pended.
    DeviceName         - Device name to bind to. This is passed to NdisOpenAdapter.例如:"\DEVICE\NDISWANIPV6","\DEVICE\NDISWANBH"
    SystemSpecific1    - Can be passed to NdisOpenProtocolConfiguration to read per-binding information.其内容为:"PASSTHRU\Parameters\Adapters\NDISWANIPV6".
    SystemSpecific2    - Unused
Return Value:
    NDIS_STATUS_PENDING    if this call is pended. In this case call NdisCompleteBindAdapter to complete.
    Anything else          Completes this call synchronously
--*/
{
    NDIS_HANDLE                     ConfigHandle = NULL;
    PNDIS_CONFIGURATION_PARAMETER   Param;
    NDIS_STRING                     DeviceStr = NDIS_STRING_CONST("UpperBindings");
    NDIS_STRING                     NdisVersionStr = NDIS_STRING_CONST("NdisVersion");
    PADAPT                          pAdapt = NULL;
    NDIS_STATUS                     Sts;
    UINT                            MediumIndex;
    ULONG                           TotalSize;

    UNREFERENCED_PARAMETER(BindContext);
    UNREFERENCED_PARAMETER(SystemSpecific2);

    NdisOpenProtocolConfiguration(Status, &ConfigHandle, SystemSpecific1);// Access the configuration section for our binding-specific parameters.
    if (*Status != NDIS_STATUS_SUCCESS) {//SystemSpecific1的内容是:"PASSTHRU\Parameters\Adapters\NDISWANIPV6"
        return;
    }

    if (NdisDotSysVersion == 0) //初始化是0.
    {
        NdisReadConfiguration(Status, &Param, ConfigHandle, &NdisVersionStr, NdisParameterInteger);//最后一个参数的值是0.
        if (*Status != NDIS_STATUS_SUCCESS)  {
            NdisCloseConfiguration(ConfigHandle);
            return;
        }          
        NdisDotSysVersion = Param->ParameterData.IntegerData;//设置值.
    }

    // Read the "UpperBindings" reserved key that contains a list of device names representing our miniport instances corresponding to this lower binding.
    // Since this is a 1:1 IM driver, this key contains exactly one name.

    // If we want to implement a N:1 mux driver (N adapter instances over a single lower binding),
    // then UpperBindings will be a MULTI_SZ containing a list of device names - we would loop through this list,calling NdisIMInitializeDeviceInstanceEx once for each name in it.
    NdisReadConfiguration(Status, &Param, ConfigHandle, &DeviceStr, NdisParameterString);//最后一个参数的值是2.
    if (*Status != NDIS_STATUS_SUCCESS) {
        NdisCloseConfiguration(ConfigHandle);
        return;
    }

    // Allocate memory for the Adapter structure. This represents both the protocol context as well as the adapter structure when the miniport is initialized.
    // In addition to the base structure, allocate space for the device instance string.
    TotalSize = sizeof(ADAPT) + Param->ParameterData.StringData.MaximumLength;
    NdisAllocateMemoryWithTag(&pAdapt, TotalSize, TAG);
    if (pAdapt == NULL) {
        *Status = NDIS_STATUS_RESOURCES;
        NdisCloseConfiguration(ConfigHandle);
        return;
    }

    // Initialize the adapter structure. We copy in the IM device name as well, because we may need to use it in a call to NdisIMCancelInitializeDeviceInstance.
    // The string returned by NdisReadConfiguration is active (i.e. available) only for the duration of this call to our BindAdapter handler.
    NdisZeroMemory(pAdapt, TotalSize);
    pAdapt->DeviceName.MaximumLength = Param->ParameterData.StringData.MaximumLength;
    pAdapt->DeviceName.Length = Param->ParameterData.StringData.Length;
    pAdapt->DeviceName.Buffer = (PWCHAR)((ULONG_PTR)pAdapt + sizeof(ADAPT));//要移动的内容是:"\Device\{F3A2DED5-DB38-4164-9CF1-48149A08DC7A}".
    NdisMoveMemory(pAdapt->DeviceName.Buffer, Param->ParameterData.StringData.Buffer, Param->ParameterData.StringData.MaximumLength);

    KdPrint(("Name: %wZ\n", DeviceName));
    KdPrint(("Name: %wZ\n", SystemSpecific1));
    KdPrint(("Name: %wZ\n", &(pAdapt->DeviceName)));

    NdisInitializeEvent(&pAdapt->Event);
    NdisAllocateSpinLock(&pAdapt->Lock);

    // Allocate a packet pool for sends. We need this to pass sends down.We cannot use the same packet descriptor that came down to our send handler (see also NDIS 5.1 packet stacking).
    NdisAllocatePacketPoolEx(Status, &pAdapt->SendPacketPoolHandle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof(SEND_RSVD));
    if (*Status != NDIS_STATUS_SUCCESS)  {
        NdisCloseConfiguration(ConfigHandle);
        return;
    }

    // Allocate a packet pool for receives. We need this to indicate receives.Same consideration as sends (see also NDIS 5.1 packet stacking).
    NdisAllocatePacketPoolEx(Status, &pAdapt->RecvPacketPoolHandle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, PROTOCOL_RESERVED_SIZE_IN_PACKET);
    if (*Status != NDIS_STATUS_SUCCESS)  {
        NdisCloseConfiguration(ConfigHandle);
        return;
    }

    //Now open the adapter below and complete the initialization.得到了设备的类型,及网卡的类型绑定句柄等信息.
    NdisOpenAdapter(Status, &Sts, &pAdapt->BindingHandle,&MediumIndex, MediumArray, sizeof(MediumArray)/sizeof(NDIS_MEDIUM), ProtHandle, pAdapt, DeviceName, 0, NULL);
    if (*Status == NDIS_STATUS_PENDING) {
        NdisWaitEvent(&pAdapt->Event, 0);
        *Status = pAdapt->Status;
    }

    if (*Status != NDIS_STATUS_SUCCESS) {
        NdisCloseConfiguration(ConfigHandle);
        return;
    }

    PtReferenceAdapt(pAdapt);//自己写的函数.

#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "Ndis guarantees MediumIndex to be within bounds");
    pAdapt->Medium = MediumArray[MediumIndex];

    // Now ask NDIS to initialize our miniport (upper) edge.
    // Set the flag below to synchronize with a possible call to our protocol Unbind handler that may come in before our miniport initialization happens.
    pAdapt->MiniportInitPending = TRUE;
    NdisInitializeEvent(&pAdapt->MiniportInitEvent);

    PtReferenceAdapt(pAdapt);//自己写的函数.

    *Status = NdisIMInitializeDeviceInstanceEx(DriverHandle, &pAdapt->DeviceName, pAdapt);//导致调用MPInitialize函数。
    if (*Status != NDIS_STATUS_SUCCESS)
    {//如果失败了.
        DBGPRINT(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n", pAdapt, *Status));
        if (pAdapt->MiniportIsHalted == TRUE)
        {
            if (pAdapt != NULL && pAdapt->BindingHandle != NULL)
            {
                NDIS_STATUS    LocalStatus;              
                NdisResetEvent(&pAdapt->Event);// Close the binding we opened above.              
                NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
                pAdapt->BindingHandle = NULL;
                if (LocalStatus == NDIS_STATUS_PENDING) {
                    NdisWaitEvent(&pAdapt->Event, 0);
                    LocalStatus = pAdapt->Status;                  
                }
                if (PtDereferenceAdapt(pAdapt))  {
                    pAdapt = NULL;
                }
            }
        }          

        NdisCloseConfiguration(ConfigHandle);
    }    

    PtDereferenceAdapt(pAdapt);//自己写的函数.

    DBGPRINT(("Protocol BindAdapter:Status %x\n", *Status));
}

打印信息如下:
Name: \DEVICE\NDISWANIPV6
Name: PASSTHRU\Parameters\Adapters\NDISWANIPV6
Name: \Device\{3AD1CC5D-C784-4EBB-9B1B-79F27229CA27}
Protocol BindAdapter:Status 0
Name: \DEVICE\NDISWANIP
Name: PASSTHRU\Parameters\Adapters\NDISWANIP
Name: \Device\{ADA93AA1-A280-42DC-9F39-16F5C1A0EC40}
Protocol BindAdapter:Status 0
Name: \DEVICE\NDISWANBH
Name: PASSTHRU\Parameters\Adapters\NDISWANBH
Name: \Device\{1AF4AD0B-9975-414F-A514-E2776F1F1750}
Protocol BindAdapter:Status 0
Name: \DEVICE\{D0144834-7DC9-4868-A5E8-33D878317E4E}
Name: PASSTHRU\Parameters\Adapters\{D0144834-7DC9-4868-A5E8-33D878317E4E}
Name: \Device\{9720D192-57F6-46FC-8ECF-32A67E0AA3C6}
Protocol BindAdapter:Status 0

made by correy
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

改进版的如下:
添加个友好名字:

VOID PtBindAdapter(OUT PNDIS_STATUS Status, IN  NDIS_HANDLE BindContext, IN  PNDIS_STRING DeviceName, IN  PVOID SystemSpecific1, IN  PVOID SystemSpecific2)
/*++
Routine Description:
    Called by NDIS to bind to a miniport below.
    此函数会调用多次,根据注册表的配置而定,由NdisRegisterProtocol引起,调用时机可能在驱动入口和ADDdevice函数运行完毕之后.
    绑定DeviceName(SystemSpecific1)的网卡.
Arguments:
    Status             - Return status of bind here.
    BindContext        - Can be passed to NdisCompleteBindAdapter if this call is pended.
    DeviceName         - Device name to bind to. This is passed to NdisOpenAdapter.值为:"\DEVICE\NDISWANIPV6" 或者"\DEVICE\{B80E2F34-2A57-4862-8D52-0EED3B6BB4F0}".
    SystemSpecific1    - Can be passed to NdisOpenProtocolConfiguration to read per-binding information.
                         值为: "PASSTHRU\Parameters\Adapters\NDISWANIPV6"或者"PASSTHRU\Parameters\Adapters\{B80E2F34-2A57-4862-8D52-0EED3B6BB4F0}".
    SystemSpecific2    - Unused
Return Value:
    NDIS_STATUS_PENDING    if this call is pended. In this case call NdisCompleteBindAdapter to complete.
    Anything else          Completes this call synchronously
--*/
{
    NDIS_HANDLE                     ConfigHandle = NULL;
    PNDIS_CONFIGURATION_PARAMETER   Param;
    NDIS_STRING                     DeviceStr = NDIS_STRING_CONST("UpperBindings");
    NDIS_STRING                     NdisVersionStr = NDIS_STRING_CONST("NdisVersion");
    PADAPT                          pAdapt = NULL;
    NDIS_STATUS                     Sts;
    UINT                            MediumIndex;
    ULONG                           TotalSize;
    BOOLEAN                         NoCleanUpNeeded = FALSE;
    NDIS_STRING                    AdapterInstanceName;

    UNREFERENCED_PARAMETER(BindContext);
    UNREFERENCED_PARAMETER(SystemSpecific2);
   
    DBGPRINT(("绑定网卡:==> Protocol BindAdapter\n"));//第一个调用的函数

    do
    {      
        NdisOpenProtocolConfiguration(Status, &ConfigHandle, SystemSpecific1);//获取配置句柄. Access the configuration section for our binding-specific parameters.
        if (*Status != NDIS_STATUS_SUCCESS) {
            break;
        }

        if (NdisDotSysVersion == 0) //这个变量的初始值为0
        {
            NdisReadConfiguration(Status, &Param, ConfigHandle, &NdisVersionStr, NdisParameterInteger);
            if (*Status != NDIS_STATUS_SUCCESS)  {
                break;
            }          
            NdisDotSysVersion = Param->ParameterData.IntegerData;//==0x60014
        }
           
        // Read the "UpperBindings" reserved key that contains a list of device names representing our miniport instances corresponding to this lower binding.
        // Since this is a 1:1 IM driver, this key contains exactly one name.
        //
        // If we want to implement a N:1 mux driver (N adapter instances over a single lower binding),
        // then UpperBindings will be a MULTI_SZ containing a list of device names - we would loop through this list,
        // calling NdisIMInitializeDeviceInstanceEx once for each name in it.
        NdisReadConfiguration(Status, &Param, ConfigHandle, &DeviceStr, NdisParameterString);//获取到第二个参数的一个成员的值是"\Device\{A58AE6BC-1CE1-4EEC-AAEC-59AB2DAFE408}"
        if (*Status != NDIS_STATUS_SUCCESS) {
            break;
        }

        // Allocate memory for the Adapter structure.
        // This represents both the protocol context as well as the adapter structure when the miniport is initialized.
        // In addition to the base structure, allocate space for the device instance string.
        TotalSize = sizeof(ADAPT) + Param->ParameterData.StringData.MaximumLength;
        NdisAllocateMemoryWithTag(&pAdapt, TotalSize, TAG);
        if (pAdapt == NULL) {
            *Status = NDIS_STATUS_RESOURCES;
            break;
        }
        // Initialize the adapter structure.
        // We copy in the IM device name as well, because we may need to use it in a call to NdisIMCancelInitializeDeviceInstance.
        // The string returned by NdisReadConfiguration is active (i.e. available) only for the duration of this call to our BindAdapter handler.
        NdisZeroMemory(pAdapt, TotalSize);
        pAdapt->DeviceName.MaximumLength = Param->ParameterData.StringData.MaximumLength;
        pAdapt->DeviceName.Length = Param->ParameterData.StringData.Length;
        pAdapt->DeviceName.Buffer = (PWCHAR)((ULONG_PTR)pAdapt + sizeof(ADAPT));
        NdisMoveMemory(pAdapt->DeviceName.Buffer, Param->ParameterData.StringData.Buffer, Param->ParameterData.StringData.MaximumLength);//复制上面的字符串.

        NdisInitializeEvent(&pAdapt->Event);
        NdisAllocateSpinLock(&pAdapt->Lock);

        // Allocate a packet pool for sends.
        // We need this to pass sends down.We cannot use the same packet descriptor that came down to our send handler (see also NDIS 5.1 packet stacking).
        NdisAllocatePacketPoolEx(Status, &pAdapt->SendPacketPoolHandle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof(SEND_RSVD));//获取内存句柄.
        if (*Status != NDIS_STATUS_SUCCESS)  {
            break;
        }
        // Allocate a packet pool for receives.
        // We need this to indicate receives.Same consideration as sends (see also NDIS 5.1 packet stacking).
        NdisAllocatePacketPoolEx(Status, &pAdapt->RecvPacketPoolHandle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, PROTOCOL_RESERVED_SIZE_IN_PACKET);
        if (*Status != NDIS_STATUS_SUCCESS)  {
            break;
        }

        // Now open the adapter below and complete the initialization
        NdisOpenAdapter(Status, &Sts, &pAdapt->BindingHandle,&MediumIndex, MediumArray, sizeof(MediumArray)/sizeof(NDIS_MEDIUM), ProtHandle, pAdapt, DeviceName, 0, NULL);
        if (*Status == NDIS_STATUS_PENDING) {//注意返回的第三个和第四个参数.
            NdisWaitEvent(&pAdapt->Event, 0);
            *Status = pAdapt->Status;
        }
        if (*Status != NDIS_STATUS_SUCCESS) {
            break;
        }

        PtReferenceAdapt(pAdapt);//自己实现的函数.

        NdisQueryAdapterInstanceName(&AdapterInstanceName, pAdapt->BindingHandle);//注意这一行的位置,不然这里蓝屏.

        KdPrint(("DeviceName: %wZ\n", DeviceName));
        KdPrint(("相对注册表路径: %wZ\n", SystemSpecific1));
        KdPrint(("DeviceName(UUID): %wZ\n", &(pAdapt->DeviceName)));
        KdPrint(("Friendly names: %wZ\n", &AdapterInstanceName));      

        NdisFreeMemory(AdapterInstanceName.Buffer, 0, 0);
        AdapterInstanceName.Buffer = NULL;

#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "Ndis guarantees MediumIndex to be within bounds");
        pAdapt->Medium = MediumArray[MediumIndex];
        // Now ask NDIS to initialize our miniport (upper) edge.
        // Set the flag below to synchronize with a possible call to our protocol Unbind handler that may come in before our miniport initialization happens.
        pAdapt->MiniportInitPending = TRUE;
        NdisInitializeEvent(&pAdapt->MiniportInitEvent);
        PtReferenceAdapt(pAdapt);//自己实现的函数.

        *Status = NdisIMInitializeDeviceInstanceEx(DriverHandle, &pAdapt->DeviceName, pAdapt);//导致调用MPInitialize函数。
        if (*Status != NDIS_STATUS_SUCCESS) //失败的处理,主要是释放和设置.
        {
            if (pAdapt->MiniportIsHalted == TRUE)  {
                NoCleanUpNeeded = TRUE;
            }          
            DBGPRINT(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n", pAdapt, *Status));          
            if (PtDereferenceAdapt(pAdapt))  {//自己实现的函数.
                pAdapt = NULL;
            }          
            break;
        }
       
        PtDereferenceAdapt(pAdapt);//自己实现的函数.
    } while(FALSE);
   
    if (ConfigHandle != NULL) {// Close the configuration handle now - see comments above with the call to NdisIMInitializeDeviceInstanceEx.
        NdisCloseConfiguration(ConfigHandle);//不再用的句柄的释放.
    }

    if ((*Status != NDIS_STATUS_SUCCESS) && (NoCleanUpNeeded == FALSE))//失败的处理
    {
        if (pAdapt != NULL)
        {
            if (pAdapt->BindingHandle != NULL)
            {
                NDIS_STATUS    LocalStatus;  
               
                NdisResetEvent(&pAdapt->Event);// Close the binding we opened above.              
                NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
                pAdapt->BindingHandle = NULL;

                if (LocalStatus == NDIS_STATUS_PENDING) {
                     NdisWaitEvent(&pAdapt->Event, 0);
                     LocalStatus = pAdapt->Status;                  
                }

                if (PtDereferenceAdapt(pAdapt))  {
                     pAdapt = NULL;
                }
            }
        }
    }

    DBGPRINT(("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *Status));
    KdPrint(("\n"));
}

打印的效果如下:

绑定网卡:==> Protocol BindAdapter
DeviceName: \DEVICE\NDISWANIPV6
相对注册表路径: PASSTHRU\Parameters\Adapters\NDISWANIPV6
DeviceName(UUID): \Device\{6192A548-9667-4920-9B23-6F286485D740}
Friendly names: WAN Miniport (IPv6)
<== Protocol BindAdapter: pAdapt FFFFFA80060CFB60, Status 0

绑定网卡:==> Protocol BindAdapter
DeviceName: \DEVICE\NDISWANIP
相对注册表路径: PASSTHRU\Parameters\Adapters\NDISWANIP
DeviceName(UUID): \Device\{A811A14F-46BE-4EED-8EB9-75C03FC32A0A}
Friendly names: WAN Miniport (IP)
<== Protocol BindAdapter: pAdapt FFFFFA80068EB010, Status 0

绑定网卡:==> Protocol BindAdapter
DeviceName: \DEVICE\NDISWANBH
相对注册表路径: PASSTHRU\Parameters\Adapters\NDISWANBH
DeviceName(UUID): \Device\{F68E4046-F7BD-4C59-BCB3-EB9CAB539544}
Friendly names: WAN Miniport (Network Monitor)
<== Protocol BindAdapter: pAdapt FFFFFA8005DCD790, Status 0

绑定网卡:==> Protocol BindAdapter
DeviceName: \DEVICE\{D0144834-7DC9-4868-A5E8-33D878317E4E}
相对注册表路径: PASSTHRU\Parameters\Adapters\{D0144834-7DC9-4868-A5E8-33D878317E4E}
DeviceName(UUID): \Device\{BDE90A81-773E-4A27-B577-5AFB5634CE40}
Friendly names: 基于 Marvell Yukon 88E8057 PCI-E 的通用千兆以太网控制器
<== Protocol BindAdapter: pAdapt FFFFFA80052D3450, Status 0

made at 2014.05.02

2013年10月9日星期三

幻方

/*
缘于:深圳腾讯2010安全技术竞赛:第一阶段第二题.
这里弄一个简单的:三阶幻方又叫九宫格.

这是一个算法题,我不懂矩阵相乘,排列组合,多元一次方程也不想用.
算法需要编程实现,这就是只最简单的编程,最慢的算法.

made by correy
made at 2013.10.09
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include "stdio.h"
#include "stdlib.h"

void print_it(int a1,int a2,int a3,int b1,int b2,int b3,int c1,int c2,int c3)
{
    printf("\n\n");

    printf("%d %d %d \n",a1,a2,a3);
    printf("%d %d %d \n",b1,b2,b3);
    printf("%d %d %d \n",c1,c2,c3);
}

bool is_it(int a1,int a2,int a3,int b1,int b2,int b3,int c1,int c2,int c3)
{
    bool b = false;

    if (a1 == a2 || a1 == a3 || a1 == b1 || a1 == b2 || a1 == b3 || a1 == c1 || a1 == c2 || a1 == c3)
    {
        return b;
    }

    if (a2 == a3 || a2 == b1 || a2 == b2 || a2 == b3 || a2 == c1 || a2 == c2 || a2 == c3)
    {
        return b;
    }

    if (a3 == b1 || a3 == b2 || a3 == b3 || a3 == c1 || a3 == c2 || a3 == c3)
    {
        return b;
    }

    if (b1 == b2 || b1 == b3 || b1 == c1 || b1 == c2 || b1 == c3)
    {
        return b;
    }

    if (b2 == b3 || b2 == c1 || b2 == c2 || b2 == c3)
    {
        return b;
    }

    if (b3 == c1 || b3 == c2 || b3 == c3)
    {
        return b;
    }

    if (c1 == c2 || c1 == c3)
    {
        return b;
    }

    if (c2 == c3)
    {
        return b;
    }

    int x1 = a1 + a2 + a3;
    int x2 = b1 + b2 + b3;
    int x3 = c1 + c2 + c3;

    int y1 = a1 + b1 + c1;
    int y2 = a2 + b2 + c2;
    int y3 = a3 + b3 + c3;

    int xy = a1 + b2 + c3;
    int yx = a3 + b2 + c1;

    if (x1 == x2 && x1 == x3 && x1 == y1 && x1 == y2 && x1 == y3 && x1 == xy && x1 == yx)
    {
        b = true;
    }

    return b;
}

int main( int argc, char *argv[] )
{
    for (int a1 = 1;a1 <= 9;a1++)
    {
        for (int a2 = 1;a2 <= 9;a2++)
        {
            for (int a3 = 1;a3 <= 9;a3++)
            {
                for (int b1 = 1;b1 <= 9;b1++)
                {
                    for (int b2 = 1;b2 <= 9;b2++)
                    {
                        for (int b3 = 1;b3 <= 9;b3++)
                        {
                            for (int c1 = 1;c1 <= 9;c1++)
                            {
                                for (int c2 = 1;c2 <= 9;c2++)
                                {
                                    for (int c3 = 1;c3 <= 9;c3++)
                                    {
                                        bool b = is_it(a1,a2,a3,b1,b2,b3,c1,c2,c3);
                                        if (b)
                                        {
                                            print_it(a1,a2,a3,b1,b2,b3,c1,c2,c3);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return 0;
}