首页
社区
课程
招聘
[原创]科锐三阶段项目---CreateProcess流程分析
发表于: 2010-6-5 16:59 65661

[原创]科锐三阶段项目---CreateProcess流程分析

2010-6-5 16:59
65661

标 题: 【原创】CreateProcess流程分析。
作 者: pyq逍遥
时 间: 2010-06-03,16:26:42
链 接: http://bbs.pediy.com/showthread.php?p=819417#post819417

工具: IDA5.2, WinDbg, Ollydbg
平台: Windows XP xp3

    这个项目是本人在科锐和同学一起完成的项目,各有分工,我的任务是分析CreateProcess从用户态到内核态的整体流程框架(部分函数的具体实现由其他同学的完成)。

声明:由于本人能力有限,文中必然有错漏之处,恳请读者不吝赐教.(第一次写文章)

这里为了方便大家查阅,给出其他同学分析的链接:

CreateProcess函数的整体流程分析http://bbs.pediy.com/showthread.php?p=819417#post819417

NtCreateProcessEx的分析http://bbs.pediy.com/showthread.php?t=114958

MmInitializeProcessAddressSpace的分析http://bbs.pediy.com/showthread.php?t=114956

内核创建进程之创建节区分析http://bbs.pediy.com/showthread.php?t=114943

线程创建流程分析http://bbs.pediy.com/showthread.php?t=114929

异常分发
http://bbs.pediy.com/showthread.php?t=114945

进程句柄表分析http://bbs.pediy.com/showthread.php?t=114820

ObCreateObject函数的分析http://bbs.pediy.com/showthread.php?t=114730

ObInsertObject函数的分析http://bbs.pediy.com/showthread.php?t=114734

以下是我的分析:

目录:
一:创建进程的大体流程。
二:3环进程的创建分析。
三:0环创建进程的分析。
四:3环创建线程的分析。
五:0环创建线程的分析。

一.   创建进程的大体流程:

        创建进程的过程就是构建一个环境,这个环境包含了很多的机制 (比如自我保护, 与外界通信等等)。 构建这个环境需要两种“人”来协调完成(用户态和内核态),他们各有分工,其中用户态提供原料(提供创建的那些参数), 内核态负责来构建这个环境,由于环境是由内核态构建的,因此他持有这个环境的控制权, 而用户由于提供了原料, 因此他具有使用权。 内核态开始构建环境中的基础设施(进程对象,等等),在构建完基础设施后,内核态通知用户态基础设施构建已经完成,是否需要继续构建其他设施,于是用户态通知内核态继续构建一条通道(既创建线程),方便两边的通信,当用户态接收到线程创建完毕的信息后,便可以开始使用这个环境(投入生产),以后缺啥补啥

二.   3环进程的创建分析:

       CreateProcesssA的分析:

        在CreateProcessA函数中调用了CreateProcessInternalA,调用该函数时,增加了两个参数(一头一尾加了个零参数),在该函数里面也没看到对这两个参数的引用,而是直接传递给CreateProcessInternalW函数。

       在CreateProcessInternalA中,首先检查了参数 lpCmdLine, 判断是否为0,不为0则将lpCmdLine初始化为UNICODE字符串, 为0则做了几个局部变量赋值后跳过初始化为UNICODE字符串。接着继续检查参数,先将lpStartupInfor的内容拷贝到一个局部变量, 然后判断参数lpApplicationName是否为0,不为0则参数转换为UNICODE字符串,为0则跳过转换继续判断参数lpCurrentDirectory是否为0,这个和参数lpAppLicationName的判断逻辑是一样的。接着判断STARTUPINFOA.lpReserved域是否为0(MSDN上说在调用CreateProcess前,要把lpReserved设置为NULL ,不过我试了下,不为0也没问题。),该域不为0则和其他字符串参数一样做UNICODE的转换,后面还判断STARTUPINFOA中的几个字符串的域,不为0的都作了下转换。最后调用了CreateProcesssW函数, 看上面的步骤大家应该知道了其实CreateProcessInternalA函数只是对字符串参数或者结构体中包含字符串类型的域的作了检查和转换工作,然后就调用了下层函数。(附图)


    分析CreateProcesssW的大概流程:

1.        将参数 保存到局部变量中。
2.        dwCreationFlags 的值至少由一个标志组合成(一些创建标志和优先级类型),首先屏蔽  CREATE_NO_WINDOW 标志,代码如下:
   

   mov   eax, [ebp+20h]        ;  ebp+20h = dwCreationFlags
   and   eax, 0F7FFFFFFh       ; 屏蔽CREATE_NO_WINDOW标志。 
   mov   [ebp+20h], eax
   mov   ecx, eax
   and   ecx, 18h		;18h = DETACHED_PROCESS | CREATE_NEW_CONSOLE
   cmp   cl, 18h
   jz    loc_7C8427DE         ;如果相等,说明创建标志不合法
  
