首页
社区
课程
招聘
[原创]Windows内核学习笔记之进程(上)
2021-12-13 15:03 14996

[原创]Windows内核学习笔记之进程(上)

2021-12-13 15:03
14996

一.基本概念

仅仅有执行程序的指令是无法让一个程序正常运行的,因为程序的运行需要用到各种各样的资源。进程就是各种资源的容器,它定义了一个地址空间作为基本的执行环境。在操作系统的管理规则中,很多资源是针对进程分配的,必须要鲜有一个进程,才能为其分配资源。

在Windows操作系统中,每个进程拥有如下资源:

  1. 一个虚拟的地址空间,一般称为进程空间。进程空间是操作系统分配给每个进程的虚拟地址空间,每个进程运行在这个受操作系统保护的虚拟空间之中,它的地址指针指向的都是这个空间中的虚拟地址,根本无法指到另一个进程空间中。也就是每个进程都在操作系统分配给它的虚拟空间中运行,它无法访问其他进程的空间,也不必担心自己的空间会被其他的进程所侵占

  2. 全局唯一的进程ID,也就是常说的PID

  3. 一个可执行映像,也就是该进程的程序文件(可执行文件)在内存中的表示

  4. 一个或多个线程

  5. 一个位于内核空间中名为EPROCESS(进程执行块)的数据结构,用以记录该进程的关键信息,包括进程的创建时间,映像文件名称等

  6. 一个位于内核空间中的对象句柄表,用以记录和索引该进程所创建/打开的内核对象。操作系统根据该表格将用户模式下的句柄翻译为指向内核对象的指针

  7. 一个用于描述内存目录表起始位置的基地址,简称页目录基地址(DirBase),当CPU切换到该进程时,会将该地址加载到页表基地址寄存器(x86之CR3, ARM之TTBR),这样当前进程的虚拟地址就会被翻译为正确的物理地址

  8. 一个位于用户空间中的进程环境块(PEB)

  9. 一个访问令牌,用于表示该进程的用户,安全组及优先级

二.进程数据结构

为了保存创建的进程的各种信息,同时也为了方便系统管理创建的进程,在用户层和内核层系统都有相应的数据结构。

1.内核层数据结构

当成功创建一个进程的时候,Windows内核中就会创建相应的进程内核对象。内核对象保存了进程的各种信息,同时操作系统也通过创建的内核对象来对进程进行管理。

Windows内核中的执行体层负责各自与管理策略相关的功能,而内核层(或微内核)实现了操作系统的核心机制。进程在这两个层上都有对应的数据结构

A.微内核层数据结构

KPROCESS是保存在微内核层最基本的进程数据结构,每个KPROCESS都代表了一个进程,该结构定义如下:

kd> dt _KPROCESS
ntdll!_KPROCESS
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 ProfileListHead  : _LIST_ENTRY
   +0x018 DirectoryTableBase : [2] Uint4B
   +0x020 LdtDescriptor    : _KGDTENTRY
   +0x028 Int21Descriptor  : _KIDTENTRY
   +0x030 IopmOffset       : Uint2B
   +0x032 Iopl             : UChar
   +0x033 Unused           : UChar
   +0x034 ActiveProcessors : Uint4B
   +0x038 KernelTime       : Uint4B
   +0x03c UserTime         : Uint4B
   +0x040 ReadyListHead    : _LIST_ENTRY
   +0x048 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x04c VdmTrapcHandler  : Ptr32 Void
   +0x050 ThreadListHead   : _LIST_ENTRY
   +0x058 ProcessLock      : Uint4B
   +0x05c Affinity         : Uint4B
   +0x060 StackCount       : Uint2B
   +0x062 BasePriority     : Char
   +0x063 ThreadQuantum    : Char
   +0x064 AutoAlignment    : UChar
   +0x065 State            : UChar
   +0x066 ThreadSeed       : UChar
   +0x067 DisableBoost     : UChar
   +0x068 PowerState       : UChar
   +0x069 DisableQuantum   : UChar
   +0x06a IdealNode        : UChar
   +0x06b Flags            : _KEXECUTE_OPTIONS
   +0x06b ExecuteOptions   : UChar
偏移名称含义
0x000Header表明KPROCESS对象也是一个分发器对象,说明进程本身是可等待的对象
0x010ProfileListHead当该进程参与性能分析时,作为一个节点加入到全局性能分析进程列表(内核全局变量KiProfileListHead)
0x018DirectoryTableBase是一个只有两项的数组,第一项指向该进程的页目录表地址,第二项指向进程的超空间的页目录表地址
0x020LdtDescriptor该进程LDT(局部描述发表)的描述符
0x028Int21Descriptor兼容DOS程序,允许它们通过int 21H指令来调用DOS系统功能
0x30IopmOffset指定IOPM(I/O权限表)的位置,内核通过IOPM可控制进程的用户模式I/O访问权限
0x32Iopl定义进程的I/O优先级
0x34ActiveProcessors记录当前进程正在哪些处理器上运行
0x38KernelTime记录一个进程对象在内核模式下所花的时间
0x3C
UserTime记录一个进程对象在用户模式下所花的时间
0x40
ReadListHead是一个双向链表头,记录了进程中处于就绪状态但尚未被加入全局就绪链表的线程,这个域的意义在于,当一个进程被换出内存后,它所属的线程一旦就绪,则被挂到此链表中,并要求换入该进程。此后,当该进程被换入内存时,ReadyListHead中的所有线程被加入到系统全局的就绪线程链表中
0x048
SwapListEntry单链表项,当一个进程要被换出内存时,它通过此域加入到KiProcessOutSwapListHead为链头的单链表中;当一个进程被换入内存时,它通过此域加入到以KiProcessInSwapListHead为链头的单链表中
0x050
ThreadListHead指向一个链表头,此链表包含了该进程的所有当前进程。当一个线程被创建的时候,被加入到此链表中,在终止的时候被从链表中移除
0x058
ProcessLock自旋锁对象,用途是保护此进程中的数据成员
0x05C
Affinity指定该进程的线程可以在哪些处理器上运行,其类型是KAFFINITY,这是一个32位或64位整数,其二进制表示的每一位分别对应于当前机器上的一个处理器(核)
0x060StackCount记录当前进程有多少个线程栈位于内存中
0x062
BasePriority指定进程中的线程优先级,所有线程在启动时都会继承进程的BasePriority
0x064
AutoAlignment用于进程中的内存访问对齐设置,此标志位会被传递到线程的数据结构中,当一个线程的对齐检查开关打开时,该线程中的未对齐数据访问将会导致对齐错误(Alignment Fault)
0x065
State

说明进程是否在内存中,共有六种可能状态

  • ProcessInMemory

  • ProcessOutOfMemory

  • ProcessInTransition

  • ProcessOutTransition

  • ProcessInSwap

  • ProcessOutSwap

0x066
ThreadSeed用于为该进程的线程指定理想处理器
0x067
DisableBoost与线程调度过程中的优先级提升和时限分配有关
0x068
PowerState用于记录电源状态
0x069
DisableQuantum与线程调度过程中的优先级提升和时限分配有关
0x06A
IdealNode用于为一个进程选择优先的处理节点,这是在进程初始化时设定
0x06B
ExecuteOptions用于设置一个进程的执行选项,这是为了支持NX而引入到系统中的

B.执行体数据结构

EPROCESS是保存在执行体的数据结构,几乎包括了进程的所有关键的信息,它侧重于提供各自管理策略,同时为上层应用程序提供基本的功能接口。所以,在执行层的数据结构中,有些成员直接对应于上层应用程序中所看到的功能,该结构定义如下:

kd> dt _EPROCESS
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER
   +0x078 ExitTime         : _LARGE_INTEGER
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : Ptr32 Void
   +0x088 ActiveProcessLinks : _LIST_ENTRY
   +0x090 QuotaUsage       : [3] Uint4B
   +0x09c QuotaPeak        : [3] Uint4B
   +0x0a8 CommitCharge     : Uint4B
   +0x0ac PeakVirtualSize  : Uint4B
   +0x0b0 VirtualSize      : Uint4B
   +0x0b4 SessionProcessLinks : _LIST_ENTRY
   +0x0bc DebugPort        : Ptr32 Void
   +0x0c0 ExceptionPort    : Ptr32 Void
   +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE
   +0x0c8 Token            : _EX_FAST_REF
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : Uint4B
   +0x0f0 AddressCreationLock : _FAST_MUTEX
   +0x110 HyperSpaceLock   : Uint4B
   +0x114 ForkInProgress   : Ptr32 _ETHREAD
   +0x118 HardwareTrigger  : Uint4B
   +0x11c VadRoot          : Ptr32 Void
   +0x120 VadHint          : Ptr32 Void
   +0x124 CloneRoot        : Ptr32 Void
   +0x128 NumberOfPrivatePages : Uint4B
   +0x12c NumberOfLockedPages : Uint4B
   +0x130 Win32Process     : Ptr32 Void
   +0x134 Job              : Ptr32 _EJOB
   +0x138 SectionObject    : Ptr32 Void
   +0x13c SectionBaseAddress : Ptr32 Void
   +0x140 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK
   +0x144 WorkingSetWatch  : Ptr32 _PAGEFAULT_HISTORY
   +0x148 Win32WindowStation : Ptr32 Void
   +0x14c InheritedFromUniqueProcessId : Ptr32 Void
   +0x150 LdtInformation   : Ptr32 Void
   +0x154 VadFreeHint      : Ptr32 Void
   +0x158 VdmObjects       : Ptr32 Void
   +0x15c DeviceMap        : Ptr32 Void
   +0x160 PhysicalVadList  : _LIST_ENTRY
   +0x168 PageDirectoryPte : _HARDWARE_PTE_X86
   +0x168 Filler           : Uint8B
   +0x170 Session          : Ptr32 Void
   +0x174 ImageFileName    : [16] UChar
   +0x184 JobLinks         : _LIST_ENTRY
   +0x18c LockedPagesList  : Ptr32 Void
   +0x190 ThreadListHead   : _LIST_ENTRY
   +0x198 SecurityPort     : Ptr32 Void
   +0x19c PaeTop           : Ptr32 Void
   +0x1a0 ActiveThreads    : Uint4B
   +0x1a4 GrantedAccess    : Uint4B
   +0x1a8 DefaultHardErrorProcessing : Uint4B
   +0x1ac LastThreadExitStatus : Int4B
   +0x1b0 Peb              : Ptr32 _PEB
   +0x1b4 PrefetchTrace    : _EX_FAST_REF
   +0x1b8 ReadOperationCount : _LARGE_INTEGER
   +0x1c0 WriteOperationCount : _LARGE_INTEGER
   +0x1c8 OtherOperationCount : _LARGE_INTEGER
   +0x1d0 ReadTransferCount : _LARGE_INTEGER
   +0x1d8 WriteTransferCount : _LARGE_INTEGER
   +0x1e0 OtherTransferCount : _LARGE_INTEGER
   +0x1e8 CommitChargeLimit : Uint4B
   +0x1ec CommitChargePeak : Uint4B
   +0x1f0 AweInfo          : Ptr32 Void
   +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f8 Vm               : _MMSUPPORT
   +0x238 LastFaultCount   : Uint4B
   +0x23c ModifiedPageCount : Uint4B
   +0x240 NumberOfVads     : Uint4B
   +0x244 JobStatus        : Uint4B
   +0x248 Flags            : Uint4B
   +0x248 CreateReported   : Pos 0, 1 Bit
   +0x248 NoDebugInherit   : Pos 1, 1 Bit
   +0x248 ProcessExiting   : Pos 2, 1 Bit
   +0x248 ProcessDelete    : Pos 3, 1 Bit
   +0x248 Wow64SplitPages  : Pos 4, 1 Bit
   +0x248 VmDeleted        : Pos 5, 1 Bit
   +0x248 OutswapEnabled   : Pos 6, 1 Bit
   +0x248 Outswapped       : Pos 7, 1 Bit
   +0x248 ForkFailed       : Pos 8, 1 Bit
   +0x248 HasPhysicalVad   : Pos 9, 1 Bit
   +0x248 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x248 SetTimerResolution : Pos 12, 1 Bit
   +0x248 BreakOnTermination : Pos 13, 1 Bit
   +0x248 SessionCreationUnderway : Pos 14, 1 Bit
   +0x248 WriteWatch       : Pos 15, 1 Bit
   +0x248 ProcessInSession : Pos 16, 1 Bit
   +0x248 OverrideAddressSpace : Pos 17, 1 Bit
   +0x248 HasAddressSpace  : Pos 18, 1 Bit
   +0x248 LaunchPrefetched : Pos 19, 1 Bit
   +0x248 InjectInpageErrors : Pos 20, 1 Bit
   +0x248 VmTopDown        : Pos 21, 1 Bit
   +0x248 Unused3          : Pos 22, 1 Bit
   +0x248 Unused4          : Pos 23, 1 Bit
   +0x248 VdmAllowed       : Pos 24, 1 Bit
   +0x248 Unused           : Pos 25, 5 Bits
   +0x248 Unused1          : Pos 30, 1 Bit
   +0x248 Unused2          : Pos 31, 1 Bit
   +0x24c ExitStatus       : Int4B
   +0x250 NextPageColor    : Uint2B
   +0x252 SubSystemMinorVersion : UChar
   +0x253 SubSystemMajorVersion : UChar
   +0x252 SubSystemVersion : Uint2B
   +0x254 PriorityClass    : UChar
   +0x255 WorkingSetAcquiredUnsafe : UChar
   +0x258 Cookie           : Uint4B
偏移名称含义
0x000Pcb即上面介绍的KPROCESS内嵌结构体,因此,在系统内部,一个进程的EPROCESS对象地址和KPROCESS对象的地址是相同的
0x06CProcessLock与KPROCESS的自旋锁同名,但是它们类型不同,保护成员也不同。这里的ProcessLock域是一个推锁对象,用于保护EPROCESS中的数据成员
0x070CreateTime进程创建时间
0x078ExitTime进程退出时间
0x080RundownProtect进程停止保护锁,当一个进程到最后被销毁时,它要等到所有其他进程和线程已经释放此锁才可以继续进行
0x084UniqueProcessId进程的唯一编号,在进程创建时设定
0x088ActiveProcessLinks双向链表,用于将所有活动进程连接在一起,表头是全局变量PsActiveProcessHead
0x0B4SessionProcessLinks双链表节点,当一个进程加入到一个系统会话中,其SessionProcessLinks域将作为一个节点加入到该会话的进程链表中
0x0BCDebugPort指向调试端口的句柄
0x0C0
Exception指向异常端口的句柄
0x0C4
ObjectTable指向进程的句柄表
0x0C8
Token是一个快速引用,指向该进程的访问令牌
0x11C
VadRoot虚拟地址描述符二叉树根节点
0x130
Win32Process指向由Windows子系统管理的进程区域,如果此指不为NULL,说明这是一个Windows子系统进程(GUI进程)
0x170Session所属会话对象
0x174ImageName指向进程名
0x190
ThreadListHead双向链表节点,该链表包含了一个进程中所有的线程
0x1A0ActiveThreads记录当前进程有多少个活动线程。当该值为0,所有线程都将退出,进程也就会退出
0x1A4
GrantedAccess进程的访问权限
0x1B0
Peb进程的环境块,这是一个位于进程地址空间的内存块,其中包含了有关进程地址空间中的堆和系统模块信息
0x24C
ExitStatus包含了进程的退出状态,从进程的退出状态通常可以获知进程非正常退出的大致原因
0x252
SubSystemMinorVersion子系统次版本号
0x253
SubSystemMajorVersion子系统主版本号
0x254
PriorityClass

