整体过程如下:

需要说明两点:

1.在XP中,新进程主线程的启动,会先执行一个用户态的APC,会执行ntdll!LdrInitializeThunk进行程序执行前的一些列初始化操作。其中很重要任务就是加载从Kernel32.dll开始的系统DLL。注意的是,这个APC的插入,根据WRK中的代码看来是在PspUserThreadStartup中进行的:

但实际调试XP SP3发现,该函数并未有这个动作。并且在进入这个函数的时候APC已经插入好了。于是追踪到在XP SP3中,该APC的插入时机是在nt!PspCreateThread中进行的。

2.虽然XP和Win7都会在主线程Ring3入口(XP是BaseProcessStart,Win7是RtlUserThreadStart)前执行LdrInitializeThunk进行初始化,但二者细节处还是不同。

对于XP,如上所述,是通过nt!PspCreateThread在创建线程完成后插入APC,等到新进程主线程得到调度,在nt!KiThreadStartup完成后,跳到nt!_KiSystemExit处返回到用户模式时,该APC得到交付从而执行到。

而对于Win7,创建进程路径发生了大变化,不再有nt!PspCreateThread,而是nt! PspAllocateThread,这里面也没有插入APC的动作。即使追踪到nt!KiThreadStartup即将跳到nt!_KiSystemExit的位置,KTHREAD中的APC队列仍然没有LdrInitializeThunk这一项。按理说,这个时候返回就会到线程启动入口ntdll!RtlUserThreadStart才对。那LdrInitializeThunk怎么会执行呢?调试发现,在即将跳到nt!_KiSystemExit的时候,线程的KTRAP_FRAME中的EIP已经是LdrInitializeThunk而不是RtlUserThreadStart了。进一步跟踪发现,原来是在nt!PspCreateThread返回的前夕,通过nt!PspInitializeThunkContext—> nt!PspSetContextThreadInternal-->nt!PspGetSetContextSpecialApc-->nt!KeContextToKframes进行对KTRAP_FRAME进行修改了。通过函数名字也可以看出,这个动作是在模拟交付用户模式APC的动作。

因此,总结一下就是,对于XP,是通过正常的插入APC的形式,在线程内核启动函数完成后返回到用户模式时,触发了APC的交付。而对于Win7,则是在内核启动函数完成时,模拟出一个APC交付的过程,提前修改了KTRAP_FRAME,等到返回到用户模式时直接就从LdrInitializeThunk处开始执行。

LdrInitializeThunk执行完成后需要进入内核(通过NtContinue),重新进入到线程的用户态执行入口。由于在XP中是通过APC进入的,所以这个工作就不用LdrInitializeThunk来做,APC的执行器ntdll!KiUserApcDispatcher会负责这件事。但在Win7上并非通过APC执行的,所以调用NtContinue的工作需要LdrInitializeThunk自己来完成了。
Win7: 

最后说一下,经常见到在LoadImageNotify回调中做(用户态)APC注入。由图可见exe&ntdll的回调通知和后面加载的dll回调通知执行的路径不一样。最开始这两个模块是在DbgkCreateThread中执行回调的,后面的是通过MmMapViewOfSection-->MiMapViewOfImageSection执行的回调。而MmMapViewOfSection在回调执行之前会通过LOCK_ADDRESS_SPACE进行进程地址空间的锁定。这个时候再进行(用户态)APC注入,在使用ZwAllocateVirtualMemory分配shellcode的内存空间时会卡死在这里。所以(用户态)APC注入的时机是在ntdll的回调中,这之后就会面临卡死的问题。