mov   eax, [ebp+20h]        ;  ebp+20h = dwCreationFlags
and   eax, 0F7FFFFFFh       ; 屏蔽CREATE_NO_WINDOW标志
mov   [ebp+20h], eax
mov   ecx, eax
and   ecx, 18h
cmp   cl, 18h  ; 判断dwCreationFlags 是否为CREATE_NEW_CONSOLE |DETACHED_PROCESS
jz    loc_7C8427DE          ; 标志组合不合法, 进行错误处理并退出
mov   [ebp+var_6D4], ebx
mov   [ebp+var_6DC], ebx
test  al, 40h
jnz   IsIdlePriority        ; 优先级为IDLE_PRIORITY_CLASS
test  ah, 40h
jnz   loc_7C8427F6
test  al, 20h
jnz   IsNormalPriority      ; 优先级为NORMAL_PRIORITY_CLASS
test  ah, ah
js    loc_7C842802
test  al, al
js    IsHighPriotity        ; 优先级为HIGH_PRIORITY_CLASS
test  ah, 1
jnz   IsRealTimePriority    ; 优先级为REALTIME_PRIORITY_CLASS

mov   [ebp+var_668], bl
and   word ptr [ebp+dwCreateFlag], 3E1Fh ; 屏蔽权限级表示的位
mov   edi, 800h
mov   esi, 1000h
test  [ebp+dwCreateFlag], edi
jnz   loc_7C842832          ; dwCreationFlag = CREATE_SEPARATE_WOW_VDM 
test  [ebp+dwCreateFlag], esi
jnz   short loc_7C819A33    ; dwCreationFlag = CREATE_SHARED_WOW_VDM
mov   eax, _BaseStaticServerData
cmp   [eax+19F4h], bl
jnz   loc_7C84283C

push  60h                   ;打开选项
push  5                       ;共享模式
lea   eax, [ebp+pIoStatusBlock]
push  eax                   ; I/0状态块
lea   eax, [ebp+pObjAttribute]	
push  eax                   ; 对象属性
push  1000A1h  	
                        ;SYNCHRONIZE |FILE_ATTRIBUTE_NORMAL|
                        ;FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY
lea   eax, [ebp+pHandleOfFile]
push  eax                   ; 文件句柄	
mov   esi, ds:__imp__NtOpenFile@24 ; NtOpenFile(x,x,x,x,x,x)
call  esi ; NtOpenFile(x,x,x,x,x,x) ; NtOpenFile(x,x,x,x,x,x)
push  [ebp+pHandleOfFile]   ; 文件句柄
push  1000000h
push  10h                   ; 内存区页面保护属性
push  ebx                   ; SETION大小
push  ebx                   ; 对象属性
push  0F001Fh               ; 访问掩码
lea   eax, [ebp+pSectionHandle]
push  eax                   ; 指向内存区对象的指针(传出参数)
call  ds:__imp__NtCreateSection@28 ; NtCreateSection(x,x,x,x,x,x,x)

push  ebx                   ; 接受返回的大小
push  30h                   ; 内存区信息的长度
lea   eax, [ebp+OepAddress]
push  eax                   ; 接受内存区信息Buffer
xor   edi, edi
inc   edi
push  edi                   ; edi = 1 = SectionImageInformation
push  [ebp+pSectionHandle]  ; 内存区句柄
call  ds:__imp__NtQuerySection@20 ; 将区对象作为镜像执行文件来查询信息
mov   ax, [ebp+MachineType]     ;	MachineType为机器类型,
cmp   ax, ds:7FFE002Ch          ; ds:7FFE002Ch中的内容为0x014c
jb    loc_7C84329E
cmp   ax, ds:7FFE002Eh
ja    loc_7C84329E
cmp   dword ptr [ebp+ SubSystemVersion], 2
jz    short loc_7C8191C4    ; 子系统次版本号
cmp   dword ptr [ebp+ SubSystemVersion], 3 ; 子系统的比较版本(PE信息中包含)
jnz   loc_7C842D0C
movzx eax, [ebp+pImageFileMinorVersion] ; 子系统次版本号
push  eax
movzx eax, [ebp+pImageFileMajorVersion] ; phSection->GpValue
push  eax                   ; 子系统的主版本号
call  _BasepIsImageVersionOk@8 ; 判断镜像文件的版本是否合法。
push  offset LibFileName    ; "advapi32.dll"
call  _LoadLibraryA@4       ; LoadLibraryA(x)
mov   esi, eax
mov   [ebp+phModuleOfAdvapi32.dll], esi ; 保存模块基地址
cmp   esi, ebx
jz    short loc_7C81923C
push  offset ProcName       ; "CreateProcessAsUserSecure"
push  esi                            ; hModule
call  _GetProcAddress@8     ; 获得指定模块中指定函数的地址