单字节,表明进程的优先级程度,分别有以下几个类别

  • 1:空闲类别

  • 2:普通类别

  • 3:高优先级类别

  • 4:实时类别

  • 5:普通之下类别

  • 6:普通之上类别

  • 0:未知类别

2.用户层数据结构

PEB的全程是进程环境块,它包含了进程大多数的用户模式信息。与EPROCESS结构位于内核空间中不同,PEB是在内核模式建立后映射到用户空间的。因此,多个进程的PEB地址可能是同一个指,PEB的结构如下:

kd> dt _PEB
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 FastPebLockRoutine : Ptr32 Void
   +0x024 FastPebUnlockRoutine : Ptr32 Void
   +0x028 EnvironmentUpdateCount : Uint4B
   +0x02c KernelCallbackTable : Ptr32 Void
   +0x030 SystemReserved   : [1] Uint4B
   +0x034 AtlThunkSListPtr32 : Uint4B
   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
   +0x03c TlsExpansionCounter : Uint4B
   +0x040 TlsBitmap        : Ptr32 Void
   +0x044 TlsBitmapBits    : [2] Uint4B
   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void
   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
   +0x058 AnsiCodePageData : Ptr32 Void
   +0x05c OemCodePageData  : Ptr32 Void
   +0x060 UnicodeCaseTableData : Ptr32 Void
   +0x064 NumberOfProcessors : Uint4B
   +0x068 NtGlobalFlag     : Uint4B
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER
   +0x078 HeapSegmentReserve : Uint4B
   +0x07c HeapSegmentCommit : Uint4B
   +0x080 HeapDeCommitTotalFreeThreshold : Uint4B
   +0x084 HeapDeCommitFreeBlockThreshold : Uint4B
   +0x088 NumberOfHeaps    : Uint4B
   +0x08c MaximumNumberOfHeaps : Uint4B
   +0x090 ProcessHeaps     : Ptr32 Ptr32 Void
   +0x094 GdiSharedHandleTable : Ptr32 Void
   +0x098 ProcessStarterHelper : Ptr32 Void
   +0x09c GdiDCAttributeList : Uint4B
   +0x0a0 LoaderLock       : Ptr32 Void
   +0x0a4 OSMajorVersion   : Uint4B
   +0x0a8 OSMinorVersion   : Uint4B
   +0x0ac OSBuildNumber    : Uint2B
   +0x0ae OSCSDVersion     : Uint2B
   +0x0b0 OSPlatformId     : Uint4B
   +0x0b4 ImageSubsystem   : Uint4B
   +0x0b8 ImageSubsystemMajorVersion : Uint4B
   +0x0bc ImageSubsystemMinorVersion : Uint4B
   +0x0c0 ImageProcessAffinityMask : Uint4B
   +0x0c4 GdiHandleBuffer  : [34] Uint4B
   +0x14c PostProcessInitRoutine : Ptr32     void 
   +0x150 TlsExpansionBitmap : Ptr32 Void
   +0x154 TlsExpansionBitmapBits : [32] Uint4B
   +0x1d4 SessionId        : Uint4B
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x1e8 pShimData        : Ptr32 Void
   +0x1ec AppCompatInfo    : Ptr32 Void
   +0x1f0 CSDVersion       : _UNICODE_STRING
   +0x1f8 ActivationContextData : Ptr32 Void
   +0x1fc ProcessAssemblyStorageMap : Ptr32 Void
   +0x200 SystemDefaultActivationContextData : Ptr32 Void
   +0x204 SystemAssemblyStorageMap : Ptr32 Void
   +0x208 MinimumStackCommit : Uint4B
偏移名称含义
0x002BeginDebugged是否被调试
0x008ImageBaseAddress执行映像的基地址
0x018ProcessHeap进程堆
0x064NumberOfProcessorsCPU个数
0x068NtGlobalFlag全局标志
0x078HeapSegmentReserve默认进程堆的总保留空间,1MB
0x07CHeapSegmentCommit默认进程堆的已提交空间
0x088NumberOfHeaps堆的个数
0x08CMaximumNumberOfHeaps堆的最多个数
0x090
ProcessHeaps保存堆句柄的数组地址
0x094
GdiSharedHandleTableGDI共享句柄表
0x0A4
OSMajorVersion操作系统主版本号
0x0A8
OSMinorVersion操作系统子版本号
0x0AC
OSBuildNumber操作系统构建号
0x0AE
OSCSDVersionService Pack版本号
0x0B0
OSPlatformId系统类别,2代表NT,1代表9x,3代表Windows CE
0x0B4
ImageSubsystem环境子系统ID
0x0B8
ImageSubsystemMajorVersion环境子系统主版本号
0x0BC
ImageSubsystemMinorVersion环境子系统次版本号
0x1D4
SessionId所属会话ID

通过上面的三个结构分别在用户层和内核层保留了创建的进程的所有的信息,操作系统通过这些信息完成对进程的管理工作。因此,在创建进程的过程中上述的三个结构体是一定要在内存中被申请出来并初始化的。

三.进程的创建

Windows API提供了很多用于创建进程的函数。其中最简单的是CreateProcess,该函数会尝试使用与创建者相同的访问令牌新建一个进程。如果需要不同的令牌,可以使用CreateProcessAsUser函数或CreateProcessWithTokenW函数来实现。如果系统快速用特定用户凭据登录并使用所获得的令牌创建进程,此时可以使用CreateProcesssWithLoginW来实现。

创建一个进程的主要步骤如下:

  1. 验证参数,将Windows子系统标志和选项转换为原生形式,解析,验证并转换属性列表为原生形式

  2. 打开要在进程中执行的映像文件(.exe)

  3. 创建Windows执行体进程对象

  4. 创建初始线程(栈,上下文,Windows执行体线程对象)

  5. 执行创建之后需要的,与Windows子系统有关的进程初始化操作

  6. 开始执行初始线程(除非指定了CREATE_SUSPENDED标志)

  7. 在新进程和线程上下文中完成地址空间的初始化操作(如加载需要的DLL),并开始执行程序的入口点

所有文档化的进程创建函数最终都会调用Kernel32.dll中的CreateProcessInternalW。以常见的CreateProcessW函数为例,可以看到在这个函数中就是将参数压入栈中,然后调用CreateProcessInternalW,因此接下来会以此函数为主进行分析

.text:7C802336 ; BOOL __stdcall CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
.text:7C802336                 public _CreateProcessW@40
.text:7C802336 _CreateProcessW@40 proc near            ; CODE XREF: UnhandledExceptionFilter(x)+835↓p
.text:7C802336                                         ; ConsoleIMERoutine(x)+D2↓p
.text:7C802336                                         ; DATA XREF: ...
.text:7C802336
.text:7C802336 lpApplicationName= dword ptr  8
.text:7C802336 lpCommandLine   = dword ptr  0Ch
.text:7C802336 lpProcessAttributes= dword ptr  10h
.text:7C802336 lpThreadAttributes= dword ptr  14h
.text:7C802336 bInheritHandles = dword ptr  18h
.text:7C802336 dwCreationFlags = dword ptr  1Ch
.text:7C802336 lpEnvironment   = dword ptr  20h
.text:7C802336 lpCurrentDirectory= dword ptr  24h
.text:7C802336 lpStartupInfo   = dword ptr  28h
.text:7C802336 lpProcessInformation= dword ptr  2Ch
.text:7C802336
.text:7C802336                 mov     edi, edi
.text:7C802338                 push    ebp
.text:7C802339                 mov     ebp, esp
.text:7C80233B                 push    0               ; hNewToken
.text:7C80233D                 push    [ebp+lpProcessInformation] ; lpProcessInformation
.text:7C802340                 push    [ebp+lpStartupInfo] ; lpStartupInfo
.text:7C802343                 push    [ebp+lpCurrentDirectory] ; lpCurrentDirectory
.text:7C802346                 push    [ebp+lpEnvironment] ; lpEnvironment
.text:7C802349                 push    [ebp+dwCreationFlags] ; dwCreationFlags
.text:7C80234C                 push    [ebp+bInheritHandles] ; bInheritHandles
.text:7C80234F                 push    [ebp+lpThreadAttributes] ; lpThreadAttributes
.text:7C802352                 push    [ebp+lpProcessAttributes] ; lpProcessAtributes
.text:7C802355                 push    [ebp+lpCommandLine] ; lpCommandLine
.text:7C802358                 push    [ebp+lpApplicationName] ; lpApplicationName
.text:7C80235B                 push    0               ; hToken
.text:7C80235D                 call    _CreateProcessInternalW@48 ; CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)
.text:7C802362                 pop     ebp
.text:7C802363                 retn    28h
.text:7C802363 _CreateProcessW@40 endp

1.转换并验证参数和标志

在函数最开始,首先是将参数赋值到相应的局部变量中,同时也会一部分局部变量初始化为0。

