第二章:ObpLookupObjectName 函数

ObjectHeader = OBJECT_TO_OBJECT_HEADER( RootDirectory );

  #define  OBJECT_TO_OBJECT_HEADER( o )   CONTAINING_RECORD( (o), OBJECT_HEADER, Body )

  #define  CONTAINING_RECORD(address, type, field)      ((type *)( \
                            (PCHAR)(address) - \
                            (ULONG_PTR)  \     

                            (&((type *)0)->field)))      // 即  _object_header = object - ( _object_body - 0 )

首先,&((type *)0) 转化为 type 类型的 NULL 指针,再取其 field 域的地址(即 Body,对象体的地址),这样即可取得其相对地址,但这种写法仅仅能使用在宏中,编译器会预编译并将值计算好。因此这个并非是所有结构体共用一个宏而是,一个结构体使用一个宏。因此,不同的类型头文件不会互相引用。

此处的 IoFileObjectType 是一个全局文件对象类型指针,当然也表示 IoFileObject 是一个全局文件对象类型,可理解为一个记录全局数据的对象类型,在 Win7 中可以增加一些特殊操作。

注意 TotalNumberOfObjects 和 HighWaterNumberOfObjects ,HighWaterxxxxx 代表文件对象最多时的数量,而 TotalNumberxxxxx 则表示当前的数量。

同时注意:此处的 ObjectName 是 PUNICODE_STRING ,其结构体为:

#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\')
(*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR)
// 注意此时比较是以 PWSTR,即 unsigned short 为单位,故只比较一个字符
[size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer; 
          //这种语法格式是 MIDL(Microsoft Interface Definition Language),

    //是微软用于服务器和客户端程序之间通信所使用的协议(例如,RPC、COM/DCOM)的接口定义语言.
  //二者同时使用时
size_is() 代表要为数据分配的内存大小,length_is() 代表要传输的数据大小
// 当 MaximumLength Length 总是相同时应省略 length_is()

其中 size_is() 指明 Buffer 指针指向的地址空间的大小,而 length_is() 则指明元素的数量。

[size_is( , m)] short ** ppshort); // Specifies a pointer to a pointer
                     // to an m-sized block of shorts

[in, size_is(m)] short b[][20]); // If m = 10, b[10][20]

[size_is(m,n)] short ** ppshort); // Specifies a pointer to an m-sized block
// of pointers, each of which points to an n-sized block of shorts.
              // m associates with the pointer closeest to the identifer it decorates.
            //n associates with rest. A 指针指向一个以 m 为单位的内存块,每块都存着一个指针 B,B 指向以 n 为单位的内存块

[size_is(size), length_is(length)] char string[*]; // counted string holding at most "size" characters.

const
ALIGNEDNAME ObpDosDevicesShortNamePrefix = { L'\\',L'?',L'?',L'\\' }; // L"\??\"

 typedef union {
  WCHAR Name[sizeof(ULARGE_INTEGER)/sizeof(WCHAR)];
  ULARGE_INTEGER Alignment;
} ALIGNEDNAME;    // Union 结构体,会选取较大的域分配空间,两个域共用一块内存。

