創建對象的三大步驟:
1.通過ObCreateObject函數創建目標對象。
2.目標對象本身的初始化
3.通過ObInsertObject將目標對象插入對象目錄和句柄表,並返回句柄。
ObCreateObject函數用來創建一個指定類型的內核對象。
NTSTATUS
ObCreateObject(IN POBJECT_TYPE Type,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
IN ULONG ObjectSize,
IN ULONG PagedPoolCharge OPTIONAL,
IN ULONG NonPagedPoolCharge OPTIONAL,
OUT PVOID *Object)
{
ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
Status = ObpCaptureObjectCreateInformation(ObjectAttributes,FALSE,ObjectCreateInfo,
&ObjectName);//提取ObjectAttributes中的字段
if (!PagedPoolCharge)
PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
if (!NonPagedPoolCharge)
NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
//從對應池中分配內存,創建對應的對象
Status = ObpAllocateObject(ObjectCreateInfo,&ObjectName,Type,ObjectSize,AccessMode,
&Header);
return Status;
}
其實真正的工作函數是ObpAllocateObject,它內部調用ExAllocatePoolWithTag(ObjectType->PoolType, 可選頭總大小+ ObjectSize, Tag)分配對象內存,然后初始化設置頭部中的Flags等其他工作。(絕大多數內核對象都分配在非分頁池中)
ObCreateObject函數的第二個參數指向一個_OBJECT_ATTRIBUTES結構,這是一個非常重要的結構。
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;//本結構體的長度
HANDLE RootDirectory;//相對目錄(不一定是父目錄)
PUNICODE_STRING ObjectName;//相對RootDirectory這個目錄的剩余路徑 或者 全路徑
//上面兩個字段一起間接構成對象的全路徑
ULONG Attributes;//打開屬性,對象屬性與句柄屬性的混合
PVOID SecurityDescriptor;// SD安全描述符
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
創建對象、打開對象時都會用到這個結構。
OBJECT_ATTRIBUTES結構體中的Attributes字段是個混合成員,由句柄屬性、對象屬性、打開屬性復合而成,可以取下面的組合
OBJ_INHERIT://句柄屬性,表示句柄是否可繼承給子進程
OBJ_PERMANENT://指該對象是否永久存在於對象目錄中直到對象銷毀.(目錄\符號鏈接\設備\文件 都是)
OBJ_EXLUSIVE://對象屬性,指該對象同一時刻只能被一個進程獨占打開
OBJ_CASE_INSENSITIVE://打開屬性,表示本次打開操作查找比較對象名時大小寫不敏感
OBJ_OPENIF://打開屬性,表示if對象存在就打開
OBJ_OPENLINK://打開屬性,表示本次打開是否可以直接打開符號鏈接
OBJ_KERNEL_HANDLE://句柄屬性,表示要求得到一個內核句柄
而對象頭中的Flags字段則完全表示對象的一些屬性標志
OB_FLAG_CREATE_INFO;//表示頭部中含有創建時的屬性信息
OB_FLAG_CREATOR_INFO;//表示含有創建者進程信息
OB_FLAG_KERNEL_MODE://表示PreviousMode是內核模式的代碼創建的本對象
OB_FLAG_EXCLUSIVE://表示同一時刻只能被一個進程獨占打開
OB_FLAG_PERMANET://永久性對象,直到對象完全銷毀時才脫離對象目錄
OB_FLAG_SINGLE_PROCESS://表示含有每進程的句柄統計信息
OB_FLAG_DEFER_DELETE;//標記本對象被延遲刪除了
創建的對象,如果有名字,就需要插入到對象目錄和句柄表中。即使沒有名字,也需要插入到句柄表中,這樣才能讓應用程序得以找到該對象以進行訪問。這就是ObInsertObject函數的功能:
NTSTATUS
ObInsertObject(IN PVOID Object,
IN PACCESS_STATE AccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE Handle)//返回得到的句柄
{
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
ObjectType = ObjectHeader->Type;
ObjectName = NULL;
if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
ObjectName = &ObjectNameInfo->Name;
PreviousMode = KeGetPreviousMode();
//無名對象(並且不需要安全控制)就不掛入對象目錄,僅僅插入句柄表中
if ( (ObjectName==NULL) && !(ObjectType->TypeInfo.SecurityRequired))
{
ObjectHeader->ObjectCreateInfo = NULL;
Status = ObpCreateUnnamedHandle(Object,DesiredAccess,ObjectCreateInfo->Attributes,
PreviousMode,Handle);
return Status;
}
InsertObject = Object;
if (ObjectName)//若是一個有名對象
{
//這個函數有兩種用途。
//當Object不為NULL表示將Object插入到對象目錄中的指定位置
//當Object為NULL表示查找指定的對象目錄位置處的對象
//兩種用途都將指定目錄位置處的對象返回到InsertObject中
Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
ObjectName,
ObjectCreateInfo->Attributes,
ObjectType,
ObjectCreateInfo->ParseContext,
Object,//要插入的對象
&InsertObject);//返回最終那個位置處的對象
//如果原位置處已有同名對象,插入失敗
if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
{
OpenReason = ObOpenHandle;//既然插入失敗了,那就是要打開對象,獲得句柄
if (ObjectCreateInfo->Attributes & OBJ_OPENIF)//檢查本次打開操作的要求
{
if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
Status = STATUS_OBJECT_TYPE_MISMATCH;
else
Status = STATUS_OBJECT_NAME_EXISTS;//看到沒,應用層經常返回這個出錯值
}
else
{
Status = STATUS_OBJECT_NAME_COLLISION;
}
return Status;
}
}
if (InsertObject == Object)//if 插入成功
OpenReason = ObCreateHandle;//只有第一次創建對象的時候才會插入對象目錄中
ObjectHeader->ObjectCreateInfo = NULL;//不再需要了
if (Handle)//如果用戶要求插入句柄表,就插入句柄表,得到一個句柄
{
Status = ObpCreateHandle(OpenReason,InsertObject,AccessState,
ObjectCreateInfo->Attributes, PreviousMode,Handle);
}
return Status;
}
