2015年5月29日星期五

一种minifilter驱动保护的方案

/*
通常的保护驱动的思路是在驱动入口不设置驱动对象的卸载函数的成员。

minifilter框架也类似。

开始的思路也是这样的,
可是经测试不行,因为通常minifilter不设置驱动对象的卸载函数,而是设置FLT_REGISTRATION的卸载函数。
经分析FltRegisterFilter是把自己的_FLT_REGISTRATION复制/修改到_FLT_FILTER。
最后经分析和原始的想法是一样的。
不罗嗦了,直接见要点.

具体的做法是:
1.FLT_REGISTRATION的Flags包含FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP。
  这是通过逆向分析出的。
  MSDN是这样说的:
  If this flag is set, the minifilter is not unloaded in response to service stop requests, even if the FilterUnloadCallback member is not NULL.
  也就是说,如果这样了即使设置了FilterUnloadCallback成员,FilterUnloadCallback成员也是无效的。
  具体的键反汇编。
  还有一个值是:FLTFL_REGISTRATION_SUPPORT_NPFS_MSFS,这个早就研究了。
2.驱动不能停止咋办?(不同于卸载,禁止卸载可以通过注册表回调来实现,更不是隐藏等别的功能)
  此时驱动还在运行,我们可以和他通讯呀!
  所以可选的思路有:
  1)设置驱动对象的卸载函数为FLT_REGISTRATION的FilterUnloadCallback应该设置的函数。
  2)设置驱动对象的卸载函数为fltmgr!FltpMiniFilterDriverUnload。
  3)设置驱动对象的卸载函数为nt!IopInvalidDeviceRequest。
  经测试:
  方法三是不可行的,这个会蓝屏,蓝屏原因就不说了,你分析吧!
  方法二是不可取的,因为那个函数是未公开的,函数的地址不好获取。
  方法以是可行的,建议的。

made by correy
made at 2015.05.29

下面附下IDA分析的FltRegisterFilter函数:
*/

NTSTATUS __stdcall FltRegisterFilter(PDRIVER_OBJECT Driver, _FLT_REGISTRATION *Registration, _FLT_FILTER **RetFilter)
    /*
    略有改动,改为自己的编码风格。
    里面还有一些数字的含义,请自己修改。
    */
{
    NTSTATUS result; // eax@2
    _FLT_REGISTRATION *P_FLT_REGISTRATION; // esi@3
    int n; // eax@10
    _FLT_OPERATION_REGISTRATION *OperationRegistration; // ecx@10
    _FLT_FILTER *Ret_Filter; // ebx@14
    _FLT_MUTEX_LIST_HEAD *ActiveOpens; // ST28_4@16
    _FLT_MUTEX_LIST_HEAD *PortList; // ST20_4@16
    _FLT_OPERATION_REGISTRATION *i; // eax@19
    char MajorFunction; // cl@20
    int temp; // ST44_4@28
    unsigned int OperationRegistration_length; // [sp+30h] [bp-24h]@14
    _FLT_OPERATION_REGISTRATION *P_FLT_OPERATION_REGISTRATION; // [sp+34h] [bp-20h]@16
    NTSTATUS result_2; // [sp+38h] [bp-1Ch]@17
    BOOL B = FALSE;

    *RetFilter = 0;

    if ( !(g_dword_BIT & 1) )
        return 0xC01C0007;                          // 见ntstatus.h的定义。

    P_FLT_REGISTRATION = Registration;

    if ( (Registration->Version & 0xFF00) != 512 )
        return 0xC000000D;  // 见ntstatus.h的定义。

    result = FltpRestoreFltMgrsPageableState();
    if ( result < 0 )
        return result;

    B = (Registration->GenerateFileNameCallback || !Registration->NormalizeNameComponentCallback) && (Registration->NormalizeNameComponentCallback || !Registration->NormalizeContextCleanupCallback);
    if ( !B )
    {
        return 0xC000000D;  // 见ntstatus.h的定义。
    }

    n = 0;
    OperationRegistration = Registration->OperationRegistration;
    if ( OperationRegistration )
    {
        while ( 1 )
        {
            ++n;
            if ( OperationRegistration->MajorFunction == -128 )
                break;
            ++OperationRegistration;
        }
    }

    OperationRegistration_length = 20 * n;

    Ret_Filter = (_FLT_FILTER *)ExAllocatePoolWithTag(0, 20 * n + Driver->DriverExtension->ServiceKeyName.Length + 288, 0x6C664D46u);
    if ( !Ret_Filter )
    {
        return 0xC000009A;
    }

    memset(Ret_Filter, 0, 0x120u);
    Ret_Filter->FilterUnload = Registration->FilterUnloadCallback;
    Ret_Filter->InstanceSetup = Registration->InstanceSetupCallback;
    Ret_Filter->InstanceQueryTeardown = Registration->InstanceQueryTeardownCallback;
    Ret_Filter->InstanceTeardownStart = Registration->InstanceTeardownStartCallback;
    Ret_Filter->InstanceTeardownComplete = Registration->InstanceTeardownCompleteCallback;
    Ret_Filter->GenerateFileName = Registration->GenerateFileNameCallback;
    Ret_Filter->NormalizeNameComponent = Registration->NormalizeNameComponentCallback;
    Ret_Filter->NormalizeContextCleanup = Registration->NormalizeContextCleanupCallback;
    P_FLT_OPERATION_REGISTRATION = (_FLT_OPERATION_REGISTRATION *)&Ret_Filter[1];
    Ret_Filter->Base.Flags = 0x2000000;
    Ret_Filter->Base.PointerCount = 1;
    FltpExInitializeRundownProtection(&Ret_Filter->Base.RundownRef);
    Ret_Filter->Base.PrimaryLink.Flink = 0;
    FltObjectReference((int)Ret_Filter);
    Ret_Filter->DriverObject = Driver;
    Ret_Filter->InstanceList.rCount = 0;
    ExInitializeResourceLite(&Ret_Filter->InstanceList.rLock);
    InitializeListHead(&Ret_Filter->InstanceList.rList);
    ActiveOpens = &Ret_Filter->ActiveOpens;
    ActiveOpens->mCount = 0;
    ActiveOpens->mLock.Count = 1;
    ActiveOpens->mLock.Owner = 0;
    ActiveOpens->mLock.Contention = 0;
    KeInitializeEvent(&Ret_Filter->ActiveOpens.mLock.Event, SynchronizationEvent, 0);
    InitializeListHead(&Ret_Filter->ActiveOpens.mList);
    PortList = &Ret_Filter->PortList;
    PortList->mCount = 0;
    PortList->mLock.Count = 1;
    PortList->mLock.Owner = 0;
    PortList->mLock.Contention = 0;
    KeInitializeEvent(&Ret_Filter->PortList.mLock.Event, SynchronizationEvent, 0);
    InitializeListHead(&Ret_Filter->PortList.mList);
    Ret_Filter->PortLock.Value = 0;

    if ( !Registration->ContextRegistration || (result_2 = FltpProcessContextRegistration((int)Ret_Filter, &Registration->ContextRegistration->ContextType), result_2 >= 0) )
    {
        if ( Registration->OperationRegistration )//各个操作的前后操作。
        {
            Ret_Filter->Operations = P_FLT_OPERATION_REGISTRATION;
            P_FLT_OPERATION_REGISTRATION = (_FLT_OPERATION_REGISTRATION *)((char *)P_FLT_OPERATION_REGISTRATION + OperationRegistration_length);
            qmemcpy(&Ret_Filter[1], Registration->OperationRegistration, OperationRegistration_length);
            for ( i = Ret_Filter->Operations; ; ++i )
            {
                MajorFunction = i->MajorFunction;
                if ( i->MajorFunction == -128 )
                    break;

                if ( MajorFunction == -19 )
                {
                    Ret_Filter->PreVolumeMount = i->PreOperation;
                    Ret_Filter->PostVolumeMount = i->PostOperation;
                }
                else if ( MajorFunction != -20 && MajorFunction == 16 )//#define IRP_MJ_SHUTDOWN                 0x10.关机是没有后操作的,有了,按思想是笑话。你设置了,这里也会给抹掉。
                {
                    i->PostOperation = 0;
                }
            }

            P_FLT_REGISTRATION = Registration;
        }

        Ret_Filter->Name.Buffer = (unsigned __int16 *)P_FLT_OPERATION_REGISTRATION;
        Ret_Filter->Name.Length = 0;
        Ret_Filter->Name.MaximumLength = Driver->DriverExtension->ServiceKeyName.Length;
        temp = (int)(&P_FLT_OPERATION_REGISTRATION->MajorFunction + Driver->DriverExtension->ServiceKeyName.Length);
        RtlCopyUnicodeString((PUNICODE_STRING)&Ret_Filter->Name, (PCUNICODE_STRING)&Driver->DriverExtension->ServiceKeyName);
        result_2 = FltpInitializeFilterVerifier(Ret_Filter);
        if ( result_2 >= 0 )
        {
            result_2 = FltpGetInstanceAltitude(Ret_Filter, 0, 0, (PUNICODE_STRING)&Ret_Filter->DefaultAltitude);
            if ( result_2 >= 0 )
            {
                result_2 = FltpFindFrameForFilter(Ret_Filter, &Ret_Filter->DefaultAltitude);
                if ( result_2 >= 0 )
                {
                    result_2 = FltpLinkFilterIntoFrame(Ret_Filter);
                    if ( result_2 >= 0 )
                    {
                        Ret_Filter->OldDriverUnload = Driver->DriverUnload;
                        if ( !P_FLT_REGISTRATION->FilterUnloadCallback || P_FLT_REGISTRATION->Flags & 1 )//#define FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP  0x00000001
                        {//If this flag is set, the minifilter is not unloaded in response to service stop requests, even if the FilterUnloadCallback member is not NULL.
                            Driver->DriverUnload = 0;
                            DriverObject->DriverUnload = 0;
                        }
                        else
                        {
                            Driver->DriverUnload = (void (__stdcall *)(_DRIVER_OBJECT *))FltpMiniFilterDriverUnload;
                        }
                        if ( !(g_dword_BIT & 0x20) )
                            g_dword_BIT |= 0x20u;

                        *RetFilter = Ret_Filter;
                    }
                }
            }
        }
    }

    if ( result_2 < 0 )
    {
        ExDeleteResourceLite(&Ret_Filter->InstanceList.rLock);
        FltpCleanupContextRegistration(Ret_Filter);
        FltpCleanupFilterVerifier(Ret_Filter);
        FltpFreeUnicodeString(&Ret_Filter->DefaultAltitude);
        ExFreePoolWithTag(Ret_Filter, 0);
    }

    result = result_2;

    return result;
}


/*
3.注意:
  文件微过滤驱动的卸载函数的原型是:
  typedef NTSTATUS (*PFLT_FILTER_UNLOAD_CALLBACK) ( FLT_FILTER_UNLOAD_FLAGS Flags );
  这个不同于常规驱动的的卸载函数。
  VOID DRIVER_UNLOAD ( _In_ struct _DRIVER_OBJECT *DriverObject );
  区别是返回值和参数。

  这里有一个值:FLTFL_FILTER_UNLOAD_MANDATORY。

  这个函数的说明是:
  Minifilter drivers are not required to register a FilterUnloadCallback routine.
  However, registering an unload routine is strongly recommended.
  If a minifilter driver does not register a FilterUnloadCallback routine, it cannot be unloaded.
  卸载函数不是必须的,但是强烈建议加上,如果没有就不能卸载。

  注意:FLTFL_FILTER_UNLOAD_MANDATORY和STATUS_FLT_DO_NOT_DETACH的关系。
  如果:是FLTFL_FILTER_UNLOAD_MANDATORY必须返回成功,如果返回STATUS_FLT_DO_NOT_DETACH会蓝屏。
        可是用net stop每次都是FLTFL_FILTER_UNLOAD_MANDATORY,sc stop没有试验,但是fltmc unload 却不是。
        所以此思路无效不可行。
*/