.text:7C8197B0 ; int __stdcall CreateProcessInternalW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAtributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, PHANDLE hNewToken)
.text:7C8197B0                 public _CreateProcessInternalW@48
.text:7C8197B0 _CreateProcessInternalW@48 proc near    ; CODE XREF: CreateProcessW(x,x,x,x,x,x,x,x,x,x)+27↑p
.text:7C8197B0                                         ; CreateProcessInternalA(x,x,x,x,x,x,x,x,x,x,x,x)+EC↓p
.text:7C8197B0                                         ; DATA XREF: ...
.text:7C8197B0
.text:7C8197B0 RegionSize      = dword ptr -0A0Ch
.text:7C8197B0 var_9FC         = dword ptr -9FCh
.text:7C8197B0 JobInformation  = byte ptr -9F8h
.text:7C8197B0 var_9F4         = dword ptr -9F4h
.text:7C8197B0 var_9F0         = dword ptr -9F0h
.text:7C8197B0 var_9EC         = dword ptr -9ECh
.text:7C8197B0 var_9E8         = dword ptr -9E8h
.text:7C8197B0 var_9E4         = dword ptr -9E4h
.text:7C8197B0 var_9E0         = dword ptr -9E0h
.text:7C8197B0 var_9DC         = dword ptr -9DCh
.text:7C8197B0 var_9D8         = dword ptr -9D8h
.text:7C8197B0 var_9D4         = dword ptr -9D4h
.text:7C8197B0 var_9D0         = dword ptr -9D0h
.text:7C8197B0 var_9CC         = dword ptr -9CCh
.text:7C8197B0 var_9C8         = dword ptr -9C8h
.text:7C8197B0 var_9C4         = dword ptr -9C4h
.text:7C8197B0 var_9C0         = dword ptr -9C0h
.text:7C8197B0 var_9BC         = dword ptr -9BCh
.text:7C8197B0 var_TeB         = dword ptr -9B8h
.text:7C8197B0 var_9B4         = dword ptr -9B4h
.text:7C8197B0 var_9B0         = dword ptr -9B0h
.text:7C8197B0 var_9AC         = dword ptr -9ACh
.text:7C8197B0 var_9A8         = dword ptr -9A8h
.text:7C8197B0 var_9A4         = dword ptr -9A4h
.text:7C8197B0 var_9A0         = dword ptr -9A0h
.text:7C8197B0 var_99C         = dword ptr -99Ch
.text:7C8197B0 var_998         = dword ptr -998h
.text:7C8197B0 var_994         = dword ptr -994h
.text:7C8197B0 var_990         = dword ptr -990h
.text:7C8197B0 var_TEb         = dword ptr -98Ch
.text:7C8197B0 var_988         = dword ptr -988h
.text:7C8197B0 var_984         = dword ptr -984h
.text:7C8197B0 var_980         = dword ptr -980h
.text:7C8197B0 var_97C         = dword ptr -97Ch
.text:7C8197B0 var_978         = dword ptr -978h
.text:7C8197B0 var_Teb         = dword ptr -974h
.text:7C8197B0 var_970         = dword ptr -970h
.text:7C8197B0 var_TEB         = dword ptr -96Ch
.text:7C8197B0 var_968         = dword ptr -968h
.text:7C8197B0 var_964         = dword ptr -964h
.text:7C8197B0 var_960         = dword ptr -960h
.text:7C8197B0 var_95C         = dword ptr -95Ch
.text:7C8197B0 var_958         = dword ptr -958h
.text:7C8197B0 var_954         = dword ptr -954h
.text:7C8197B0 var_950         = dword ptr -950h
.text:7C8197B0 var_94C         = dword ptr -94Ch
.text:7C8197B0 var_948         = LSA_UNICODE_STRING ptr -948h
.text:7C8197B0 var_940         = dword ptr -940h
.text:7C8197B0 MessageStrings  = dword ptr -93Ch
.text:7C8197B0 var_938         = dword ptr -938h
.text:7C8197B0 var_934         = dword ptr -934h
.text:7C8197B0 var_930         = dword ptr -930h
.text:7C8197B0 var_92C         = dword ptr -92Ch
.text:7C8197B0 var_928         = dword ptr -928h
.text:7C8197B0 var_924         = dword ptr -924h
.text:7C8197B0 var_920         = dword ptr -920h
.text:7C8197B0 Parameters      = dword ptr -91Ch
.text:7C8197B0 var_lpStartupInfo= dword ptr -914h
.text:7C8197B0 var_910         = dword ptr -910h
.text:7C8197B0 var_dwCreateFlags= dword ptr -90Ch
.text:7C8197B0 var_908         = dword ptr -908h
.text:7C8197B0 var_hNewToken   = dword ptr -904h
.text:7C8197B0 var_900         = dword ptr -900h
.text:7C8197B0 var_8FC         = dword ptr -8FCh
.text:7C8197B0 var_8F8         = dword ptr -8F8h
.text:7C8197B0 var_8F4         = dword ptr -8F4h
.text:7C8197B0 var_8F0         = dword ptr -8F0h
.text:7C8197B0 SourceString    = _STRING ptr -8ECh
.text:7C8197B0 InJob           = byte ptr -8E4h
.text:7C8197B0 DestinationString= LSA_UNICODE_STRING ptr -8E0h
.text:7C8197B0 var_8D8         = dword ptr -8D8h
.text:7C8197B0 var_8D4         = dword ptr -8D4h
.text:7C8197B0 DebugPort       = dword ptr -8D0h
.text:7C8197B0 var_8CC         = byte ptr -8CCh
.text:7C8197B0 var_lpThreadAttributes= dword ptr -8C8h
.text:7C8197B0 var_8C1         = byte ptr -8C1h
.text:7C8197B0 var_lpProcessInformation= dword ptr -8C0h
.text:7C8197B0 ThreadInformation= dword ptr -8BCh
.text:7C8197B0 Response        = dword ptr -8B8h
.text:7C8197B0 var_lpProcessAttributes= dword ptr -8B4h
.text:7C8197B0 var_8B0         = dword ptr -8B0h
.text:7C8197B0 dwErrCode       = dword ptr -8ACh
.text:7C8197B0 var_8A8         = dword ptr -8A8h
.text:7C8197B0 var_8A4         = dword ptr -8A4h
.text:7C8197B0 var_StartupInfo = dword ptr -8A0h
.text:7C8197B0 var_DesktopInfoBuffer= dword ptr -898h
.text:7C8197B0 var_874         = dword ptr -874h
.text:7C8197B0 lpFileName      = dword ptr -85Ch
.text:7C8197B0 var_858         = dword ptr -858h
.text:7C8197B0 var_854         = word ptr -854h
.text:7C8197B0 var_850         = dword ptr -850h
.text:7C8197B0 var_84C         = dword ptr -84Ch
.text:7C8197B0 var_848         = dword ptr -848h
.text:7C8197B0 Handle          = dword ptr -844h
.text:7C8197B0 JobHandle       = dword ptr -840h
.text:7C8197B0 var_hToken      = dword ptr -83Ch
.text:7C8197B0 var_838         = dword ptr -838h
.text:7C8197B0 SectionInformation= dword ptr -834h
.text:7C8197B0 var_82C         = dword ptr -82Ch
.text:7C8197B0 var_828         = dword ptr -828h
.text:7C8197B0 var_824         = dword ptr -824h
.text:7C8197B0 var_820         = word ptr -820h
.text:7C8197B0 var_81E         = word ptr -81Eh
.text:7C8197B0 var_817         = byte ptr -817h
.text:7C8197B0 var_814         = word ptr -814h
.text:7C8197B0 Flags           = dword ptr -804h
.text:7C8197B0 var_800         = dword ptr -800h
.text:7C8197B0 var_7FC         = dword ptr -7FCh
.text:7C8197B0 var_SearchPath  = dword ptr -7F8h
.text:7C8197B0 ProcessInformation= byte ptr -7F4h
.text:7C8197B0 var_7F0         = dword ptr -7F0h
.text:7C8197B0 Source          = dword ptr -7DCh
.text:7C8197B0 var_HeapMemory  = dword ptr -7D8h
.text:7C8197B0 var_7D1         = byte ptr -7D1h
.text:7C8197B0 var_7D0         = dword ptr -7D0h
.text:7C8197B0 ObjectAttributes= _OBJECT_ATTRIBUTES ptr -7CCh
.text:7C8197B0 UserStack       = _INITIAL_TEB ptr -7B4h
.text:7C8197B0 var_7A0         = dword ptr -7A0h
.text:7C8197B0 var_79A         = byte ptr -79Ah
.text:7C8197B0 var_799         = byte ptr -799h
.text:7C8197B0 var_798         = dword ptr -798h
.text:7C8197B0 var_794         = dword ptr -794h
.text:7C8197B0 var_790         = byte ptr -790h
.text:7C8197B0 var_784         = dword ptr -784h
.text:7C8197B0 var_780         = byte ptr -780h
.text:7C8197B0 var_774         = dword ptr -774h
.text:7C8197B0 var_770         = dword ptr -770h
.text:7C8197B0 var_76C         = dword ptr -76Ch
.text:7C8197B0 var_768         = dword ptr -768h
.text:7C8197B0 var_764         = dword ptr -764h
.text:7C8197B0 var_760         = dword ptr -760h
.text:7C8197B0 var_75C         = dword ptr -75Ch
.text:7C8197B0 var_754         = dword ptr -754h
.text:7C8197B0 var_Environment = dword ptr -750h
.text:7C8197B0 var_749         = byte ptr -749h
.text:7C8197B0 Status          = dword ptr -748h
.text:7C8197B0 DirectoryInfo   = _RTL_RELATIVE_NAME_U ptr -744h
.text:7C8197B0 var_734         = dword ptr -734h
.text:7C8197B0 var_72C         = dword ptr -72Ch
.text:7C8197B0 var_728         = dword ptr -728h
.text:7C8197B0 var_lpCommandLine= dword ptr -720h
.text:7C8197B0 var_lpApplicationName= dword ptr -71Ch
.text:7C8197B0 var_716         = byte ptr -716h
.text:7C8197B0 var_715         = byte ptr -715h
.text:7C8197B0 IoStatusBlock   = _IO_STATUS_BLOCK ptr -714h
.text:7C8197B0 var_709         = byte ptr -709h
.text:7C8197B0 var_708         = dword ptr -708h
.text:7C8197B0 var_704         = dword ptr -704h
.text:7C8197B0 var_700         = dword ptr -700h
.text:7C8197B0 var_6FC         = dword ptr -6FCh
.text:7C8197B0 var_6F8         = dword ptr -6F8h
.text:7C8197B0 var_6F4         = dword ptr -6F4h
.text:7C8197B0 var_6F0         = dword ptr -6F0h
.text:7C8197B0 var_6EC         = dword ptr -6ECh
.text:7C8197B0 ClientId        = _CLIENT_ID ptr -6E8h
.text:7C8197B0 var_6E0         = UNICODE_STRING ptr -6E0h
.text:7C8197B0 AnsiString      = _STRING ptr -6D8h
.text:7C8197B0 UnicodeString   = LSA_UNICODE_STRING ptr -6D0h
.text:7C8197B0 var_6C8         = LSA_UNICODE_STRING ptr -6C8h
.text:7C8197B0 Destination     = LSA_UNICODE_STRING ptr -6C0h
.text:7C8197B0 NtPathName      = LSA_UNICODE_STRING ptr -6B8h
.text:7C8197B0 var_6AD         = byte ptr -6ADh
.text:7C8197B0 SuspendCount    = dword ptr -6ACh
.text:7C8197B0 SystemInformation= byte ptr -6A8h
.text:7C8197B0 var_6A4         = dword ptr -6A4h
.text:7C8197B0 FilePart        = dword ptr -6A0h
.text:7C8197B0 BaseAddress     = dword ptr -69Ch
.text:7C8197B0 var_698         = dword ptr -698h
.text:7C8197B0 NumberOfBytesToWrite= dword ptr -694h
.text:7C8197B0 CaptureBuffer   = dword ptr -690h
.text:7C8197B0 P               = dword ptr -68Ch
.text:7C8197B0 var_688         = dword ptr -688h
.text:7C8197B0 var_684         = dword ptr -684h
.text:7C8197B0 var_680         = dword ptr -680h
.text:7C8197B0 ThreadHandle    = dword ptr -67Ch
.text:7C8197B0 FileHandle      = dword ptr -678h
.text:7C8197B0 var_674         = dword ptr -674h
.text:7C8197B0 SectionHandle   = dword ptr -670h
.text:7C8197B0 ProcessHandle   = dword ptr -66Ch
.text:7C8197B0 var_668         = byte ptr -668h
.text:7C8197B0 var_PriorityClass= byte ptr -667h
.text:7C8197B0 ThreadContext   = CONTEXT ptr -664h
.text:7C8197B0 ApiMessage      = byte ptr -398h
.text:7C8197B0 ExitStatus      = dword ptr -378h
.text:7C8197B0 var_370         = byte ptr -370h
.text:7C8197B0 var_348         = dword ptr -348h
.text:7C8197B0 var_33C         = byte ptr -33Ch
.text:7C8197B0 var_314         = byte ptr -314h
.text:7C8197B0 var_2F0         = byte ptr -2F0h
.text:7C8197B0 var_2D8         = byte ptr -2D8h
.text:7C8197B0 var_2C4         = dword ptr -2C4h
.text:7C8197B0 var_2B4         = byte ptr -2B4h
.text:7C8197B0 var_2A0         = dword ptr -2A0h
.text:7C8197B0 var_290         = byte ptr -290h
.text:7C8197B0 var_27C         = dword ptr -27Ch
.text:7C8197B0 var_26C         = byte ptr -26Ch
.text:7C8197B0 var_258         = dword ptr -258h
.text:7C8197B0 UnicodeStringOrUnicodeStringBuffer= byte ptr -248h
.text:7C8197B0 var_234         = dword ptr -234h
.text:7C8197B0 Buffer          = word ptr -224h
.text:7C8197B0 var_Cookie      = dword ptr -1Ch
.text:7C8197B0 ms_exc          = CPPEH_RECORD ptr -18h
.text:7C8197B0 hToken          = dword ptr  8
.text:7C8197B0 lpApplicationName= dword ptr  0Ch
.text:7C8197B0 lpCommandLine   = dword ptr  10h
.text:7C8197B0 lpProcessAtributes= dword ptr  14h
.text:7C8197B0 lpThreadAttributes= dword ptr  18h
.text:7C8197B0 bInheritHandles = dword ptr  1Ch
.text:7C8197B0 dwCreationFlags = dword ptr  20h
.text:7C8197B0 lpEnvironment   = dword ptr  24h
.text:7C8197B0 lpCurrentDirectory= dword ptr  28h
.text:7C8197B0 lpStartupInfo   = dword ptr  2Ch
.text:7C8197B0 lpProcessInformation= dword ptr  30h
.text:7C8197B0 hNewToken       = dword ptr  34h
.text:7C8197B0
.text:7C8197B0                 push    0A08h
.text:7C8197B5                 push    offset stru_7C819A88
.text:7C8197BA                 call    __SEH_prolog
.text:7C8197BF                 mov     eax, ___security_cookie
.text:7C8197C4                 mov     [ebp+var_Cookie], eax
.text:7C8197C7                 mov     eax, [ebp+hToken]
.text:7C8197CA                 mov     [ebp+var_hToken], eax
.text:7C8197D0                 mov     eax, [ebp+lpApplicationName]
.text:7C8197D3                 mov     [ebp+var_lpApplicationName], eax
.text:7C8197D9                 mov     eax, [ebp+lpCommandLine]
.text:7C8197DC                 mov     [ebp+var_lpCommandLine], eax
.text:7C8197E2                 mov     eax, [ebp+lpProcessAtributes]
.text:7C8197E5                 mov     [ebp+var_lpProcessAttributes], eax
.text:7C8197EB                 mov     eax, [ebp+lpThreadAttributes]
.text:7C8197EE                 mov     [ebp+var_lpThreadAttributes], eax
.text:7C8197F4                 mov     eax, [ebp+lpEnvironment]
.text:7C8197F7                 mov     [ebp+var_Environment], eax
.text:7C8197FD                 mov     eax, [ebp+lpCurrentDirectory]
.text:7C819800                 mov     [ebp+lpFileName], eax
.text:7C819806                 mov     eax, [ebp+lpStartupInfo]
.text:7C819809                 mov     [ebp+var_lpStartupInfo], eax
.text:7C81980F                 mov     esi, [ebp+lpProcessInformation]
.text:7C819812                 mov     [ebp+var_lpProcessInformation], esi
.text:7C819818                 mov     edx, [ebp+hNewToken] ; 将hNewToken赋值到edx中
.text:7C81981B                 mov     [ebp+var_hNewToken], edx
.text:7C819821                 xor     ebx, ebx        ; ebx清0
.text:7C819823                 mov     [ebp+var_674], ebx
.text:7C819829                 mov     [ebp+Source], ebx
.text:7C81982F                 mov     [ebp+var_680], ebx
.text:7C819835                 mov     [ebp+var_754], ebx
.text:7C81983B                 mov     [ebp+var_7D0], ebx
.text:7C819841                 mov     [ebp+var_8D8], ebx
.text:7C819847                 mov     eax, [ebp+dwCreationFlags]
.text:7C81984A                 and     eax, CREATE_NO_WINDOW ; dwCreateFlags加上CREATE_NO_WINDOWS标志
.text:7C81984F                 mov     [ebp+var_dwCreateFlags], eax
.text:7C819855                 mov     [ebp+var_749], bl
.text:7C81985B                 mov     [ebp+DebugPort], ebx
.text:7C819861                 mov     [ebp+P], ebx
.text:7C819867                 mov     [ebp+NumberOfBytesToWrite], ebx
.text:7C81986D                 mov     [ebp+var_715], bl
.text:7C819873                 mov     [ebp+var_688], ebx
.text:7C819879                 mov     [ebp+var_698], ebx
.text:7C81987F                 mov     [ebp+CaptureBuffer], ebx
.text:7C819885                 mov     [ebp+var_84C], ebx
.text:7C81988B                 lea     eax, [ebp+var_2B4]
.text:7C819891                 mov     [ebp+var_930], eax
.text:7C819897                 lea     eax, [ebp+var_26C]
.text:7C81989D                 mov     [ebp+var_92C], eax
.text:7C8198A3                 lea     eax, [ebp+UnicodeStringOrUnicodeStringBuffer]
.text:7C8198A9                 mov     [ebp+var_928], eax
.text:7C8198AF                 lea     eax, [ebp+var_2D8]
.text:7C8198B5                 mov     [ebp+var_924], eax
.text:7C8198BB                 lea     eax, [ebp+var_290]
.text:7C8198C1                 mov     [ebp+var_920], eax
.text:7C8198C7                 mov     [ebp+var_764], ebx
.text:7C8198CD                 xor     eax, eax        ; eax清0
.text:7C8198CF                 lea     edi, [ebp+var_760]
.text:7C8198D5                 stosd
.text:7C8198D6                 stosd
.text:7C8198D7                 stosd
.text:7C8198D8                 mov     [ebp+var_784], ebx
.text:7C8198DE                 xor     eax, eax        ; eax清0
.text:7C8198E0                 lea     edi, [ebp+var_780]
.text:7C8198E6                 stosd
.text:7C8198E7                 stosd
.text:7C8198E8                 stosd
.text:7C8198E9                 lea     eax, [ebp+var_6C8]
.text:7C8198EF                 mov     [ebp+var_6F8], eax
.text:7C8198F5                 lea     eax, [ebp+var_6F0]
.text:7C8198FB                 mov     [ebp+var_6F4], eax
.text:7C819901                 lea     eax, [ebp+var_2B4]
.text:7C819907                 mov     [ebp+var_708], eax
.text:7C81990D                 lea     eax, [ebp+var_2D8]
.text:7C819913                 mov     [ebp+var_704], eax
.text:7C819919                 lea     eax, [ebp+var_26C]
.text:7C81991F                 mov     [ebp+var_700], eax
.text:7C819925                 lea     eax, [ebp+var_290]
.text:7C81992B                 mov     [ebp+var_6FC], eax
.text:7C819931                 mov     [ebp+var_794], ebx
.text:7C819937                 xor     eax, eax
.text:7C819939                 lea     edi, [ebp+var_790]
.text:7C81993F                 stosd
.text:7C819940                 stosd
.text:7C819941                 stosd
.text:7C819942                 mov     [ebp+var_7FC], ebx
.text:7C819948                 mov     dword ptr [ebp+InJob], ebx
.text:7C81994E                 mov     [ebp+JobHandle], ebx
.text:7C819954                 mov     [ebp+Handle], ebx
.text:7C81995A                 mov     dword ptr [ebp+var_8CC], ebx
.text:7C819960                 mov     [ebp+var_72C], ebx
.text:7C819966                 xor     eax, eax
.text:7C819968                 lea     edi, [ebp+var_728]
.text:7C81996E                 stosd
.text:7C81996F                 stosd
.text:7C819970                 mov     [ebp+DirectoryInfo.CurDirRef], ebx
.text:7C819976                 xor     eax, eax
.text:7C819978                 lea     edi, [ebp+var_734]
.text:7C81997E                 stosd
.text:7C81997F                 stosd
.text:7C819980                 mov     [ebp+var_799], bl
.text:7C819986                 push    18h
.text:7C819988                 pop     ecx
.text:7C819989                 xor     eax, eax
.text:7C81998B                 lea     edi, [ebp+var_348]
.text:7C819991                 rep stosd
.text:7C819993                 mov     edi, esi
.text:7C819995                 stosd
.text:7C819996                 stosd
.text:7C819997                 stosd
.text:7C819998                 stosd

接下来函数会查看hNewToken中是否传入了参数,如果有参数,就将对应地址中的内容赋值为0

.text:7C819999                 cmp     edx, ebx        ; 保存hNewToken地址是否为NULL,不为NULL则跳转
.text:7C81999B                 jnz     loc_7C82E52F    ; 
            。。。
.text:7C82E52F loc_7C82E52F:       
.text:7C82E52F                 mov     [edx], ebx  ; 将hNewToken赋值为0
.text:7C82E531                 jmp     loc_7C8199A1

接下来函数会对进程的优先级进行设定,而进程优先级是由参数dwCreateFlags标志来决定的。

在windows中,对于参数有如下宏定义

#define CREATE_NO_WINDOW            0x08000000

所以如下代码的作用就是从标志中删除CREATE_NO_WINDOWS参数

.text:7C8199A1 loc_7C8199A1:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+14D81↓j
.text:7C8199A1                 mov     eax, [ebp+dwCreationFlags]
.text:7C8199A4                 and     eax, 0F7FFFFFFh ; 清除CREATE_NO_WINDOWS标志
.text:7C8199A9                 mov     [ebp+dwCreationFlags], eax

