首页
社区
课程
招聘
科锐三阶段项目---线程创建流程分析
发表于: 2010-6-11 17:38 11860

科锐三阶段项目---线程创建流程分析

2010-6-11 17:38
11860
科锐五期 tariq
NTSTATUS
NtCreateThread(                     // <相关参数说明>
    __out PHANDLE ThreadHandle,     //返回创建线程的句柄
    __in ACCESS_MASK DesiredAccess, //对新线程的访问权限
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes, //指定了线程对象的属性
    __in HANDLE ProcessHandle,      //进程句柄
    __out PCLIENT_ID ClientId, 		 //返回新线程的ClientId 结构
    __in PCONTEXT ThreadContext, 	 //新线程的执行环境
    __in PINITIAL_TEB InitialTeb,   //提供新线程的TEB初始值
    __in BOOLEAN CreateSuspended    //新创建的线程是否要先被挂起
)
mov     eax, _MmUserProbeAddress 
; 用户使允许用的最高断地址  = 7FFF0000 检测标记
mov     ecx, [ebp+ThreadHandle]
cmp     ecx, eax
jb      short ThreadHandleProc 
; 判断threadhand传出参数的地址是否在用户所允许申请的空间
;通过相减 得出的结果是否进位来判断是否越界
mov     [ebp+SaveClientID], ebx 
;保存传入进程结构体地址指针  ClientId
test    bl, 3          
; 等于0 bl=4   对ClientId这个结构体进行对齐判断标记
           ; 结构体的开始地址末尾从00 04 08偏移 方便成员对齐
           ; 用TEST bl,3起到对齐作用 因为这个结构体成员是以4字节对齐
jnz     short MisalignmentProc 
; 结构体首地址如果不是从00 04 08开始
            ; 导致成员变量对齐问题  因为系统遵循对齐规则
            ;  进入末对齐异常处理函数
参数处理后,进入PspCreateThread线程创建.
NTSTATUS
PspCreateThread(                       //<相关参数说明>
    OUT PHANDLE ThreadHandle,          //返回创建线程的句柄
    IN ACCESS_MASK DesiredAccess,		 //对新线程的访问权限
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,  
										 //指定了线程对象的属性
    IN HANDLE ProcessHandle,			 //进程句柄
    IN PEPROCESS ProcessPointer,		 //指向所属进程的EPROCESS对象         
    OUT PCLIENT_ID ClientId OPTIONAL,   //返回新线程的ClientId 结构
    IN PCONTEXT ThreadContext OPTIONAL, //新线程的执行环境
    IN PINITIAL_TEB InitialTeb OPTIONAL,//提供新线程的TEB初始值
    IN BOOLEAN CreateSuspended,         //新创建的线程是否要先被挂起
    IN PKSTART_ROUTINE StartRoutine OPTIONAL, //系统线程启动函数地址
    IN PVOID StartContext               //系统线程启动函数的执行环境
)
cmp   [ebp+StartRoutine], esi 
; 判断是否是系统线程启动函数的地址
jz    short NoKelnelModeProc 
; StartRoutine有值代表线程当前是内核模式
mov   byte ptr [ebp+PreviousMode], 0 
; 0代表内核模式
jmp   short GetCurModeProc
NoKelnelModeProc:
; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)+1D j
mov     al, [eax+_ETHREAD.Tcb.___u33._s2.PreviousMode] 
; StartRoutine为空  则通过当前ETHREAD->Tcb的值获得前运行模式
mov     byte ptr [ebp+PreviousMode], al
xor     ebx, ebx                    ;清零
mov     [ebp+Process], ebx          ;初始化为零
cmp     [ebp+ProcessHandle], esi    ;比较值
jz      short NoProcessHandleProc
push    esi             ; HandleInformation
lea     eax, [ebp+TargetProcess] ; 保存进程对象的地址
push    eax             ; Object
push    [ebp+PreviousMode] ; AccessMode
push    _PsProcessType     ; ObjectType
push    2                  ; DesiredAccess
push    [ebp+ProcessHandle] ; ProcessHandle保存从3环传入的进程句柄
call    _ObReferenceObjectByHandle@24  ; ObReferenceObjectByHandle 
;在当前进程的句柄表或内核句柄表中找到相应的表项,并通过参数返回指向目标对象<数据结构>的指针 
mov     ebx, [ebp+TargetProcess]
mov     [ebp+Process], ebx    ;另保存通过函数获得进程对象
cmp     byte ptr [ebp+PreviousMode], 0 ;判断是否内核模式
jz      short ModeAndObject_OK   
cmp     ebx, _PsInitialSystemProcess   ;全局变量,记录系统的初始进程
jnz     short ModeAndObject_OK 
mov     esi, STATUS_INVALID_HANDLE     ;满足条件即返回错误码
and     dword ptr [esi+_ETHREAD.RundownProtect.___u0], eax 
; 变量L_EThreadRundPtOffset     线程的停止保护锁 用于跨线程初始化TEB,挂起线程
mov     [esi+_ETHREAD.ThreadsProcess], ebx 
; 变量L_EThreadProcessOffset   设置线程的进程CID。
mov     eax, [ebx+_EPROCESS.UniqueProcessId] 
; 变量L_EProcessUniqueProcessIdOffset
mov     [esi+_ETHREAD.Cid.UniqueProcess], eax 
; 变量L_ETreadCidUPSOffset  == Thread->Cid.UniqueProcess 的偏移地址
mov     dword ptr [ebp+CidEntry.___u0], esi 
; 相当于___u0保存的线程对象<CidEntry.Object> 创建线程的CID句柄。
and     dword ptr [ebp+CidEntry.___u1], 0 ; 赋值0
lea     eax, [ebp+CidEntry]
push    eax                               ; HandleTableEntry
push    _PspCidTable                      ; HandleTable  句柄表
; PspCidTable是个独立的句柄表,CID即进程号+线程号是这个句柄表中的句柄
call    _ExCreateHandle@8 
; ExCreateHandle(x,x)通过句柄表创建句柄的入口地址       
mov     [esi+_ETHREAD.Cid.UniqueThread], eax       ; 保存句柄
lea     eax, [esi+_ETHREAD.___u2.LpcReplyChain.Flink] 
; _EThread结构体中一个共用体结构的首地址
; 1._ETHREAD.ExitTime
; 2._ETHREAD.LpcReplyChain   //用于跨进程通信<lpc>
; 3._ETHREAD.KeyedWaitChain
mov     [eax+4], eax   
; _EThread.LpcReplyChain.Blink指向_EThread共用体中的LpcReplyChain首地址
mov     [eax], eax     
; _EThread.LpcReplyChain.Flink 指向_EThread共用体中的LpcReplyChain首地址
lea     eax, [esi+_ETHREAD.IrpList] 
;  _ETHREAD.IrpList的地址
// 初始化所有正在处理单尚末完成的I/O请求<IRP对象>
mov     [eax+4], eax   
;  _EThread.IrpList.Blink  链表地址指向_EThread.IrpList
mov     [eax], eax     
 			;  _EThread.IrpList.Flink 链表地址指向_EThread.IrpList