2015年5月28日星期四

IDAPRO之结构分析

在IDA中是可以这样的:
NTSTATUS __stdcall FltRegisterFilter(PDRIVER_OBJECT Driver, _FLT_REGISTRATION *Registration, _FLT_FILTER **RetFilter)
{
  NTSTATUS result; // eax@2
  _FLT_REGISTRATION *v4; // esi@3
  int v5; // eax@10
  _FLT_OPERATION_REGISTRATION *v6; // ecx@10
  _FLT_FILTER *Ret_Filter; // ebx@14
  _LIST_ENTRY *InstanceList_rList; // ST2C_4@16
  _FLT_MUTEX_LIST_HEAD *ActiveOpens; // ST28_4@16
  _LIST_ENTRY *ActiveOpens_mList; // ST24_4@16
  _FLT_MUTEX_LIST_HEAD *PortList; // ST20_4@16
  _LIST_ENTRY *PortList_mList; // ST1C_4@16
  _FLT_OPERATION_REGISTRATION *i; // eax@19
  char MajorFunction; // cl@20
  int temp; // ST44_4@28
  unsigned int OperationRegistration_length; // [sp+30h] [bp-24h]@14
  _FLT_OPERATION_REGISTRATION *v17; // [sp+34h] [bp-20h]@16
  NTSTATUS result_2; // [sp+38h] [bp-1Ch]@17

  *RetFilter = 0;
  if ( !(g_dword_XXX & 1) )
    return 0xC01C0007;                          // 见ntstatus.h的定义。
  v4 = Registration;
  if ( (Registration->Version & 0xFF00) != 512 )
    goto LABEL_46;
  result = FltpRestoreFltMgrsPageableState();
  if ( result < 0 )
    return result;
  if ( (Registration->GenerateFileNameCallback || !Registration->NormalizeNameComponentCallback)
    && (Registration->NormalizeNameComponentCallback || !Registration->NormalizeContextCleanupCallback) )
  {
    v5 = 0;
    v6 = Registration->OperationRegistration;
    if ( v6 )
    {
      while ( 1 )
      {
        ++v5;
        if ( v6->MajorFunction == -128 )
          break;
        ++v6;
      }
    }
    OperationRegistration_length = 20 * v5;
    Ret_Filter = (_FLT_FILTER *)ExAllocatePoolWithTag(
                                  0,
                                  20 * v5 + Driver->DriverExtension->ServiceKeyName.Length + 288,
                                  0x6C664D46u);
    if ( Ret_Filter )
    {
      memset(Ret_Filter, 0, 0x120u);
      Ret_Filter->FilterUnload = Registration->FilterUnloadCallback;
      Ret_Filter->InstanceSetup = Registration->InstanceSetupCallback;
      Ret_Filter->InstanceQueryTeardown = Registration->InstanceQueryTeardownCallback;
      Ret_Filter->InstanceTeardownStart = Registration->InstanceTeardownStartCallback;
      Ret_Filter->InstanceTeardownComplete = Registration->InstanceTeardownCompleteCallback;
      Ret_Filter->GenerateFileName = Registration->GenerateFileNameCallback;
      Ret_Filter->NormalizeNameComponent = Registration->NormalizeNameComponentCallback;
      Ret_Filter->NormalizeContextCleanup = Registration->NormalizeContextCleanupCallback;
      v17 = (_FLT_OPERATION_REGISTRATION *)&Ret_Filter[1];
      Ret_Filter->Base.Flags = 0x2000000;
      Ret_Filter->Base.PointerCount = 1;
      FltpExInitializeRundownProtection(&Ret_Filter->Base.RundownRef);
      Ret_Filter->Base.PrimaryLink.Flink = 0;
      FltObjectReference((int)Ret_Filter);
      Ret_Filter->DriverObject = Driver;
      Ret_Filter->InstanceList.rCount = 0;
      ExInitializeResourceLite(&Ret_Filter->InstanceList.rLock);
      InstanceList_rList = &Ret_Filter->InstanceList.rList;
      InstanceList_rList->Blink = InstanceList_rList;
      InstanceList_rList->Flink = InstanceList_rList;
      ActiveOpens = &Ret_Filter->ActiveOpens;
      ActiveOpens->mCount = 0;
      ActiveOpens->mLock.Count = 1;
      ActiveOpens->mLock.Owner = 0;
      ActiveOpens->mLock.Contention = 0;
      KeInitializeEvent(&Ret_Filter->ActiveOpens.mLock.Event, SynchronizationEvent, 0);
      ActiveOpens_mList = &Ret_Filter->ActiveOpens.mList;
      ActiveOpens_mList->Blink = ActiveOpens_mList;
      ActiveOpens_mList->Flink = ActiveOpens_mList;
      PortList = &Ret_Filter->PortList;
      PortList->mCount = 0;
      PortList->mLock.Count = 1;
      PortList->mLock.Owner = 0;
      PortList->mLock.Contention = 0;
      KeInitializeEvent(&Ret_Filter->PortList.mLock.Event, SynchronizationEvent, 0);
      PortList_mList = &Ret_Filter->PortList.mList;
      PortList_mList->Blink = PortList_mList;
      PortList_mList->Flink = PortList_mList;
      Ret_Filter->PortLock.Value = 0;
      if ( !Registration->ContextRegistration
        || (result_2 = FltpProcessContextRegistration((int)Ret_Filter, &Registration->ContextRegistration->ContextType),
            result_2 >= 0) )
      {
        if ( Registration->OperationRegistration )
        {
          Ret_Filter->Operations = v17;
          v17 = (_FLT_OPERATION_REGISTRATION *)((char *)v17 + OperationRegistration_length);
          qmemcpy(&Ret_Filter[1], Registration->OperationRegistration, OperationRegistration_length);
          for ( i = Ret_Filter->Operations; ; ++i )
          {
            MajorFunction = i->MajorFunction;
            if ( i->MajorFunction == -128 )
              break;
            if ( MajorFunction == -19 )
            {
              Ret_Filter->PreVolumeMount = i->PreOperation;
              Ret_Filter->PostVolumeMount = i->PostOperation;
            }
            else if ( MajorFunction != -20 && MajorFunction == 16 )
            {
              i->PostOperation = 0;
            }
          }
          v4 = Registration;
        }
        Ret_Filter->Name.Buffer = (unsigned __int16 *)v17;
        Ret_Filter->Name.Length = 0;
        Ret_Filter->Name.MaximumLength = Driver->DriverExtension->ServiceKeyName.Length;
        temp = (int)(&v17->MajorFunction + Driver->DriverExtension->ServiceKeyName.Length);
        RtlCopyUnicodeString(
          (PUNICODE_STRING)&Ret_Filter->Name,
          (PCUNICODE_STRING)&Driver->DriverExtension->ServiceKeyName);
        result_2 = FltpInitializeFilterVerifier(Ret_Filter);
        if ( result_2 >= 0 )
        {
          result_2 = FltpGetInstanceAltitude(Ret_Filter, 0, 0, (PUNICODE_STRING)&Ret_Filter->DefaultAltitude);
          if ( result_2 >= 0 )
          {
            result_2 = FltpFindFrameForFilter(Ret_Filter, &Ret_Filter->DefaultAltitude);
            if ( result_2 >= 0 )
            {
              result_2 = FltpLinkFilterIntoFrame(Ret_Filter);
              if ( result_2 >= 0 )
              {
                Ret_Filter->OldDriverUnload = Driver->DriverUnload;
                if ( !v4->FilterUnloadCallback || v4->Flags & 1 )
                {
                  Driver->DriverUnload = 0;
                  DriverObject->DriverUnload = 0;
                }
                else
                {
                  Driver->DriverUnload = (void (__stdcall *)(_DRIVER_OBJECT *))FltpMiniFilterDriverUnload;
                }
                if ( !(g_dword_XXX & 0x20) )
                  g_dword_XXX |= 0x20u;
                *RetFilter = Ret_Filter;
              }
            }
          }
        }
      }
      if ( result_2 < 0 )
      {
        ExDeleteResourceLite(&Ret_Filter->InstanceList.rLock);
        FltpCleanupContextRegistration(Ret_Filter);
        FltpCleanupFilterVerifier(Ret_Filter);
        FltpFreeUnicodeString(&Ret_Filter->DefaultAltitude);
        ExFreePoolWithTag(Ret_Filter, 0);
      }
      result = result_2;
    }
    else
    {
      result = 0xC000009A;                      // 见ntstatus.h的定义。
    }
  }
  else
  {
LABEL_46:
    result = 0xC000000D;                        // 见ntstatus.h的定义。
  }
  return result;
}

这主要是导入/创建几个结构,修改下变量的名字和类型就可以了。
再次认识到:程序就是数据和指令的含义。

WINDBG辅助分析如下:
0: kd> dt fltmgr!_FLT_REGISTRATION
   +0x000 Size             : Uint2B
   +0x002 Version          : Uint2B
   +0x004 Flags            : Uint4B
   +0x008 ContextRegistration : Ptr32 _FLT_CONTEXT_REGISTRATION
   +0x00c OperationRegistration : Ptr32 _FLT_OPERATION_REGISTRATION
   +0x010 FilterUnloadCallback : Ptr32     long
   +0x014 InstanceSetupCallback : Ptr32     long
   +0x018 InstanceQueryTeardownCallback : Ptr32     long
   +0x01c InstanceTeardownStartCallback : Ptr32     void
   +0x020 InstanceTeardownCompleteCallback : Ptr32     void
   +0x024 GenerateFileNameCallback : Ptr32     long
   +0x028 NormalizeNameComponentCallback : Ptr32     long
   +0x02c NormalizeContextCleanupCallback : Ptr32     void
1: kd> dd gFilterHandle
ba08b558  81f84390
1: kd> dt _FLT_FILTER  81f84390
fltMgr!_FLT_FILTER
   +0x000 Base             : _FLT_OBJECT
   +0x014 Frame            : 0x81c62000 _FLTP_FRAME
   +0x018 Name             : _UNICODE_STRING "ahsh"
   +0x020 DefaultAltitude  : _UNICODE_STRING "370030"
   +0x028 Flags            : 0 (No matching name)
   +0x02c DriverObject     : 0x81d9ff38 _DRIVER_OBJECT
   +0x030 InstanceList     : _FLT_RESOURCE_LIST_HEAD
   +0x074 VerifierExtension : 0x81f855e8 _FLT_VERIFIER_EXTENSION
   +0x078 FilterUnload     : 0xba08b810     long  ahsh!FltUnload+0
   +0x07c InstanceSetup    : 0xba607790     long  fltMgr!FltvInstanceSetup+0
   +0x080 InstanceQueryTeardown : 0xba6077b4     long  fltMgr!FltvInstanceQueryTeardown+0
   +0x084 InstanceTeardownStart : (null)
   +0x088 InstanceTeardownComplete : (null)
   +0x08c SupportedContextsListHead : (null)
   +0x090 SupportedContexts : [6] (null)
   +0x0a8 PreVolumeMount   : (null)
   +0x0ac PostVolumeMount  : (null)
   +0x0b0 GenerateFileName : 0xba072800     long  ahsh!GenerateFileName+0
   +0x0b4 NormalizeNameComponent : 0xba072c30     long  ahsh!NormalizeNameComponent+0
   +0x0b8 NormalizeContextCleanup : (null)
   +0x0bc Operations       : 0x81f844b0 _FLT_OPERATION_REGISTRATION
   +0x0c0 OldDriverUnload  : (null)
   +0x0c4 ActiveOpens      : _FLT_MUTEX_LIST_HEAD
   +0x0f0 PortList         : _FLT_MUTEX_LIST_HEAD
   +0x11c PortLock         : _EX_PUSH_LOCK