call  _DbgUiConnectToDbg@0  ; 实现调用中NtCreateDebugObject
mov   [ebp+nReturnStatus], eax
cmp   eax, ebx
jl    loc_7C82DF58
call  _DbgUiGetThreadDebugObject@0 ; 获得线程调试对象teb->0xF24,
mov   [ebp+phandleOfDebugObj], eax

push  [ebp+JobLevel]                  ; 作业级别
push  ebx                                    ; 异常端口对象句柄
push  [ebp+phandleOfDebugObj]   ; 调试对象句柄
push  [ebp+pSectionHandle]      ; 内存区对象句柄
push  [ebp+CreateFlag]             ; 创建标志
or    esi, 0FFFFFFFFh
push  esi                                    ; 父进程句柄(FFFFFFFF)
push  [ebp+ObjAttibute]           ; 对象属性
push  1F0FFFh                            ; (访问掩码)
lea   eax, [ebp+pHandleOfProcess]
push  eax                                 ; 保留进程句柄值(传出参数)
call  ds:__imp__NtCreateProcessEx@36 ; 创建进程(x,x,x,x,x,x,x,x,x)

mov     eax, large fs:124h    ; eax保存了指向KTHREAD结构的指针
mov     [ebp+pKthread], eax
mov    cl, [eax+_KTHREAD.PreviousMode] ; 线程的前一个模式
mov     [ebp+PreviousMode], cl

push    esi                   ; HandleInformation
lea  eax, [ebp+pParentObject] ; eax 为EPROCESS局部变量的地址(作传出参数)
push    eax                   ; Object
push    dword ptr [ebp+PreviousMode] ; AccessMode
push    _PsProcessType        ; ObjectType
push    80h                   ; DesiredAccess
push    [ebp+ParentProcessHandle] ; Handle
call    _ObReferenceObjectByHandle@24 ; 通过句柄得到父进程对象指针
lea     eax, [ebp+pNewProcessObj]
push    eax                   ; 新对象指针
push    esi                   ; int
push    esi                   ; 对象的大小
push    260h                  ; paseContext
push    esi                   ; int
push    dword ptr [ebp+PreviousMode] ; int
push    [ebp+ObjectAttributes] ; 对象属性
push    _PsProcessType        ; 对象类型
push    dword ptr [ebp+PreviousMode] ; 处理器模式
call    _ObCreateObject@36    ; 创建进程对象 
mov     edi, eax
cmp     edi, esi
jl      loc_4AAB6B            ; 判断ObCreateObject函数调用是否成功
mov     ecx, 98h
xor     eax, eax
mov     ebx, [ebp+pNewProcessObj]
mov     edi, ebx
rep stosd                     ; 将新建对象初始化为0

cmp     [ebp+SectionHandle], esi
jz      loc_4F449F            ; 判断区对象句柄是否为0
push    esi                   ; HandleInformation
eax, [ebp+pSectionObj]
push    eax                   ; 内存区对象指针
push    dword ptr [ebp+PreviousMode] ; 处理器模式
push    _MmSectionObjectType  ; 对象类型
push    8                     ; 访问掩码
push    [ebp+SectionHandle]   ; 内存去句柄
call    _ObReferenceObjectByHandle@24 ; 通过区对象句柄得到区对象指针

mov     eax, [ebp+HandleInformation]
mov     [ebx+_EPROCESS.SectionObject], eax ; pNewProcessObject->SectionObject = 内存区对象指针
cmp     [ebp+DebugPort], esi
jnz     IsDebugger            ; 判断参数DebugPort是否为0

IsDebugger:(DebugPort不为0时)
push    esi                   ; HandleInformation
lea     eax, [ebp+pDebugObj]
push    eax                   ; 新调试对象指针
push    dword ptr [ebp+PreviousMode] ; 处理器模式
push    _DbgkDebugObjectType  ; 对象类型
push    2                     ; 访问模式
push    [ebp+DebugPort]       ; 调试端口句柄
call    _ObReferenceObjectByHandle@24 ; 通过调试对象句柄得到调试对象指针