lea     eax, [esi+_ETHREAD.PostBlockList] 
;  _ETHREAD.PostBlockList的地址   
// 初始化配置管理器等级注册表的变化通知
mov     [eax+4], eax    
;  _EThread.PostBlockList.Blink  链表地址指向_EThread.PostBlockList
mov     [eax], eax      
;  _EThread.PostBlockList.Flink  链表地址指向_EThread.PostBlockList
mov     dword ptr [esi+_ETHREAD.ThreadLock.___u0], edi 
; _EThread.ThreadLock  // 初始化线程锁
mov     [esi+_ETHREAD.ActiveTimerListLock], edi 
; _EThread.ActiveTimerListLock   初始化时间旋转锁
lea     eax, [esi+_ETHREAD.ActiveTimerListHead] 
; 初始化当前线程的所有定时器
mov     [eax+4], eax    
; _EThread.ActiveTimerListHead.Blink 指向_EThread.ActiveTimerListHead
mov     [eax], eax      
;_EThread.ActiveTimerListHead.Flink 指向_EThread.ActiveTimerListHead
lea     edi, [ebx+_EPROCESS.RundownProtect] 
; RundownProtection跨进程<线程>访问标志
mov     ecx, [edi]
and     ecx, 0FFFFFFFEh      ; 提取最低位
lea     edx, [ecx+2]			 
mov     eax, ecx
lock cmpxchg [edi], edx 
; 检测RundownProtect是否为0或1  如果不是则调用ExfAcquireRundownProtection求值
;  X不为0或1(>=2)           eax = X的最地位<0或1>        ECX = X的值<最低位为0>    最后值 = EAX   不一定等于0
;  X为0或1(0 1)     eax = X                ECX = X                   最后的值为X的第2位 = 0
; <ExfAcquireRundownProtection == X>
cmp     [ebp+ThreadContext], 0 ;  线程上下文  3环传入参数
jz      THreadContext_NoExist 
; ThreadContext是否存在值  存在即用此值创建内核态的对象<用户模式线程>
; 否则用内核态Context创建内核对象<系统线程>
lea     eax, [ebp+Teb]
push    eax             ; Base
lea     eax, [esi+_ETHREAD.Cid]
push    eax             ; ClientId
push    [ebp+InitialTeb] ; InitialTeb
push    ebx             ; TargetProcess
call    _MmCreateTeb@16 ; MmCreateTeb(x,x,x,x)  创建对象TEB
mov     [ebp+Status], eax ; 此例程将创建一个TEB加入它的目标进程内页并复制初始TEB
mov     eax, [ebp+ThreadContext] 
; 通过用户模式的线程来初始化内核线程对象
mov     ecx, [eax+_CONTEXT._Eip]
; ThreadContext->Eip  初始化线程的启动地址
mov     [esi+_ETHREAD.StartAddress], ecx
mov     ecx, [eax+_CONTEXT._Eax] 
; ThreadContext->Eax  初始化WINDOWS子系统的启动地址
mov     [esi+_ETHREAD.___u17.Win32StartAddress], ecx
push    ebx             ; Process
push    [ebp+Teb]       ; Teb
push    eax             ; ThreadContext
push    [esi+_ETHREAD.StartAddress]
push    ecx             ; NULL
push    offset _PspUserThreadStartup@8 
; PspUserThreadStartup(x,x) 启动调用用户态的线程
push    ecx             ; NULL
jmp     short Call_KeInitThread
THreadContext_NoExist:                  
; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)+1A3 j
xor     eax, eax        
; 进入没有创建新线程的情况下处理流程  即用内核线程创建系统线程
     mov     [ebp+Teb], eax  ; Teb = NULL;
     push    10h
     pop     ecx             ; PS_CROSS_THREAD_FLAGS_SYSTEM
     lea     edx, [esi+_ETHREAD.CrossThreadFlags]
     lock or [edx], ecx     