0: kd> !drvobj \filesystem\ahsh 7
Driver object (81ff6750) is for:
 \FileSystem\ahsh
Driver Extension List: (id , addr)

Device Object list:


DriverEntry:   ba0c1e80 ahsh!GsDriverEntry
DriverStartIo: 00000000
DriverUnload:  00000000
AddDevice:     00000000

Dispatch routines:
[00] IRP_MJ_CREATE                      804f55ce nt!IopInvalidDeviceRequest
[01] IRP_MJ_CREATE_NAMED_PIPE           804f55ce nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       804f55ce nt!IopInvalidDeviceRequest
[03] IRP_MJ_READ                        804f55ce nt!IopInvalidDeviceRequest
[04] IRP_MJ_WRITE                       804f55ce nt!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION           804f55ce nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION             804f55ce nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA                    804f55ce nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      804f55ce nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               804f55ce nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    804f55ce nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      804f55ce nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           804f55ce nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         804f55ce nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              804f55ce nt!IopInvalidDeviceRequest
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     804f55ce nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN                    804f55ce nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                804f55ce nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     804f55ce nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT             804f55ce nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              804f55ce nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                804f55ce nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       804f55ce nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL              804f55ce nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE               804f55ce nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 804f55ce nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   804f55ce nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         804f55ce nt!IopInvalidDeviceRequest

0: kd> dt _FLT_FILTER  81f84390  -b
fltMgr!_FLT_FILTER
   +0x000 Base             : _FLT_OBJECT
      +0x000 Flags            : 0xb000b (No matching name)
      +0x004 PointerCount     : 0x200028
      +0x008 RundownRef       : _EX_RUNDOWN_REF
         +0x000 Count            : 0x200048
         +0x000 Ptr              : 0x00200048
      +0x00c PrimaryLink      : _LIST_ENTRY [ 0x10018 - 0x108 ]
         +0x000 Flink            : 0x00010018
         +0x004 Blink            : 0x00000108
   +0x014 Frame            : 0x00000002
   +0x018 Name             : _UNICODE_STRING ""
      +0x000 Length           : 0xb47
      +0x002 MaximumLength    : 0
      +0x004 Buffer           : (null)
   +0x020 DefaultAltitude  : _UNICODE_STRING ""
      +0x000 Length           : 0xb47
      +0x002 MaximumLength    : 0xc
      +0x004 Buffer           : (null)
   +0x028 Flags            : 0x79d0000 (No matching name)
   +0x02c DriverObject     : (null)
   +0x030 InstanceList     : _FLT_RESOURCE_LIST_HEAD
      +0x000 rLock            : _ERESOURCE
         +0x000 SystemResourcesList : _LIST_ENTRY [ 0x7997a78 - 0x0 ]
            +0x000 Flink            : 0x07997a78
            +0x004 Blink            : (null)
         +0x008 OwnerTable       : 0x07997a78
         +0x00c ActiveCount      : 0n0
         +0x00e Flag             : 0
         +0x010 SharedWaiters    : 0x008d0000
         +0x014 ExclusiveWaiters : (null)
         +0x018 OwnerThreads     :
          [00] _OWNER_ENTRY
            +0x000 OwnerThread      : 0x79d0000
            +0x004 OwnerCount       : 0n0
            +0x004 TableSize        : 0
          [01]
            +0x000 OwnerThread      : 0x7997a10
            +0x004 OwnerCount       : 0n0
            +0x004 TableSize        : 0
         +0x028 ContentionCount  : 0x7997a78
         +0x02c NumberOfSharedWaiters : 0
         +0x02e NumberOfExclusiveWaiters : 0
         +0x030 Address          : 0x008d0000
         +0x030 CreatorBackTraceIndex : 0x8d0000
         +0x034 SpinLock         : 0
      +0x038 rList            : _LIST_ENTRY [ 0x7c2e8c7f - 0x67260000 ]
         +0x000 Flink            : 0x7c2e8c7f
         +0x004 Blink            : 0x67260000
      +0x040 rCount           : 0x7c2e8c6c
   +0x074 VerifierExtension : (null)
   +0x078 FilterUnload     : (null)
   +0x07c InstanceSetup    : (null)
   +0x080 InstanceQueryTeardown : 0x00000028
   +0x084 InstanceTeardownStart : (null)
   +0x088 InstanceTeardownComplete : 0x00000001
   +0x08c SupportedContextsListHead : 0x00000018
   +0x090 SupportedContexts :
    [00] (null)
    [01] (null)
    [02] 0x0001001b
    [03] 0x00000028
    [04] 0x00080028
    [05] 0x00000018
   +0x0a8 PreVolumeMount   : (null)
   +0x0ac PostVolumeMount  : (null)
   +0x0b0 GenerateFileName : (null)
   +0x0b4 NormalizeNameComponent : (null)
   +0x0b8 NormalizeContextCleanup : 0x07997a78
   +0x0bc Operations       : (null)
   +0x0c0 OldDriverUnload  : 0x7c2e8c8a
   +0x0c4 ActiveOpens      : _FLT_MUTEX_LIST_HEAD
      +0x000 mLock            : _FAST_MUTEX
         +0x000 Count            : 0n0
         +0x004 Owner            : (null)
         +0x008 Contention       : 0
         +0x00c Event            : _KEVENT
            +0x000 Header           : _DISPATCHER_HEADER
               +0x000 Type             : 0 ''
               +0x001 Absolute         : 0 ''
               +0x002 Size             : 0 ''
               +0x003 Inserted         : 0 ''
               +0x004 SignalState      : 0n0
               +0x008 WaitListHead     : _LIST_ENTRY [ 0x68 - 0x0 ]
                  +0x000 Flink            : 0x00000068
                  +0x004 Blink            : (null)
         +0x01c OldIrql          : 1
      +0x020 mList            : _LIST_ENTRY [ 0x18 - 0x0 ]
         +0x000 Flink            : 0x00000018
         +0x004 Blink            : (null)
      +0x028 mCount           : 0
      +0x028 mInvalid         : 0y0
   +0x0f0 PortList         : _FLT_MUTEX_LIST_HEAD
      +0x000 mLock            : _FAST_MUTEX
         +0x000 Count            : 0n720907
         +0x004 Owner            : 0x00200028
         +0x008 Contention       : 0x200048
         +0x00c Event            : _KEVENT
            +0x000 Header           : _DISPATCHER_HEADER
               +0x000 Type             : 0x18 ''
               +0x001 Absolute         : 0 ''
               +0x002 Size             : 0x1 ''
               +0x003 Inserted         : 0 ''
               +0x004 SignalState      : 0n264
               +0x008 WaitListHead     : _LIST_ENTRY [ 0x2 - 0xb47 ]
                  +0x000 Flink            : 0x00000002
                  +0x004 Blink            : 0x00000b47
         +0x01c OldIrql          : 0
      +0x020 mList            : _LIST_ENTRY [ 0xc0b47 - 0x0 ]
         +0x000 Flink            : 0x000c0b47
         +0x004 Blink            : (null)
      +0x028 mCount           : 0x79d0000
      +0x028 mInvalid         : 0y0
   +0x11c PortLock         : _EX_PUSH_LOCK
      +0x000 Waiting          : 0y0
      +0x000 Exclusive        : 0y0
      +0x000 Shared           : 0y000000000000000000000000000000 (0)
      +0x000 Value            : 0
      +0x000 Ptr              : (null)

0: kd> dt 0x81f844b0 _FLT_OPERATION_REGISTRATION
ahsh!_FLT_OPERATION_REGISTRATION
   +0x000 MajorFunction    : 0x78 'x'
   +0x004 Flags            : 0
   +0x008 PreOperation     : 0x07997ae0     _FLT_PREOP_CALLBACK_STATUS  +7997ae0
   +0x00c PostOperation    : (null)
   +0x010 Reserved1        : 0x008d0000 Void

解析PspCidTable获取进程列表‏

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

/*
功能:。

句柄表分一下几类:
1.进程内的句柄表。因为内核句柄是进程所有的,但是排除进程句柄,线程句柄。USER句柄和GDI句柄是全局的。
2.PspCidTable。因为进程句柄和线程句柄是全局,这些东西放置在哪里呢?就是这里。这个变量没有导出。
3.system这个进程的句柄表,及ObpKernelHandleTable。这个变量没有导出。
4.USER对象,也应该有个句柄表。
5.GDI对象,也应该有个句柄表。


一。进程的句柄表。
    进程对象的某个成员指向此值。
    以后具体分析。


二。PspCidTable的分析。

    \WRK-v1.2\base\ntos\ps\psinit.c文件包含如下信息:
    PHANDLE_TABLE PspCidTable; // nonpaged
    PspCidTable = ExCreateHandleTable (NULL);这个函数在PspInitPhase0中。
    等好多的函数调用需要这个变量,如句柄的创建,销毁,映射,锁等。估计这些 句柄是进程或线程。

    另一个要注意的是:
    KDDEBUGGER_DATA32结构中包含ULONG   PspCidTable;
    KDDEBUGGER_DATA64结构中包含ULONG64   PspCidTable;
    所在的文件是:\WRK-v1.2\public\sdk\inc\wdbgexts.h

kd> vertarget
Windows XP Kernel Version 2600 (Service Pack 3) MP (1 procs) Free x86 compatible
Built by: 2600.xpsp_sp3_qfe.130704-0421
Machine Name:
Kernel base = 0x804d8000 PsLoadedModuleList = 0x8055e720
Debug session time: Wed May 20 11:07:41.772 2015 (UTC + 8:00)
System Uptime: 0 days 0:38:07.921
kd> x nt!PspCidTable
805649c0          nt!PspCidTable = <no type information>
kd> dt _handle_table 805649c0
ntdll!_HANDLE_TABLE
   +0x000 TableCode        : 0xe1001c60 一级表。
   +0x004 QuotaProcess     : 0x00000002 _EPROCESS
   +0x008 UniqueProcessId  : (null)
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null)
   +0x02c ExtraInfoPages   : 0n0
   +0x030 FirstFree        : 0
   +0x034 LastFree         : 0
   +0x038 NextHandleNeedingPool : 0
   +0x03c HandleCount      : 0n0
   +0x040 Flags            : 0
   +0x040 StrictFIFO       : 0y0
kd> dd 0xe1001c60 注意低两位清零
e1001c60  e1005000 00000000 00000000 00000000
e1001c70  00000000 00000000 00000000 e1001c7c
e1001c80  e1001c7c 00000000 00000000 00000000
e1001c90  00000734 000006b4 00000800 0000012e
e1001ca0  00000001 00000000 0c0b060a 64546553
e1001cb0  00000101 05000000 00000012 00440002
e1001cc0  00000002 00140000 10000000 00000101
e1001cd0  05000000 00000012 00180000 a0020000
kd> dq e1005000 这里的内容就是进程对象或者线程对象。
e1005000  fffffffe`00000000 00000000`8214e661
e1005010  00000000`8214e2d9 00000000`8214dd19
e1005020  00000000`8214da99 00000000`8214d819
e1005030  00000000`8214d599 00000000`8214d319
e1005040  00000000`8214c021 00000000`8214cda1
e1005050  00000000`8214cb21 00000000`8214c8a1
e1005060  00000000`8214c621 00000000`8214c3a1
e1005070  00000000`8214b021 00000000`8214bda1
kd> dt _HANDLE_TABLE_ENTRY e1005008 等于8*1 8 == sizeof(HANDLE_TABLE_ENTRY)
nt!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0x8214e661 Void
   +0x000 ObAttributes     : 0x8214e661
   +0x000 InfoTable        : 0x8214e661 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0x8214e661
   +0x004 GrantedAccess    : 0
   +0x004 GrantedAccessIndex : 0
   +0x006 CreatorBackTraceIndex : 0
   +0x004 NextFreeTableEntry : 0n0
kd> !object 0x8214e660 注意低两位清零
Object: 8214e660  Type: (8214eca0) Process
    ObjectHeader: 8214e648 (old version)
    HandleCount: 2  PointerCount: 57
kd> !object 8214e2d8 注意低两位清零
Object: 8214e2d8  Type: (8214ead0) Thread
    ObjectHeader: 8214e2c0 (old version)
    HandleCount: 0  PointerCount: 2


三。ObpKernelHandleTable的分析。
    ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL );
    这在ObInitSystem函数里,这在\WRK-v1.2\base\ntos\ob\obinit.c


made by correy
made at 2015.05.18

参考资料:
WRK
《windows内核原理与实现》的3.4.1节。
*/


