一、背景

为了确保被替换后的进程能顺利执行不崩溃,需要获取原进程各种上下文,并修改被替换后的新进程上下文,其中在原进程被挂起还没开始执行的时候,需要将eax指向新oep,而ebx指向新peb,而为什么这样设置的原因却很少有人提及。为此,在经过查阅了一定的资料与简单的分析后,我们可以找到答案。

二、具体分析

先抛出结论,这里的eax与ebx属于线程上下文信息,在一个PE文件开始被运行的过程中,主线程上下文初始化过程是在进程已经创建完成,而主线程还没创建的阶段发生的,下面是具体更详细的分析:

首先我们需要对进程的创建有一个大概的认识,在ring3下创建进程API无非是CreateProcessA/W,但是无论调用哪一个,最终都会将相关参数转化为Unicode字符串,并最终调用CreateProcessInternalW,因此以下将主要分析CreateProcessInternalW,而在xp和win7下,它具体实现又有一些不一样的地方。

2.1 XP下执行流程
在xp下,它大概分为四个部分,分别是ring3下创建进程,ring0下创建进程,ring3下创建线程,ring0下创建线程,以NtCreateProcessEx为分界线,NtCreateProcessEx之前为ring3下创建进程主要流程。

2.1.1 Ring3下创建进程

  1. 判断处理dwCreationFlag各种标志位,包括是否包含不合法标记组合,判断优先级。
  2. 判断lpEnvironment是否为空,不为空则调用RtlAnsiStringToUnicodeString将其转为UniCode字符串。
  3. 判断lpApplicationName、lpCommandLine是否为空。

    如果lpApplicationName不为空直接调用RtlDosPathNameToNtPathName_U函数将DOS路径(C:\WINDOWS\XXX)转换为NT路径(\Device\HarddiskVolume1\WINDOWS\XXX),为空则会解析lpCommandLine,主要按照’”’引号,’ ’空格,’\t’制表符作为分隔符进行解析并获取相应的PE文件,然后将DOS路径转换为NT路径。