再根据这两个宏定义

#define DETACHED_PROCESS            0x00000008
#define CREATE_NEW_CONSOLE          0x00000010

可以直到接下来的代码就是判断标志中是否同时有DETACHED_PROCESS和CREATE_NEW_CONSOLE

.text:7C8199AC                 mov     ecx, eax
.text:7C8199AE                 and     ecx, 18h   
.text:7C8199B1                 cmp     cl, 18h
.text:7C8199B4                 jz      loc_7C8427DE

是的话就会跳转到下面的代码,此时会设定错误并退出函数

.text:7C8427DE loc_7C8427DE:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+204↑j
.text:7C8427DE                 push    ERROR_INVALID_PARAMETER
.text:7C8427E0                 call    _SetLastError@4 ; SetLastError(x)    ;设置错误类型
.text:7C8427E5                 jmp     loc_7C81D783
                。。。
.text:7C81D783 loc_7C81D783:                           
.text:7C81D783                                      
.text:7C81D783                 xor     eax, eax        ; 返回值清0
.text:7C81D785                 jmp     loc_7C81A058
                。。。
.text:7C81A058 loc_7C81A058:                           
.text:7C81A058                 mov     ecx, [ebp+var_Cookie]
.text:7C81A05B                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:7C81A060                 call    __SEH_epilog
.text:7C81A065                 retn    30h
.text:7C81A065 ; } // starts at 7C819BDF

以下宏定义则是用来判别如何设置进程优先级

#define IDLE_PRIORITY_CLASS         0x00000040
#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000
#define NORMAL_PRIORITY_CLASS       0x00000020
#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
#define HIGH_PRIORITY_CLASS         0x00000080
#define REALTIME_PRIORITY_CLASS     0x00000100

函数会使用这些宏来判断创建进程的标志中指定了什么样的进程优先级

.text:7C8199C6                 test    al, 40h         ; 标记是否有IDLE_PRIORITY_CLASS
.text:7C8199C8                 jnz     loc_7C8427EA
.text:7C8199CE                 test    ah, 40h         ; 标记是否有BELOW_NORMAL_PRIORITY_CLASS
.text:7C8199D1                 jnz     loc_7C8427F6
.text:7C8199D7                 test    al, 20h         ; 标记是否有NORMAL_PRIORITY_CLASS
.text:7C8199D9                 jnz     loc_7C82C9A1
.text:7C8199DF                 test    ah, ah          ; 最高位是否为1,此时就会判断是否有ABOVE_NORMAL_PRIORITY_CLASS标志
.text:7C8199E1                 js      loc_7C842802
.text:7C8199E7                 test    al, al          ; 最高位是否为1,此时会判断是否有HIGH_PRIORITY_CLASS
.text:7C8199E9                 js      loc_7C84280E
.text:7C8199EF                 test    ah, 1           ; 判断是否有REALTIME_PRIORITY_CLASS标志
.text:7C8199F2                 jnz     loc_7C84281A
.text:7C8199F8                 mov     [ebp+var_PriorityClass], bl ; 如果不是上述情况,进程优先级就会赋值为0

接着根据指定的优先级来赋值不同的进程优先级

.text:7C8427EA loc_7C8427EA:
.text:7C8427EA                 mov     [ebp+var_PriorityClass], PROCESS_PRIORITY_CLASS_IDLE
.text:7C8427F1                 jmp     loc_7C8199FE
.text:7C8427F6 ; ---------------------------------------------------------------------------
.text:7C8427F6
.text:7C8427F6 loc_7C8427F6: 
.text:7C8427F6                 mov     [ebp+var_PriorityClass], PROCESS_PRIORITY_CLASS_BELOW_NORMAL
.text:7C8427FD                 jmp     loc_7C8199FE
.text:7C842802 ; ---------------------------------------------------------------------------
.text:7C842802
.text:7C842802 loc_7C842802:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+231↑j
.text:7C842802                 mov     [ebp+var_PriorityClass], PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
.text:7C842809                 jmp     loc_7C8199FE
.text:7C84280E ; ---------------------------------------------------------------------------
.text:7C84280E                               mov     [ebp+var_PriorityClass], PROCESS_PRIORITY_CLASS_HIGH
.text:7C842815                 jmp     loc_7C8199FE
.text:7C84281A ; ---------------------------------------------------------------------------
.text:7C84281A                 push    ebx
.text:7C84281B                 call    _BasepIsRealtimeAllowed@4 ; BasepIsRealtimeAllowed(x)
.text:7C842820                 test    eax, eax
.text:7C842822                 setnz   al
.text:7C842825                 add     al, 3
.text:7C842827                 mov     [ebp+var_PriorityClass], al
.text:7C84282D                 jmp     loc_7C8199FE

设置完进程优先级,函数就会把创建进程中指定的标志中有关进程优先级的内容删除

.text:7C8199FE                 mov     [ebp+var_668], bl
.text:7C819A04                 and     word ptr [ebp+dwCreationFlags], 3E1Fh ;删除标志中和进程优先级有关的内容

接下来的内容则判断标记中和VDM相关的内容

.text:7C819A0A                 mov     edi, CREATE_SEPARATE_WOW_VDM
.text:7C819A0F                 mov     esi, CREATE_SHARED_WOW_VDM
.text:7C819A14                 test    [ebp+dwCreationFlags], edi
.text:7C819A17                 jnz     loc_7C842832
.text:7C819A1D                 test    [ebp+dwCreationFlags], esi
.text:7C819A20                 jnz     short loc_7C819A33
.text:7C819A22                 mov     eax, _BaseStaticServerData
.text:7C819A27                 cmp     [eax+19F4h], bl
.text:7C819A2D                 jnz     loc_7C84283C
.text:7C819A33
.text:7C819A33 loc_7C819A33:              
.text:7C819A33                 test    [ebp+dwCreationFlags], edi
.text:7C819A36                 jnz     short loc_7C819A56
.text:7C819A38                 push    ebx             ; ReturnLength
.text:7C819A39                 push    4               ; JobInformationLength
.text:7C819A3B                 lea     eax, [ebp+JobInformation]
.text:7C819A41                 push    eax             ; JobInformation
.text:7C819A42                 push    4               ; JobInformationClass
.text:7C819A44                 push    ebx             ; JobHandle
.text:7C819A45                 call    ds:__imp__NtQueryInformationJobObject@20 ; NtQueryInformationJobObject(x,x,x,x,x)
.text:7C819A4B                 cmp     eax, STATUS_ACCESS_DENIED
.text:7C819A50                 jnz     loc_7C842844
                。。。
.text:7C842832 loc_7C842832:                          
.text:7C842832                 test    [ebp+dwCreationFlags], esi
.text:7C842835                 jnz     short loc_7C8427DE
.text:7C842837                 jmp     loc_7C819A33

.text:7C8427DE loc_7C8427DE:                           
.text:7C8427DE                 push    ERROR_INVALID_PARAMETER
.text:7C8427E0                 call    _SetLastError@4 ; SetLastError(x)
.text:7C8427E5                 jmp     loc_7C81D783

接下去就会判断创建进程时传入的参数lpEnvironment是否有效以及是否有CREATE_PROTECTED_PROCESS标志,满足的话则会将eax指向保存环境字符串的地址的末尾

.text:7C819A56 loc_7C819A56:               
.text:7C819A56                 mov     ecx, [ebp+var_Environment]
.text:7C819A5C                 cmp     ecx, ebx        ; 传入的lpEnvironment是否为NULL
.text:7C819A5E                 jz      loc_7C818E17
.text:7C819A64                 test    byte ptr [ebp+dwCreationFlags+1], 4 ; 标志中是否带有CREATE_PROTECTED_PROCESS
.text:7C819A68                 jnz     loc_7C818E17
.text:7C819A6E                 mov     eax, ecx
.text:7C819A70                 mov     [ebp+SourceString.Buffer], ecx
.text:7C819A76
.text:7C819A76 loc_7C819A76:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+2CF↓j
.text:7C819A76                 cmp     [eax], bl       ; 找到末尾为0的位置
.text:7C819A78                 jz      loc_7C818D8A
.text:7C819A7E
.text:7C819A7E loc_7C819A7E:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)-A23↑j
.text:7C819A7E                 inc     eax
.text:7C819A7F                 jmp     short loc_7C819A76

然后把传入的Unicode字符串转换为Ansi字符串后保存

.text:7C818D8A loc_7C818D8A:             
.text:7C818D8A                 cmp     [eax+1], bl
.text:7C818D8D                 jnz     loc_7C819A7E
.text:7C818D93                 sub     eax, ecx
.text:7C818D95                 inc     eax
.text:7C818D96                 mov     [ebp+SourceString.Length], ax
.text:7C818D9D                 mov     eax, dword ptr [ebp+SourceString.Length]
.text:7C818DA3                 inc     eax
.text:7C818DA4                 mov     [ebp+SourceString.MaximumLength], ax
.text:7C818DAB                 movzx   eax, ax
.text:7C818DAE                 shl     eax, 1
.text:7C818DB0                 mov     [ebp+RegionSize], eax
.text:7C818DB6                 mov     [ebp+DestinationString.Buffer], ebx
.text:7C818DBC                 push    PAGE_READWRITE  ; Protect
.text:7C818DBE                 push    esi             ; AllocationType
.text:7C818DBF                 lea     eax, [ebp+RegionSize]
.text:7C818DC5                 push    eax             ; RegionSize
.text:7C818DC6                 push    ebx             ; ZeroBits
.text:7C818DC7                 lea     eax, [ebp+DestinationString.Buffer]
.text:7C818DCD                 push    eax             ; BaseAddress
.text:7C818DCE                 push    0FFFFFFFFh      ; ProcessHandle
.text:7C818DD0                 call    ds:__imp__NtAllocateVirtualMemory@24 ; NtAllocateVirtualMemory(x,x,x,x,x,x)
.text:7C818DD6                 cmp     eax, ebx
.text:7C818DD8                 jl      loc_7C842856
.text:7C818DDE                 mov     ax, word ptr [ebp+RegionSize]
.text:7C818DE5                 mov     [ebp+DestinationString.MaximumLength], ax
.text:7C818DEC                 push    ebx             ; AllocateDestinationString
.text:7C818DED                 lea     eax, [ebp+SourceString]
.text:7C818DF3                 push    eax             ; SourceString
.text:7C818DF4                 lea     eax, [ebp+DestinationString]
.text:7C818DFA                 push    eax             ; DestinationString
.text:7C818DFB                 call    ds:__imp__RtlAnsiStringToUnicodeString@12 ; RtlAnsiStringToUnicodeString(x,x,x)
.text:7C818E01                 mov     esi, eax
.text:7C818E03                 cmp     esi, ebx
.text:7C818E05                 jl      loc_7C842861
.text:7C818E0B                 mov     eax, [ebp+DestinationString.Buffer]
.text:7C818E11                 mov     [ebp+var_Environment], eax ; 保存转换后的环境变量

接着函数会继续初始化局部变量,并且将传入的StartupInfo内容保存到局部变量中

.text:7C818E17 loc_7C818E17:           
.text:7C818E17                 mov     [ebp+FileHandle], ebx
.text:7C818E1D                 mov     [ebp+SectionHandle], ebx
.text:7C818E23                 mov     [ebp+ProcessHandle], ebx
.text:7C818E29                 mov     [ebp+ThreadHandle], ebx
.text:7C818E2F                 mov     [ebp+var_SearchPath], ebx
.text:7C818E35                 mov     [ebp+var_HeapMemory], ebx
.text:7C818E3B                 mov     [ebp+UnicodeString.Buffer], ebx
.text:7C818E41                 mov     [ebp+BaseAddress], 1
.text:7C818E4B                 mov     [ebp+var_684], ebx
.text:7C818E51                 mov     [ebp+var_8B0], ebx
.text:7C818E57                 mov     [ebp+FilePart], ebx
.text:7C818E5D                 mov     [ebp+Destination.Buffer], ebx
.text:7C818E63                 mov     [ebp+var_716], bl
.text:7C818E69                 mov     [ebp+var_800], ebx
.text:7C818E6F                 mov     [ebp+ms_exc.registration.TryLevel], ebx
.text:7C818E72                 push    11h
.text:7C818E74                 pop     ecx
.text:7C818E75                 mov     esi, [ebp+var_lpStartupInfo]
.text:7C818E7B                 lea     edi, [ebp+var_StartupInfo]
.text:7C818E81                 rep movsd               ; 将传入的参数StartupInfo保存到局部变量中

接下来的内容最主要的就是传入的将要启动的文件名通过RtlDosPathNameToNtPathName转换为NT内部名称(比如:c:\temp\1.exe会转换为\device\harddiskvolumn1\temp\1.exe),因为在内核中需要使用这样的名字来打开文件。

.text:7C818EF9 loc_7C818EF9:          
.text:7C818EF9                 lea     eax, [ebp+DirectoryInfo]
.text:7C818EFF                 push    eax             ; DirectoryInfo
.text:7C818F00                 push    ebx             ; NtFileNamePart
.text:7C818F01                 lea     eax, [ebp+NtPathName] ; 要在内核中使用的文件名
.text:7C818F07                 push    eax             ; NtPathName
.text:7C818F08                 mov     edi, [ebp+var_lpApplicationName]
.text:7C818F0E                 push    edi             ; DosPathName
.text:7C818F0F                 call    ds:__imp__RtlDosPathNameToNtPathName_U@16 ; RtlDosPathNameToNtPathName_U(x,x,x,x)
.text:7C818F15                 mov     [ebp+var_8C1], al
.text:7C818F1B                 cmp     al, bl
.text:7C818F1D                 jz      loc_7C84293F
.text:7C818F23                 mov     eax, [ebp+NtPathName.Buffer]
.text:7C818F29                 mov     [ebp+var_SearchPath], eax
.text:7C818F2F                 push    edi             ; SourceString
.text:7C818F30                 lea     eax, [ebp+var_6C8]
.text:7C818F36                 push    eax             ; DestinationString
.text:7C818F37                 mov     esi, ds:__imp__RtlInitUnicodeString@8 ; RtlInitUnicodeString(x,x)
.text:7C818F3D                 call    esi ; RtlInitUnicodeString(x,x) ; RtlInitUnicodeString(x,x)
.text:7C818F3F                 push    edi             ; Path
.text:7C818F40                 call    ds:__imp__RtlDetermineDosPathNameType_U@4 ; RtlDetermineDosPathNameType_U(x)
.text:7C818F46                 mov     [ebp+var_984], eax
.text:7C818F4C                 cmp     eax, 2
.text:7C818F4F                 jnz     loc_7C81D712

2.打开要执行的映像

将经过转换以后的文件名作为参数调用NtOpenFile来获得文件句柄。