#define TAG 'tset' //test

////\WRK-v1.2\base\ntos\inc\ex.h
// Define a structure to track handle usage
//

#define HANDLE_TRACE_DB_MAX_STACKS 65536
#define HANDLE_TRACE_DB_MIN_STACKS 128
#define HANDLE_TRACE_DB_DEFAULT_STACKS 4096
#define HANDLE_TRACE_DB_STACK_SIZE 16

//\WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TRACE_DB_ENTRY {
    CLIENT_ID ClientId;
    HANDLE Handle;
#define HANDLE_TRACE_DB_OPEN    1
#define HANDLE_TRACE_DB_CLOSE   2
#define HANDLE_TRACE_DB_BADREF  3
    ULONG Type;
    PVOID StackTrace[HANDLE_TRACE_DB_STACK_SIZE];
} HANDLE_TRACE_DB_ENTRY, *PHANDLE_TRACE_DB_ENTRY;


//\WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TRACE_DEBUG_INFO {

    //
    // Reference count for this structure
    //
    LONG RefCount;

    //
    // Size of the trace table in entries
    //

    ULONG TableSize;

    //
    // this flag will clean the TraceDb.
    // once the TraceDb is cleaned, this flag will be reset.
    // it is needed for setting the HANDLE_TRACE_DEBUG_INFO_COMPACT_CLOSE_HANDLE
    // dynamically via KD
    //
#define HANDLE_TRACE_DEBUG_INFO_CLEAN_DEBUG_INFO        0x1

    //
    // this flag will do the following: for each close
    // it will look for a matching open, remove the open
    // entry and compact TraceDb
    // NOTE: this should not be used for HANDLE_TRACE_DB_BADREF
    //      because you will not have the close trace
    //
#define HANDLE_TRACE_DEBUG_INFO_COMPACT_CLOSE_HANDLE    0x2

    //
    // setting this flag will break into debugger when the trace list
    // wraps around. This way you will have a chance to loot at old entries
    // before they are deleted
    //
#define HANDLE_TRACE_DEBUG_INFO_BREAK_ON_WRAP_AROUND    0x4

    //
    // these are status flags, do not set them explicitly
    //
#define HANDLE_TRACE_DEBUG_INFO_WAS_WRAPPED_AROUND      0x40000000
#define HANDLE_TRACE_DEBUG_INFO_WAS_SOMETIME_CLEANED    0x80000000

        ULONG BitMaskFlags;

        FAST_MUTEX CloseCompactionLock;

        //
        // Current index for the stack trace DB
        //
        ULONG CurrentStackIndex;

        //
        // Save traces of those who open and close handles
        //
        HANDLE_TRACE_DB_ENTRY TraceDb[1];

} HANDLE_TRACE_DEBUG_INFO, *PHANDLE_TRACE_DEBUG_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  One handle table exists per process.  Unless otherwise specified, via a
//  call to RemoveHandleTable, all handle tables are linked together in a
//  global list.  This list is used by the snapshot handle tables call.
//


typedef struct _HANDLE_TABLE {

    //
    //  A pointer to the top level handle table tree node.
    //

    ULONG_PTR TableCode;

    //
    //  The process who is being charged quota for this handle table and a
    //  unique process id to use in our callbacks
    //

    struct _EPROCESS *QuotaProcess;
    HANDLE UniqueProcessId;


    //
    // These locks are used for table expansion and preventing the A-B-A problem
    // on handle allocate.
    //

#define HANDLE_TABLE_LOCKS 4

    EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS];

    //
    //  The list of global handle tables.  This field is protected by a global
    //  lock.
    //

    LIST_ENTRY HandleTableList;

    //
    // Define a field to block on if a handle is found locked.
    //
    EX_PUSH_LOCK HandleContentionEvent;

    //
    // Debug info. Only allocated if we are debugging handles
    //
    PHANDLE_TRACE_DEBUG_INFO DebugInfo;

    //
    //  The number of pages for additional info.
    //  This counter is used to improve the performance
    //  in ExGetHandleInfo
    //
    LONG ExtraInfoPages;

    //
    //  This is a singly linked list of free table entries.  We don't actually
    //  use pointers, but have each store the index of the next free entry
    //  in the list.  The list is managed as a lifo list.  We also keep track
    //  of the next index that we have to allocate pool to hold.
    //

    ULONG FirstFree;

    //
    // We free handles to this list when handle debugging is on or if we see
    // that a thread has this handles bucket lock held. The allows us to delay reuse
    // of handles to get a better chance of catching offenders
    //

    ULONG LastFree;

    //
    // This is the next handle index needing a pool allocation. Its also used as a bound
    // for good handles.
    //

    ULONG NextHandleNeedingPool;

    //
    //  The number of handle table entries in use.
    //

    LONG HandleCount;

    //
    // Define a flags field
    //
    union {
        ULONG Flags;

        //
        // For optimization we reuse handle values quickly. This can be a problem for
        // some usages of handles and makes debugging a little harder. If this
        // bit is set then we always use FIFO handle allocation.
        //
        BOOLEAN StrictFIFO : 1;
    };

} HANDLE_TABLE, *PHANDLE_TABLE;


//  \WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TABLE_ENTRY_INFO {


    //
    //  The following field contains the audit mask for the handle if one
    //  exists.  The purpose of the audit mask is to record all of the accesses
    //  that may have been audited when the handle was opened in order to
    //  support "per operation" based auditing.  It is computed by walking the
    //  SACL of the object being opened and keeping a record of all of the audit
    //  ACEs that apply to the open operation going on.  Each set bit corresponds
    //  to an access that would be audited.  As each operation takes place, its
    //  corresponding access bit is removed from this mask.
    //

    ACCESS_MASK AuditMask;

} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  A handle table stores multiple handle table entries, each entry is looked
//  up by its exhandle.  A handle table entry has really two fields.
//
//  The first field contains a pointer object and is overloaded with the three
//  low order bits used by ob to denote inherited, protected, and audited
//  objects.   The upper bit used as a handle table entry lock.  Note, this
//  means that all valid object pointers must be at least longword aligned and
//  have their sign bit set (i.e., be negative).
//
//  The next field contains the access mask (sometimes in the form of a granted
//  access index, and creator callback trace) if the entry is in use or a
//  pointer in the free list if the entry is free.
//
//  Two things to note:
//
//  1. An entry is free if the object pointer is null, this means that the
//     following field contains the FreeTableEntryList.
//
//  2. An entry is unlocked if the object pointer is positive and locked if its
//     negative.  The handle package through callbacks and Map Handle to
//     Pointer will lock the entry (thus making the pointer valid) outside
//     routines can then read and reset the attributes field and the object
//     provided they don't unlock the entry.  When the callbacks return the
//     entry will be unlocked and the callers or MapHandleToPointer will need
//     to call UnlockHandleTableEntry explicitly.
//

typedef struct _HANDLE_TABLE_ENTRY {

    //
    //  The pointer to the object overloaded with three ob attributes bits in
    //  the lower order and the high bit to denote locked or unlocked entries
    //

    union {

        PVOID Object;

        ULONG ObAttributes;

        PHANDLE_TABLE_ENTRY_INFO InfoTable;

        ULONG_PTR Value;
    };

    //
    //  This field either contains the granted access mask for the handle or an
    //  ob variation that also stores the same information.  Or in the case of
    //  a free entry the field stores the index for the next free entry in the
    //  free list.  This is like a FAT chain, and is used instead of pointers
    //  to make table duplication easier, because the entries can just be
    //  copied without needing to modify pointers.
    //

    union {

        union {

            ACCESS_MASK GrantedAccess;

            struct {

                USHORT GrantedAccessIndex;
                USHORT CreatorBackTraceIndex;
            };
        };

        LONG NextFreeTableEntry;
    };

} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;


typedef struct _SE_PROCESS_AUDIT_INFO {
    PEPROCESS Process;
    PEPROCESS Parent;
} SE_PROCESS_AUDIT_INFO, *PSE_PROCESS_AUDIT_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  A function to enumerate through the handle table of a process using a
//  callback.
//

typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
    IN PHANDLE_TABLE_ENTRY HandleTableEntry,
    IN HANDLE Handle,
    IN PVOID EnumParameter
    );
//EX_ENUMERATE_HANDLE_ROUTINE eehr;


//  \WRK-v1.2\base\ntos\inc\ex.h
NTKERNELAPI
BOOLEAN
ExEnumHandleTable (
    __in PHANDLE_TABLE HandleTable,
    __in EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
    __in PVOID EnumParameter,
    __out_opt PHANDLE Handle
    );
/*++
Routine Description:
    This function enumerates all the valid handles in a handle table.
    For each valid handle in the handle table, the specified eumeration function is called.
    If the enumeration function returns TRUE, then the enumeration is stopped,
    the current handle is returned to the caller via the optional Handle parameter,
    and this function returns TRUE to indicated that the enumeration stopped at a specific handle.
Arguments:
    HandleTable - Supplies a pointer to a handle table.
    EnumHandleProcedure - Supplies a pointer to a function to call for each valid handle in the enumerated handle table.
    EnumParameter - Supplies an uninterpreted 32-bit value that is passed to the EnumHandleProcedure each time it is called.
    Handle - Supplies an optional pointer a variable that receives the Handle value that the enumeration stopped at.
             Contents of the variable only valid if this function returns TRUE.
Return Value:
    If the enumeration stopped at a specific handle, then a value of TRUE
    is returned. Otherwise, a value of FALSE is returned.
--*/


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//因为ObGetObjectType在XP上没有。
//所以用这些结构解析。

#define OBJ_PROTECT_CLOSE       0x00000001L
#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L
#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)

//
// Object Directory Structure
//

#define NUMBER_HASH_BUCKETS 37
#define OBJ_INVALID_SESSION_ID 0xFFFFFFFF