4. 调用NtOpenFile得到文件句柄,调用了NtCreateSectiond函数得到内存区对象句柄。

  1. 调用BasepIsProcessAllowed函数, 该函数用来判断应用程序名是否在授权文件列表中。

  2. 之后会经过一大段的函数进行各种校验,再得到内存区对象句柄后调用NtQuerySection函数,返回后得到节的基本信息(节基地址,大小,属性),并判断创建标志中是否包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS,如果不包含该标志,则判断PEB->ReadImageFileExecOptions域是否为0,如果包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS,或者不包含该标志但ReadImageFileExecOptions域不为0, 调用LdrQueryImageFileExecutionOptions函数查询该信息。

  3. 之后会经过一大段的函数进行各种校验,再得到内存区对象句柄后调用NtQuerySection函数,返回后得到节的基本信息(节基地址,大小,属性),并判断创建标志中是否包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS,如果不包含该标志,则判断PEB->ReadImageFileExecOptions域是否为0,如果包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS,或者不包含该标志但ReadImageFileExecOptions域不为0, 调用LdrQueryImageFileExecutionOptions函数查询该信息。

  4. 检查镜像文件的部分信息的有效性,并调用函数BasepIsImageVersionOk判断镜像文件版本是否合法。

  5. 加载advapi32.dll并获得CreateProcessAsUserSecure函数的地址。

  6. 调用BaseFormatObjectAttributes将安全属性结构格式为NT对象属性结构(得到了对象属性),接着调用了_DbgUiConnectToDbg在实现通过调用NtCreateDebugObject函数来创建调试对象,调用DbgUiGetThreadDebugObject来获得调试对象(作为参数传递到0环)。

  7. 最后调用NtCreateProcessEx函数。

    2.1.2 Ring0下创建进程
    NtCreateProcessEx内为ring0下创建进程主要流程。

  8. 判断父进程是否存在,若不存在则退出,否则,调用PspCreateProcess。

  1. 在PspCreateProcess中,保存当前线程运行的前一个模式,通过KTHREAD->PreviousMode可以得到前一个模式,并判断创建标志是否包含除DEBUG_PROCESS, DEBUG_ONLY_THIS_PROCESS,CREATE_SUSPENDED的标志之外其它标志, 如果包含其他的标志,则报错退出。

  2. 通过参数ParentProcess调用ObReferenceObjectByHandle函数得到父进程对象的指针。

  3. 判断参数 JobMemberLevel是否为0, 如果不为0,接着判断父进程的EPROCESS->Job是否为0,如果JobMemberLevel不为为0且EPROCESS->Job为0,则返回无效参数错误后退出该函数;否则的话,将父进程对象中的属性保存到局部变量中。

  4. 调用ObCreateObject函数创建新进程对象并将对象内容初始化为0,然后从父进程继承配额信息(PspInheritQuot)和设备位图信息(ObInheritDeviceMap),将父进程对象中的部分域给新进程。

  5. 判断参数SectionHandle是否为0,若不为0,调用ObReferenceObjectByHandle函数得到区对象指针,然后将区对象指针赋值给新进程EPROCESS的相应域。

  6. 接着就判断参数DebugPort是否为0,若不为0,调用ObReferenceObjectByHandle函数通过调试对象句柄得到调试对象指针,否则调用DbgkCopyProcessDebugPort函数从父进程拷贝DebugPort给新进程。

  7. 判断参数ExceptionPort是否为0,若不为0,调用ObReferenceObjectByHandle函数通过异常端口对象句柄得到异常端口对象指针。

  8. 接着调用PspInitializeProcessSecurity函数来设置新进程的安全属性, 主要是设置新进程的安全令牌对象。该函数会调用SeSubProcessToken函数来设置新进程对象的令牌对象。

  9. 接着调用MmCreateProcessAddressSpace为新进程创建地址空间,并构建页目录表、页表及物理页的关系。

  10. 调用KeInitializeProcess函数初始化新进程对象中内核对象、优先级、亲和性、页目录表物理地址帧号。

  11. 调用ObInitProcess函数来初始化新进程对象的表。

  12. 调用MmInitializeProcessAddressSpace函数初始化进程地址空间,该函数的实现中调用了KiAttachProcess函数来实现进程的切换(将当前线程挂靠到新进程中),以及初始化EPROCESS中的部分域和PFN、工作集列表等。

  13. 调用PspMapSystemDll函数映射新进程对象的系统DLL(即NTDLL,映射第一个DLL),该函数会调用MmMapViewOfSection映射节区,而MmMapViewOfSection会调用MiMapViewOfImageSection函数将DLL作为镜像映射。

  14. 接着调用MmGetSessionId函数获得指定进程的会话ID,然后调用SeSetSessionIdToken函数设置令牌的会话ID,之后再调用ExCreateHandle函数在PspCidTable中添加一项(PID)。

  15. 调用MmCreatePeb为新进程创建PEB,该函数首先通过调用KeAttachProcess函数将当前线程切换到新进程对象,然后通过MmMapViewOfSection函数将NLS节区映射到新进程的地址空间中,随后调用MiCreatePebOrTeb创建PEB/TEB。

    在MiCreatePebOrTeb函数中,该函数首先会通过ExAllocatePoolWithTag来申请0x34大小的空间,接着通过MiFindEmptyAddressRangeDownTree函数在VAD树中查找一块未被使用的地址空间范围,并返回该范围的起始地址,最后通过MiInsertVad函数将申请的地址空间插入到VAD树中。



在创建PEB结构后,初始化PEB中部分域的值(镜像基地址,操作系统编译号等域),最后调用KeDetachProcess函数使线程回到原来的线程中。截止此步骤,PEB创建完成。


同时观察也可以发现,这里也解析了包括Nt头、扩展头、扩展头魔术字效验等关键PE结构信息,联想到之前分析流程也处理了一部分PE结构,可以猜测早期的PE文件结构逆向可能也是通过逆向进程创建过程,即逆向CreateProcess API来实现的。

  1. 最后将新进程对象EPROCESS.ActiveProcessLinks更新为全局的活动进程链表(PsActiveProcessHead), 判断父进程是否为系统进程,调用SeCreateAccessStateEx设置访问状态,调用ObInsertObject函数将进程对象加入到进程对象的句柄表中,并通过KeQuerySystemTime(获取当前系统时间)结束PspCreateProcess的调用,完成ring0下进程的创建。

    接下来我们回到CreateProcessInternalW,以NtCreateThread为分界线,NtCreateProcessEx之后到NtCreateThread之前为ring3下创建线程流程,而NtCreateThread内则是ring0下创建线程流程,经过分析发现,我们所需要寻找的线程上下文设置其实就在ring3下创建线程流程内。

