首页
社区
课程
招聘
[原创]科锐三阶段项目---CreateProcess流程分析之二:ObCreateObject分析报告
发表于: 2010-6-7 21:39 11870

[原创]科锐三阶段项目---CreateProcess流程分析之二:ObCreateObject分析报告

2010-6-7 21:39
11870

这个是武汉科锐 第三阶段 的分析项目,每个同学负责不同的模块。在此我将我所分析的模块发出来。

声明:由于本人能力有限,文中必然有错漏之处,恳请读者不吝赐教。
因为这个函数比较简单,都是直线下来的,所以没有画流程图!

ObCreateObject它的作用是创建指定类型(OBJECT_TYPE)的对象示例。
堆是系统数据动态申请及释放的地方,WinNT把堆叫做pool。根据是否可以换出,分为PagedPool和NonPagedPool。
如果系统频繁的申请和释放内存,开销很大.于是WinNT利用LookasideList做缓冲,内存释放时并不是直接到pool,而是放到LookasideList中,等申请内存时,先检查表中是否有合适大小的快,若有就直接使用.系统定时检查表项的数目,以保持pool有足够的可用内存。
可以将Lookaside对象想像成一个内存容器。在初始的时候,它先向Windows申请了一块比较大的内存。以后程序员每次申请内存的时候,不是直接向Windows申请内存,而是向Lookaside对象申请内存。Lookaside对象会智能地避免产生内存“空洞”。如果Lookaside对象内部的内存不够用时,它会向操作系统申请更多的内存。当Lookaside对象内部有大量的末使用的内存时,它会自动让Windows回收一部分内存。总之,Lookaside是一个自动的内存分配容器,通过对Lookaside对象申请内存,效率要高于直接向Windows申请内存。
看实现代码之前我先大概的描述一下这个函数的工作流程吧!
ObCreateObject内部通过调用 ObpAllocateObject为对象申请空间。在调用ObpAllocateObject调用之前ObCreateObject函数做一些相关信息的收集以及判断,ObpAllocateObject函数返回通过参数返回其起始地址(即&Header->Body),同时函数里面还做一些对象本身的初始化工作,申请成功后,如果要求对象成为“永久对象”,即具有OB_FLAG_PERMANENT_OBJECT标志的话,再检查是否为系统的安全机制所允许,如果不允话的话,还要把刚刚申请的空间释放掉,同时返回一个错误代码STATUS_PRIVILEGE_NOT_HELD。
整个函数就是完成一个目标对象的创建工作。
下面先来看ObCreateObject函数
这个函数有9个参数,但是有一个没有使用,所以IDA里面没有标识出来。参数如下:

ProbeMode       = byte ptr  8
ObjectType      = dword ptr  0Ch
ObjectAttributes= dword ptr  10h
ObjectHeader    = byte ptr  14h
ObjectBodySize  = dword ptr  1Ch
PagedPoolCharge = dword ptr  20h
NonPagedPoolCharge= dword ptr  24h
arg_Object          = dword ptr  28h
0:000> dt _OBJECT_ATTRIBUTES
ntdll!_OBJECT_ATTRIBUTES
+0x000 Length           : Uint4B
+0x004 RootDirectory    : Ptr32 Void
+0x008 ObjectName       : Ptr32 _UNICODE_STRING
+0x00c Attributes       : Uint4B
+0x010 SecurityDescriptor : Ptr32 Void
+0x014 SecurityQualityOfService : Ptr32 Void
mov    ebx, large fs:20h ; 取得_KPRCB地址
push    esi
mov    esi, [ebx+5F8h] ; 取得_KPRCB的PPLookasideList[3]中指向后一个节点的值;_PP_LOOKASIDE_LIST
inc	    [esi+GENERAL_LOOKASIDE.TotalAllocates] ; _GENERAL_LOOKASIDE.TotalAllocates
push   edi            ; 保存环镜,还不是传参
mov   ecx, esi        ; 通过寄存器ecx传参
call    @ExInterlockedPopEntrySList@8 ; 删除单向链表互锁操作
mov   edi, eax        ; eax的值为指向previously _GENERAL_LOOKASIDE
test    edi, edi
jnz     short FillObjectCreateInformation
inc     [esi+GENERAL_LOOKASIDE.anonymous_0.AllocateHits]
mov   esi, [ebx+5FCh] ; 取得_KPRCB的PPLookasideList[3]中指向前一个节点的值;_PP_LOOKASIDE_LIST
inc    [esi+GENERAL_LOOKASIDE.TotalAllocates]
mov   ecx, esi
call    @ExInterlockedPopEntrySList@8 ; 删除单向链表互锁操作
mov   edi, eax
test    edi, edi
jnz     short FillObjectCreateInformation
push    [esi+GENERAL_LOOKASIDE.Tag] ; ULONG
inc     dword ptr [esi+GENERAL_LOOKASIDE.anonymous_0]
push    [esi+GENERAL_LOOKASIDE.Size] ; SIZE_T
push    [esi+GENERAL_LOOKASIDE.Type] ; POOL_TYPE
call  [esi+GENERAL_LOOKASIDE.Allocate] ;通常放 ExAllocatePoolWithTag
                        ; 还有一个Free释放函数,通常放 ExFreePool