typedef struct _OBJECT_DIRECTORY {
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
    EX_PUSH_LOCK Lock;
    struct _DEVICE_MAP *DeviceMap;
    ULONG SessionId;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
// end_ntosp


// begin_ntosp
typedef struct _OBJECT_HEADER_NAME_INFO {
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
#if DBG
    ULONG Reserved2;
    LONG DbgDereferenceCount;
#ifdef _WIN64
    ULONG64  Reserved3;   // Win64 requires these structures to be 16 byte aligned.
#endif
#endif
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
// end_ntosp


typedef struct _OBJECT_CREATE_INFORMATION {
    ULONG Attributes;
    HANDLE RootDirectory;
    PVOID ParseContext;
    KPROCESSOR_MODE ProbeMode;
    ULONG PagedPoolCharge;
    ULONG NonPagedPoolCharge;
    ULONG SecurityDescriptorCharge;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    PSECURITY_QUALITY_OF_SERVICE SecurityQos;
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
} OBJECT_CREATE_INFORMATION;


typedef struct _OBJECT_DUMP_CONTROL {
    PVOID Stream;
    ULONG Detail;
} OB_DUMP_CONTROL, *POB_DUMP_CONTROL;

typedef VOID (*OB_DUMP_METHOD)(
    IN PVOID Object,
    IN POB_DUMP_CONTROL Control OPTIONAL
    );

typedef enum _OB_OPEN_REASON {
    ObCreateHandle,
    ObOpenHandle,
    ObDuplicateHandle,
    ObInheritHandle,
    ObMaxOpenReason
} OB_OPEN_REASON;


typedef NTSTATUS (*OB_OPEN_METHOD)(
    IN OB_OPEN_REASON OpenReason,
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG HandleCount
    );

typedef BOOLEAN (*OB_OKAYTOCLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN HANDLE Handle,
    IN KPROCESSOR_MODE PreviousMode
    );

typedef VOID (*OB_CLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG_PTR ProcessHandleCount,
    IN ULONG_PTR SystemHandleCount
    );

typedef VOID (*OB_DELETE_METHOD)(
    IN  PVOID   Object
    );

typedef NTSTATUS (*OB_PARSE_METHOD)(
    IN PVOID ParseObject,
    IN PVOID ObjectType,
    IN OUT PACCESS_STATE AccessState,
    IN KPROCESSOR_MODE AccessMode,
    IN ULONG Attributes,
    IN OUT PUNICODE_STRING CompleteName,
    IN OUT PUNICODE_STRING RemainingName,
    IN OUT PVOID Context OPTIONAL,
    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
    OUT PVOID *Object
    );

typedef NTSTATUS (*OB_SECURITY_METHOD)(
    IN PVOID Object,
    IN SECURITY_OPERATION_CODE OperationCode,
    IN PSECURITY_INFORMATION SecurityInformation,
    IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN OUT PULONG CapturedLength,
    IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    IN POOL_TYPE PoolType,
    IN PGENERIC_MAPPING GenericMapping
    );

typedef NTSTATUS (*OB_QUERYNAME_METHOD)(
    IN PVOID Object,
    IN BOOLEAN HasObjectName,
    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength,
    IN KPROCESSOR_MODE Mode
    );

//
// Object Type Structure
//

typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;
    BOOLEAN UseDefaultObject;
    BOOLEAN CaseInsensitive;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    BOOLEAN MaintainTypeList;
    POOL_TYPE PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
    OB_DUMP_METHOD DumpProcedure;
    OB_OPEN_METHOD OpenProcedure;
    OB_CLOSE_METHOD CloseProcedure;
    OB_DELETE_METHOD DeleteProcedure;
    OB_PARSE_METHOD ParseProcedure;
    OB_SECURITY_METHOD SecurityProcedure;
    OB_QUERYNAME_METHOD QueryNameProcedure;
    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

#define OBJECT_LOCK_COUNT 4

typedef struct _OBJECT_TYPE {
    ERESOURCE Mutex;
    LIST_ENTRY TypeList;
    UNICODE_STRING Name;            // Copy from object header for convenience
    PVOID DefaultObject;
    ULONG Index;
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
    ULONG HighWaterNumberOfObjects;
    ULONG HighWaterNumberOfHandles;
    OBJECT_TYPE_INITIALIZER TypeInfo;
#ifdef POOL_TAGGING
    ULONG Key;
#endif //POOL_TAGGING
    ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];
} OBJECT_TYPE, *POBJECT_TYPE;


// begin_ntosp
typedef struct _OBJECT_CREATE_INFORMATION *POBJECT_CREATE_INFORMATION;;

typedef struct _OBJECT_HEADER {
    LONG_PTR PointerCount;
    union {
        LONG_PTR HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;

    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PSECURITY_DESCRIPTOR SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;


//\WRK-v1.2\base\ntos\inc\ob.h
// begin_ntosp
#define OBJECT_TO_OBJECT_HEADER( o ) \
    CONTAINING_RECORD( (o), OBJECT_HEADER, Body )
// end_ntosp


// begin_ntosp
//\WRK-v1.2\base\ntos\inc\ob.h
FORCEINLINE
POBJECT_HEADER_NAME_INFO
OBJECT_HEADER_TO_NAME_INFO_EXISTS (
    IN POBJECT_HEADER ObjectHeader
    )
{
    ASSERT(ObjectHeader->NameInfoOffset != 0);
    return (POBJECT_HEADER_NAME_INFO)((PUCHAR)ObjectHeader -
                                      ObjectHeader->NameInfoOffset);
}

//\WRK-v1.2\base\ntos\inc\ob.h
FORCEINLINE
POBJECT_HEADER_NAME_INFO
OBJECT_HEADER_TO_NAME_INFO (
    IN POBJECT_HEADER ObjectHeader
    )
{
    POBJECT_HEADER_NAME_INFO nameInfo;

    if (ObjectHeader->NameInfoOffset != 0) {
        nameInfo = OBJECT_HEADER_TO_NAME_INFO_EXISTS(ObjectHeader);
        __assume(nameInfo != NULL);
    } else {
        nameInfo = NULL;
    }

    return nameInfo;
}

// end_ntosp

NTKERNELAPI
UCHAR *
PsGetProcessImageFileName(
    __in PEPROCESS Process
    );

    #define PS_PROCESS_FLAGS_PROCESS_EXITING        0x00000004UL // PspExitProcess entered
BOOLEAN
PsGetProcessExitProcessCalled(
    __in PEPROCESS Process
    );
//{
//    return (BOOLEAN) ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_EXITING) != 0);
//}

//NTDDKK.H 已经定义。
//NTSTATUS
//PsGetProcessExitStatus(
//    __in PEPROCESS Process
//    );
//{
//    return Process->ExitStatus;
//}


/*
从一个对象获取对象的类型的思路。
kd> !handle 4

PROCESS 8055d0c0  SessionId: none  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00336000  ObjectTable: e1003e38  HandleCount: 275.
    Image: Idle

Kernel handle table at e1003e38 with 275 entries in use

0004: Object: 8214e660  GrantedAccess: 001f0fff Entry: e1004008
Object: 8214e660  Type: (8214eca0) Process
    ObjectHeader: 8214e648 (old version)
        HandleCount: 2  PointerCount: 59

kd> dt _object_header 8214e648 对象的地址减去对象头的大小。
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n59
   +0x004 HandleCount      : 0n2
   +0x004 NextToFree       : 0x00000002 Void
   +0x008 Type             : 0x8214eca0 _OBJECT_TYPE
   +0x00c NameInfoOffset   : 0 ''
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x22 '"'
   +0x010 ObjectCreateInfo : 0x80564960 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x80564960 Void
   +0x014 SecurityDescriptor : 0xe1001be4 Void
   +0x018 Body             : _QUAD
kd> dt 0x8214eca0 _OBJECT_TYPE
nt!_OBJECT_TYPE
   +0x000 Mutex            : _ERESOURCE
   +0x038 TypeList         : _LIST_ENTRY [ 0x8214ecd8 - 0x8214ecd8 ]
   +0x040 Name             : _UNICODE_STRING "Process"
   +0x048 DefaultObject    : (null)
   +0x04c Index            : 5
   +0x050 TotalNumberOfObjects : 0x17
   +0x054 TotalNumberOfHandles : 0x62
   +0x058 HighWaterNumberOfObjects : 0x17
   +0x05c HighWaterNumberOfHandles : 0x69
   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0ac Key              : 0x636f7250
   +0x0b0 ObjectLocks      : [4] _ERESOURCE
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_SUCCESS;

}


BOOLEAN eehr0(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN PVOID EnumParameter)
    /*
    感觉这里是系统进程的句柄信息,不只是进程和线程的句柄。
    这个获取的进程和线程的数量不全。
    */
{
    NTSTATUS status = STATUS_SUCCESS;
    PVOID  Object;
    ULONG                   actualLen;
    PUNICODE_STRING         fullUniName;
   
    status = ObReferenceObjectByHandle( Handle, FILE_READ_ACCESS, NULL, KernelMode, &Object, NULL );
    if (!NT_SUCCESS( status ))
    {
        /*
        这里是无效的句柄,
        从打印的信息看,这个句柄是一个挨着一个来的,不是一个挨着一个,而是从小到大的顺序,按照结构/表里面有的,可用/显示的。
        所以这里有无效,废弃,无用的句柄。
        */
        //KdPrint(("ObReferenceObjectByHandle, handle:0x%x,:0x%X, in line: %d at file:%s。\n", Handle, status, __LINE__, __FILE__));
        return FALSE;
    }

    fullUniName = ExAllocatePoolWithTag( NonPagedPool, 1024 *sizeof(WCHAR)+2*sizeof(ULONG), TAG);//用原来的fullname,会导致在释放的时候蓝屏。双重释放。
    if( !fullUniName ) {
        KdPrint(("ExAllocatePoolWithTag fail, in line: %d at file:%s。\n", __LINE__, __FILE__));
        ObDereferenceObject( Object );
        return FALSE;
    }

    status = ObQueryNameString( Object, (POBJECT_NAME_INFORMATION)fullUniName, 1024, &actualLen );
    if(!NT_SUCCESS(status))
    {
        KdPrint(("ObQueryNameString:0x%X, in line: %d at file:%s。\n", status, __LINE__, __FILE__));
        ObDereferenceObject( Object );
        ExFreePool( fullUniName );
        return FALSE;
    }

    if (fullUniName->Length != 0)
    {
        //KdPrint(("name:%wZ\n", fullUniName)); //有名字的肯定不是进程对象或者线程对象。
    }
    else
    {
        //KdPrint(("handle:%X的名字为空\n", Handle));
    }

    {
        //POBJECT_HEADER_NAME_INFO NameInfo;
        UNICODE_STRING process  = RTL_CONSTANT_STRING(L"process");
        UNICODE_STRING thread  = RTL_CONSTANT_STRING(L"thread");
        POBJECT_HEADER ObjectHeader = 0;
        POBJECT_TYPE Type = 0;

        //\WRK-v1.2\base\ntos\ob\obwait.c
        ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
        ObjectHeader = (POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(Object);
        Type = ObjectHeader->Type;

        //NameInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(Object));
        //NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);

        if (Type != NULL)
        {
            if (RtlCompareUnicodeString(&Type->Name, &process, TRUE) == 0 || RtlCompareUnicodeString(&Type->Name, &thread, TRUE) == 0 )
            {
                KdPrint(("handle:%X\n", Handle));
            }
        }
    }

    ExFreePool( fullUniName );
    ObDereferenceObject( Object );

    return FALSE;
}


BOOLEAN eehr(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN PVOID EnumParameter)
    /*
    感觉这里是系统进程的句柄信息,不只是进程和线程的句柄。
    */
{
    NTSTATUS status = STATUS_SUCCESS;
    UNICODE_STRING process  = RTL_CONSTANT_STRING(L"process");
    UNICODE_STRING thread  = RTL_CONSTANT_STRING(L"thread");
    POBJECT_HEADER ObjectHeader = 0;
    POBJECT_TYPE Type = 0;

    //\WRK-v1.2\base\ntos\ob\obwait.c
    //ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);//测试不行。
    ObjectHeader = (POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(HandleTableEntry->Object);
    Type = ObjectHeader->Type;

    //NameInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(Object));//无用,不对。
    //NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);//无用,不对。

    //这里列举的信息太多了,可能有过时的。
    if (Type != NULL)
    {
        //这里是没有IDLE进程的。
        if (RtlCompareUnicodeString(&Type->Name, &process, TRUE) == 0)
        {
            //不用PsLookupProcessByProcessId转换了。直接用(PEPROCESS)HandleTableEntry->Object

            status = PsGetProcessExitStatus((PEPROCESS)HandleTableEntry->Object);

            //KdPrint(("process handle:0x%X, %s, status:%0x%x\n", Handle, PsGetProcessImageFileName((PEPROCESS)HandleTableEntry->Object), status));  
            KdPrint(("process handle:0x%p, status:0x%p, %s\n", Handle, status, PsGetProcessImageFileName((PEPROCESS)HandleTableEntry->Object)));            
        }
        else if (RtlCompareUnicodeString(&Type->Name, &thread, TRUE) == 0 )
        {
            //KdPrint(("thread handle:%X\n", Handle));

            //不用PsLookupThreadByThreadId,而直接用线程对象:HandleTableEntry->Object。          
        }
    }

    return FALSE;
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    //kd> dd PspCidTable L1
    //805649c0  e1001c60
    //这个可以通过解析符号文件传递过来。
    PHANDLE_TABLE PspCidTable = (PHANDLE_TABLE)0xe1001c60;

    BOOLEAN B = FALSE;
    //SE_PROCESS_AUDIT_INFO ProcessAuditInfo;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    B = ExEnumHandleTable(PspCidTable, eehr, NULL, NULL);

    return status;//STATUS_SUCCESS
}  

用ZwQueryDirectoryObject遍历驱动对象

#include <ntifs.h>
#include <windef.h>
#include <Aux_klib.h> //source里面要有TARGETLIBS=$(DDK_LIB_PATH)\Aux_klib.lib

#define TAG 'tset' //test

/*
文件名:ZwEnumerateObject.C
功能:遍历驱动对象。

made by correy
made at 2015.05.19
*/

//\WRK-v1.2\public\internal\base\inc\zwapi.h
//https://msdn.microsoft.com/en-us/library/bb470238(v=vs.85).aspx
NTSYSAPI
NTSTATUS
NTAPI
ZwQueryDirectoryObject (
    __in HANDLE DirectoryHandle,
    __out_bcount_opt(Length) PVOID Buffer,
    __in ULONG Length,
    __in BOOLEAN ReturnSingleEntry,
    __in BOOLEAN RestartScan,
    __inout PULONG Context,
    __out_opt PULONG ReturnLength
    );

//\WRK-v1.2\public\sdk\inc\ntobapi.h
//https://msdn.microsoft.com/en-us/library/bb470238(v=vs.85).aspx
typedef struct _OBJECT_DIRECTORY_INFORMATION {
    UNICODE_STRING Name;
    UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{  
   
}


NTSTATUS ZwEnumerateObject(IN UNICODE_STRING * directory)
    /*
    功能:枚举一个DirectoryObject下的对象。
    */
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    OBJECT_ATTRIBUTES ob;
    HANDLE FileHandle = 0;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    PVOID FileInformation = 0;
    ULONG Length = sizeof (FILE_DIRECTORY_INFORMATION);//这个数设置的太小会导致ZwQueryDirectoryFile蓝屏。  
    BOOLEAN           RestartScan;
    ULONG             Context = 0;
    ULONG             ReturnedLength;
    UNICODE_STRING driver = RTL_CONSTANT_STRING(L"Driver");

    InitializeObjectAttributes(&ob, directory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwOpenDirectoryObject(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob);
    if (!NT_SUCCESS (status))
    {
        KdPrint(("ZwOpenDirectoryObject fail with 0x%x.\n", status));
        return status;
    }

    Length = Length + 520;//为何加这个数字,请看ZwEnumerateFile1的说明。
    FileInformation = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);
    if (FileInformation == NULL) {
        status = STATUS_UNSUCCESSFUL;
        DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
        ZwClose(FileHandle);
        return status;
    }
    RtlZeroMemory(FileInformation, Length);

    //RestartScan = FALSE;//为TRUE会导致死循环;
    //status = ZwQueryDirectoryObject( FileHandle, FileInformation, Length, TRUE, RestartScan, &Context, &ReturnedLength );
    //if (!NT_SUCCESS (status)) //此时也会得到数据。
    //{
    //    KdPrint(("ZwQueryDirectoryFile fail with 0x%x.\n", status));//STATUS_BUFFER_TOO_SMALL == C0000023
    //    ExFreePoolWithTag(FileInformation, TAG);
    //    ZwClose(FileHandle);
    //    return status;
    //}

    do
    {
        UNICODE_STRING FileName ={0};
        POBJECT_DIRECTORY_INFORMATION podi = 0;
        UNICODE_STRING FullName = {0};

        RestartScan = FALSE;//为TRUE会导致死循环;
        status = ZwQueryDirectoryObject( FileHandle, FileInformation, Length, TRUE, RestartScan, &Context, &ReturnedLength );
        if (status != STATUS_NO_MORE_FILES && status != STATUS_SUCCESS)
        {
            break;//这里好像没有走过。
        }

        podi = (POBJECT_DIRECTORY_INFORMATION)FileInformation;

        //不是驱动对象就放过。
        if (RtlCompareUnicodeString(&podi->TypeName, &driver, TRUE ) != 0 )
        {
            continue;
        }

        //申请要显示的内存,另一思路是格式化。
        FullName.MaximumLength = (USHORT)Length + directory->MaximumLength;
        FullName.Buffer = ExAllocatePoolWithTag(NonPagedPool, FullName.MaximumLength, TAG);
        if (FullName.Buffer == NULL) {            
            DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        RtlZeroMemory(FullName.Buffer, FullName.MaximumLength);

        RtlCopyUnicodeString(&FullName, directory);

        status = RtlAppendUnicodeToString(&FullName, L"\\");
        if (!NT_SUCCESS (status)) {
            KdPrint(("RtlAppendUnicodeToString fail with 0x%X!\n", status));
            ExFreePoolWithTag(FullName.Buffer, TAG);
            break;
        }

        status = RtlAppendUnicodeStringToString(&FullName, &podi->Name);
        if (!NT_SUCCESS (status)) {
            KdPrint(("RtlAppendUnicodeStringToString fail with 0x%X. 文件为:%s, 代码行为:%d\n", status, __FILE__, __LINE__));
            ExFreePoolWithTag(FullName.Buffer, TAG);
            break;
        }

        //KdPrint(("Name %wZ\n", &podi->Name));
        KdPrint(("Name %wZ\n", &FullName));

        ExFreePoolWithTag(FullName.Buffer, TAG);      

    } while (status != STATUS_NO_MORE_FILES);

    if (status = STATUS_NO_MORE_FILES)
    {
        status = STATUS_SUCCESS;
    }

    if (FileInformation)
    {
        ExFreePoolWithTag(FileInformation, TAG);
        FileInformation = NULL;
    }

    ZwClose(FileHandle);

    return status;
}


NTSTATUS ZwEnumerateDriverObject()
    /*
    功能:枚举系统的驱动对象。
    记得:有一个函数可以实现此功能,当时是热衷于枚举系统的模块,所以当时没有注意那个函数,现在有想不起了,一晃又几年过去了。
          记得devicetree就是通过枚举driver和FileSystem下的对象实现的,甚至是WINOBJ等类似的对象浏览器也是通过这实现的。
          看来ZwQueryDirectoryObject的功能应该不小,现在微软在应用层已经公开此函数,在内核使用此函数应该没有问题。
    说明:FileSystem下虽然还有子目录对象,但是下没有驱动,所以没有递归。可能原理也应该没有。
          这个有啥好处呢?因为不包括NT模块(就是那个几个NTOS*.EXE)和HAL.DLL(也包括几个类型的),所以可以根据此驱动对象进一步获取分发函数,设备对象等操作。此操作只判断存在,余下的还要自己动手。
    */
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    UNICODE_STRING directory  = RTL_CONSTANT_STRING(L"\\driver");
    UNICODE_STRING FileSystem  = RTL_CONSTANT_STRING(L"\\FileSystem");

    status = ZwEnumerateObject(&directory);
    if (!NT_SUCCESS (status))
    {
        return status;
    }

    status = ZwEnumerateObject(&FileSystem);

    return status;
}


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    return ZwEnumerateDriverObject();
}

2015年5月8日星期五

编码遍历进程的VAD

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


/*
功能:遍历进程的VAD。仅仅是演示的目录,不支持X64,X64需要自己改造。

参考资料:
http://bbs.pediy.com/showthread.php?t=66886
http://lilxam.tuxfamily.org/blog/?p=326&lang=en
http://forum.sysinternals.com/vad-tree-walking_topic12362.html
http://bbs.pediy.com/showthread.php?t=117634
http://forum.eviloctal.com/viewthread.php?action=printable&tid=17929

结构的定义来自:
\WRK-v1.2\base\ntos\mm\mi.h
\WRK-v1.2\base\ntos\mm\i386\mi386.h
\WRK-v1.2\base\ntos\mm\amd64\miamd.h
\WRK-v1.2\base\ntos\inc\mm.h
\WRK-v1.2\public\sdk\inc\ntmmapi.h
\WRK-v1.2\base\ntos\inc\i386.h
注意:一些X64的结构没有摘抄。

made by correy
made at 2015.05.08
*/


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


/*
0: kd> !process 0 1 smss.exe
PROCESS 81e15da0  SessionId: none  Cid: 020c    Peb: 7ffdf000  ParentCid: 0004
    DirBase: 02940040  ObjectTable: e149f4c8  HandleCount:  17.
    Image: smss.exe
    VadRoot 81c25be8 Vads 16 Clone 0 Private 30. Modified 8. Locked 0.
    DeviceMap e10002a0
    Token                             e17ea020
    ElapsedTime                       00:00:26.468
    UserTime                          00:00:00.031
    KernelTime                        00:00:00.906
    QuotaPoolUsage[PagedPool]         6068
    QuotaPoolUsage[NonPagedPool]      640
    Working Set Sizes (now,min,max)  (112, 50, 345) (448KB, 200KB, 1380KB)
    PeakWorkingSetSize                117
    VirtualSize                       3 Mb
    PeakVirtualSize                   14 Mb
    PageFaultCount                    206
    MemoryPriority                    BACKGROUND
    BasePriority                      11
    CommitCharge                      43

0: kd> dt nt!_eprocess VadRoot 81e15da0
   +0x11c VadRoot : 0x81c25be8 Void
0: kd> dt nt!_MMVAD 81c25be8
   +0x000 StartingVpn      : 0x48580
   +0x004 EndingVpn        : 0x4858e
   +0x008 Parent           : (null)
   +0x00c LeftChild        : 0x82110778 _MMVAD
   +0x010 RightChild       : 0x81c27c28 _MMVAD
   +0x014 u                : __unnamed
   +0x018 ControlArea      : 0x81e1b6e0 _CONTROL_AREA
   +0x01c FirstPrototypePte : 0xe176c4b0 _MMPTE
   +0x020 LastContiguousPte : 0xfffffffc _MMPTE
   +0x024 u2               : __unnamed
0: kd> dt 0x81e1b6e0 _CONTROL_AREA
nt!_CONTROL_AREA
   +0x000 Segment          : 0xe176c470 _SEGMENT
   +0x004 DereferenceList  : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x00c NumberOfSectionReferences : 1
   +0x010 NumberOfPfnReferences : 0xd
   +0x014 NumberOfMappedViews : 1
   +0x018 NumberOfSubsections : 5
   +0x01a FlushInProgressCount : 0
   +0x01c NumberOfUserReferences : 2
   +0x020 u                : __unnamed
   +0x024 FilePointer      : 0x81c42f28 _FILE_OBJECT
   +0x028 WaitingForDeletion : (null)
   +0x02c ModifiedWriteCount : 0
   +0x02e NumberOfSystemCacheViews : 0
0: kd> dt 0x81c42f28 _FILE_OBJECT
nt!_FILE_OBJECT
   +0x000 Type             : 0n5
   +0x002 Size             : 0n112
   +0x004 DeviceObject     : 0x820be900 _DEVICE_OBJECT
   +0x008 Vpb              : 0x821611e8 _VPB
   +0x00c FsContext        : 0xe1610d90 Void
   +0x010 FsContext2       : 0xe1697630 Void
   +0x014 SectionObjectPointer : 0x81fd82f4 _SECTION_OBJECT_POINTERS
   +0x018 PrivateCacheMap  : (null)
   +0x01c FinalStatus      : 0n0
   +0x020 RelatedFileObject : (null)
   +0x024 LockOperation    : 0 ''
   +0x025 DeletePending    : 0 ''
   +0x026 ReadAccess       : 0x1 ''
   +0x027 WriteAccess      : 0 ''
   +0x028 DeleteAccess     : 0 ''
   +0x029 SharedRead       : 0x1 ''
   +0x02a SharedWrite      : 0x1 ''
   +0x02b SharedDelete     : 0x1 ''
   +0x02c Flags            : 0x44040
   +0x030 FileName         : _UNICODE_STRING "\WINDOWS\system32\smss.exe"
   +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
   +0x040 Waiters          : 0
   +0x044 Busy             : 0
   +0x048 LastLock         : (null)
   +0x04c Lock             : _KEVENT
   +0x05c Event            : _KEVENT
   +0x06c CompletionContext : (null)
0: kd> !vad 0x81c25be8
VAD     level      start      end    commit
82110778 ( 1)          0       ff         0 Private      READWRITE        
820cf5c0 ( 2)        100      100         1 Private      READWRITE        
820cf930 ( 3)        110      110         1 Private      READWRITE        
820fc4a8 ( 4)        120      15f         4 Private      READWRITE        
81c24a80 ( 5)        160      25f         6 Private      READWRITE        
82114570 ( 6)        260      26f         6 Private      READWRITE        
821143b8 ( 7)        270      2af         4 Private      READWRITE        
82113ca0 ( 8)        2b0      2ef         4 Private      READWRITE        
820beae0 ( 9)        2f0      2f0         1 Private      READWRITE        
81c25be8 ( 0)      48580    4858e         2 Mapped  Exe  EXECUTE_WRITECOPY  \WINDOWS\system32\smss.exe
81c27c28 ( 1)      7c920    7c9b5         5 Mapped  Exe  EXECUTE_WRITECOPY  \WINDOWS\system32\ntdll.dll
81c25c78 ( 2)      7ffa0    7ffd2         0 Mapped       READONLY           Pagefile-backed section
81f77068 ( 6)      7ffdc    7ffdc         1 Private      READWRITE        
81c27c90 ( 5)      7ffdd    7ffdd         1 Private      READWRITE        
82136278 ( 4)      7ffde    7ffde         1 Private      READWRITE        
81fe6a90 ( 3)      7ffdf    7ffdf         1 Private      READWRITE        

Total VADs: 16, average level: 5, maximum depth: 9
*/

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


#define tag  'tset' //test

#if defined (_WIN64)

#define COMMIT_SIZE 51

#if ((COMMIT_SIZE + PAGE_SHIFT) < 63)
#error COMMIT_SIZE too small
#endif

#else
#define COMMIT_SIZE 19

#if ((COMMIT_SIZE + PAGE_SHIFT) < 31)
#error COMMIT_SIZE too small
#endif
#endif

#define MM_MAX_COMMIT (((ULONG_PTR) 1 << COMMIT_SIZE) - 1)

#define MM_VIEW_UNMAP 0
#define MM_VIEW_SHARE 1

typedef struct _MMVAD_FLAGS {
    ULONG_PTR CommitCharge : COMMIT_SIZE; // limits system to 4k pages or bigger!
    ULONG_PTR NoChange : 1;
    ULONG_PTR VadType : 3;
    ULONG_PTR MemCommit: 1;
    ULONG_PTR Protection : 5;
    ULONG_PTR Spare : 2;
    ULONG_PTR PrivateMemory : 1;    // used to tell VAD from VAD_SHORT
} MMVAD_FLAGS;

typedef struct _EVENT_COUNTER {
    SLIST_ENTRY ListEntry;
    ULONG RefCount;
    KEVENT Event;
} EVENT_COUNTER, *PEVENT_COUNTER;

typedef struct _MMSECTION_FLAGS {
    unsigned BeingDeleted : 1;
    unsigned BeingCreated : 1;
    unsigned BeingPurged : 1;
    unsigned NoModifiedWriting : 1;

    unsigned FailAllIo : 1;
    unsigned Image : 1;
    unsigned Based : 1;
    unsigned File : 1;

    unsigned Networked : 1;
    unsigned NoCache : 1;
    unsigned PhysicalMemory : 1;
    unsigned CopyOnWrite : 1;

    unsigned Reserve : 1;  // not a spare bit!
    unsigned Commit : 1;
    unsigned FloppyMedia : 1;
    unsigned WasPurged : 1;

    unsigned UserReference : 1;
    unsigned GlobalMemory : 1;
    unsigned DeleteOnClose : 1;
    unsigned FilePointerNull : 1;

    unsigned DebugSymbolsLoaded : 1;
    unsigned SetMappedFileIoComplete : 1;
    unsigned CollidedFlush : 1;
    unsigned NoChange : 1;

    unsigned filler0 : 1;
    unsigned ImageMappedInSystemSpace : 1;
    unsigned UserWritable : 1;
    unsigned Accessed : 1;

    unsigned GlobalOnlyPerSession : 1;
    unsigned Rom : 1;
    unsigned WriteCombined : 1;
    unsigned filler : 1;
} MMSECTION_FLAGS;

typedef struct _MMVAD_FLAGS2 {
    unsigned FileOffset : 24;       // number of 64k units into file
    unsigned SecNoChange : 1;       // set if SEC_NOCHANGE specified
    unsigned OneSecured : 1;        // set if u3 field is a range
    unsigned MultipleSecured : 1;   // set if u3 field is a list head
    unsigned ReadOnly : 1;          // protected as ReadOnly
    unsigned LongVad : 1;           // set if VAD is a long VAD
    unsigned ExtendableFile : 1;
    unsigned Inherit : 1;           //1 = ViewShare, 0 = ViewUnmap
    unsigned CopyOnWrite : 1;
} MMVAD_FLAGS2;

typedef struct _MMADDRESS_LIST {
    ULONG_PTR StartVpn;
    ULONG_PTR EndVpn;
} MMADDRESS_LIST, *PMMADDRESS_LIST;

typedef struct _MMEXTEND_INFO {
    UINT64 CommittedSize;
    ULONG ReferenceCount;
} MMEXTEND_INFO, *PMMEXTEND_INFO;

typedef struct _SEGMENT_FLAGS {
    ULONG_PTR TotalNumberOfPtes4132 : 10;
    ULONG_PTR ExtraSharedWowSubsections : 1;
    ULONG_PTR LargePages : 1;
#if defined (_WIN64)
    ULONG_PTR Spare : 52;
#else
    ULONG_PTR Spare : 20;
#endif
} SEGMENT_FLAGS, *PSEGMENT_FLAGS;

#if !defined (_X86PAE_)
typedef struct _HARDWARE_PTE {
    ULONG Valid : 1;
    ULONG Write : 1;
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG LargePage : 1;
    ULONG Global : 1;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
    ULONG reserved : 1;  // software field
    ULONG PageFrameNumber : 20;
} HARDWARE_PTE, *PHARDWARE_PTE;

#else
typedef struct _HARDWARE_PTE {
    union {
        struct {
            ULONGLONG Valid : 1;
            ULONGLONG Write : 1;
            ULONGLONG Owner : 1;
            ULONGLONG WriteThrough : 1;
            ULONGLONG CacheDisable : 1;
            ULONGLONG Accessed : 1;
            ULONGLONG Dirty : 1;
            ULONGLONG LargePage : 1;
            ULONGLONG Global : 1;
            ULONGLONG CopyOnWrite : 1; // software field
            ULONGLONG Prototype : 1;   // software field
            ULONGLONG reserved0 : 1;  // software field
            ULONGLONG PageFrameNumber : 26;
            ULONGLONG reserved1 : 26;  // software field
        };
        struct {
            ULONG LowPart;
            ULONG HighPart;
        };
    };
} HARDWARE_PTE, *PHARDWARE_PTE;
#endif

// A Page Table Entry on the x86 has the following definition.
// Note the MP version is to avoid stalls when flushing TBs across processors.
typedef struct _MMPTE_HARDWARE {
    ULONG Valid : 1;
#if defined(NT_UP)
    ULONG Write : 1;       // UP version
#else
    ULONG Writable : 1;    // changed for MP version
#endif
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG LargePage : 1;
    ULONG Global : 1;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
#if defined(NT_UP)
    ULONG reserved : 1;    // software field
#else
    ULONG Write : 1;       // software field - MP change
#endif
    ULONG PageFrameNumber : 20;
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;

typedef struct _MMPTE_PROTOTYPE {
    ULONG Valid : 1;
    ULONG ProtoAddressLow : 7;
    ULONG ReadOnly : 1;  // if set allow read only access.
    ULONG WhichPool : 1;
    ULONG Prototype : 1;
    ULONG ProtoAddressHigh : 21;
} MMPTE_PROTOTYPE;

typedef struct _MMPTE_SOFTWARE {
    ULONG Valid : 1;
    ULONG PageFileLow : 4;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG Transition : 1;
    ULONG PageFileHigh : 20;
} MMPTE_SOFTWARE;

typedef struct _MMPTE_TRANSITION {
    ULONG Valid : 1;
    ULONG Write : 1;
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG Transition : 1;
    ULONG PageFrameNumber : 20;
} MMPTE_TRANSITION;

typedef struct _MMPTE_SUBSECTION {
    ULONG Valid : 1;
    ULONG SubsectionAddressLow : 4;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG SubsectionAddressHigh : 20;
    ULONG WhichPool : 1;
} MMPTE_SUBSECTION;

typedef struct _MMPTE_LIST {
    ULONG Valid : 1;
    ULONG OneEntry : 1;
    ULONG filler0 : 8;

    //
    // Note the Prototype bit must not be used for lists like freed nonpaged
    // pool because lookaside pops can legitimately reference bogus addresses
    // (since the pop is unsynchronized) and the fault handler must be able to
    // distinguish lists from protos so a retry status can be returned (vs a
    // fatal bugcheck).
    //

    ULONG Prototype : 1;            // MUST BE ZERO as per above comment.
    ULONG filler1 : 1;
    ULONG NextEntry : 20;
} MMPTE_LIST;

typedef struct _MMPTE {
    union  {
        ULONG Long;
        HARDWARE_PTE Flush;
        MMPTE_HARDWARE Hard;
        MMPTE_PROTOTYPE Proto;
        MMPTE_SOFTWARE Soft;
        MMPTE_TRANSITION Trans;
        MMPTE_SUBSECTION Subsect;
        MMPTE_LIST List;
        } u;
} MMPTE;

typedef MMPTE *PMMPTE;

typedef
VOID
(*PBANKED_SECTION_ROUTINE) (
    IN ULONG ReadBank,
    IN ULONG WriteBank,
    IN PVOID Context
    );

typedef struct _MMBANKED_SECTION {
    PFN_NUMBER BasePhysicalPage;
    PMMPTE BasedPte;
    ULONG BankSize;
    ULONG BankShift; // shift for PTEs to calculate bank number
    PBANKED_SECTION_ROUTINE BankedRoutine;
    PVOID Context;
    PMMPTE CurrentMappedPte;
    MMPTE BankTemplate[1];
} MMBANKED_SECTION, *PMMBANKED_SECTION;

typedef struct _SECTION_IMAGE_INFORMATION {
    PVOID TransferAddress;
    ULONG ZeroBits;
    SIZE_T MaximumStackSize;
    SIZE_T CommittedStackSize;
    ULONG SubSystemType;
    union {
        struct {
            USHORT SubSystemMinorVersion;
            USHORT SubSystemMajorVersion;
        };
        ULONG SubSystemVersion;
    };
    ULONG GpValue;
    USHORT ImageCharacteristics;
    USHORT DllCharacteristics;
    USHORT Machine;
    BOOLEAN ImageContainsCode;
    BOOLEAN Spare1;
    ULONG LoaderFlags;
    ULONG ImageFileSize;
    ULONG Reserved[ 1 ];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

//
// This structure is used only by Wow64 processes. The offsets
// of structure elements should the same as viewed by a native Win64 application.
//
typedef struct _SECTION_IMAGE_INFORMATION64 {
    ULONGLONG TransferAddress;
    ULONG ZeroBits;
    ULONGLONG MaximumStackSize;
    ULONGLONG CommittedStackSize;
    ULONG SubSystemType;
    union {
        struct {
            USHORT SubSystemMinorVersion;
            USHORT SubSystemMajorVersion;
        };
        ULONG SubSystemVersion;
    };
    ULONG GpValue;
    USHORT ImageCharacteristics;
    USHORT DllCharacteristics;
    USHORT Machine;
    BOOLEAN ImageContainsCode;
    BOOLEAN Spare1;
    ULONG LoaderFlags;
    ULONG ImageFileSize;
    ULONG Reserved[ 1 ];
} SECTION_IMAGE_INFORMATION64, *PSECTION_IMAGE_INFORMATION64;

#define MM_PROTO_PTE_ALIGNMENT ((ULONG)PAGE_SIZE)

//\WRK-v1.2\base\ntos\mm\amd64\miamd.h
//#define MM_PROTO_PTE_ALIGNMENT ((ULONG)MM_MAXIMUM_NUMBER_OF_COLORS * (ULONG)PAGE_SIZE)

typedef struct _SEGMENT {
    struct _CONTROL_AREA *ControlArea;
    ULONG TotalNumberOfPtes;
    ULONG NonExtendedPtes;
    ULONG Spare0;

    UINT64 SizeOfSegment;
    MMPTE SegmentPteTemplate;

    SIZE_T NumberOfCommittedPages;
    PMMEXTEND_INFO ExtendInfo;

    SEGMENT_FLAGS SegmentFlags;
    PVOID BasedAddress;

    //
    // The fields below are for image & pagefile-backed sections only.
    // Common fields are above and new common entries must be added to
    // both the SEGMENT and MAPPED_FILE_SEGMENT declarations.
    //

    union {
        SIZE_T ImageCommitment;     // for image-backed sections only
        PEPROCESS CreatingProcess;  // for pagefile-backed sections only
    } u1;

    union {
        PSECTION_IMAGE_INFORMATION ImageInformation;    // for images only
        PVOID FirstMappedVa;        // for pagefile-backed sections only
    } u2;

    PMMPTE PrototypePte;
    MMPTE ThePtes[MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE];

} SEGMENT, *PSEGMENT;

//这个WRK定义的与WINDBG显示的不一样。
//typedef struct _CONTROL_AREA {
//    PSEGMENT Segment;                   //1
//    LIST_ENTRY DereferenceList;         //2
//    ULONG NumberOfSectionReferences;    //3 All section refs & image flushes
//    ULONG NumberOfPfnReferences;        //4 valid + transition prototype PTEs
//    ULONG NumberOfMappedViews;          //5 total # mapped views, including system cache & system space views
//    ULONG NumberOfSystemCacheViews;     //6 system cache views only
//    ULONG NumberOfUserReferences;       //7 user section & view references
//    union {
//        ULONG LongFlags;
//        MMSECTION_FLAGS Flags;
//    } u;                                //8
//    PFILE_OBJECT FilePointer;           //9
//    PEVENT_COUNTER WaitingForDeletion;  //10
//    USHORT ModifiedWriteCount;          //11
//    USHORT FlushInProgressCount;        //12
//    ULONG WritableUserReferences;       //13
//#if !defined (_WIN64)
//    ULONG QuadwordPad;                  //14
//#endif
//} CONTROL_AREA, *PCONTROL_AREA;

//其实这个和上面的是一样的,只不过更详细点。
typedef struct _CONTROL_AREA {
    PSEGMENT Segment;                   //1
    LIST_ENTRY DereferenceList;         //2
    ULONG NumberOfSectionReferences;    //3 All section refs & image flushes
    ULONG NumberOfPfnReferences;        //4 valid + transition prototype PTEs
    ULONG NumberOfMappedViews;          //5 total # mapped views, including system cache & system space views  
    USHORT NumberOfSubsections;         //6
    USHORT FlushInProgressCount;        //7
    ULONG NumberOfUserReferences;       //8 user section & view references
    union {
        ULONG LongFlags;
        MMSECTION_FLAGS Flags;
    } u;                                //9
    PFILE_OBJECT FilePointer;           //10
    PEVENT_COUNTER WaitingForDeletion;  //11
    USHORT ModifiedWriteCount;          //12
    USHORT NumberOfSystemCacheViews;    //13ULONG NumberOfSystemCacheViews;     // system cache views only
    //
    //ULONG WritableUserReferences;
#if !defined (_WIN64)
    ULONG QuadwordPad;                  //14
#endif
} CONTROL_AREA, *PCONTROL_AREA;
//因为:XP-32下sizeof(_CONTROL_AREA) == 0x30,所以NumberOfSystemCacheViews是Uint2B,而不是不是ULONG。

typedef struct _MMVAD_LONG {
    union {
        LONG_PTR Balance : 2;
        struct _MMVAD *Parent;
    } u1;
    struct _MMVAD *LeftChild;
    struct _MMVAD *RightChild;
    ULONG_PTR StartingVpn;
    ULONG_PTR EndingVpn;

    union {
        ULONG_PTR LongFlags;
        MMVAD_FLAGS VadFlags;
    } u;
    PCONTROL_AREA ControlArea;
    PMMPTE FirstPrototypePte;
    PMMPTE LastContiguousPte;
    union {
        ULONG LongFlags2;
        MMVAD_FLAGS2 VadFlags2;
    } u2;
    union {
        LIST_ENTRY List;
        MMADDRESS_LIST Secured;
    } u3;
    union {
        PMMBANKED_SECTION Banked;
        PMMEXTEND_INFO ExtendedInfo;
    } u4;
} MMVAD_LONG, *PMMVAD_LONG;

//这个WRK定义的和WINDBG命令显示的不一样。
//typedef struct _MMVAD {
//    union {
//        LONG_PTR Balance : 2;
//        struct _MMVAD *Parent;
//    } u1;
//    struct _MMVAD *LeftChild;
//    struct _MMVAD *RightChild;
//    ULONG_PTR StartingVpn;
//    ULONG_PTR EndingVpn;
//
//    union {
//        ULONG_PTR LongFlags;
//        MMVAD_FLAGS VadFlags;
//    } u;
//    PCONTROL_AREA ControlArea;
//    PMMPTE FirstPrototypePte;
//    PMMPTE LastContiguousPte;
//    union {
//        ULONG LongFlags2;
//        MMVAD_FLAGS2 VadFlags2;
//    } u2;
//} MMVAD, *PMMVAD;

typedef struct _MMVAD {
    LONG_PTR StartingVpn;//用指针兼容64
    LONG_PTR EndingVpn;//用指针兼容64
    struct _MMVAD *Parent;
    struct _MMVAD *LeftChild;
    struct _MMVAD *RightChild;
    union {
        ULONG_PTR LongFlags;
        MMVAD_FLAGS VadFlags;
    } u;
    PCONTROL_AREA ControlArea;
    PMMPTE FirstPrototypePte;
    PMMPTE LastContiguousPte;
    union {
        ULONG LongFlags2;
        MMVAD_FLAGS2 VadFlags2;
    } u2;
} MMVAD, *PMMVAD;


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


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


VOID print(IN PMMVAD t)
    /*
    看看还需要附加进程不?
    */
{
    PCONTROL_AREA ControlArea = 0;
    PFILE_OBJECT FilePointer = 0;
    UNICODE_STRING FileName = {0};
    NTSTATUS status = STATUS_UNSUCCESSFUL;    

    __try {
        //ProbeForRead(t, sizeof (MMVAD), sizeof(UCHAR));
        ControlArea = t->ControlArea;
        if (ControlArea != NULL && (PVOID)ControlArea >= MmSystemRangeStart && MmIsAddressValid((PVOID)ControlArea))
        {
            //ProbeForRead(ControlArea, sizeof (CONTROL_AREA), sizeof(UCHAR));
            FilePointer = ControlArea->FilePointer;
            if (FilePointer != NULL && (PVOID)FilePointer>= MmSystemRangeStart && MmIsAddressValid((PVOID)FilePointer))
            {
                //ProbeForRead(FilePointer, sizeof (FILE_OBJECT), sizeof(UCHAR));
                FileName = FilePointer->FileName;//这里简单获取下,有可能获取的不是全路径。
                //if (FileName != NULL)
                {
                    //KdPrint(("FileName:%wZ\n", &FileName));
                }
            }
        }
    }__except (EXCEPTION_EXECUTE_HANDLER) {
        status = GetExceptionCode();
        //KdPrint(("access user memory exception:0x%X, in line: %d at file:%s。\n", status, __LINE__, __FILE__));
    }  

    //可以仿照!VAD命令打印信息。
    KdPrint(("VAD:%p, start:%p, end:%p, FileName:%wZ\n", t, t->StartingVpn, t->EndingVpn, &FileName));
}


VOID traversal(IN PMMVAD t)
{
    if ( t != 0)
    {
        print(t);

        traversal(t->LeftChild);
        traversal(t->RightChild);
    }
}


VOID test(wchar_t * process_name)
    /*
    这个名字改如何填写才不导致ZwOpenProcess失败呢?
    smss.exe
    \\smss.exe
    \\Process\\smss.exe
    都失败。
    网上只有传递ID成功的代码。
    */
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;    
    HANDLE  ProcessHandle;
    OBJECT_ATTRIBUTES ob;
    UNICODE_STRING  ObjectName;

    RtlInitUnicodeString(&ObjectName, process_name);
    InitializeObjectAttributes(&ob, &ObjectName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwOpenProcess(&ProcessHandle, GENERIC_ALL, &ob, 0);
    if (!NT_SUCCESS(status)) {
        KdPrint(("ZwOpenProcess fail with 0x%x, file:%s,fun:%s,line:%d\n",status,  __FILE__,__FUNCTION__, __LINE__));
        return;
    }


}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    unsigned int x = (unsigned int)((unsigned char *)PsInitialSystemProcess + 0x11c);
    PMMVAD p = 0;

    x = *(unsigned int *)x;
    p = (PMMVAD)x;

    KdBreakPoint();//此时可以用!process 0 1 pname获取一个进程的VAD,然后改写p的值,可以试试看测试效果。

    DriverObject->DriverUnload = Unload;  
   
    traversal(p);

    return status;//STATUS_SUCCESS
}