首页
社区
课程
招聘
[原创]XX之NTDLL随机化“逆向”(XP系统)
2021-6-24 11:54 10546

[原创]XX之NTDLL随机化“逆向”(XP系统)

2021-6-24 11:54
10546

XX之NTDLL随机化“逆向”

        DLL随机化是从Vista版本之后开始出现的,主要是为了增加漏洞的利用难度,但是XP系统DLL的基址都是固定的,那么出现了一个问题,如何让XP系统的DLL也随机化?

        这个问题的抛出是在我踏入公司的第一个月 Leader闲谈时提出的,说可以尝试去想想,由于当时刚毕业,样本都不会怎么分析,所以一直将一个问题抛入脑后,直到距离毕业只剩一个月快一年的的时候,重拾了这个问题。

起初这个问题,我是通过多次运行EXE发现有时候其基址会一样,有时不一样(在Win10系统),突然来的灵感,于是有了第一个标题的内容。然后在别人告知下知道有个“XX”的产品,于是花了3天下班时间(毕竟工作是样本分析...)分析了一下,如果有不对的地方望告知,毕竟自己还很菜,难免很多地方理解不到位。

    注:逆向优秀的代码仿佛是和作者跨时代的交流...好是好,就是有点太累hhh....

EXE基址随机化的尝试


    可执行文件(EXE,后续都用此代替)的随机化其实比较简单,关键点在于是理解CONTROL_AREA、SEGMENT、FILE_OBJECT,三者结构体之间的关系(以后有时间再说...这个涉及映射、原型PTE的那套东西)。只需要修改其中的_SEGMENT.BaseAddress即可让这个EXE加载地址变化。以此类推我便在开机启动的时候尝试修改NTDLL的这个属性,结果带来的就是不断蓝屏...其实看一下蓝屏错误就能很容易找到问题。既然修改了基址,那么你的基址内容就要申请,所以这个涉及到了VAD和BITMAP的知识(这个在被鸽的文章里面有介绍...)。在这里大概说几句:

1. VAD是给用户使用的API提供的接口,也是验证内存地址有效的一道关卡。

2. BITMAP是在VAD上的一层优化(快速分配),两者功能有交集(即保留内存分配信息)。

第一个自导自演的问题:

    此时有人会想既然有了位图,那么为什么还要有VAD呢?其实位图只是为了快速分配大内存,而且在Win7和Win10只有一部分才被投入使用。(因为它所在的地址也需要有效哦!)

第二个自导自演的问题:

    ExE的随机化如此简单吗?答案当然是不!在Win10中,对象内存重用的概念好像脱颖而出,比如:APC对象的复用,在exe映射的过程中,也涉及到了对象的重用。重用就意为着地址不会改变(这就解释了开篇说EXE基址有时候变有时候不变的问题),当然还有一些标志问题。这里就简单抛砖引玉一下:

在Win10中可以尝试想想exe内容不改变,多次运行基址会改变吗?改变一点内容,地址又会改变吗?等等。


系统DLL(如NTDLL)的随机化猜想


回归正题,简单总结一下猜想:

1. _SEGMENT.BaseAddress内容的提前内存占用

2. _SEGMENT.BaseAddress地址改变

带着这两个猜想,于是就开始探究生活中活生生的例子“盾甲”。

盾甲的逆向

1.    关键SYS的确认

    对于关键sys文件的确认,只要对MmMapViewOfSection下手就行,然后就会容易的定位到关键模块,称为B模块吧。

2.    撸起袖子加油逆

    只看关键部分其实会没有意思,因为对于这么好的代码,难得多看几眼。所以就从B模块DriverEntry开始逆。

主函数:

    在驱动一开始就对当前系统版本进行了效验,于是得知该版本只适用于Major=5,Minor=1的版本。

    判断完版本后,就开始将partmgr.sys中movzx eax,byte ptr ds:[0xFFDFF051]的硬编码修改为movzx eax,byte ptr fs:[0x51],这一步我的猜测是为了代码的复用性因为别的版本FS基址会变化的(因为可能不止一个)。

声明一下,get_mode_imagebase_size和get_sec_start_end_addr函数,都是逆完修复好idb,自己命名的名字,是由理论依据的!,所以就不公开了。

    接着判断全局变量InitSafeBootMode是否开启安全模式,没有则查看注册表。



    然后验证当前win32k.sys还没有加载(这里可以体现出这个函数的复用性)。


    前期验证工作完成后,便开始创建符号连接,初始化功能号函数。到这里和一般的驱动操作没什么区别。


    接着利用固定的地址,初始化了一个链表。这里猜测可以是为了后续的同步操作。

    接着开始产生随机种子。产生的算法为[当前时间xor异常信息各个字段xor平台信息各个字段]

    接着判断.data段起始地址的第一个字节。此时这里不调用。这里我没有去研究。

    接着就调用IoRegisterBootDriverReinitialization函数来实现DLL随机化的操作。

  


DriverReinitializationRoutine回调函数分析


    在回调函数一开始,便获取其驱动的DEVICE_OBJECT对象,主要是为了获取其扩展结构体指针。

     

    接着调用设备扩展中的函数初始化一些自定义结构体以及进行效验一些字段的正确性。

首先调用设备扩展的第一个函数,初始化包含SSDT和SSSDT表以及一些自定义字段的结构体。其次验证第一个字段是否为3和最后一个字段是否为0x3F0。

      

设备扩展对象第一个函数分析:


    设备结构体的定义都在A模块中,这个模块主要是完成很多的初始化操作。后续会进一步看到。

在这个函数中,不难看出,主要申请了SSDT和SSSDT表的空间,并将其分配的地址保存在自己定义的结构体中。