mov     edi, eax        ; 这里判断有没有申请空间成功
test    edi, edi
jnz     short FillObjectCreateInformation
mov     ebx, 0C000009Ah ; STATUS_INVALID_PARAMETER
                        ; 如果没有申请成功,跳到函数末
                        ; 尾部有个将ebx给eax的操作,ebx为返回值
jmp     ObCreateObjectEnd
mov     esi, [ebp+ObjectType]
push    0
push    edi             ; ObjectCreateInfo
lea     eax, [ebp+CapturedObjectName]
push    eax
push    [ebp+ObjectAttributes]
push    dword ptr [ebp+ObjectHeader]
push    dword ptr [ebp+ProbeMode]
push    esi             ; ObjectType
call    ObpCaptureObjectCreateInformation 
ProbeMode       = byte ptr  0Ch
CreatorMode     = byte ptr  10h
ObjectAttributes= dword ptr  14h
CapturedObjectName= dword ptr  18h
ObjectCreateInfo= dword ptr  1Ch
arg_18          = dword ptr  20h
xor     eax, eax
mov     ebx, [ebp+ObjectCreateInfo]
mov     edi, ebx
rep stosd               ; 将ObjectCreateInformation结构体清零
mov     eax, [ebp+ObjectAttributes]
cmp     eax, esi 
mov     eax, [esi+OBJECT_TYPE.TypeInfo.InvalidAttributes]
test    [edi+_OBJECT_CREATE_INFORMATION.Attributes], eax
mov     ecx, [ebp+PagedPoolCharge] ;属性没有冲突,就填写Charge
test    ecx, ecx        ; 判断是否为0
jnz     short FillNonPagedPoolCharge
mov     ecx, [esi+OBJECT_TYPE.TypeInfo.DefaultPagedPoolCharge] ; 
FillNonPagedPoolCharge:
mov     eax, [ebp+NonPagedPoolCharge]
test    eax, eax 
jnz     short AllocObjectCreateInformation
mov     eax, [esi+OBJECT_TYPE.TypeInfo.DefaultNonPagedPoolCharge]
AllocObjectCreateInformation:
mov     [edi+_OBJECT_CREATE_INFORMATION.NonPagedPoolCharge], eax 
call    ObpAllocateObject
mov     ebx, eax
test    ebx, ebx
jl      ReleaseObjectCreateInformation
mov     edi, dword ptr [ebp+ObjectHeader]
mov     esi, [ebp+ arg_Object]
lea     eax, [edi+_OBJECT_CREATE_INFORMATION.SecurityDescriptorCharge]
mov    [esi], eax ;将申请的空间地址给传出参数
test    byte ptr [edi+(_OBJECT_CREATE_INFORMATION+0Fh)], 10h ; ProbeMode是一个char的宽度
jz      short CheckPrivilege
push    dword ptr [ebp+ProbeMode] ;
push    ds:SeCreatePermanentPrivilege.HighPart
push    ds:SeCreatePermanentPrivilege.LowPart ; PrivilegeValue
call    SeSinglePrivilegeCheck ; 如果固定的对像已经创建,则检查是否为系统的安全机制所允许
test    al, al
jnz     short CheckPrivilege
mov     ecx, [esi]
call    ObpFreeObject
mov     ebx, 0C0000061h ; 060000061h == STATUS_PRIVILEGE_NOT_HELD
cmp     ObpTraceEnabled, 0
jz      short ObCreateObjectEnd
test    ebx, ebx
jl      short ObCreateObjectEnd
push    edi             ; NewIrql
call    ObpRegisterObject ; 如果上面的那个条件都成功,执行下面的二个函数
push    1
push    edi
call    ObpPushStackInfo
jmp     short ObCreateObjectEnd
POBJECT_CREATE_INFORMATION ObjectCreateInfo,
KPROCESSOR_MODE OwnershipMode,
POBJECT_TYPE ObjectType OPTIONAL,
PUNICODE_STRING ObjectName,
ULONG ObjectBodySize,
POBJECT_HEADER *ReturnedObjectHeader
mov     eax, [ebp+arg_ObjectCreateInfo]
push    ebx
push    esi
mov     esi, [ebp+arg_HandleInfoSize] 
xor     ecx, ecx
cmp     eax, ecx        ; 这里判断一下ObjectCreateInfo参数是否为空
                        ; 空的话使用默认值,空的话也说明是一个类型对像
                        ; 默认有OBJECT_HEADER_NAME_INFO、OBJECT_HEADER_NAME_INFO可选头部