一张图系列——从CreateProcess到main函数的过程的更多相关文章

  1. 一张图系列——为什么在DllMain里面创建了线程并Wait会卡死

    这是一个老话题了,推荐一篇文章: http://blog.csdn.net/breaksoftware/article/details/8150476#0-tsina-1-83826-39723281 ...

  2. Linux下main函数启动过程【程序员自我修养笔记】【自用】

    1. 入口函数和程序初始化 1.1 程序从main开始吗? 当程序执行到main函数的第一行时,很多事情都已经完成了: [证1]如下是一段C语言代码: 代码中可以看到,在程序刚刚执行到main的时候, ...

  3. .Net程序员学用Oracle系列(7):视图、函数、过程、包

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.视图 1.1.创建视图 2.函数 2.1.创建函数 2.2.调用函数 3.过程 3.1.创建过程 3.2.调用过程 4.包 ...

  4. linux编程之main()函数启动过程【转】

    转自:http://blog.csdn.net/gary_ygl/article/details/8506007 1 最简单的程序  1)编辑helloworld程序,$vim helloworld. ...

  5. 精华!一张图进阶 RocketMQ

    前 言 大家好,我是三此君,一个在自我救赎之路上的非典型程序员. "一张图"系列旨在通过"一张图"系统性的解析一个板块的知识点: 三此君向来不喜欢零零散散的知识 ...

  6. Nginx源码分析:3张图看懂启动及进程工作原理

    编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」.   导读:很多工程师及架构师都希望了解及掌握高性能服务器 ...

  7. 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域

    × 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...

  8. 一张图进阶 RocketMQ - 整体架构

    前 言 三此君看了好几本书,看了很多遍源码整理的 一张图进阶 RocketMQ 图片链接,关于 RocketMQ 你只需要记住这张图!如果你第一次看到这个系列,墙裂建议你打开链接.觉得不错的话,记得点 ...

  9. 一张图进阶 RocketMQ - 消息发送

    前 言 三此君看了好几本书,看了很多遍源码整理的 一张图进阶 RocketMQ 图片链接,关于 RocketMQ 你只需要记住这张图!觉得不错的话,记得点赞关注哦. [重要]视频在 B 站同步更新,欢 ...

随机推荐

  1. django test

    django的单元测试 官方文档:https://docs.djangoproject.com/en/dev/topics/testing/ 相对于自己封装urllib/urllib2/request ...

  2. wget 断点续传 & nginx文件服务器

    nginx默认支持断点续传: 测试方法: wget -S http://httpd.apache.org/images/httpd_logo_wide_new.png 2>&1 | gr ...

  3. JSON 的标准:双引号而非单引号!

    刚刚测试发现一段很简单的.看似正确的代码却是错误的: <?php $json_str = "{'name':'Eric', 'age':23}"; var_dump(json ...

  4. ubuntu-docker-consul-swarm-shipyard-portainer

    --- env --- root@node1:~# cat /etc/issueUbuntu 12.04.4 LTS \n \l root@node1:~# docker -vDocker versi ...

  5. xtrabackup 使用说明(续)

    背景: 关于物理备份工具xtrabackup的一些说明可以先看之前写过的文章说明:xtrabackup 安装使用.现在xtrabackup版本升级到了2.4.4,相比之前的2.1有了比较大的变化:in ...

  6. excel小技巧

    数据呈文本格式,怎么改成数字? 数据前有'号,如何去掉? 为什么数据格式在修改后需要再双击一下单元格才改过来了? 解决办法:你选中需要更改格式的那列              数据          ...

  7. DataTable导出到Excel

    简单的导出到Excel中: 代码如下: using System; using System.Collections.Generic; using System.Data; using System. ...

  8. 解决VMware虚拟机宿主机与虚拟机通讯慢

    本地连接--> 属性 --> 配置(C) -->高级 页面的属性框中找到"Large Send Offload"(中文名称叫:大量传送减负)==>Disab ...

  9. splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目

    删除位于 index 2 的元素,并添加一个新元素来替代被删除的元素: <script type="text/javascript"> var arr = new Ar ...

  10. 搜索引擎广告过滤Chrome插件

    搜索广告屏蔽Chrome插件:自动过滤:百度,360,搜狗,google,bing的搜索广告,让魏则西的悲剧不再重演.珍爱生命,远离搜索广告! 下载:FuckAd.zip 安装:方法自行百度. 关闭百 ...