; 永远受系统线程的CrossThreadFlags标志位的控制
     mov     ecx, [ebp+StartRoutine] 
; 从这里开始为KeInitThread传参   用内核线程来创建内核对象
     mov     [esi+_ETHREAD.StartAddress], ecx
     push    ebx             ; Process
     push    eax             ; Teb
     push    eax             ; ContextFrame
     push    [ebp+StartContext] ; StartContext
     push    ecx             ; StartRoutine
     push    offset _PspSystemThreadStartup@8 ; SystemRoutine
     push    eax             ; KernelStack
Call_KeInitThread:                      
; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)+24E j
     push    esi             ; Thread
     call    _KeInitThread@32 ; KeInitThread(x,x,x,x,x,x,x,x)
; 初始化线程对象 <继续初始新线程属性。> 同步Header, WaitBlock,
; 系统服务表 ,APC ,定时器, 线程的内核栈等
dec     [edi+_KTHREAD.___u29._s0.KernelApcDisable] 
; KeEnterCriticalRegionThread (&CurrentThread->Tcb);
           ; 将此值设为-1   关闭当前线程的内核APC
       lea     eax, [ebx+_EPROCESS.ProcessLock.___u0]
       mov     [ebp+PushLock], eax
       mov     eax, 0
       mov     ecx, [ebp+PushLock] ; 锁定进程
           ; 确保当前进程的状态不是退出或正在终止。
           ; Process->Flags 判断进程是否是死进程。
           ; CurrentThread->CrossThreadFlags跨线程访问的标志位
           ; 包括Terminated 线程已执行终止操作 创建失败 等。
       lock bts [ecx], eax
       setb    al
       test    al, al
       jz      short PushLock_OK ; 跳转成功
       mov     ecx, [ebp+PushLock] ; PushLock
       call @ExfAcquirePushLockExclusive@4 
; ExfAcquirePushLockExclusive(x) 获得PUSHLOCK值

PushLock_OK:                            
; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)+2DB j
        test    byte ptr [ebx+_EPROCESS.Flags], 8 
; PS_PROCESS_FLAGS_PROCESS_DELETE 检测Flags标记位
        jnz     NoRightFlagsExitProc
 ; 进程和线程的标志位至少一个必须为0  否则引发错误
        test    byte ptr [edi+_ETHREAD.CrossThreadFlags], 1
;PS_CROSS_THREAD_FLAGS_TERMINATED 检测CrossThreadFlags位
lea     eax, [ebx+_EPROCESS.ActiveThreads] ;记录进程的活动线程数
mov     ecx, [eax]
mov     [ebp+L_OldActiveThreads], ecx ; 保存原ActiveThreads
inc     ecx             ; 进程的活动线程数+1
mov     [eax], ecx
lea     eax, [esi+_ETHREAD.ThreadListEntry]
lea     ecx, [ebx+_EPROCESS.ThreadListHead]
mov     edx, [ecx+4]    ; _EPROCESS.ThreadListHead.blink
mov     [eax], ecx      ; _EPROCESS.ThreadListEntry.Flink
mov     [eax+4], edx    ; _ETHREAD.ThreadListEntry.blink
mov     [edx], eax
mov     [ecx+4], eax    
; 1.从_EPROCESS.ThreadListHead => _ETHREAD.ThreadListHead
; 2._EPROCESS.ThreadListHead .blink =>_EPROCESS.ThreadListHead .Flink
; 挂入目标进程(EPROCESS中)的线程队列
push    esi             ; Thread
call    _KeStartThread@4 ; KeStartThread  启动线程
; 并再次初始化末完成的域,设置线程的优先级, 时限设置等

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (3)
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
2
又是我的沙发 ~~ 哈哈
2010-6-11 18:31
0
雪    币: 270
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
顶楼上的肺。。。。
顺便问下楼主怎么配合ida来分析来?
2010-7-1 22:16
0
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
4
哈哈, 头像是嫂子么?
2010-7-1 22:32
0
游客
登录 | 注册 方可回帖
返回
//