push    edi
mov     edi, [ebp+CreatorInfoSize] ; 这里原来是ObjectName参数,用来编译器优化,用于它用了,后来用来做变量了
jnz     short cmpDefaultQuota 
push    10h
pop     ebx             ; CreatorInfoSize等于10
mov     [ebp+var_QuotaInfoSize], ecx
mov     [ebp+arg_HandleInfoSize], ecx
mov     [ebp+CreatorInfoSize], ebx
jmp     short ComputerHeaderSize:
mov     edx, [eax+_OBJECT_CREATE_INFORMATION.PagedPoolCharge] ; 
cmp     edx, [esi+OBJECT_TYPE.TypeInfo.DefaultPagedPoolCharge]
jnz     short cmpPsInitialSystemProcess
mov     edx, [eax+_OBJECT_CREATE_INFORMATION.NonPagedPoolCharge]
cmp     edx, [esi+OBJECT_TYPE.TypeInfo.DefaultNonPagedPoolCharge] jnz     short cmpPsInitialSystemProcess
cmp     [eax+_OBJECT_CREATE_INFORMATION.SecurityDescriptorCharge], 800h ; SE_DEFAULT_SECURITY_QUOTA
jbe     short loc_525BD5 ; OBJ_EXCLUSIVE
                        ; 判断是否允许别的进程打开

cmpPsInitialSystemProcess: ; 
mov     edx, large fs:124h
mov     edx, [edx+38h]
cmp     edx, PsInitialSystemProcess ; 判断是不是系统初始化进程
jnz     short HaveQuotaInfo ; 给QuotaInfo留空间

loc_525BD5:
test    byte ptr [eax+_OBJECT_CREATE_INFORMATION.Attributes], 20h 
                                ; 判断是否允许别的进程打开
mov     [ebp+var_QuotaInfoSize], ecx   ; ecx 为零值
jz      short loc_525BE4
HaveQuotaInfo:
mov     [ebp+var_QuotaInfoSize], 10h ; 给QuotaInfo留空间
mov     al, [esi+OBJECT_TYPE.TypeInfo.MaintainHandleCount] ; 对象的类型决定了是否需要OBJECT_HEADER_HANDLE_INFO结构
mov     ebx, [edi+UNICODE_STRING.Buffer] 
neg     al
sbb     eax, eax
and     eax, 8
neg     ebx
mov     [ebp+arg_HandleInfoSize], eax
mov     al, [esi+OBJECT_TYPE.TypeInfo.MaintainTypeList]
sbb     ebx, ebx
and     ebx, 10h 
neg     al
sbb     eax, eax
and     eax, 10h
mov     [ebp+CreatorInfoSize], eax
mov     ebx, [edi+UNICODE_STRING.Buffer]
neg     ebx
sbb     ebx, ebx
and     ebx, 10h
mov     eax, [ebp+CreatorInfoSize]
mov     ecx, [ebp+var_QuotaInfoSize]
add     eax, ebx        ; 这里开始对头的大小进么计算
                        ; ebx为NameInfoSize
add     eax, [ebp+arg_HandleInfoSize]
xor     edx, edx
cmp     esi, edx 
lea     ecx, [eax+ecx+18h]
jz      short loc_525C26
cmp     [esi+OBJECT_TYPE.TypeInfo.PoolType], edx ; NonPagedPool
jz      short loc_525C26
inc     edx             ; edx为分页类型
loc_525C26
test    esi, esi
mov     eax, 546A624Fh  ; 字符串TjbO
jz      short loc_525C35
 ; (ObjectType==NULL?'TjbO':ObjectType->Key)|PROTECTED_POOL
mov     eax, [esi+OBJECT_TYPE.Key]
loc_525C35:
or      eax, 80000000h 
 ; (ObjectType==NULL?'TjbO':ObjectType->Key)|PROTECTED_POOL