【安全报告】揭秘创建进程时ebx为什么指向peb的答案相关推荐

  1. linux创建进程读共享写复制,Linux下进程的创建、执行和终止

    1)进程的创建和执行 许多操作系统提供的都是产生进程的机制,也就是说,首先在新的地址空间里创建进程.读入可执行文件,后再开始执行.Linux中进程的创建很特别,它把上述步骤分解到两个单独的函数中去执行 ...

  2. 循环中fork创建进程的个数

    linux下创建进程的系统调用是fork.其定义如下 #include <sys/types.h> #include <unistd.h> pid_t fork(); 在循环中 ...

  3. C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?

    在 .NET 中创建进程时,可以传入 ProcessStartInfo 类的一个新实例.在此类型中,有一个 UseShellExecute 属性. 本文介绍 UseShellExecute 属性的作用 ...

  4. 操作系统实验报告5:进程的创建和终止

    操作系统实验报告5 实验内容 实验内容:进程的创建和终止. 编译运行课件 Lecture 06 例程代码:Algorithm 6-1 ~ 6-6. 实验环境 架构:Intel x86_64 (虚拟机) ...

  5. 蛤蟆吃服务器显示无网络,hamachi创建网络时服务器报告了一个错误.doc

    hamachi创建网络时服务器报告了一个错误 hamachi创建网络时服务器报告了一个错误 蛤蟆吃无法连接到服务器怎么办 蛤蟆吃无法连接到服务器 如果出现这样的情况 先打开运行 后输入 service ...

  6. oracle杀死进程时权限不足_在oracle中创建函数时权限不足

    我对oracle有一点了解.我试图创建一个如下所示的函数.在oracle中创建函数时权限不足 CREATE OR REPLACE FUNCTION "BOOK"."CON ...

  7. 深入探索.NET内部了解CLR如何创建运行时对象

    前言 SystemDomain, SharedDomain, and DefaultDomain. 对象布局和内存细节. 方法表布局. 方法分派(Method dispatching). 因为公共语言 ...

  8. [转载]深入探索.NET框架内部了解CLR如何创建运行时对象

    深入探索.NET框架内部了解CLR如何创建运行时对象 发布日期: 9/19/2005 | 更新日期: 9/19/2005 Hanu Kommalapati Tom Christian 本文讨论: • ...

  9. Linux C : 进程管理实验:创建进程、上下文切换

    进程可以看成程序的执行过程,可以展示在当前时刻的执行状态.它是程序在一个数据集合上的一次动态执行的过程.这个数据集合通常包含存放可执行代码的代码段,存放初始化全局变量和初始化静态局部变量的数据段.用于 ...

最新文章

  1. 线程池之CachedThreadPool学习
  2. js请求结果拦截机器_分享:一步一个脚印,vue入门之axios的应用及拦截封装
  3. python环境变量的配置 alias_vim-python环境配置
  4. jquery.form.js插件中ajaxSubmit提交在jquery1.4版本中的应用
  5. 2018-2019-2 20175328 《Java程序设计》第十一周学习总结
  6. 【Python】Pygame模块设计游戏
  7. JavaScript对象的创建之外部属性定义方式(基于已有对象扩充其属性和方法)
  8. http请求代理proxy-ajax
  9. 刀剑乱舞网页版选不了服务器,《刀剑乱舞》不魔法进入游戏方法
  10. 【k8s】K8S中的IP地址(Node IP、Pod IP、Cluster IP、External IP、Internal-IP)
  11. 基于聚合数据的移动联通基站API接口的php完整代码实例
  12. 树莓派python脚本开机自启动设置
  13. K8S异常 sonar status is ‘PENDING’
  14. 【卡特兰数】【高精】WZK打雪仗(war)
  15. 基于高斯两步移动搜寻法(2SFCA)的城市绿地可达性分析
  16. 第二讲:ADS入门和Data DisPlay操作详解
  17. Python 之圆周率 π 的计算
  18. C++中构造函数的超详细讲解
  19. DAB变换器的变频控制
  20. 微服务 RocketMQ-延时消息 消息过滤 管控台搜索问题

热门文章

  1. 成功解决UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xba in position 2: illegal multibyte sequence
  2. DL之BN-Inception:BN-Inception算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  3. Dataset之谷歌地图数据集:谷歌地图数据集的简介、安装、使用方法之详细攻略
  4. CV之FR:DIY脚本通过人脸图像得到人脸特征向量并输出多张人脸图片之两两图片之间的距离
  5. errno_t open_s()打开文件出现的错误分析
  6. http和https的一种能力?
  7. Python是如何进行内存管理的?
  8. mysql查询时强制区分大小写
  9. paho.mqtt.embedded-c-master c语言版本架构
  10. ESP32 OTA 接口简略说明