1. 程式人生 > 其它 >第二章:ObpLookupObjectName 函式

第二章: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 引數,將重新從根目錄開始解析,gotoParseFromRoot
        • elif MaxReparse == 0 ,而 Object == NULL ,則返回 STATUS_OBJECT_NAME_NOT_FOUND,否則返回找到物件
    • ELIF ObjectName 為 NULL,呼叫 ObReferenceObjectByPointer ,若得到RootDirectory 的 Object (是的)則返回找到,否則返回失敗
  • ELSE
    • RootDirectory = ObpRootDirectoryObject,IF ObjectName 為 NULL 或沒有以 \ 開頭,則函式返回
    • IFObjectName -> Length ==sizeof( (WCHAR)L'\\')
      • IF RootDirectory 為 NULL
        • IFInsertObject 存在,則呼叫ObReferenceObjectByPointer 為 InsertObject 增加一個引用,成功則返回InsertObject,否則返回STATUS_INVALID_PARAMETER
      • ELSE呼叫ObReferenceObjectByPointer 為RootDirectory 增加一個引用,成功則返回RootDirectory,否則返回函式返回的 Status
    • ELSE

ParseFromRoot::

    • IFDeviceMap == NULL ,則呼叫 ObfDereferenceDeviceMap 解引用它,並將其置為 NULL
    • IFObjectName-> Buffer 指標按1位元組對齊後不為 NULL,且ObjectName-> Buffer 為 ‘\??\'
      • IFObpReferenceDeviceMap() 返回不為 NULL
        • IF DeviceMap -> DosDevicesDirectory != NULL ,則 goto quickStart 去 dosdevice directory 下搜尋
    • ELSE IFObjectName-> Buffer 為 ‘\??’,那麼返回DeviceMap->DosDevicesDirectory
  • While Reparse:
  • While True:

quickStart::

  • 繼續解析剩餘的字串,在這個迴圈中,每次移動 sizeof(WCHAR) 位元組,每次解析兩個 \xxx\之間的字串
  • IF 不存在,則退出 While 迴圈,否則通過引數 AccessState 檢查和 Attributes 檢查 Caller 是否有許可權訪問這個目錄,沒有則 Break
  • IF 取得的字串是最後一段,會呼叫ObpLockLookupContext 鎖住這個目錄,接著呼叫ObpLookupDirectoryEntry 函式取得物件體
  • IF 物件體不存在,則會做一系列的安全檢查,然後呼叫 ExAllocatePoolWithTag ,並建立一個物件體

ReparseObject::

  • IF 物件體不存在,則會做一系列的安全檢查,然後呼叫ExAllocatePoolWithTag ,並建立一個物件體,Break。
  • IFParseProcedure ==ObpParseSymbolicLink 且InsertObject 為 NULL,呼叫ParseProcedure
  • IF 返回引數是STATUS_REPARSE_OBJECT,則 gotoReparseObject,若為 STATUS_REPARSE 則 goto ParseFromRoot,若解析到的物件不為 NULL ,且 Status 不為前兩種情況,則 Break。

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