大致逆向的结构体如下(还有一些字段没有去尝试..所以请忽略):

     

     


      接着会再次调用初始化随机种子、申请自己定义的BITMAP空间(用于快速分配内存和记录内存分配情况)等操作:

      

       

    接着还初始化了一个AVL树,这里不做详细研究,因为不会影响关键内容。

      

接着大量的调用设备扩展中的第二个函数,这个函数具体是完成了自己申请的SSDT和SSSDT的一些函数HOOK。

     

    在这个函数中,首先会初始化一些函数的调用号,然后对某些函数进行替换,比较复杂。因为它分了3层,2001一层,4002一层,6003一层。经过分析,2001主要是用于序列号低于1000的,6003用于序列号高于1000的,对于中间一层主要用于处理一些比较特殊的序列号,而且所执行的相关操作有点像稀疏矩阵。因为大概看一下,它将比较高的序列号进行转换到1000内,然后只是简单的在6003层进行相应的设置标志。


1.首先获取相关函数地址



2.其次通过函数地址去获取原来的调用号。


3. 构造自己的调用号数组

4. 执行相关HOOK以及相关标志位置位。



5. 接着调用设备扩展第三个函数,进行相关调用号标志位置位。



随机化的重点部分

    接着采用inlinehook的方式,对MmMapViewOfSection函数进行hook,这里利用的是微软在每个函数之上保留的5字节0xCC(微软用于热补丁的后手)。


    MmMapViewOfSection Hook完毕后便对ZwCreateSection函数进行hook,同时获取内核NT模块,对其中的PAGEVRFY节区的函数,进行逐个HOOK。

现在整个流程是讲解完毕了,接着就需要详细分析自定义的MmMapViewOfSection 函数是如何进行DLL随机化的。


自定义的MmMapViewOfSection

此处只对NTDLL的随机化进行讲解,其他的DLL不予讲解(处理流程还是不太一样)

       Graph View如下:

       绿色部分:验证和随机化部分

       粉色部分:调用原来函数部分

       黄色部分:重定位部分

由于篇幅问题,这里只挑一些重点讲解:

    只有文件的CONTROL_AREA中的FLAG标志,满足Image,才会进行随机化。(第一个条件)

    这里可以看出对NTDLL的优待性。如果是NTDLL,则会对某一标志位进行置位影响后续操作。(第二个条件)

    这里是对别的DLL的一些处理,具体不予讲解。

    紧接着根据SECTION对象,获取CONTROL_AREA中的基址,FILE_OBJECT对象、映射的PFN数量以及根据进程ID获取进程对象等。

    接着判断进程对象中的SectionObject字段和当前section对象进行对比,这里是不相等的。然后并便进行AVL树查询,以及根据当前PFN数量分配位图,并计算其基址等。

1. 计算位图大小(因为位图和VAD一样都是64K为一个单位,只有PTE是以页为单位)。

2. 将位图中根据1所计算出来的大小,都进行置1,这里的0x7800是对基址的限定。

    此时便拥有了随机化的基址,其次便是对其进行修复重定位。

    首先会有一个开启修复重定位的标志fix_mem_flag(自命名),在函数一开始部分,都是对其初始化为0的。

    其次便调用自定义设置节表属性以及修复重定位函数。

设置节表属性的函数:

    这里可以通过参数进行选择获取VirtualProtect的fProtect参数。

  修复重定位的函数:

    到此就结束了。纵观来看,其实思路比较简单,但是对其细节的把控至关重要,这里这可以体现出设计者的功底是如此的强大!!!

    其中有很多东西还不是很明白..但是总体上还是了了一桩心愿。

                                                                                                                                                                            谢谢观看!






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

最后于 2021-6-25 18:46 被烟花易冷丶编辑 ,原因:
收藏
点赞8
打赏
分享
最新回复 (7)
雪    币: 52
活跃值: (2178)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
实都 2021-6-24 17:35
2
0
当时很佩服360XP遁甲的设计者,这尼玛叼
雪    币: 753
活跃值: (3898)
能力值: ( LV6,RANK:98 )
在线值:
发帖
回帖
粉丝
还我六千雪币 2021-6-24 18:24
3
0
真不错呀
雪    币: 1226
活跃值: (1605)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
烟花易冷丶 2021-6-24 18:38
4
0
实都 当时很佩服360XP遁甲的设计者,这尼玛叼[em_34]

是啊,...一眼就能看出来,TQL,我比较担心,所以用XX代替了 hhh

最后于 2021-6-24 18:38 被烟花易冷丶编辑 ,原因:
雪    币: 1226
活跃值: (1605)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
烟花易冷丶 2021-6-24 18:39
5
0
情话布墨 真不错呀
还不是因为大哥教的好,哈哈
雪    币: 753
活跃值: (3898)
能力值: ( LV6,RANK:98 )
在线值:
发帖
回帖
粉丝
还我六千雪币 2021-6-25 12:53
6
0
烟花易冷丶 还不是因为大哥教的好,哈哈
我信了
雪    币: 3776
活跃值: (5379)
能力值: ( LV7,RANK:115 )
在线值:
发帖
回帖
粉丝
独钓者OW 2 2021-7-17 22:23
7
0
妙啊
雪    币: 482
活跃值: (419)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xyjstone 2021-8-10 23:41
8
0
DLL是一定支持随机化,毕竟DLL的加载时机不固定,PE文件的重定位节保存了所有的需要重定位的全局地址,只要程序加载的位置和PE中的ImageBase不一致,就会根据重定位节的数据修复全局地址,不过只要修改了PE中的DLLCharactersitics属性,PE加载时就不会使用重定位节的数据了,
游客
登录 | 注册 方可回帖
返回