.text:7C818F82 loc_7C818F82:        
.text:7C818F82                 mov     [ebp+ObjectAttributes.Length], 18h
.text:7C818F8C                 mov     eax, [ebp+DirectoryInfo.ContainingDirectory]
.text:7C818F92                 mov     [ebp+ObjectAttributes.RootDirectory], eax
.text:7C818F98                 mov     [ebp+ObjectAttributes.Attributes], OBJ_CASE_INSENSITIVE
.text:7C818FA2                 lea     eax, [ebp+NtPathName] ; 经过转换以后的映像名
.text:7C818FA8                 mov     [ebp+ObjectAttributes.ObjectName], eax
.text:7C818FAE                 mov     [ebp+ObjectAttributes.SecurityDescriptor], ebx
.text:7C818FB4                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], ebx
.text:7C818FBA                 push    60h             ; OpenOptions
.text:7C818FBC                 push    5               ; ShareAccess
.text:7C818FBE                 lea     eax, [ebp+IoStatusBlock]
.text:7C818FC4                 push    eax             ; IoStatusBlock
.text:7C818FC5                 lea     eax, [ebp+ObjectAttributes]
.text:7C818FCB                 push    eax             ; ObjectAttributes
.text:7C818FCC                 push    1000A1h         ; 要获得句柄的权限
.text:7C818FD1                 lea     eax, [ebp+FileHandle]
.text:7C818FD7                 push    eax             ; FileHandle
.text:7C818FD8                 mov     esi, ds:__imp__NtOpenFile@24 ; NtOpenFile(x,x,x,x,x,x)
.text:7C818FDE                 call    esi ; NtOpenFile(x,x,x,x,x,x) ; NtOpenFile(x,x,x,x,x,x)
.text:7C818FE0                 mov     [ebp+Status], eax
.text:7C818FE6                 cmp     eax, ebx        ; 如果返回值小于0说明打开失败
.text:7C818FE8                 jl      loc_7C81D7AD

而第二个参数指定了句柄的权限,而根据以下的宏定义可以知道要获得的权限。

#define SYNCHRONIZE              (0x00100000L)
#define FILE_READ_DATA             ( 0x0001 )    // file & pipe
#define FILE_READ_ATTRIBUTES            ( 0x0080 )    // all
#define FILE_EXECUTE              ( 0x0020 )    // file

如果第一次调用NtOpenFile失败,则函数会再次调用该函数打开文件,只是此时要获得的权限发生改变。

.text:7C81D7AD loc_7C81D7AD:         
.text:7C81D7AD                 push    60h             ; OpenOptions
.text:7C81D7AF                 push    5               ; ShareAccess
.text:7C81D7B1                 lea     eax, [ebp+IoStatusBlock]
.text:7C81D7B7                 push    eax             ; IoStatusBlock
.text:7C81D7B8                 lea     eax, [ebp+ObjectAttributes]
.text:7C81D7BE                 push    eax             ; ObjectAttributes
.text:7C81D7BF                 push    100020h         ; DesiredAccess
.text:7C81D7C4                 lea     eax, [ebp+FileHandle]
.text:7C81D7CA                 push    eax             ; FileHandle
.text:7C81D7CB                 call    esi ; NtOpenFile(x,x,x,x,x,x) ; NtOpenFile(x,x,x,x,x,x)
.text:7C81D7CD                 mov     [ebp+Status], eax
.text:7C81D7D3                 cmp     eax, ebx        ; 如果大于等于则说明打开成功
.text:7C81D7D5                 jge     loc_7C818FEE

根据宏定义可以知道,这次是以只要获得执行权限的方式打开

#define FILE_EXECUTE              ( 0x0020 )    // file

如果这次打开还是失败,那么函数接下来就会判断失败原因。首先通过RtlIsDosDeviceName判断是否是因为正在执行设备导致失败,是的话会设置相应的错误码。

.text:7C81D7DC                 call    ds:__imp__RtlIsDosDeviceName_U@4 ; RtlIsDosDeviceName_U(x)
.text:7C81D7E2                 test    eax, eax        ; 非0则说明正在执行设备
.text:7C81D7E4                 jnz     loc_7C84294D
                。。。
.text:7C84294D loc_7C84294D:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+4034↑j
.text:7C84294D                 push    ERROR_BAD_DEVICE
.text:7C842952                 jmp     loc_7C83589C
                。。。
.text:7C83589C loc_7C83589C:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+29191↓j
.text:7C83589C                                         ; CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+29198↓j ...
.text:7C83589C                 call    _SetLastError@4 ; SetLastError(x)
.text:7C8358A1                 jmp     loc_7C81D776

如果不是则会将NtOpenFile函数执行失败的结果作为error code返回。

.text:7C81D7F0 loc_7C81D7F0:
.text:7C81D7F0                 call    _BaseSetLastNTError@4 ; BaseSetLastNTError(x)
.text:7C81D7F5                 jmp     loc_7C81D776

接下来函数会判断调用方是否指定了桌面,如果没有的话就会将本进程PEB中的桌面内容赋值过去

.text:7C818FEE loc_7C818FEE:             
.text:7C818FEE                 cmp     [ebp+var_DesktopInfoBuffer], ebx
.text:7C818FF4                 jz      loc_7C819BA7
                。。。
.text:7C819BA7 loc_7C819BA7:          
.text:7C819BA7                 mov     eax, large fs:18h
.text:7C819BAD                 mov     [ebp+var_TEb], eax
.text:7C819BB3                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C819BB6                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C819BB9                 mov     eax, [eax+RTL_USER_PROCESS_PARAMETERS.DesktopInfo.Buffer]
.text:7C819BBC                 mov     [ebp+var_DesktopInfoBuffer], eax
.text:7C819BC2                 jmp     loc_7C818FFA
.text:7C819BC2 ; } // starts at 7C819BA7

随后函数就通过NtCreateSection来对打开的文件句柄创建内存映射

.text:7C818FFA loc_7C818FFA:         
.text:7C818FFA                 push    [ebp+FileHandle] ; FileHandle
.text:7C819000                 push    SEC_IMAGE       ; AllocationAttributes
.text:7C819005                 push    PAGE_EXECUTE    ; SectionPageProtection
.text:7C819007                 push    ebx             ; MaximumSize
.text:7C819008                 push    ebx             ; ObjectAttributes
.text:7C819009                 push    SECTION_ALL_ACCESS ; DesiredAccess
.text:7C81900E                 lea     eax, [ebp+SectionHandle]
.text:7C819014                 push    eax             ; SectionHandle
.text:7C819015                 call    ds:__imp__NtCreateSection@28 ; NtCreateSection(x,x,x,x,x,x,x)
.text:7C81901B                 mov     edi, eax
.text:7C81901D                 mov     [ebp+Status], edi
.text:7C819023                 cmp     edi, ebx
.text:7C819025                 jl      short loc_7C81904C

打开成功以后,将会调用BasepIsProcessAllowed函数来得知是否可以加载进程

.text:7C819027                 push    [ebp+var_lpApplicationName] ; Size
.text:7C81902D                 call    _BasepIsProcessAllowed@4 ; BasepIsProcessAllowed(x)
.text:7C819032                 mov     edi, eax
.text:7C819034                 mov     [ebp+Status], edi
.text:7C81903A                 cmp     edi, ebx        ; 返回值小于0则说明无法加载
.text:7C81903C                 jl      loc_7C842957
            。。。
.text:7C842957 loc_7C842957:        
.text:7C842957                 push    edi             ; Status
.text:7C842958                 call    _BaseSetLastNTError@4 ; BaseSetLastNTError(x)
.text:7C84295D                 push    [ebp+SectionHandle] ; Handle
.text:7C842963                 call    ds:__imp__NtClose@4 ; NtClose(x)
.text:7C842969                 jmp     loc_7C81D776

根据宏定义

#define CREATE_FORCEDOS             0x00002000

可以知道,接下来会判断创建进程的标志中是否带有CREATE_FORCEDOS

.text:7C819042                 test    byte ptr [ebp+dwCreationFlags+1], 20h ; 是否具有CREATE_FORCEDOS标志
.text:7C819046                 jnz     loc_7C84296E

如果没有,则会设置错误码,释放句柄等等

.text:7C84296E loc_7C84296E:        
.text:7C84296E                 mov     eax, _BaseStaticServerData
.text:7C842973                 cmp     [eax+19F5h], bl
.text:7C842979                 jz      loc_7C81904C
.text:7C84297F                 and     byte ptr [ebp+dwCreationFlags+1], 0CFh
.text:7C842983                 mov     esi, CREATE_SEPARATE_WOW_VDM
.text:7C842988                 or      [ebp+dwCreationFlags], esi
.text:7C84298B                 mov     edi, STATUS_INVALID_IMAGE_WIN_16
.text:7C842990                 mov     [ebp+Status], edi
.text:7C842996                 mov     [ebp+var_8D8], 1
.text:7C8429A0                 push    [ebp+SectionHandle] ; Handle
.text:7C8429A6                 call    ds:__imp__NtClose@4 ; NtClose(x)
.text:7C8429AC                 mov     [ebp+SectionHandle], ebx
.text:7C8429B2                 jmp     loc_7C819051

如果内存映射成功,函数会进行一系列验证,然后通过NtQuerySection来获得文件的信息

.text:7C819128 loc_7C819128:    
.text:7C819128                 push    ebx             ; ResultLength
.text:7C819129                 push    30h             ; Length
.text:7C81912B                 lea     eax, [ebp+SectionInformation]
.text:7C819131                 push    eax             ; SectionInformation
.text:7C819132                 xor     edi, edi
.text:7C819134                 inc     edi
.text:7C819135                 push    edi             ; SectionInformationClass
.text:7C819136                 push    [ebp+SectionHandle] ; SectionHandle
.text:7C81913C                 call    ds:__imp__NtQuerySection@20 ; NtQuerySection(x,x,x,x,x)
.text:7C819142                 mov     [ebp+Status], eax
.text:7C819148                 cmp     eax, ebx
.text:7C81914A                 jl      loc_7C82DF58

根据宏定义

#define DEBUG_PROCESS               0x00000001
#define DEBUG_ONLY_THIS_PROCESS     0x00000002

函数会判断传入的参数中是否带有调试相关的标志

.text:7C819164                 test    byte ptr [ebp+dwCreationFlags], 3 ; 是否带有DEBUG_PROCESS或DEBUG_ONLY_THIS_PROCESS标志
.text:7C819168                 jnz     loc_7C842CEF

如果有,则会进一步验证PEB中的ReadImageFileExecOptions字段是否为0

.text:7C842CEF loc_7C842CEF:        
.text:7C842CEF                 mov     eax, large fs:18h
.text:7C842CF5                 mov     [ebp+var_tEB], eax
.text:7C842CFB                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C842CFE                 cmp     [eax+_PEB.ReadImageFileExecOptions], bl
.text:7C842D01                 jnz     loc_7C81916E
.text:7C842D07                 jmp     loc_7C81918D

如果不为0,接下来就会通过LdrQueryImageFileExecutionOptions来查询调试器信息

.text:7C81916E loc_7C81916E:          
.text:7C81916E                 push    ebx             ; RetunedLength
.text:7C81916F                 push    208h            ; BufferSize
.text:7C819174                 lea     eax, [ebp+Buffer]
.text:7C81917A                 push    eax             ; Buffer
.text:7C81917B                 push    edi             ; ValueSize
.text:7C81917C                 push    offset aDebugger ; "Debugger"
.text:7C819181                 lea     eax, [ebp+NtPathName]
.text:7C819187                 push    eax             ; SubKey
.text:7C819188                 call    _LdrQueryImageFileExecutionOptions@24

随后函数会再次判断参数中是否有调试标志

.text:7C819279 loc_7C819279:          
.text:7C819279                 test    byte ptr [ebp+dwCreationFlags], 3 ; 是否有DEBUG_PROCESS或DEBUG_ONLY_THIS_PROCESS标志
.text:7C81927D                 jnz     loc_7C842E87

有的话就会调用DbgUiConnectToDbg来建立调试关系

.text:7C842E87 loc_7C842E87:         
.text:7C842E87                 call    _DbgUiConnectToDbg@0 ; DbgUiConnectToDbg()
.text:7C842E8C                 mov     [ebp+Status], eax
.text:7C842E92                 cmp     eax, ebx
.text:7C842E94                 jl      loc_7C82DF58
.text:7C842E9A                 call    _DbgUiGetThreadDebugObject@0 ; DbgUiGetThreadDebugObject()
.text:7C842E9F                 mov     [ebp+DebugPort], eax
.text:7C842EA5                 test    byte ptr [ebp+dwCreationFlags], 2
.text:7C842EA9                 jz      loc_7C819283
.text:7C842EAF                 or      [ebp+Flags], 2
.text:7C842EB6                 jmp     loc_7C819283

3.创建Windows执行体对象

至此已经打开了有效的Windows可执行文件并将其映射到相应的地址空间,接下来就需要通过系统调用NtCreateProcessEx来创建内核对象,由于这个部分内容比较多,后面再详细说。

.text:7C8192AD                 push    dword ptr [ebp+InJob] ; InJob
.text:7C8192B3                 push    ebx             ; ExceptionPort
.text:7C8192B4                 push    [ebp+DebugPort] ; DebugPort
.text:7C8192BA                 push    [ebp+SectionHandle] ; SectionHandle
.text:7C8192C0                 push    [ebp+Flags]     ; Flags
.text:7C8192C6                 or      esi, 0FFFFFFFFh
.text:7C8192C9                 push    esi             ; ParentProcess
.text:7C8192CA                 push    [ebp+var_838]   ; ObjectAttributes
.text:7C8192D0                 push    1F0FFFh         ; DesiredAccess
.text:7C8192D5                 lea     eax, [ebp+ProcessHandle]
.text:7C8192DB                 push    eax             ; ProcessHandle
.text:7C8192DC                 call    ds:__imp__NtCreateProcessEx@36 ; NtCreateProcessEx(x,x,x,x,x,x,x,x,x)
.text:7C8192E2                 mov     [ebp+Status], eax
.text:7C8192E8                 cmp     eax, ebx
.text:7C8192EA                 jl      loc_7C82DF60

创建完成以后函数会判断是否设置了进程的优先级

.text:7C8192F0                 cmp     [ebp+var_PriorityClass], bl
.text:7C8192F6                 jnz     loc_7C82C954

如果设置了,接着会判断进程优先级是否为实时优先级

.text:7C82C954 loc_7C82C954:       
.text:7C82C954                 mov     [ebp+RealTimePrivilegeState], ebx
.text:7C82C95A                 cmp     [ebp+var_PriorityClass], PROCESS_PRIORITY_CLASS_REALTIME
.text:7C82C961                 jz      loc_7C842EC6

是的话就会调用函数来判断是否权限是否足够

.text:7C842EC6 loc_7C842EC6:       
.text:7C842EC6                 push    edi
.text:7C842EC7                 call    _BasepIsRealtimeAllowed@4 ; BasepIsRealtimeAllowed(x)
.text:7C842ECC                 mov     [ebp+RealTimePrivilegeState], eax
.text:7C842ED2                 jmp     loc_7C82C967

如果符合条件,接下来就会调用函数来设置进程的优先级

.text:7C82C967 loc_7C82C967:    
.text:7C82C967                 push    2               ; ProcessInformationLength
.text:7C82C969                 lea     eax, [ebp+var_668]
.text:7C82C96F                 push    eax             ; ProcessInformation
.text:7C82C970                 push    ProcessPriorityClass ; ProcessInformationClass
.text:7C82C972                 push    [ebp+ProcessHandle] ; ProcessHandle
.text:7C82C978                 call    ds:__imp__NtSetInformationProcess@16 ; NtSetInformationProcess(x,x,x,x)
.text:7C82C97E                 mov     [ebp+Status], eax
.text:7C82C984                 cmp     [ebp+RealTimePrivilegeState], ebx
.text:7C82C98A                 jnz     loc_7C842ED7

根据以下的宏定义就可以知道

#define CREATE_DEFAULT_ERROR_MODE   0x04000000

设置完进程优先级以后,函数会继续判断传入的标志中是否有

.text:7C8192FC loc_7C8192FC:    
.text:7C8192FC                 test    byte ptr [ebp+dwCreationFlags+3], 4 ; 是否有CREATE_DEFAULT_ERROR_MODE标志
.text:7C819300                 jnz     loc_7C81FEFB

如果有,接下来就会通过函数来设置错误模式