push    eax             ; Tag
mov     eax, [ebp+arg_ObjectBodySize]
add     ecx, eax        ; HeaderSize + ObjectBodySize
push    ecx             ; NumberOfBytes
push    edx             ; PoolType
call    ExAllocatePoolWithTag
test    eax, eax        ; 这里判断有没有申请成功
jnz     short AllocObjectSuccess
mov     eax, 0C000009Ah ; STATUS_INSUFFICIENT_RESOURCES
jmp     FunctionEnd
mov     ecx, [ebp+var_QuotaInfoSize]
test    ecx, ecx
jz      short cmpHandleInfoSize
mov     edx, [ebp+arg_ObjectCreateInfo]
mov     edx, [edx+_OBJECT_CREATE_INFORMATION.PagedPoolCharge]
mov     [eax+_OBJECT_HEADER_QUOTA_INFO.PagedPoolCharge], edx
mov     edx, [ebp+arg_ObjectCreateInfo]
mov     edx, [edx+_OBJECT_CREATE_INFORMATION.NonPagedPoolCharge]
mov     [eax+_OBJECT_HEADER_QUOTA_INFO.NonPagedPoolCharge], edx 
mov     edx, [ebp+arg_ObjectCreateInfo]
mov    edx, [edx+_OBJECT_CREATE_INFORMATION.SecurityDescriptorCharge]
and     dword ptr [eax+0Ch], 0 ; QuotaInfo->ExclusiveProcess
mov     [eax+_OBJECT_HEADER_QUOTA_INFO.SecurityDescriptorCharge], edx
add     eax, 10h
cmp     [ebp+arg_HandleInfoSize], 0
jz      short cmpNameInfoSize
and     [eax+_OBJECT_HEADER_HANDLE_INFO.anonymous_0.SingleEntry.HandleCount], 0 add     eax, 8
test    ebx, ebx  ; ebx为NameInfoSize,上面一直没有改过
jz      short cmpCreatorInfoSize
mov     edx, [edi]  ; edi指向ObjectName
mov     dword ptr [eax+_OBJECT_HEADER_NAME_INFO.Name.Length], ed 
mov     edx, [edi+_UNICODE_STRING.Buffer] 
and     [eax+_OBJECT_HEADER_NAME_INFO.Directory], 0 
cmp     [ebp+arg_OwnershipMode], 0 ;这里判断是不是内核模式
mov     edi, [ebp+arg_ObjectCreateInfo]
mov     [eax+_OBJECT_HEADER_NAME_INFO.Name.Buffer], edx 
mov     [eax+_OBJECT_HEADER_NAME_INFO.QueryReferences], 1
jnz     short loc_525CBD
test    edi, edi
jz      short loc_525CBD
test    byte ptr [edi+_UNICODE_STRING.MaximumLength], 1 
jz      short loc_525CBD
mov     [eax+_OBJECT_HEADER_NAME_INFO.QueryReferences], 40000001h

loc_525CBD:
add     eax, 10h
jmp     short cmp_CreatorInfoSize
mov     edi, [ebp+arg_ObjectCreateInfo]
cmp_CreatorInfoSize:
cmp     [ebp+CreatorInfoSize], 0
jz      short loc_525CEB ; ecx等于QuotaInfoSize的值
and     word ptr [eax+0Ch], 0; CreatorBackTraceIndex
mov     edx, large fs:124h
mov     edx, [edx+38h];PsGetCurrentProcess函数实现
mov     edx, [edx+94h]; UniqueProcessId
mov     [eax+_OBJECT_HEADER_CREATOR_INFO.CreatorUniqueProcess], edx
mov     [eax+_OBJECT_HEADER_CREATOR_INFO.TypeList.Blink], eax
mov     [eax+_OBJECT_HEADER_CREATOR_INFO.TypeList.Flink], eax
add     eax, 10h

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
好有拼劲啊,顶
2010-6-7 22:34
0
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
3
丫丫,错过沙发了~~~~
坐板凳吧~~
2010-6-7 22:36
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习ing!
2010-6-16 11:15
0
雪    币: 247
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
EvilKnight同学现在越来越厉害了呀,希望能够互相学习
2010-6-16 20:17
0
雪    币: 388
活跃值: (707)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
6
哎,分析能力不行呀,这二篇分析了我二周。
恩恩,互相学习,有啥问题可以互相交流一下的。
对了,有兴趣的研究的话可以发邮件问我要idb文件!
2010-6-16 21:55
0
游客
登录 | 注册 方可回帖
返回
//