内容简介:OceanLotus APT,也称为APT32和APT-C-00,是从2012年开始活跃的间谍组织。BlackBerry Cylance研究人员近期发现该组指的一个新的payload加载器,其中使用隐写术来读取隐藏在.png图像文件中的加密payload。隐写算法使用了最低有效位(least significant bit)算法来减少与原始图片的差别,以预防给分析人员和工具发现。解码、解密并执行后,可以看到一个混淆后的加载器来加载APT 32的后门。Cylance研究人员共发现2个与隐写加载器共同使用的后门
简介
OceanLotus APT,也称为APT32和APT-C-00,是从2012年开始活跃的间谍组织。BlackBerry Cylance研究人员近期发现该组指的一个新的payload加载器,其中使用隐写术来读取隐藏在.png图像文件中的加密payload。隐写算法使用了最低有效位(least significant bit)算法来减少与原始图片的差别,以预防给分析人员和 工具 发现。解码、解密并执行后,可以看到一个混淆后的加载器来加载APT 32的后门。Cylance研究人员共发现2个与隐写加载器共同使用的后门,分别是Denes 后门和Remy后门的变种。
隐写加载器#1
该OceanLotus恶意软件加载器尝试模拟McAfee的McVsoCfg DLL并尝试通过合法On Demand Scanner可执行文件进行顺带加载。与该加载器一起出现的是保存在.png图像文件中的加密payload。该.png文件本身是非恶意的,其中的payload是用隐写术编码在图像文件中的,具体是使用了颜色代码的最低有效位来保存隐藏信息,这样就不会改变原来的图片。编码的payload是用AES128加密的,并用XOR算法进行混淆试图欺骗隐写检测工具。
特征
·顺带加载DLL
· 用定制的.PNG隐写术来加载下一阶段payload
· 用AES128实现payload解密
· 加载Denes后门
加载器分析
恶意DLL会导出相同的函数名作为原始的mcvsocfg.dll库。所有的导出都含有解密payload的相同的代码,然后注入到内存并执行。
图1. 常见的导出入口
Payload是用隐写术编码在一个单独的.png文件中的。解码的payload是用AES 128加密的,最后使用XOR 0X3B进行混淆。XOR KEY并不是硬编码的,而是从C:\Windows\system.ini文件的第1个字节读取的:
图2. Payload解码和解密路径
研究人员发现其中一个payload是编码在怪盗基德(日文:怪盗キッド;英文:Kid the Phantom Thief,是日本动漫《魔术快斗》中的主人公以及《名侦探柯南》中的客串角色)的图片中的。
图3. “Kaito Kid” 怪盗基德
为了提取payload,恶意软件会初始化GDI+ API,并获取图片的宽度和长度值:
图4. 使用GDI+ APIs
Payload的大小是编码在图片的前4个像素值中的。在获取了payload的大小后,恶意软件会分配适当的内存缓冲区并一个字节一个字节地解码剩下的payload:
图5. 获取payload的大小
Payload的编码方式与大小类似,payload的每个字节都是通过图片中之后的像素的ARGB色值计算得来的:
图6. 隐写解码路径
如果payload的大小比用来保存payload的图片大的话,剩下的payload就会负载图片的IEND marker之后,可以从文件中直接读取:
图7. 读取剩余的payload的字节
像素编码算法也非常直接,目的就是减少修改带来的视觉差异,而且只修改红绿蓝色字节值的最低有效位。阿尔法通道(α Channel或Alpha Channel)字节值并没有修改。为了编码payload的字节,前3位(0-2)会保存在红色中,接下来3位(3-5)会保存在绿色中,最后的2位(6-7)会保存在蓝色中。解码是非常简单的逆向操作:
图8. RGBA像素解码
Windows会把.png像素的RGBA值通过GdpiBitmapGetPixel API转化为ARGB编码,如下图所示:
图9. 像素颜色解码
比如,ARGB像素值0xFF4086DB会解码为0xF0:
图10. ARGB像素值解码
为了帮助加密payload的恢复,下面的 python 脚本用来从.png图像中解码出像素值:
图11. 从.png图像中解码像素值的python脚本
在从.png图像中加密后,加载器会初始化密钥和IV(初始向量)来执行加密payload的AES解密。这些值都硬编码在二进制文件的.rdata区域的一个256伪随机字节数组中。数组的前2个字节指明了key和IV的相对偏移值:
图12. 提取key和IV值
图13. 256伪随机字节数组中的AES key和IV
加载器从开源的Crypto++2库来完成AES 128实现:
图14. Crypto++接口
研究人员与Crypto++ github上的源码进行了对比,恶意软件作者应该并没有对代码进行修改。SimpleKeyringInterface class用于初始化key,而IV会传递给SetCipherWithIV函数:
图15. 算法和密钥初始化
解密是用treamTransformationFilter类进行的,其中StreamTransformation cipher设置为AES CBC解密模式:
图16. 使用CryptoPP StreamTransformationFilter类进行Payload解密
库代码会对CPU特征进行无数次检查,基于检查的结果会选择与特定处理器对应的加密函数实现:
图17. CPU特征检查和调用AES解密路径
其中一种AES实现使用Intel AES-NI加密指令集,许多Intel和AMD CPU都支持该指令集:
图18. 使用Intel AES-NI加密指令集
解密的payload会进行最后的转变,与从C:\Windows\system. Ini文件中读取的第1个字节进行异或计算,ini文件应该是‘;’ (0x3B)开头的:
图19. 移除 payload混淆的最后一层
研究人员执行了CyberChef相同的步骤并解码出加密的payload,是一个x86 shellcode,是调用立刻opcode序列开始的:
图20. 用CyberChef 解密payload的第一个区块
隐写加载器#2
概览
第二个隐写加载器在实现上有隐写区别,但是payload提取与前面的是一样的。主要的区别在于:
·解密路径调用的方式,是从DLLMain函数调用的,而不是导出函数;
· Payload调用的方式,是从覆盖栈中的返回地址而不是直接调用;
· 其他反分析检查的实现
研究人员对多个该DLL的变种进行了分析,发现其可能与受害者的环境有关。其中一些名字含有与安全软件相关的进程:
· wsc_proxy.exe
· plugins-setup.exe
· SoftManager.exe
· GetEFA.exe
特征
· 顺带加载的DLL
· 父进程名的反调试/反沙箱检查
· 用定制的.png隐写术来加载下一阶段payload
· 用AES128实现payload解密
· 通过覆写栈中的返回地址来执行payload
·加载Remy后门的变种
加载器分析
DLL并不含有导出表,其完整功能位于DllMain路径:
图21.变种2
DllMain函数执行后,恶意软件首先会从其resources解密一个字符串,并与父进程的名字进行比较。如果名字不同,恶意软件就会直接退出。含有期望进程名(ICON/1)的resource会与合法C:\Windows\system.ini file – 0x3B (“;”)进行异或计算:
图22. ICON/1 resource中混淆的文件名
图23. 父进程名比较
如果父进程名匹配,恶意软件就会遍历栈来找出进入父进程的text section的内存的返回地址:
图24.找到栈中的返回地址
Payload会从.png文件中读取。在该实例中,payload完全包含在图片的像素色值中,IEND marker中没有其他剩余信息。
图25. 含有编码的payload的图像
最后加载器会解密payload到内存缓冲区中,并用到该缓冲区的指针来覆写之前发现的返回地址,确保恶意shellcode会在DLL尝试返回该调用时执行:
图26. 用到解密payload的指针来覆盖返回地址
嵌入在payload中的加载器看似是Veil “shellcode_inject” payload的一个变种,之前OceanLotus用它来加载过Remy后门。在该例子中,shellcode被配置为从payload中加载编码的后门:
图27. 解码进程
后门启动器
Final payload是以启动器DLL的形式出现的,DLL中的.rdata区域含有加密的后门,在resource中含有明文的配置数据。Resources中还保存了至少1个C2通信模块。后门DLL和C2通信dll都用了大量垃圾代码来混淆,因此很难使用静态分析技术和调试工具进行分析。除了Denes和Remy后门外,研究人员还发现至少两个不同的通信模块,分别是DNSProvider和HTTPProv。
初始shellcode
含有final后门的启动器二进制文件是RC4加密的,封装在混淆的shellcode中。研究人员还发现了熟悉的明文DOS stub,但是header和二进制文件body的其他部分都是加密的:
图28. Payload中的DOS stub
Shellcode使用OceanLotus的标准方法扁平化控制流和插入垃圾跳转代码的形式来混淆:
图29.垃圾opcodes
Shellcode以非常变种的方式开始,在加载的模块中寻找kernel32.dll库的基:
图30. Walk模块
图31. Find模块
图32. 检查kernel32.dl
找到kernel32 base之后,shellcode会计算LoadLibraryA和GetProcAddress函数的地址,并用来解析其他必要的API,包括VirtualAlloc, RtlMoveMemory和RtlZeroMemory:
图33. 解析kernel32.dll imports
图34. VirtualAlloc字符串
图35. Shellcode imports
在解析完API之后,shellcode会解密启动器库并加载到内存中。MZ header, PE header和其他section都用RC4算法和硬编码的key进行解密:
图36. PE头部进行RC4解密的代码
一旦所有的section都加载了,MZ/PE header就会在内存中0化:
图37. 在加载的模块中找出.reloc section
Shellcode会继续执行payload DLL的入口点:
图38. 执行payload DLL的入口点
启动器DLL
DLL的内部吗是随机寻找的CLSID,它只导出一个名为DllEntry的函数
图39. DLL name和export
执行后,启动器会通过用恶意路径的地址来覆盖内存中的入口点来尝试hook合法的wininet.dll库。如果成功的话,每当系统加载wininet.dll时,随后释放的后门DLL的入口点会在原始wininet入口点之前被执行:
图40. Hook wininet.dll的路径
图41. 后门解密路径
因为payload只是解压缩到内存中,还没有DLL注入路径,所以恶意软件需要固定解压缩的代码中的所有指针,这是用硬编码的值和偏移量来完成的。这部分利用了全部启动器代码的90%,包括超过11000次修订:
图42. 用来固定指针的代码
启动器会调用后门DLL的入口点:
图43. 调用后门DLL的入口点
从resource中读取配置和解压缩C2通信库的路径会被临时替换到函数CComCriticalSection的指针来调用。这样混淆的方法就很难在代码中看出来:
图44. 到资源解密路径的混淆调用
启动器会从resource加载配置,并用来自后门DLL的导出来初始化内存中的配置值。Resource P1/1含有配置值,包括端口号和注册表路径:
图45. 嵌入的配置
Resource P1/2含有的C2 url:
图46. 硬编码的C2 URL
Resource P1/ 0xC8含有用于C2通信的其他压缩的DLL:
图47. 压缩的C2通信库
来自resource的配置值会以参数的形式传递给后门函数:
图48. 初始化配置值
Resource 0XC8的内容在被解压缩后,来自后门DLL的另一个函数会用来加载C2模块到内存中,并调用CreateInstance:
图49. 解压缩第二个DLL
最后,启动器将控制权传递给主后门路径:
图50. 调用主后门路径
配置
后门DLL
后门DLL保存在启动器的.rdata section,并用LZMA压缩用RC4加密。二进制文件用大量的垃圾代码进行了混淆。DLLMAIN函数用到hook路径的指针替换了到GetModuleHandleA API的指针,当以NULL作为参数调用时,该指针会返回后门DLL base:
图51. 覆盖GetModuleHandleA指针
图52. GetModuleHandleA hook
后门还含有从resource中加载C2通信模块到内存中的导出函数,然后调用“CreateInstance” export。研究人员在分析后门的全部功能时发现与之前发现的Remy后门比较类似。
C2通信模块
DLL保存在启动器的resources中,并用LZMA压缩。也是严重混淆的,但是与后门混淆的方式有所不同。虽然不含有内部名,但研究人员相信它是HttpProv库的一个变种。后门使用该模块与C2服务器进行HTTP/HTTPS通信,并有代理绕过的功能。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。