.text:7C81FEFB loc_7C81FEFB:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)-4B0↑j
.text:7C81FEFB ; __unwind { // __SEH_prolog
.text:7C81FEFB                 mov     [ebp+var_ProcessInformation], edi
.text:7C81FF01                 push    4               ; ProcessInformationLength
.text:7C81FF03                 lea     eax, [ebp+var_ProcessInformation]
.text:7C81FF09                 push    eax             ; ProcessInformation
.text:7C81FF0A                 push    ProcessDefaultHardErrorMode ; ProcessInformationClass
.text:7C81FF0C                 push    [ebp+ProcessHandle] ; ProcessHandle
.text:7C81FF12                 call    ds:__imp__NtSetInformationProcess@16 ; NtSetInformationProcess(x,x,x,x)
.text:7C81FF18                 jmp     loc_7C819306

接下来会调用函数从创建的进程的内存中读出数据

.text:7C81FE2E                 push    ebx             ; NumberOfBytesRead
.text:7C81FE2F                 push    4               ; NumberOfBytesToRead
.text:7C81FE31                 lea     eax, [ebp+var_798]
.text:7C81FE37                 push    eax             ; Buffer
.text:7C81FE38                 mov     eax, [ebp+var_848]
.text:7C81FE3E                 add     eax, 10h
.text:7C81FE41                 push    eax             ; BaseAddress
.text:7C81FE42                 push    [ebp+ProcessHandle] ; ProcessHandle
.text:7C81FE48                 call    ds:__imp__NtReadVirtualMemory@20 ; NtReadVirtualMemory(x,x,x,x,x)
.text:7C81FE4E                 mov     [ebp+Status], eax
.text:7C81FE54                 cmp     eax, ebx
.text:7C81FE56                 jl      loc_7C819DEC

接下来会分别对输入输出以及错误句柄进行判断,如果不是控制台句柄就会通过StuffStdHandle进行复制

.text:7C81FE5C                 mov     eax, large fs:18h
.text:7C81FE62                 mov     [ebp+var_teb0], eax
.text:7C81FE68                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C81FE6B                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C81FE6E                 mov     eax, [eax+RTL_USER_PROCESS_PARAMETERS.StandardInput] ; 对输入句柄判断
.text:7C81FE71                 mov     esi, 10000003h
.text:7C81FE76                 and     eax, esi
.text:7C81FE78                 cmp     eax, edi
.text:7C81FE7A                 jnz     loc_7C82DF7C
            。。。
.text:7C82DF7C loc_7C82DF7C: 
.text:7C82DF7C                 mov     eax, large fs:18h
.text:7C82DF82                 mov     [ebp+var_teb5], eax
.text:7C82DF88                 mov     ecx, [ebp+var_798]
.text:7C82DF8E                 add     ecx, 18h
.text:7C82DF91                 push    ecx             ; BaseAddress
.text:7C82DF92                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C82DF95                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C82DF98                 push    [eax+RTL_USER_PROCESS_PARAMETERS.StandardInput] ; 对输入句柄复制
.text:7C82DF9B                 push    [ebp+ProcessHandle] ; TargetProcessHandle
.text:7C82DFA1                 call    _StuffStdHandle@12 ; StuffStdHandle(x,x,x)
.text:7C82DFA6                 jmp     loc_7C81FE80
.text:7C81FE80 loc_7C81FE80: 
.text:7C81FE80                 mov     eax, large fs:18h
.text:7C81FE86                 mov     [ebp+var_teb1], eax
.text:7C81FE8C                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C81FE8F                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C81FE92                 mov     eax, [eax+RTL_USER_PROCESS_PARAMETERS.StandardOutput] ; 输出句柄的判断
.text:7C81FE95                 and     eax, esi
.text:7C81FE97                 cmp     eax, edi
.text:7C81FE99                 jnz     loc_7C82DF29
            。。。
.text:7C82DF29 loc_7C82DF29:  
.text:7C82DF29                 mov     eax, large fs:18h
.text:7C82DF2F                 mov     [ebp+var_teb4], eax
.text:7C82DF35                 mov     ecx, [ebp+var_798]
.text:7C82DF3B                 add     ecx, 1Ch
.text:7C82DF3E                 push    ecx             ; BaseAddress
.text:7C82DF3F                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C82DF42                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C82DF45                 push    [eax+RTL_USER_PROCESS_PARAMETERS.StandardOutput] ; 对输出句柄复制
.text:7C82DF48                 push    [ebp+ProcessHandle] ; TargetProcessHandle
.text:7C82DF4E                 call    _StuffStdHandle@12 ; StuffStdHandle(x,x,x)
.text:7C82DF53                 jmp     loc_7C81FE9F
.text:7C81FE9F loc_7C81FE9F:  
.text:7C81FE9F                 mov     eax, large fs:18h
.text:7C81FEA5                 mov     [ebp+var_teb2], eax
.text:7C81FEAB                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C81FEAE                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C81FEB1                 mov     eax, [eax+RTL_USER_PROCESS_PARAMETERS.StandardError] ; 对错误句柄进行判断
.text:7C81FEB4                 and     eax, esi
.text:7C81FEB6                 cmp     eax, edi
.text:7C81FEB8                 jz      loc_7C819DEC
.text:7C81FEBE                 mov     eax, large fs:18h
.text:7C81FEC4                 mov     [ebp+var_teb3], eax
.text:7C81FECA                 mov     ecx, [ebp+var_798]
.text:7C81FED0                 add     ecx, 20h
.text:7C81FED3                 push    ecx             ; BaseAddress
.text:7C81FED4                 mov     eax, [eax+_TEB.ProcessEnvironmentBlock]
.text:7C81FED7                 mov     eax, [eax+_PEB.ProcessParameters]
.text:7C81FEDA                 push    [eax+RTL_USER_PROCESS_PARAMETERS.StandardError] ; 对错误句柄进行复制
.text:7C81FEDD                 push    [ebp+ProcessHandle] ; TargetProcessHandle
.text:7C81FEE3                 call    _StuffStdHandle@12 ; StuffStdHandle(x,x,x)
.text:7C81FEE8                 jmp     loc_7C819DEC

现在进程执行体已经创建完成,但是想要执行指令,还需要线程才可以完成。因此,要继续创建再进程中运行的线程。

4.创建线程和栈及上下文

至此,Windows执行体进程对象已经创建完成,然而其中依然不具备线程,因此还无法开始工作。接下来的工作就需要创建线程,而创建线程之前需要初始化创建线程需要的资源。

首先需要调用BaseCreateStack来创建线程栈

.text:7C819DEC loc_7C819DEC:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+631↑j
.text:7C819DEC                                         ; CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+665C↓j ...
.text:7C819DEC                 mov     eax, 40000h     ; 是否小于0x4000
.text:7C819DF1                 cmp     [ebp+ImageInformation.MaximumStackSize], eax
.text:7C819DF7                 jb      short loc_7C819DFF
.text:7C819DF9                 mov     eax, [ebp+ImageInformation.MaximumStackSize]
.text:7C819DFF
.text:7C819DFF loc_7C819DFF:                           ; CODE XREF: CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+647↑j
.text:7C819DFF                 lea     ecx, [ebp+InitialTeb]
.text:7C819E05                 push    ecx             ; int
.text:7C819E06                 push    eax             ; RegionSize
.text:7C819E07                 push    [ebp+ImageInformation.CommittedStackSize] ; UINT_PTR
.text:7C819E0D                 push    [ebp+ProcessHandle] ; ProcessHandle
.text:7C819E13                 call    _BaseCreateStack@16 ; BaseCreateStack(x,x,x,x)
.text:7C819E18                 mov     [ebp+var_CreateStackStatus], eax
.text:7C819E1E                 cmp     eax, ebx
.text:7C819E20                 jl      loc_7C82DF58

接着需要调用BaseInitializeContext来初始化线程的CONTEXT

.text:7C819E26                 push    ebx
.text:7C819E27                 push    [ebp+InitialTeb.StackBase]
.text:7C819E2D                 push    [ebp+SectionInformation]
.text:7C819E33                 push    [ebp+var_PEB]
.text:7C819E39                 lea     eax, [ebp+ThreadContext]
.text:7C819E3F                 push    eax
.text:7C819E40                 call    _BaseInitializeContext@20 ; BaseInitializeContext(x,x,x,x,x)

最后通过系统调用NtCreateThread来创建内核线程对象,但是此时是以挂起的方式创建的线程

.text:7C819E72                 push    1               ; CreateSuspended
.text:7C819E74                 lea     eax, [ebp+InitialTeb]
.text:7C819E7A                 push    eax             ; UserStack
.text:7C819E7B                 lea     eax, [ebp+ThreadContext]
.text:7C819E81                 push    eax             ; ThreadContext
.text:7C819E82                 lea     eax, [ebp+ClientId]
.text:7C819E88                 push    eax             ; ClientId
.text:7C819E89                 push    [ebp+ProcessHandle] ; ProcessHandle
.text:7C819E8F                 push    [ebp+var_838]   ; ObjectAttributes
.text:7C819E95                 push    THREAD_ALL_ACCESS ; DesiredAccess
.text:7C819E9A                 lea     eax, [ebp+ThreadHandle]
.text:7C819EA0                 push    eax             ; ThreadHandle
.text:7C819EA1                 call    ds:__imp__NtCreateThread@32 ; NtCreateThread(x,x,x,x,x,x,x,x)
.text:7C819EA7                 mov     [ebp+Status], eax
.text:7C819EAD                 cmp     eax, ebx
.text:7C819EAF                 jl      loc_7C82DF58

5.执行与Windows子系统有关的初始化工作

当创建了进程与线程对象以后,接下来函数就会使用CsrClientCallServer来给Windows子系统(Csrss)发送消息

.text:7C819F76 loc_7C819F76:       
.text:7C819F76                 push    98h             ; DataLength
.text:7C819F7B                 push    10000h          ; ApiNumber
.text:7C819F80                 push    [ebp+CaptureBuffer] ; CaptureBuffer
.text:7C819F86                 lea     eax, [ebp+ApiMessage]
.text:7C819F8C                 push    eax             ; ApiMessage
.text:7C819F8D                 call    ds:__imp__CsrClientCallServer@16 ; CsrClientCallServer(x,x,x,x)
.text:7C819F93                 cmp     [ebp+CaptureBuffer], ebx
.text:7C819F99                 jnz     loc_7C82BA1A

该消息包含以下信息:

  • 路径名称和SxS路径名称

  • 进程和线程句柄

  • 区域句柄

  • 访问令牌句柄

  • 媒体信息

  • AppCompat和填充数据

  • 沉浸式进程信息

  • PEB地址

  • 各种标志,如是否为受保护进程,是否需要再提权后运行等

  • 代表进程是否属于某个Windows应用程序(Csrss借此决定是否显示启动光标)的标志

  • UI语言信息

  • DLL重定向和.local标志

  • 清单文件信息

收到该消息后,Windows子系统将执行下列操作:

  1. CsrCreateProcess复制进程和线程句柄。在这一步中,进程和线程的使用计数会从1增加到2

  2. 分配Csrss进程结构(CSR_PROCESS)

  3. 新进程的异常端口设置为Windows子系统的通用功能端口,借此Windows子系统能再进程中发送二次异常

  4. 如果要新建进程组,且该新进程称为进程组的根(在CreateProcess中使用了CREATE_NEW_PROCESS_GROUP标志),则在CSR_PROCESS中设置。进程组可用于将控制事件发送给一组共享了同一控制台进程

  5. 分配并初始化Csrss线程结构(CSR_THREAD)

  6. CsrCreateThread将该线程插入到进程的线程列表

  7. 递增会话中的进程计数

  8. 进程的关机级别(shutdown level)设置为0x280,这是默认的进程关机级别

  9. 新建的Csrss进程结构被插入到Windows子系统范围内的进程列表

6.初始线程的启动执行

由于上面创建线程对象的时候是以挂起的形式创建的,所以现在需要通过NtResumeThread来恢复线程的执行

.text:7C819FC3 loc_7C819FC3:             
.text:7C819FC3                 test    byte ptr [ebp+dwCreationFlags], CREATE_SUSPENDED
.text:7C819FC7                 jnz     short loc_7C819FDC
.text:7C819FC9                 lea     eax, [ebp+SuspendCount]
.text:7C819FCF                 push    eax             ; SuspendCount
.text:7C819FD0                 push    [ebp+ThreadHandle] ; ThreadHandle
.text:7C819FD6                 call    ds:__imp__NtResumeThread@8 ; NtResumeThread(x,x)

7.在新线程的上下文中执行进程初始化工作

此时新创建的进程中的初始线程正式开始工作,由于进程中还有一些资源需要初始化以后才可以保证线程的正常运行。所以,线程最开始的工作依然是对进程的初始化,这部分内容较多,之后再详细说。

四.系统调用NtCreateProcess

上面说到,创建进程过程中会通过系统调用NtCreateProcess来创建进程的内核对象,而再该函数中则是对几个参数进行检验并赋值相应的标记以后就调用NtCreateProcessEx来完成操作。其中参数InherObjectTable说明新创建的进程是否要继承父进程的句柄表,如果要,则参数ParentProcess就是父进程的句柄,一般这就是当前进程,但也可以不是。换言之,当前进程可以为别的进程创建子进程,让新创建的进程从别的进程继承句柄表,实际上还包括一些资源的配额和有关的属性。另一个参数SectionHandle是一个文件映射区的句柄,这个映射区代表目标映像文件。最后两个进程间的通信端口DebugPort和ExceptionPort的句柄。顾名思义,这两个端口是供新创进程发送调试信息和异常处理信息的端口,是可以为所有进程共用的系统资源。

PAGE:004DFDCD ; NTSTATUS __stdcall NtCreateProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, BOOLEAN InheritObjectTable, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort)
PAGE:004DFDCD _NtCreateProcess@32 proc near           ; DATA XREF: .text:0040D8DC↑o
PAGE:004DFDCD
PAGE:004DFDCD ProcessHandle   = dword ptr  8
PAGE:004DFDCD DesiredAccess   = dword ptr  0Ch
PAGE:004DFDCD ObjectAttributes= dword ptr  10h
PAGE:004DFDCD ParentProcess   = dword ptr  14h
PAGE:004DFDCD InheritObjectTable= byte ptr  18h
PAGE:004DFDCD SectionHandle   = dword ptr  1Ch
PAGE:004DFDCD DebugPort       = dword ptr  20h
PAGE:004DFDCD ExceptionPort   = dword ptr  24h
PAGE:004DFDCD
PAGE:004DFDCD ; FUNCTION CHUNK AT PAGE:0052E198 SIZE 00000016 BYTES
PAGE:004DFDCD
PAGE:004DFDCD                 mov     edi, edi
PAGE:004DFDCF                 push    ebp
PAGE:004DFDD0                 mov     ebp, esp
PAGE:004DFDD2                 xor     eax, eax
PAGE:004DFDD4                 test    byte ptr [ebp+SectionHandle], 1
PAGE:004DFDD8                 jnz     loc_52E198
PAGE:004DFDDE
PAGE:004DFDDE loc_4DFDDE:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+4E3CC↓j
PAGE:004DFDDE                 test    byte ptr [ebp+DebugPort], 1
PAGE:004DFDE2                 jnz     loc_52E19E
PAGE:004DFDE8
PAGE:004DFDE8 loc_4DFDE8:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+4E3D4↓j
PAGE:004DFDE8                 cmp     [ebp+InheritObjectTable], 0
PAGE:004DFDEC                 jnz     loc_52E1A6
PAGE:004DFDF2
PAGE:004DFDF2 loc_4DFDF2:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+4E3DC↓j
PAGE:004DFDF2                 push    0               ; InJob
PAGE:004DFDF4                 push    [ebp+ExceptionPort] ; ExceptionPort
PAGE:004DFDF7                 push    [ebp+DebugPort] ; DebugPort
PAGE:004DFDFA                 push    [ebp+SectionHandle] ; SectionHandle
PAGE:004DFDFD                 push    eax             ; Flags
PAGE:004DFDFE                 push    [ebp+ParentProcess] ; ParentProcess
PAGE:004DFE01                 push    [ebp+ObjectAttributes] ; ObjectAttributes
PAGE:004DFE04                 push    [ebp+DesiredAccess] ; DesiredAccess
PAGE:004DFE07                 push    [ebp+ProcessHandle] ; ProcessHandle
PAGE:004DFE0A                 call    _NtCreateProcessEx@36 ; NtCreateProcessEx(x,x,x,x,x,x,x,x,x)
PAGE:004DFE0F                 pop     ebp
PAGE:004DFE10                 retn    20h
PAGE:004DFE10 _NtCreateProcess@32 endp
                    。。。
PAGE:0052E198 loc_52E198:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+B↑j
PAGE:0052E198                 inc     eax
PAGE:0052E199                 jmp     loc_4DFDDE
PAGE:0052E19E ; ---------------------------------------------------------------------------
PAGE:0052E19E
PAGE:0052E19E loc_52E19E:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+15↑j
PAGE:0052E19E                 or      eax, 2
PAGE:0052E1A1                 jmp     loc_4DFDE8
PAGE:0052E1A6 ; ---------------------------------------------------------------------------
PAGE:0052E1A6
PAGE:0052E1A6 loc_52E1A6:                             ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+1F↑j
PAGE:0052E1A6                 or      eax, 4
PAGE:0052E1A9                 jmp     loc_4DFDF2

NtCreateProcessEx函数首先就是对PreviousMode进行判断

PAGE:004B4A0C ; NTSTATUS __stdcall NtCreateProcessEx(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort, BOOLEAN InJob)
PAGE:004B4A0C _NtCreateProcessEx@36 proc near         ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+3D↓p
PAGE:004B4A0C                                         ; DATA XREF: .text:0040D8E0↑o
PAGE:004B4A0C
PAGE:004B4A0C var_1C          = dword ptr -1Ch
PAGE:004B4A0C ms_exc          = CPPEH_RECORD ptr -18h
PAGE:004B4A0C ProcessHandle   = dword ptr  8
PAGE:004B4A0C DesiredAccess   = dword ptr  0Ch
PAGE:004B4A0C ObjectAttributes= dword ptr  10h
PAGE:004B4A0C ParentProcess   = dword ptr  14h
PAGE:004B4A0C Flags           = dword ptr  18h
PAGE:004B4A0C SectionHandle   = dword ptr  1Ch
PAGE:004B4A0C DebugPort       = dword ptr  20h
PAGE:004B4A0C ExceptionPort   = dword ptr  24h
PAGE:004B4A0C InJob           = byte ptr  28h
PAGE:004B4A0C                 push    0Ch
PAGE:004B4A0E                 push    offset stru_4285B0
PAGE:004B4A13                 call    __SEH_prolog
PAGE:004B4A18                 mov     eax, large fs:124h ; 获取当前线程地址
PAGE:004B4A1E                 xor     edx, edx
PAGE:004B4A20                 cmp     [eax+140h], dl  ; PreviousMode是否为0
PAGE:004B4A26                 jz      loc_4E9036

如果不为0,说明是从用户层模式调用的函数,此时就需要对句柄是否可读进行验证

PAGE:004B4A2F                 mov     ecx, [ebp+ProcessHandle]
PAGE:004B4A32                 mov     eax, _MmUserProbeAddress
PAGE:004B4A37                 cmp     ecx, eax
PAGE:004B4A39                 jnb     loc_52E165
PAGE:004B4A3F loc_4B4A3F:                             ; CODE XREF: NtCreateProcessEx(x,x,x,x,x,x,x,x,x)+7975B↓j
PAGE:004B4A3F                 mov     eax, [ecx]
PAGE:004B4A41                 mov     [ecx], eax

接着判断父进程句柄是否为空,如果是则报错

PAGE:004B4A47 loc_4B4A47:                             ; CODE XREF: NtCreateProcessEx(x,x,x,x,x,x,x,x,x)+3462D↓j
PAGE:004B4A47                 cmp     [ebp+ParentProcess], edx ; 判断父进程句柄是否为NULL
PAGE:004B4A4A                 jz      loc_4E903E
            。。。
PAGE:004E903E loc_4E903E:                             ; CODE XREF: NtCreateProcessEx(x,x,x,x,x,x,x,x,x)+3E↑j
PAGE:004E903E                 mov     eax, STATUS_INVALID_PARAMETER
PAGE:004E9043                 jmp     loc_4B4A6E

如果不是则将参数入栈以后调用PspCreateProcess

PAGE:004B4A50                 push    dword ptr [ebp+InJob] ; int
PAGE:004B4A53                 push    [ebp+ExceptionPort] ; HANDLE
PAGE:004B4A56                 push    [ebp+DebugPort] ; HANDLE
PAGE:004B4A59                 push    [ebp+SectionHandle] ; HANDLE
PAGE:004B4A5C                 push    [ebp+Flags]     ; int
PAGE:004B4A5F                 push    [ebp+ParentProcess] ; Handle
PAGE:004B4A62                 push    [ebp+ObjectAttributes] ; int
PAGE:004B4A65                 push    [ebp+DesiredAccess] ; AccessMask
PAGE:004B4A68                 push    ecx             ; int
PAGE:004B4A69                 call    _PspCreateProcess@36 ; PspCreateProcess(x,x,x,x,x,x,x,x,x)

在PspCreateProcess函数中首先会对局部变量进行赋值,然后会判断创建标志中是否有相关标志

PAGE:004B450E ; int __stdcall PspCreateProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel)
PAGE:004B450E _PspCreateProcess@36 proc near          ; CODE XREF: NtCreateProcessEx(x,x,x,x,x,x,x,x,x)+5D↓p
PAGE:004B450E                                         ; PsCreateSystemProcess(x,x,x)+1B↓p ...
PAGE:004B450E
PAGE:004B450E var_12C         = dword ptr -12Ch
PAGE:004B450E var_B8          = dword ptr -0B8h
PAGE:004B450E var_9C          = dword ptr -9Ch
PAGE:004B450E SubjectSecurityContext= _SECURITY_SUBJECT_CONTEXT ptr -98h
PAGE:004B450E var_88          = dword ptr -88h
PAGE:004B450E var_CurThraed   = dword ptr -84h
PAGE:004B450E ParentProcObject= dword ptr -80h
PAGE:004B450E var_7C          = dword ptr -7Ch
PAGE:004B450E var_78          = dword ptr -78h
PAGE:004B450E var_74          = dword ptr -74h
PAGE:004B450E var_70          = dword ptr -70h
PAGE:004B450E var_6C          = dword ptr -6Ch
PAGE:004B450E var_WorkingSetMaximum= dword ptr -68h
PAGE:004B450E var_Affinity    = dword ptr -64h
PAGE:004B450E var_WorkingSetMinimum= dword ptr -60h
PAGE:004B450E var_5C          = dword ptr -5Ch
PAGE:004B450E var_CurEProcess = dword ptr -58h
PAGE:004B450E var_ProcObject  = dword ptr -54h
PAGE:004B450E var_50          = dword ptr -50h
PAGE:004B450E AccessStatus    = dword ptr -4Ch
PAGE:004B450E SpinLock        = dword ptr -48h
PAGE:004B450E var_44          = dword ptr -44h
PAGE:004B450E var_40          = dword ptr -40h
PAGE:004B450E var_3C          = dword ptr -3Ch
PAGE:004B450E MemoryAllocated = byte ptr -38h
PAGE:004B450E var_34          = dword ptr -34h
PAGE:004B450E BugCheckParameter1= dword ptr -30h
PAGE:004B450E SecurityDescriptor= dword ptr -2Ch
PAGE:004B450E var_28          = dword ptr -28h
PAGE:004B450E var_22          = byte ptr -22h
PAGE:004B450E AccessMode      = byte ptr -21h
PAGE:004B450E var_1D          = byte ptr -1Dh
PAGE:004B450E var_ParentProcObject= dword ptr -1Ch
PAGE:004B450E ms_exc          = CPPEH_RECORD ptr -18h
PAGE:004B450E ProcessHandle   = dword ptr  8
PAGE:004B450E AccessMask      = dword ptr  0Ch
PAGE:004B450E ObjectAttributes= dword ptr  10h
PAGE:004B450E ParentProcessHandle= dword ptr  14h
PAGE:004B450E Flags           = dword ptr  18h
PAGE:004B450E SectionHandle   = dword ptr  1Ch
PAGE:004B450E DebugPort       = dword ptr  20h
PAGE:004B450E ExceptionPort   = dword ptr  24h
PAGE:004B450E JobMemberLevel  = dword ptr  28h
PAGE:004B450E                 push    11Ch
PAGE:004B4513                 push    offset stru_4285C0
PAGE:004B4518                 call    __SEH_prolog
PAGE:004B451D                 mov     eax, large fs:124h ; 获取ETHREAD
PAGE:004B4523                 mov     [ebp+var_CurThraed], eax
PAGE:004B4529                 mov     cl, [eax+140h]  ; 获取PrevMode
PAGE:004B452F                 mov     [ebp+AccessMode], cl
PAGE:004B4532                 mov     eax, [eax+44h]  ; 获取当前进程EPROCESS
PAGE:004B4535                 mov     [ebp+var_CurEProcess], eax
PAGE:004B4538                 xor     esi, esi
PAGE:004B453A                 mov     [ebp+var_1D], 0
PAGE:004B453E                 mov     [ebp+SpinLock], esi
PAGE:004B4541                 mov     [ebp+var_44], esi
PAGE:004B4544                 test    [ebp+Flags], 0FFFFFFF0h ; 是否具有PROCESS_CREATE_FLAGS_LEGAL_MSK标志
PAGE:004B454B                 jnz     loc_52DE13

如果没有,则会返回错误

PAGE:0052DE13 loc_52DE13:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+3D↑j
PAGE:0052DE13                 mov     eax, STATUS_INVALID_PARAMETER
PAGE:0052DE18                 jmp     loc_4B49D0

接下来会判断是否有父进程句柄

PAGE:004B4551                 cmp     [ebp+ParentProcessHandle], esi
PAGE:004B4554                 jz      loc_4F1B06

如果没有,则会对会父进程的EPROCESS赋值为空且使用KeActiveProcessors来赋值eax

PAGE:004F1B06 loc_4F1B06:                          
PAGE:004F1B06                 mov     [ebp+var_ParentProcObject], esi
PAGE:004F1B09                 mov     eax, _KeActiveProcessors
PAGE:004F1B0E                 jmp     loc_4B458F

否则会调用ObReferenceObjectByHandle来获得父进程的对象地址,并且使用父进程的Affinity来赋值eax

PAGE:004B455A                 push    esi             ; HandleInformation
PAGE:004B455B                 lea     eax, [ebp+ParentProcObject]
PAGE:004B455E                 push    eax             ; Object
PAGE:004B455F                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:004B4562                 push    _PsProcessType  ; ObjectType
PAGE:004B4568                 push    PROCESS_CREATE_PROCESS ; DesiredAccess
PAGE:004B456D                 push    [ebp+ParentProcessHandle] ; Handle
PAGE:004B4570                 call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
PAGE:004B4575                 mov     ecx, [ebp+ParentProcObject] ; Object
PAGE:004B4578                 mov     [ebp+var_ParentProcObject], ecx
PAGE:004B457B                 cmp     eax, esi
PAGE:004B457D                 jl      loc_4B49D0
PAGE:004B458C loc_4B458C:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+798FA↓j
PAGE:004B458C                 mov     eax, [ecx+5Ch]  ; EPROCESS->Pcb.Affinity

接着在对局部变量进行赋值

PAGE:004B458F loc_4B458F:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+3D600↓j
PAGE:004B458F                 mov     [ebp+var_Affinity], eax
PAGE:004B4592                 mov     eax, ds:_PsMinimumWorkingSet
PAGE:004B4597                 mov     [ebp+var_WorkingSetMinimum], eax
PAGE:004B459A                 mov     eax, ds:_PsMaximumWorkingSet
PAGE:004B459F                 mov     [ebp+var_WorkingSetMaximum], eax

接下来就会通过ObCreateObject来在内核中创建进程对象并将创建的进程对象赋值到局部变量中

PAGE:004B45A2                 lea     eax, [ebp+var_ProcObject]
PAGE:004B45A5                 push    eax             ; Object
PAGE:004B45A6                 push    esi             ; NonPagedPoolCharge
PAGE:004B45A7                 push    esi             ; PagePoolCharge
PAGE:004B45A8                 push    260h            ; ObjectBodySize
PAGE:004B45AD                 push    esi             ; ParentContext
PAGE:004B45AE                 push    dword ptr [ebp+AccessMode] ; OwnershipMode
PAGE:004B45B1                 push    [ebp+ObjectAttributes] ; ObjectAttributes
PAGE:004B45B4                 push    _PsProcessType  ; ObjectType
PAGE:004B45BA                 push    dword ptr [ebp+AccessMode] ; PreviousMode
PAGE:004B45BD                 call    _ObCreateObject@36 ; ObCreateObject(x,x,x,x,x,x,x,x,x)
PAGE:004B45C2                 mov     edi, eax
PAGE:004B45C4                 cmp     edi, esi
PAGE:004B45C6                 jl      loc_4B49C2
PAGE:004B45CC                 mov     ecx, 98h
PAGE:004B45D1                 xor     eax, eax
PAGE:004B45D3                 mov     ebx, [ebp+var_ProcObject] ; 将EPROCESS赋值给ebx
PAGE:004B45D6                 mov     edi, ebx
PAGE:004B45D8                 rep stosd

创建好了内核对象以后,就要开始完成对对象的初始化。要注意此时得到的地址指向的是内核对象的对象体,也就是EPROCESS结构,此时ebx的值保存的就是创建的进程对象的EPROCESS地址,所以接下来的代码执行的就是对其成员的赋值,根据上面的EPROCESS结构不难知道要赋值的内容

PAGE:004B45DA                 mov     [ebx+80h], esi  ; 将RundownProtect赋值为NULL
PAGE:004B45E0                 mov     [ebx+6Ch], esi  ; 将ProcessLock赋值为NULL
PAGE:004B45E3                 lea     eax, [ebx+190h] ; 取出ThreadListHead的地址赋给eax
PAGE:004B45E9                 mov     [eax+LIST_ENTRY.Blink], eax ; 为ThreadListHead初始化
PAGE:004B45EC                 mov     [eax+LIST_ENTRY.Flink], eax

初始化过程也包含了继承父进程资源和属性的过程。这里首先通过PspInheritQuota继承父进程的资源配额,在通过ObInheritDeviceMap继承父进程的(磁盘)设备位图DeviceMap

PAGE:004B45EE                 push    [ebp+var_ParentProcObject]
PAGE:004B45F1                 push    ebx
PAGE:004B45F2                 call    _PspInheritQuota@8 ; PspInheritQuota(x,x)
PAGE:004B45F7                 push    [ebp+var_ParentProcObject]
PAGE:004B45FA                 push    ebx
PAGE:004B45FB                 call    _ObInheritDeviceMap@8 ; ObInheritDeviceMap(x,x)

接下来判断是否存在父进程的对象

PAGE:004B4600                 mov     edi, [ebp+var_ParentProcObject]
PAGE:004B4603                 cmp     edi, esi
PAGE:004B4605                 jz      loc_4F1B13

如果不存在,则会为创建的进程初始化为默认数值

PAGE:004F1B13 loc_4F1B13:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+F7↑j
PAGE:004F1B13                 mov     dword ptr [ebx+1A8h], 1 ; 为DefaultHardErrorProcessing赋值为1
PAGE:004F1B1D                 mov     [ebx+14Ch], esi ; 为InheritedFromUniquePricessId赋值为0
PAGE:004F1B23                 jmp     loc_4B4623

否则就用父进程的数据来初始化创建的进程

PAGE:004B460B                 mov     eax, [edi+1A8h] ; 取出父进程的DefaultHardErrorProcessing
PAGE:004B4611                 mov     [ebx+1A8h], eax ; 将其赋给创建的进程的DefaultHardErrorProcessing
PAGE:004B4617                 mov     eax, [edi+84h]  ; 取出父进程的UniqueProcessId
PAGE:004B461D                 mov     [ebx+14Ch], eax ; 将其赋值给创建的进程的InheritedFromUniquePricessId

接着判断传入的SectionHandle是否为NULL

PAGE:004B4623                 cmp     [ebp+SectionHandle], esi
PAGE:004B4626                 jz      loc_4F1B28

如果不为空,则会通过函数来获得想要的对象地址并将其赋值到局部变量SectionObj中

PAGE:004B462C                 push    esi             ; HandleInformation
PAGE:004B462D                 lea     eax, [ebp+var_SectionObject]
PAGE:004B4633                 push    eax             ; Object
PAGE:004B4634                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:004B4637                 push    _MmSectionObjectType ; ObjectType
PAGE:004B463D                 push    SECTION_MAP_EXECUTE ; DesiredAccess
PAGE:004B463F                 push    [ebp+SectionHandle] ; Handle
PAGE:004B4642                 call    _ObReferenceObjectByHandle@24 
PAGE:004B4647                 mov     ecx, [ebp+var_SectionObject]
PAGE:004B464D                 mov     [ebp+var_SectionObj], ecx
PAGE:004B4650                 mov     edi, eax
PAGE:004B4652                 cmp     eax, esi
PAGE:004B4654                 jl      loc_4B49BB

如果为空会对父进程进行判断

PAGE:004F1B28 loc_4F1B28:                             
PAGE:004F1B28                 mov     [ebp+var_SectionObj], esi
PAGE:004F1B2B                 cmp     edi, _PsInitialSystemProcess
PAGE:004F1B31                 jz      loc_4B465D
PAGE:004F1B37                 jmp     loc_52DE63

如果父进程为PsInitialSystemProcess则会对SectionObj赋值为空,否则会将父进程的SectionObject赋给局部变量SectionObj,注意此时的edi指向的是父进程对象

PAGE:0052DE63 loc_52DE63:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+3D629↑j
PAGE:0052DE63                 lea     ecx, [edi+80h]  ; 取出RunDownProtect
PAGE:0052DE69                 call    @ExAcquireRundownProtection@4 ; ExAcquireRundownProtection(x)
PAGE:0052DE6E                 test    al, al
PAGE:0052DE70                 jz      short loc_52DE8F
PAGE:0052DE72                 mov     ecx, [edi+138h] ; 取出父进程SectionObjection
PAGE:0052DE78                 mov     [ebp+var_SectionObj], ecx

随后将局部变量赋值到创建的进程的SectionObject中

PAGE:004B465D loc_4B465D:                  
PAGE:004B465D                 mov     eax, [ebp+var_SectionObj]
PAGE:004B4660                 mov     [ebx+138h], eax ; 赋值给创建的进程的SectionObject

接下来函数会判断是否有DebugPort句柄,有的话获取对象地址然后赋值到当前进程中

PAGE:004B4666                 cmp     [ebp+DebugPort], esi
PAGE:004B4669                 jnz     loc_52DE1D
            。。。
PAGE:0052DE1D loc_52DE1D:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+15B↑j
PAGE:0052DE1D                 push    esi             ; HandleInformation
PAGE:0052DE1E                 lea     eax, [ebp+var_DebugPortObj]
PAGE:0052DE21                 push    eax             ; Object
PAGE:0052DE22                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0052DE25                 push    _DbgkDebugObjectType ; ObjectType
PAGE:0052DE2B                 push    2               ; DesiredAccess
PAGE:0052DE2D                 push    [ebp+DebugPort] ; Handle
PAGE:0052DE30                 call    _ObReferenceObjectByHandle@24 ;
PAGE:0052DE35                 mov     edi, eax
PAGE:0052DE37                 cmp     edi, esi
PAGE:0052DE39                 jl      loc_4B49BB
PAGE:0052DE3F                 mov     eax, [ebp+var_DebugPortObj]
PAGE:0052DE42                 mov     [ebx+0BCh], eax ; 将DebugPortObj地址赋值给当前进程的DebugPort

接着在判断ExceptionPort句柄是否存在,存在的话依然是获取对象地址后赋值到当前进程中

PAGE:004B467A                 cmp     [ebp+ExceptionPort], esi
PAGE:004B467D                 jnz     loc_52DEA2
            。。。
PAGE:0052DEA2 loc_52DEA2:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+16F↑j
PAGE:0052DEA2                 push    esi             ; HandleInformation
PAGE:0052DEA3                 lea     eax, [ebp+var_ExceptionPortObj]
PAGE:0052DEA6                 push    eax             ; Object
PAGE:0052DEA7                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0052DEAA                 push    _LpcPortObjectType ; ObjectType
PAGE:0052DEB0                 push    esi             ; DesiredAccess
PAGE:0052DEB1                 push    [ebp+ExceptionPort] ; Handle
PAGE:0052DEB4                 call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
PAGE:0052DEB9                 mov     edi, eax
PAGE:0052DEBB                 cmp     edi, esi
PAGE:0052DEBD                 jl      loc_4B49BB
PAGE:0052DEC3                 mov     eax, [ebp+var_ExceptionPortObj]
PAGE:0052DEC6                 mov     [ebx+0C0h], eax ; 赋值到当前进程的ExceptionPort
PAGE:0052DECC                 jmp     loc_4B4683

随后初始化创建的进程的退出状态及调用函数来设置父进程的安全属性

PAGE:004B4683 loc_4B4683:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+799BE↓j
PAGE:004B4683                 mov     dword ptr [ebx+24Ch], STATUS_PENDING ; 为当前进程的ExitStatus赋值
PAGE:004B468D                 push    ebx
PAGE:004B468E                 push    [ebp+var_ParentProcObject]
PAGE:004B4691                 call    _PspInitializeProcessSecurity@8
PAGE:004B4696                 mov     edi, eax
PAGE:004B4698                 cmp     edi, esi
PAGE:004B469A                 jl      loc_4B49BB

接下来会判断是否具有父进程对象

PAGE:004B46A0                 mov     edi, [ebp+var_ParentProcObject]
PAGE:004B46A3                 cmp     edi, esi
PAGE:004B46A5                 jz      loc_4FA05C

如果没有的话,就会将当前进程的句柄表赋值给创建的进程并调用函数来完成进程地址空间的初始化

PAGE:004FA05C loc_4FA05C:                             ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+197↑j
PAGE:004FA05C                 mov     eax, [ebp+var_CurEProcess]
PAGE:004FA05F                 mov     eax, [eax+0C4h] ; 将当前进程的ObjectTable赋值给eax
PAGE:004FA065                 mov     [ebx+0C4h], eax ; 将eax赋值给创建的进程的ObjectTable
PAGE:004FA06B                 lea     eax, [ebp+SpinLock]
PAGE:004FA06E                 push    eax             ; SpinLock
PAGE:004FA06F                 push    ebx             ; int
PAGE:004FA070                 call    _MmInitializeHandBuiltProcess@8 ; MmInitializeHandBuiltProcess(x,x)
PAGE:004FA075                 jmp     loc_4B46C0

如果有的话,就会直接通过函数为新进程创建地址空间,并构建页目录表,页表及物理页的关系

PAGE:004B46AB                 lea     eax, [ebp+SpinLock]
PAGE:004B46AE                 push    eax             ; SpinLock
PAGE:004B46AF                 push    ebx             ; int
PAGE:004B46B0                 push    [ebp+var_WorkingSetMinimum] ; int
PAGE:004B46B3                 call    _MmCreateProcessAddressSpace@12 ; MmCreateProcessAddressSpace(x,x,x)
PAGE:004B46B8                 test    al, al
PAGE:004B46BA                 jz      loc_52DF97

在对创建的进程成员赋值以后继续调用函数来初始化进程的优先级,页面映射表等等

PAGE:004B46C0                 mov     eax, 40000h
PAGE:004B46C5                 lea     ecx, [ebx+248h] ; 将Flags的地址赋给ecx
PAGE:004B46CB                 lock or [ecx], eax      ; 对ecx地址中保存的内容进程异或操作
PAGE:004B46CE                 mov     eax, [ebp+var_WorkingSetMaximum]
PAGE:004B46D1                 mov     [ebx+214h], eax
PAGE:004B46D7                 xor     eax, eax
PAGE:004B46D9                 mov     al, [ebx+1A8h]  ; 将DefaultHardErrorProcessing赋给al
PAGE:004B46DF                 and     eax, 0FFFFFF04h
PAGE:004B46E4                 push    eax
PAGE:004B46E5                 lea     eax, [ebp+SpinLock]
PAGE:004B46E8                 push    eax
PAGE:004B46E9                 push    [ebp+var_Affinity]
PAGE:004B46EC                 push    8
PAGE:004B46EE                 push    ebx
PAGE:004B46EF                 call    _KeInitializeProcess@20

调用函数来初始化创建的进程的句柄表,如果此时父进程被指定了,父进程的句柄表就会被拷贝到新进程中,句柄表中的每个对象的引用计数都加1

PAGE:004B4725                 push    ebx
PAGE:004B4726                 mov     eax, [ebp+Flags]
PAGE:004B4729                 and     al, 4
PAGE:004B472B                 neg     al
PAGE:004B472D                 sbb     eax, eax
PAGE:004B472F                 and     eax, [ebp+var_ParentProcObject]
PAGE:004B4732                 push    eax
PAGE:004B4733                 call    _ObInitProcess@8

调用函数初始化新创建进程地址空间

PAGE:004B474E                 lea     eax, [ebx+1F4h]
PAGE:004B4754                 push    eax             ; int
PAGE:004B4755                 push    [ebp+var_SectionObj] ; int
PAGE:004B4758                 push    esi             ; int
PAGE:004B4759                 push    ebx             ; P
PAGE:004B475A                 call    _MmInitializeProcessAddressSpace@16

调用函数将进程对象的系统DLL(NTDLL.DLL)映射到创建的进程空间中

PAGE:004B476C                 push    esi             ; int
PAGE:004B476D                 push    ebx             ; FastMutex
PAGE:004B476E                 call    _PspMapSystemDll@

调用函数获得新进程的会话ID以后在调用函数来设置令牌的会话ID

PAGE:004B4781                 mov     edi, [ebx+0C8h] ; 取出进创建进程的TOKEN
PAGE:004B4787                 and     edi, 0FFFFFFF8h ; 低3位清0
PAGE:004B478A                 push    ebx
PAGE:004B478B                 call    _MmGetSessionId@4 ; MmGetSessionId(x)
PAGE:004B4790                 push    eax             ; 新进程的会话ID
PAGE:004B4791                 push    edi
PAGE:004B4792                 call    _SeSetSessionIdToken@8

调用函数在全局句柄表PspCidTable中增加进程的句柄并获得进程PID,将返回值赋给新建进程

PAGE:004B4797                 mov     [ebp+var_NewEProcess], ebx
PAGE:004B479A                 mov     [ebp+var_6C], esi
PAGE:004B479D                 lea     eax, [ebp+var_NewEProcess]
PAGE:004B47A0                 push    eax
PAGE:004B47A1                 push    _PspCidTable
PAGE:004B47A7                 call    _ExCreateHandle@8
PAGE:004B47AC                 mov     [ebx+84h], eax  ; 将返回值赋给新进程的UniqueProcessId
PAGE:004B47B2                 cmp     eax, esi
PAGE:004B47B4                 jz      loc_52DF97

对句柄表所指向对象中的UniqueProcessId进程赋值,随后调用函数设置访问状态

PAGE:004B47BA                 mov     ecx, [ebx+0C4h] ; 将进程句柄表赋值给ecx
PAGE:004B47C0                 mov     [ecx+8], eax    ; 将返回值赋给句柄表对象中的UniqueProcessId
PAGE:004B47C3                 xor     ecx, ecx
PAGE:004B47C5                 call    @SeDetailedAuditingWithToken@4 ; SeDetailedAuditingWithToken(x)
PAGE:004B47CA                 test    al, al
PAGE:004B47CC                 jnz     loc_52DFA1

初始化局部变量为0以后,调用函数将新建对象的PEB赋值为0

PAGE:004B47F2                 xor     eax, eax
PAGE:004B47F4                 lea     edi, [ebp+var_InitPeb]
PAGE:004B47F7                 stosd                   ; 将局部变量InitPeb进行初始化为0
PAGE:004B4805                 lea     eax, [ebx+1B0h] ; 取出新建进程的PEB地址赋给eax
PAGE:004B480B                 push    eax             ; int
PAGE:004B480C                 lea     eax, [ebp+var_InitPeb]
PAGE:004B480F                 push    eax             ; int
PAGE:004B4810                 push    ebx             ; 新建进程的EPROCESS
PAGE:004B4811                 call    _MmCreatePeb@12

将新建进程的ActiveProcessLinks插入到全局链表PsActiveProcessHead尾部中

PAGE:004B4836                 lea     eax, [ebx+88h]  ; 取出新建进程的ActiveProcessLinks地址赋给eax
PAGE:004B483C                 mov     ecx, _PsActiveProcessHeadPlus4 ; 取出全局变量_PsActiveProcessHead+4的地址中的内容赋给ecx
PAGE:004B4842                 mov     [eax+LIST_ENTRY.Flink], offset _PsActiveProcessHead
PAGE:004B4848                 mov     [eax+LIST_ENTRY.Blink], ecx
PAGE:004B484B                 mov     [ecx+LIST_ENTRY.Flink], eax

调用SetCreateAccessStateEx设置状态访问以后,调用ObInsertObject将创建的对象插入到句柄表中

PAGE:004B4881                 mov     ecx, _PsProcessType
PAGE:004B4887                 add     ecx, 68h
PAGE:004B488A                 push    ecx             ; GenericMapping
PAGE:004B488B                 push    [ebp+AccessMask] ; AccessMask
PAGE:004B488E                 lea     ecx, [ebp+var_B8]
PAGE:004B4894                 push    ecx             ; int
PAGE:004B4895                 lea     ecx, [ebp+AccessState]
PAGE:004B489B                 push    ecx             ; int
PAGE:004B489C                 push    eax             ; int
PAGE:004B489D                 push    esi             ; int
PAGE:004B489E                 call    _SeCreateAccessStateEx@24
PAGE:004B48AD                 lea     eax, [ebp+ObjHandle]
PAGE:004B48B0                 push    eax             ; Handle
PAGE:004B48B1                 push    esi             ; NewObject
PAGE:004B48B2                 push    1               ; ObjectPointerBias
PAGE:004B48B4                 push    [ebp+AccessMask] ; DesiredAccess
PAGE:004B48B7                 lea     eax, [ebp+AccessState]
PAGE:004B48BD                 push    eax             ; PACCESS_STATE
PAGE:004B48BE                 push    ebx             ; Object
PAGE:004B48BF                 call    _ObInsertObject@2

最后设置了进程的访问权限和创建时间以后,就把新建进程的句柄赋值到输出参数ProcessHandle中,从而创建者可以获得新进程的句柄。

PAGE:004B49A6                 mov     eax, [ebp+ProcessHandle]
PAGE:004B49A9                 mov     ecx, [ebp+ObjHandle]
PAGE:004B49AC                 mov     [eax], ecx

下篇:Windows内核学习笔记之进程(下)


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2021-12-21 18:22 被1900编辑 ,原因:
收藏
点赞6
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回