句柄的创建
创建对象的三大步骤:
1.通过ObCreateObject函数创建目标对象。
2.目标对象本身的初始化
3.通过ObInsertObject将目标对象插入对象目录和句柄表,并返回句柄。
ObCreateObject函数用来创建一个指定类型的内核对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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结构,这是一个非常重要的结构。
1 2 3 4 5 6 7 8 9 10 11 | 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函数的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