push    ebx                   ; 新进程对象
push    [ebp+ParentObj]       ; 父进程对象
call    _PspInitializeProcessSecurity@8 ; 初始进程的安全属性(设置新进程对象的令牌对象)
push    1                     ; TOKEN是否为活动
lea     eax, [ebp+8]
push    eax                   ; eax指向父进程对象的指针
push    edi                   ; 父进程对象中的令牌对象
call    _SeSubProcessToken@12 ; 将父进程的令牌对象赋值给新进程对象
lea     eax, [ebp+pDirTableBase]
push    eax                   ; 页目录表基地指针
push    ebx                   ; 新进程对象
push    [ebp+MinimumWorkingSet] ; 最小工作集
call    _MmCreateProcessAddressSpace@12 ; 创建进程地址空间(并构建页目录表,页表 及物理页的关系)
push    eax
lea     eax, [ebp+pDirTableBase]
push    eax                   ; 页目录表基地址
push    [ebp+Affinity]        ; 亲和性
push    8                     ; 进程基本优先级
push    ebx                   ; 新进程对象
call    _KeInitializeProcess@20 ; 
push    ebx                   ; 新进程对象
mov     eax, [ebp+CreateFlag]
and     al, 4
neg     al
sbb     eax, eax
and     eax, [ebp+ParentObj]
push    eax                   ; 父进程对象
call    _ObInitProcess@8      ; 初始化新进程对象的对象表(如果父进程被指定,父进程的对象表拷贝到新进程中, 对象表 的每个对象中HandleCount域都+1)


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

上传的附件:
收藏
免费 9
支持
分享
最新回复 (57)
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
2
坐沙发了~~~
膜拜下楼上的大牛~
2010-6-5 22:10
0
雪    币: 247
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
想问下你分析WRK的还是XP3中用IDA出来的?有分析过他们的相似度和不同么??
2010-6-8 22:08
0
雪    币: 306
活跃值: (153)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
你好,  我分析的是XP3 的内核, 当然参考了WRK的源码, 至于相似度和不同没有特别的去注意
2010-6-9 21:52
0
雪    币: 656
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
竟然没人顶!!!!
2010-6-10 02:39
0
雪    币: 1946
活跃值: (248)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
6
蛋疼的顶一下
2010-6-10 03:56
0
雪    币: 334
活跃值: (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
我顶!,强烈支持一下
2010-6-10 06:37
0
雪    币: 2513
活跃值: (580)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
mark一下
2010-6-10 09:07
0
雪    币: 517
活跃值: (64)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
9
好文,留个印记
2010-6-10 09:16
0
雪    币: 314
活跃值: (271)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
占了个第一页,顶一下
2010-6-10 09:46
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
11
太强大了,在第一页膜拜
2010-6-10 12:20
0
雪    币: 28
活跃值: (12)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
谢谢楼主的好文……
我这里看不到图,是我的原因还是图挂掉了?
2010-6-10 15:03
0
雪    币: 306
活跃值: (153)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
谢谢各位朋友的支持,论坛好像还不稳定, 发的时候图片没问题, 等等吧。
2010-6-10 15:26
0
雪    币: 240
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
不错的东西   学习一下
2010-6-10 15:59
0
雪    币: 227
活跃值: (407)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
学习一下!!!
2010-6-10 20:39
0
雪    币: 28
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
顶一下,学习。
2010-6-11 09:40
0
雪    币: 1102
活跃值: (1298)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
mark l
2010-6-11 11:36
0
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
18
谢谢楼主的共享,学习了.!
2010-6-13 08:31
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
太强大了啊。。。在只能膜拜在第二页了啊。。。
2010-6-13 12:02
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
第一个图。。。。

CreateProcessA调用了CreateProcessInternalA。。。又调用到CreateProcessW??

我很迷糊。。。请楼主指点!!
2010-6-13 12:07
0
雪    币: 306
活跃值: (153)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
CreateProcessA函数的实现是通过调用CreateProcessInternalA来完成, 只是在CreateProcessA函数传递下来的参数基础上在一头一尾增加了两个参数0, 不过惭愧的是我还没弄清楚添加这两个参数的意义。

而最终调用CreateProcessW函数的原因简单来说就是WINDOWS内核是由UNICOED编码,所以ANSIC 版的函数都会调用UNICODE版。 其实真正做实事的是CreateProcessW函数,不过也离不开CreateProcessInternalA的支持

希望我的回复能解开你的迷惑。
2010-6-13 14:25
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
好东西 收藏!
2010-6-16 10:48
0
雪    币: 262
活跃值: (36)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
23
好文,占位学习
2010-6-22 11:24
0
雪    币: 217
活跃值: (45)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
24
这个正是我需要的,谢谢楼主。
2010-6-23 09:58
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
长见识了···
2010-6-24 17:12
0
游客
登录 | 注册 方可回帖
返回
//