在上一篇文章中完成了 Stageless Beacon 生成的分析,接下来就是对 Beacon 的分析了,在分析上线之前先将 C2Profile 的解析理清楚,因为 Beacon 中大量的内容都是由 C2Profile 决定的。

而且,目前 C2Profile 也是被作为检测 CobaltStrike 的一种手段,只有在理解了它的实现原理,才能真正明白检测原理和绕过方法。

0x01 Controller 端分析

直接跟到 beacon/BeaconPayload.java,看 exportBeaconStage 方法

对于前面值的获取暂时不管,直接看重点,是如何添加的,因为最后是直接把 settings 转 byte 数组,然后混淆后 Patch 的,所以就重点看一下 settings 都干了什么事

看一眼 settings 的设置,可以很明显的发现四个方法 addShort、addInt、addString、addData

但是可以发现 addString 根本上调用的就是 addData,所以重点就是 addShort、addInt、addData 三个方法

再回头看一下前面在调用时候的情况,后面的参数是需要添加进去的内容、长度,但在第一个参数位置还有一些不明白含义的数字,这个序号是在 Beacon 端解析 C2Profile 的时候需要用到的,在后面来进行解释。

在分析这三个关键方法的时候,还有三个 final 类型的值需要注意一下,到这里也就可以猜个八九不离十了,C2Profile 一定是用某个字节的值来表示数据类型,然后将对应的数据存储在后面

所以来整体看一下这三个方法,首先将序号添加进来;接着 addShort 添加了 1,addInt 添加了 2,addData 添加了 3,这刚好就是上面所定义的几个值;然后 addShort 添加了 2,addInt 添加了 4,addData 添加了 长度值,所以推测,这个位置应该是后面数据的长度;最后他们都将数据添加在了后面

所以整体的结构应该是

0x02 Beacon 端分析

在理 C2Profile 的时候,顺便把解析前的一些内容一起分析一下,在之前分析 Beacon 生成的时候,已经分析过了,实际执行的 Beacon 是由一个 Loader 加载执行的,所以在实际运行的时候,运行的是 Loader,我们在 CreateThread 下断,然后在线程函数中下断也就跟到了熟悉的 PE 头,这里也就是之前说的引导头

首先,它通过计算偏移的方式调用了 ReflectiveLoad

跟进去后,可以发现 ReflectiveLoad 最后调用 DLLMain 的时候传递的 fdwReason 为 1,同时在 return 的时候,也将 DLLMain 的地址 return 回来了

继续往下跟,可以发现它再次调用了 DLLMain,并且传递的 fdwReason 为 4

接下来就该分析真正核心的 beacon.dll 在 DLLMain 中干了什么事,经过分析发现,当 fdwReason 为 1 时,实际执行的是解析 C2Profile 的操作,当 fdwReason 为 4 时,才是真正的功能执行,很明显,这里我们更关心的是解析 C2Profile 的操作

跟进分析,先申请了一片 0x800 的内存用于存储,接着有一个很明显的操作,将一片内存异或,这些都与之前分析生成时候的逻辑一致

AAAABBBBCCCCDDDD 的内存特征

4096 的内存大小

0x2E 的异或操作

接着设置了一个结构体,将 C2Profile 的地址存两份,将其大小也存两份,这个结构体在后面解析的时候会用到

之后就是循环解析,并在最后的时候将这片区域抹零

首先在最开始的时候取了 Short 类型,并且这个函数也是结束解析的关键,首先判断一下结构当中的 Size,如果小于 2,直接 return 0,也就是说所有的都解析完了,这个 0 也就刚好在外层结束了整个解析的流程

转换字节序,取两个字节,这个值也就是之前所说的 index,然后将位置偏移加二,总大小减二,返回 index

然后按照刚才的逻辑可以取出 type 和 size

接着将 index*16,并将 type 存储到对应的位置,到这里 index 的作用也就明确了,是用来指定存储的偏移位置的,这样做就相当于内存对齐一样,在查找的时候是非常方便的

接着便是根据 type 类型来决定执行操作了

获取 Short 与 Int 的都是一样的,就不细说了,重点说一下 Ptr 类型的

先根据 size 申请了一片内存空间,并将地址存储在了对应的位置上,然后去解析

如果剩余大小小于 Ptr 要取的大小,说明有问题,直接 return;然后与之前一样,将所存储的这个结构体的位置偏移后移,将大小进行对应的减小,最后将数据的地址 return 回来

最后使用内存拷贝的方式将数据拷到所申请的内存当中

所以最终在 Beacon 中所使用的样子是这样的

0x03 展示图

所以 Controller Patch 到 Beacon 中的 C2Profile 与 Beacon 在运行时所使用的 C2Profile 长的并不是一样的

Controller

Beacon

文章首发于公众号平台

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