科锐五期 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期)
上传的附件: