映射文件到内存中
createprocess函数会调用kernel32中的CreateProcessInternalW函数并检查参数和目标文件是否正确,根据结果执行必要操作后,ntdll中的NTCreateUserProcess会先创建程序的区域对象,创建区域对象时,文件并没有创建对应的内存映射关系,只有在调用mapviewoffile的时候才会创建文件到虚拟内存的映射关系,映射关系创建完成后,文件的内容也并没有被实际加载到内存,操作系统只是为文件分配了一个虚拟内存的空间并与文件相关联,等虚拟内存和物理内存建立关系后,操作系统在文件被访问时才会进行实际的内存映射。
区域对象
区域对象在关联一个硬盘上具体的文件的时候代表的就是虚拟内存即将要映射的具体文件,调用mapviewoffile函数后操作系统才会真正将文件和虚拟内存的建立映射关系。建立了映射关系后可以理解成内核中出现了一张映射表,代表了从磁盘上某个文件到虚拟内存的映射关系,如果操作系统要加载文件到内存,则会按照这张表上的信息进行加载。但此时并没有发生任何实际的将文件载入内存的行为,只是产生了映射行为,生成了映射表。
当不关联磁盘上具体的文件时,区域对象就可以代表一段可共享的虚拟内存。
创建进程执行体对象和线程执行体对象
- NTCreateUserProcess调用PspAllocateProcess创建内核中的进程对象执行体,本质是创建eprocess(其中存在kprocess,pcb),创建ntdll.dll。
- NTCreateUserProcess接着会调用PspCreateThread函数来创建线程执行体对象,进而创建初始线程,不过此时这个线程是挂起状态。
初始化windows子系统环境并启动初始线程
- 初始化windows子系统环境,收集SxS和软件策略等大量信息发送给csrss。让子系统知道是什么线程即将被启动。
- 如果指定了create_suspended,会停在这一步,如果是调试器模式,默认也会停在这一步,此时Ntdll.dll的LdrInitialThunk并未执行,进程的内存中只有ntdll.dll这一个dll。
- 从Ntdll.dll的LdrInitialThunk处启动初始线程,还会初始化用户空间执行环境例如初始化堆管理器,初始化IAT并加载必要的dll等工作。此时会有ntdll.dll中的各种ldr开头的函数参与,这种函数统称为映像加载函数.这些函数的最后一步是建立依赖项的关系图(dll与dll之间的依赖关系).
- 操作系统强行将线程的eip改为RtUserThreadStart函数的入口点,RtUserThreadStart函数的参数是用户希望线程真正执行的函数,和此函的参数。
- ntdll.dll中的RtUserThreadStart调用kernel32.dll中的BaseThreadInitThunk,将用户真正要执行的函数的参数压入栈中,然后调用用户真正希望执行的函数,一般是入口点函数。