隔壁工程师都馋哭了我的逆向工程IDA,说要给我搓背捏脚

逆向工程IDA

  • 主要内容
    • 涉及到的内容如下:
      • 1、内核对象及内核对象管理;
      • 2、进程回调;
      • 3、内核调试;
      • 4、Windbg双击调试;
  • 引言
    • 1 进程回调原理分析
      • 1.1 安装与卸载逆向分析
      • 1.2 OS执行回调例程分析
      • 1.3 触发调用的调用链分析
    • 2 实验
      • 2.1 观察系统中已安装的回调例程
  • 3 结束语

紧接着调用ExCompareExchangeCallBack将初始化好的CallBack对象添加到PspCreateProcessNotifyRoutine所维护的全局数组中。值得注意的是,ExCompareExchangeCallBack中在安装回调例程时,对回调例程有一个特殊的操作如图所示。

然后根据v3的值判断是通过上述三个API中的哪个安装的回调,来更新相应的全局变量。
其中PspCreateProcessNotifyRoutineExCount和PspCreateProcessNotifyRoutineCount分别记录当前通过PsSetCreateProcessNotifyRoutineEx和PsSetCreateProcessNotifyRoutine安装回调例程的个数。

PspNotifyEnableMask用以表征当前数组中是否安装了回调例程,该值在系统遍历回调数组执行回调例程时,用以判断数组是否为空,加快程序的执行效率。

除了能够安装回调例程,这三个API也能卸载指定的回调例程。以PsSetCreateProcessNotifyRoutine为例,分析其实现的关键部分,如图所示。

ExReferenceCallBackBlock成功返回后,调用ExGetCallBackBlockRoutine从返回的回调对象中取出回调例程,并判断取出的是否为当前指定需要卸载的项,如果是则调用ExDereferenceCallBackBlock递减引用计数,接着调用ExFreePoolWithTag释放掉Callback所占用的内存。期间也会更新PspCreateProcessNotifyRoutineExCount或PspCreateProcessNotifyRoutineCount的值。根据源码还可以得知,该数组总计64项,也即只能安装64个回调例程。如果遍历完数组的64项依旧没有找到,则返回0xC000007A错误码。

1.2 OS执行回调例程分析

回调例程安装完之后,如果有新的进程创建或退出,内核则便会遍历该数组来执行其中安装的每一项回调例程。通过IDA的交叉引用功能,可分析出内核其他地方对PspCreateProcessNotifyRoutine的交叉引用,如图所示

PspNotifyEnableMask & 2的操作即为判断当前数组中是否安装有回调例程,加快程序的执行效率,这个变量的值在PsSetCreateProcessNotifyRoutine中安装回调例程时设置。bRemove & 2这个if分支,是用来判断当前的回调例程是通过PsSetCreateProcessNotifyRoutine还是PsSetCreateProcessNotifyRoutineEx安装,因为这两个API安装的回调例程的原型不同,在实际调用时传入的参数也不同。两者的回调例程原分别为:

此外,图8中IDA给出的伪C代码RoutineFun((unsigned __int64)RoutineFun)明显不对,因为回调例程的参数个数是3个,而IDA分析出的参数只有1个,显然有问题。直接看下反汇编代码即可得知,如图所示

该函数根据dwEnumType来判断想要枚举的是哪个数组,由代码分析可知,系统内核维护了三个回调相关的数组,分别为镜像加载回调数组,进程创建退出回调数组,线程创建退出数组。类似之前的函数校验,这里也检测了索引是否超过0x40,超过了则返回0,以示失败。

1.3 触发调用的调用链分析

上节分析了回调例程的直接调用上级函数,本节分析整个调用链,主要分析调用源及调用过程中涉及到的关键函数。根据IDA给出的交叉引用图如图所示。

虚线以上部分为用户态程序,虚线以下为内核态程序,红色标注的都是标准导出的API。

根据图12可知,当用户态进程调用RtlCreateUserProcess、RtlCreateUserProcesersEx或RtlExitUserProcess时,内核都会去遍历PspCreateProcessNotifyRoutine数组,依次执行回调例程,通知给驱动程序做相应的处理。

驱动接管之后,可以做安全校验处理,分析进程的父进程或者进一步分析进程链,此外还可以对即将被拉起的子进程做特征码匹配,PE指纹识别,导入表检测等防御手段。

这种方式不需要去Hook任何API,也无需做特征码定位等重复繁琐的工作,完全基于系统提供的回调机制,且在Windows系统中都可以无缝衔接。且各个安全厂家之间也不存在相互竞争,大大缩小了系统蓝屏的风险。

图12中NtCreateUserProcess调用PspInsertThread的原因是创建进程的API内部会创建该进程的主线程。将遍历回调例程数组的工作统一到PspInsertThread中,由其去调用下层的PspCallProcessNotifyRoutines更为合理。

2 实验

2.1 观察系统中已安装的回调例程

实验环境如表1所示,借助于VMWare进行双机调试。

在Windbg中观察PspCreateProcessNotifyRoutine数组,共计14项有效数据,如下所示;

拆解第一项,寻找其所对应的回调例程,如下:

由此可知,安装的回调例程起始地址为fffff802`13fd6268,且还可知道Remove为0,即这个是已经安装的。寻找该回调例程对应的驱动模块,如下:

可知该回调例程是360官方提供。借助PCHunter来对比下,其给出的数据如图所示

image.png
2.2 动态调试回调例程
以表项的第14项为例,内容如下,

断点命中,查看父进程相关信息,如下,

由此可知,是svchost.exe这个父进程创建或者销毁了一个子进程,更具体的信息如下分析;查看下当前的上下文环境;

可以获取到该进程的EXE路径,创建时的命令行参数,父进程的PID等信息,这些足以用于安全软件的检测。
父进程的完整调用栈如下,

由于前四个参数是通过的寄存器传递的,所以无法直接通过栈来回溯到参数,但可以通过手动方式分析得到。分析ntdll!NtCreateUserProcess的调用父函数,其返回地址处的汇编代码如下所示:

由此可知,svchost拉起的子进程为UpdateAssistant.exe,与之前分析得到的参数也相吻合。从调用栈可知,是在svchost创建子进程UpdateAssistant.exe时遍历的回调例程,通知给驱动软件做相应的处理。

3 结束语

此外,通过逆向分析,给出了整个机制的调用源与调用链。最后基于双机调试环境,动态查看内核中维护的进程回调例程表,并且下断点实际动态调试了整个过程。

文章知识点与官方知识档案匹配,可进一步学习相关知识 络技能树首页概览22491 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年6月6日
下一篇 2021年6月6日

相关推荐