#if defined(MIDL_PASS)
typedef struct _ULARGE_INTEGER {
#else // MIDL_PASS
typedef union _ULARGE_INTEGER {
  struct {
    ULONG LowPart;
    ULONG HighPart;
  };
  struct {
    ULONG LowPart;
    ULONG HighPart;
  } u;
#endif //MIDL_PASS
  ULONGLONG QuadPart;
} ULARGE_INTEGER;    // 如果如果没有定义 MIDL_PASS,则有三个域共用一块内存(8字节)

            // 此处 MIDL_PASS 的意义是,如果 CPU 不支持一次读取 8 字节,则一次读 4 字节

    InsertObject: 为 \ ,且没给出 RootDirectoryHandle 且 根目录对象未被创建时,是期望找到的对象名字。其它情况将为这个参数创建一个目录对象。

  FoundObject: Receives a pointer to the object body if found

主要的逻辑结构:

  • IF RootDirectoryHandle 参数给出
    • 调用 ObReferenceObjectByHandle 获得 RootDirectory 地址
    • 若传入的参数 ObjectName 由 \  开头,且 ObjectName.Type 不为 IoFileObjectType ,则函数返回
    • IF RootDirectory 的 ObjectHeader.Type 不是 ObpDirectoryObjectType:
      • if ParseProcedure 为 NULL ,则函数返回
      • 在 While 循环中,Reparse 次数限定为 32 次
        • 调用 ParseProcedure
        • if 函数返回值不为 Reparse,判若返回值大于0,则函数返回找到对象,否则函数返回没找到对象
        • elif  caller 没给 ObjectName 参数,将重新从根目录开始解析,goto ParseFromRoot
        • elif  MaxReparse == 0 ,而 Object == NULL ,则返回 STATUS_OBJECT_NAME_NOT_FOUND,否则返回找到对象
    • ELIF ObjectName 为 NULL,调用 ObReferenceObjectByPointer  ,若得到 RootDirectory 的 Object (是的)则返回找到,否则返回失败
  • ELSE(从全局根目录 ObpRootDirectoryObject 开始解析)
    • RootDirectory = ObpRootDirectoryObject,IF ObjectName 为 NULL 或没有以  \ 开头,则函数返回
    • IF ObjectName -> Length == sizeof( (WCHAR)L'\\'
      • IF RootDirectory  为 NULL
        • IF InsertObject 存在,则调用 ObReferenceObjectByPointer 为 InsertObject 增加一个引用,成功则返回 InsertObject,否则返回 STATUS_INVALID_PARAMETER
      • ELSE 调用 ObReferenceObjectByPointer 为 RootDirectory 增加一个引用,成功则返回 RootDirectory,否则返回函数返回的 Status
    • ELSE 

ParseFromRoot::

    • IF DeviceMap == NULL ,则调用 ObDereferenceDeviceMap 解引用它,并将其置为 NULL
    • IF ObjectName-> Buffer 指针按1字节对齐后不为 NULL,且 ObjectName-> Buffer 为 ‘\??\'
      • IF ObpReferenceDeviceMap() 返回不为 NULL
        • IF  DeviceMap -> DosDevicesDirectory != NULL ,则 goto quickStart 去 dos device directory 下搜索
    • ELSE IF ObjectName-> Buffer 为 ‘\??’,那么返回 DeviceMap->DosDevicesDirectory
  • While Reparse:
  • While True:

quickStart::

  • Reparse = False
  • 继续解析剩余的字符串,每次移动 sizeof(WCHAR) 字节,每次解析两个 \xxx\之间的字符串
  • IF 取得的字符串不存在,则退出 While 循环,否则通过参数 AccessState 检查和 Attributes 检查 Caller 是否有权限访问这个目录,没有则 Break
  • IF 取得的字符串是最后一段,会调用 ObpLockLookupContext 锁住这个目录,接着调用 ObpLookupDirectoryEntry 函数取得对象体
  • IF 对象体不存在,则会做一系列的安全检查,然后调用 ExAllocatePoolWithTag ,并创建一个对象体,创建成功则用 ObpInsertDirectoryEntry ,然后 break

ReparseObject::

  • IF ParseProcedure && ( ! InsertObject || (ParseProcedure == ObpParseSymbolicLink)),调用 ParseProcedure
    • IF 返回参数是 STATUS_REPARSE_OBJECT,则 goto ReparseObject,若为 STATUS_REPARSE 则 goto ParseFromRoot,若解析到的对象不为 NULL ,且 Status 不为前两种情况,则表明没找到对象。
    • Break
  • ELIF InsertObject 为空且安全检查通过,则为 Object 调用 ObReferenceObjectByPointer ,break

解引用、释放 Contex ,return(Status)

 

posted @ 2021-06-20 15:54  Rev_omi  阅读(433)  评论(0编辑  收藏  举报