前言
一个很有意思的事情,3月初GandCrab(Crab->螃蟹)勒索病毒的服务器被罗马尼亚一家安全公司和警方攻破,可以成功恢复GandCrab加密的文件。病毒开发人员迅速升级了版本V2,并将服务器主机命名为politiaromana.bit,挑衅罗马尼亚警方。
恰巧有坛友中了招,那我们就来分析下,看看版本2这只螃蟹的进击。
样本概述
样本信息:
病毒名称:hmieuy.exe
文件大小:315912 bytes
MD5值:F42774332FB637650FF0E524CE1B1685
SHA1值:0012363A8A6EFDD93FBD4624EE5E8DDF1F7BE8D5
CRC32:9732F21C
样本来源:
https://www.52pojie.cn/forum.php?mod=viewthread&tid=707668
VirusTotal:
https://www.virustotal.com/#/file/15846ed8f38c0fac876b96a9d2eb55c3c98a428147ae372ade22efb854cfc4aa/detection
71款杀软PASS了45个,还是有些威力的(截止2018.03.18)
行为预览
勒索信息:
勒索软件要求的不是比特币,而是Dash(达世币),还有中文显示外加二维码支付,可谓是极其贴心了,不过算一下,1200 USD=7596 RMB,病毒老哥,我直接换个电脑不好嘛!
技术分析
GandCrab一代程序非常简单,并没有混淆数据或代码,甚至直接用IDA反汇编都能较精确的得到结果。而GandCrab二代相比一代多了三层封装和代码混淆,使用了大量的PE结构解析操作,并且很有意思的采用了反射式DLL注入,我们必须多次从OD中将内存DUMP出来,才得以在IDA中同步静态分析,大大增加了分析难度,也降低了被杀软查杀的机率。
原始样本分析
通过IDA定位到WinMain入口点0x004010B4,进入主逻辑发现很多无用函数和循环干扰分析,函数循环的次数是这样的:
甚至是这样的:
测试循环极其耗时,我们通过设置条件断点和nop循环跳转,在不影响程序正常运行的情况下略过无用函数,寻找关键点。
病毒会申请一块堆空间,之后从资源段找到加密的shellcode,复制到堆内存中。
然后会将shellcode解密,我们将内存中的恶意代码DUMP下来,命名为shellcode.txt,拖入IDA分析。
最后更改shellcode内存保护为可读可写可执行,并执行shellcode。
注:程序中还会有一些简单的反调试,如IsDebuggerPresent,StrongOD轻松过掉。
Shellcode分析
Shellcode部分存在花指令,导致OD和IDA显示异常,IDA 也因为堆栈不平衡难以F5。
但通过常见的编写思路和PE结构解析我们还是能推测出病毒的意图。
Shellcode的常见执行流程:
1)获取kernel32.dll基址
由于shellcode无法直接调用API,所以需要先获取kernel32.dll基址,从而遍历导出表获得所需函数地址。
2)遍历导出表取得GetProcAddress、LoadLibrary等函数地址
3)再次申请空间,并解密了一段代码(我们命名为PE1)
4)加载PE1数据
将解密后的PE文件以文件对齐的方式加载到内存中
拷贝PE1头部、遍历拷贝区段:
之后就是PE1数据的执行了,此时不需像之前一样获取kernel32.dll基址再获取API地址了,因为我们解析的是完整的PE文件,文件里有导入表,修复IAT即可。
5)修复PE文件IAT
这样整个过程PE数据没有在磁盘落地,可以躲避杀软的文件检测。本来以为这样就可以了,但是病毒又做了一层封装,使用反射式DLL注入,我们DUMP下此时的内存(命名为PE1.EXE),继续分析。
反射式DLL注入分析
反射式DLL注入原理:
简单说,常见DLL注入最终都会使用LoadLibrary完成DLL装载,而反射式注入通过为DLL添加一个导出函数ReflectiveLoader来实现装载自身,这样只需要将DLL文件写入目标进程的虚拟空间中,然后通过DLL的导出表找到这个ReflectiveLoader并调用它就可以了。不需要在文件系统存放目标DLL,减少了文件“落地”被删的风险。同时它没有通过LoadLibrary等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己,因此更容易通过杀软的行为检测。
难点在于ReflectiveLoader运行时DLL没有被装载,所以编写的代码必须是地址无关,也即ReflectiveLoader中的代码无论处于虚拟空间的哪个位置,它都必须能正确运行。
需要注意的是,病毒本身是利用了DLL导出函数实现DLL装载,并没有真正的注入其它进程,也就是相比完整的反射式注入少了注射器部分(VirtualAllocEx、WriteProcessMemory、CreateRemoteThread),但反射原理相同,暂且理解为是"反射式注入自身”吧。
OD继续调试原程序hmieuy.exe,IDA解析PE1.EXE,此时会有一些代码混淆,OD指令会出现很多错乱。
发现关键点,怀疑病毒使用了反射注入DLL的方式(遇到大量花指令,可直接从IDA找地址OD跳转,不需一步一步跟,为方便调试,使用OD调试PE1.EXE)
最终得到了PE1.EXE释放的PE2.DLL,DUMP下来。
之后病毒会先CALL进导出函数,实现ReflectiveLoader:
1)定位DLL文件在内存中的基址
2)获取所需的系统API
通过PEB找到kernel32.dll中的LoadLibraryA(), GetProcAddress(),VirtualAlloc()以及ntdll.dll中的NtFlushInstructionCache()函数。
3)分配一片用来装载DLL的空间
4) 复制PE文件头和各个节
类似PE1
5) 修复DLL的导入表
类似PE1
6) 修复DLL重定位表
7) 调用DLL入口点
NtFlushInstructionCache用来清除指令缓存以避免一些问题。
最终跳转到核心DLL入口。
PE2.DLL数据分析
折腾半天,终于见到毒螃蟹真身了。
病毒核心代码可以分成3个主要部分:初始化部分、网络部分和文件加密部分。
初始化部分
1)整体逻辑:
首先病毒会创建一个新线程来执行代码,主线程会挂起,新线程的初始化部分如下:
2)获取信息及创建互斥体
GranCrab2会从系统中收集各类信息, 如:
• 用户名
• 主机名
• 处理器类型
• 操作系统版本
• IP地址
• 磁盘空间
• 系统语言等
之后会通过系统信息来命名创建互斥体(Mutex),若判断互斥体存在,则结束进程,防止多开。
3) 查找杀软内核驱动
创建线程(Find_Antivirus),首先会单独寻找卡巴斯基驱动(Klif.sys),看来很是惧怕卡巴的淫威啊,哈哈,看图:
之后会再寻找其它杀软驱动sys如:
• Fsdfw.sys
• Srtsp.sys (诺顿)
• Srtsp64.sys
• NavEng.sys
• NavEx15.sys
检测完毕,病毒会将自身释放到系统目录,并设置开机自启动 。
4) 遍历终止进程
由于是勒索软件,自然需要将需加密的程序结束,以防文件被占用无法加密,结束进程清单如下:
msftesql.exe、sqlagent.exe、sqlbrowser.exe、sqlservr.exe、sqlwriter.exe、oracle.exe、ocssd.exe、dbsnmp.exe、synctime.exe、mydesktopqos.exe、agntsvc.exe、isqlplussvc.exe、xfssvccon.exe、mydesktopservice.exe、ocautoupds.exe、agntsvc.exe、agntsvc.exe、agntsvc.exe、encsvc.exe、firefoxconfig.exe、tbirdconfig.exe、ocomm.exe、mysqld.exe、mysqld-nt.exe、mysqld-opt.exe、dbeng50.exe、sqbcoreservice.exe、excel.exe、infopath.exe、msaccess.exe、mspub.exe、onenote.exe、outlook.exe、powerpnt.exe、steam.exe、thebat.exe、thebat64.exe、thunderbird.exe、visio.exe、winword.exe、wordpad.exe
5) CSP生成RSA密钥
简单介绍下CSP,全名“加密服务提供者(Cryptographic Service Provider)”, 是微软定义的一套密码服务API,主要存在于Advapi32.dll中,利用CSP可以非常方便的实现AES、RSA、MD5、SHA1等常用加密算法。
病毒使用了微软的CSP容器来加解密,主要分为以下几个步骤:
①产生CSP容器
连接CSP,获得指定CSP的密钥容器的句柄
②生成密钥
生成密钥有两种方式,CryptGenKey(生成随机密钥)和CryptImportKey(导入密钥),病毒使用了CryptGenKey方式。
另:Microsoft Base Cryptographic Provider v1.0:密钥长度为512位
Microsoft Enhanced Cryptographic Provider v1.0:密钥长度为1024位
③导出密钥
由于使用的是RSA算法,所以分别导出公、私钥,如图:
③加解密
④销毁容器
注:加解密部分在4.3加密部分描述
网络部分
1) 遍历杀软进程
病毒会首先寻找是否有杀软进程,相关信息会处理后发往服务器。
2) 生成请求包字符串
GandCrab的服务器托管在.bit域名上,共有以下几种,默认使用第一个
"politiaromana.bit"
"malwarehunterteam.bit"
"gdcb.bit"
检查杀软后,病毒会将之前生成的RSA公私钥通过CryptBinaryToStringA(Windows API)转换为base64编码,之后将编码结果加入到要发送的GET请求字符串中。
RSA公钥:
06 02 00 00 00 A4 00 00 52 53 41 31 00 08 00 00 01 00 01 00 23 58 07 3F B4 3C 3A 82 57 EA F0 5165 71 93 F6 49 BC AB 90 14 37 11 CC 89 2A 7F 36 11 D4 76 A4 5D D3 09 F3 E2 2B 5D 2F B2 36 AF C2A8 F4 D1 DC 54 8E BB 77 08 38 A4 D0 64 2B 5E 30 22 E0 29 6F B3 62 AA 42 DC 51 35 1A BB 02 E5 7D52 6F 32 D0 00 6B A6 4C 15 E2 D3 D4 5E 77 E6 4D 2D 0D 6C 1F 73 D9 A0 6B C1 5D 87 B8 A8 89 C1 20C5 99 32 B1 02 36 6E 4E 11 E6 F2 C1 CA 7B ED 2C 4E B1 C8 7E C6 51 3C A3 6D 7A 56 81 88 66 BF 1DEA 1C 98 2F E6 62 42 C6 BE 5E D7 53 C5 9A 86 4E AE 21 B2 07 8B 92 72 52 87 BA 8D 7E 85 E4 80 FD22 83 52 E5 BF 68 36 AF 36 1F 4B 6C 54 4F 19 71 84 00 A3 72 A2 48 52 29 AE 7E BE 3D 3A C0 43 D1CC 2F C1 05 59 06 5A 24 10 12 9C A8 D4 36 3D 9E 53 F1 51 3D 1F 92 EA 6A 4A 5D F0 47 5B D4 CC 172C F7 02 85 F6 4D 29 91 EB 8D AF 98 75 9D 1A 93 06 59 62 C8
转换为BASE64:
BgIAAACkAABSU0ExAAgAAAEAAQAjWAc/tDw6glfq8FFlcZP2SbyrkBQ3EcyJKn82EdR2pF3TCfPiK10vsjavwqj00dxUjrt3CDik0GQrXjAi4Clvs2KqQtxRNRq7AuV9Um8y0ABrpkwV4tPUXnfmTS0NbB9z2aBrwV2HuKiJwSDFmTKxAjZuThHm8sHKe+0sTrHIfsZRPKNtelaBiGa/HeocmC/mYkLGvl7XU8Wahk6uIbIHi5JyUoe6jX6F5ID9IoNS5b9oNq82H0tsVE8ZcYQAo3KiSFIprn6+PTrAQ9HML8EFWQZaJBASnKjUNj2eU/FRPR+S6mpKXfBHW9TMFyz3AoX2TSmR642vmHWdGpMGWWLI
我们同时也获得了私钥,太长就不贴出来了~
请求字符串:病毒程序会将搜索到的各种系统信息和公私钥信息整合在一起,如图:
内容很长,这里只截取重要部分,后面私钥部分省略……
百度确认一下本机外网IP,恩,病毒老哥没毛病~
准备完毕后必然是要发送给它自己的服务器了~
伪装成->Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/53
3)通过管道创建nslookup.exe子进程
病毒会通过创建nslookup.exe子进程的方式来检测服务器是否正常(注:nslookup是系统内置的应用程序,可以通过域名查询服务器ip等DNS信息)。
简单介绍一下管道通信,管道是一种用于在进程间共享数据的机制,其实质是一段共享内存,病毒利用了管道进行父子进程的通信,这样子进程就可以直接影响父进程内存。
为实现父子进程间通信,需要对子进程的管道进行重定向:
创建子进程函数 CreateProcess中有一个参数STARUIINFO,默认情况下子进程的输入输出管道是标准输入输出流,可以通过下面的方法实现管道重定向:
STARTUPINFO si;
si.hStdInput = hPipeInputRead; //输入由标准输入 -> 从管道中读取
si.hStdOutput = hPipeOutputWrite; //输出由标准输出 -> 输出到管道
nslookup politiaromana.bit ns1.virmach.ru(.ru后缀,应该是俄罗斯黑客)
可以看到nslookup通过命令发出请求(服务器IP:109.234.35.56),正常解析后的地址如下:
大佬们可以试试把服务器日了~
4) HTTP协议发送信息
信息的发送是通过HTTP协议进行的:
如果出现网络连接错误或者服务器异常,则代码会进入无限循环,直到找到可用的服务器为止,然后重新查询客户端IP,再次运行nslookup,解析IP地址。如下图:
加密部分
我们已经知道病毒使用了RSA算法,不过加密前病毒还会对特殊文件、文件路径以及后缀等进行过滤处理。
1) 创建加密线程
过滤磁盘,只对固定磁盘和网络磁盘加密,且每个磁盘创建一个线程:
0 DRIVE_UNKNOWN 未知的磁盘类型
1 DRIVE_NO_ROOT_DIR 说明lpRootPathName是无效的
2 DRIVE_REMOVABLE 可移动磁盘
3 DRIVE_FIXED 固定磁盘
4 DRIVE_REMOTE 网络磁盘
5DRIVE_CDROM 光驱
6 DRIVE_RAMDISK 为RAM
2)过滤文件及路径
如果病毒处于以下文件路径时,会过滤并跳过,防止关键目录被加密系统无法运行:
关键目录:
ProgramData
IETldCache
Boot
Program Files
Tor Browser(洋葱浏览器)
Ransomware
All Users
Local Settings
Windows
其它系统特殊文件夹(SHGetSpecialFolderPathW查找,如C:\Program Files)
跳过指定文件:
.sql
desktop.ini
autorun.inf
ntuser.dat
iconcache.db
bootsect.bak
boot.ini
ntuser.dat .log
thumbs.db
GDCB-DECRYPT.txt
过滤指定后缀(以下后缀文件不加密):
3)创建勒索信息文件
之后,病毒会在各文件夹根目录创建勒索信息,V2版本的GandCrab很人性啊,怕大家不会用洋葱浏览器,还提供了可直接访问的洋葱链接~
4)文件加密分析
CSP加密基本函数:
-
CryptImportKey将密钥从BLOB转换到CSP中
-
CryptGetKeyParam获取密钥的一些参数
-
CryptEncrypt加密文件
加密逻辑:
文件会使用CryptGenRandom(CSP函数,为空间产生随机字节) 配合盐(salt)来加密文件:
这里为了方便测试我们准备文件”1.txt”,内容为11112222
病毒共对4个部分进行了加密拼接,组成最后的加密文件:
第一段:
病毒通过CryptGenRandom函数,将字符串”GandCrabGandCrab”(长度0x10) 随机后得到随机值,由于后面会用到,我们命名为R1,如图:
可以看到,字符串被随机化,然后病毒会申请一块内存(如图中拷贝到0x1A0000),将随机数拷贝过去,最后通过CryptEncrypt函数加密,结果如下:
第二段:
加密方式与第一段相同,只是字符串变化为“GandCrabGandCrabGandCrabGandCrab”(长度0x20),命名为R2。
随机后:
加密后:
第三段:
首先病毒会CreateFileW打开待加密文件,并通过ReadFile将原程序映射到内存中,之后会来到下图函数:
可以观察到,函数的三个参数中有一个是R1(随机数),这样我们有理由怀疑函数中可能使用R1加密。经过反复对比,果然找到了一段非常规的异或代码,将原程序二进制流与R1做pxor操作。
原程序: 01310000 31 31 31 31 31 32 32 32 32 32
R1: 02A2F254 87 0F 72 81 00 92 6E F0 38 0E 98 31 BF 41 F2 E8
异或后: 01310000 B6 3E 43 B0 31 A0 5C C2 0A 3C 98 31 BF 41 F2 E8
此时不禁小激动一下,有没有可能这毒螃蟹一抽把没加密的盐存在文件中呢?我就单纯的意淫下,哈哈,我们继续往下看~
终于到了最终的文件加密了,函数压入了3个参数:
- 原始文本异或R1(随机数)后的字段(0x1310000)
- 新申请的存储地址 (0x1320000)
- R2(随机数)
加密时首先会用R2对密文进行异或,0x10字节为一组,利用了EAX、EBX、ECX、EDX分别存储4字节密文
之后是一段F5后长达500行的加密
看起来虽长,但原理不难,病毒利用了一段内存的各种偏移(偏移值由被加密的ECX寄存器低16位动态获取)进行异或加密(辅以循环位移),我们可以通过把内存DUMP下来,模拟加解密~因为我们之前也得到了私钥,那么现在已经是可以实现解密的,然而有什么意义呢?毕竟中毒时如果没有实时抓包,是无法记录下发送的密钥的,那么即使逆出算法,也没法破解公钥体制,毕竟这是1024位的RSA。
最终看一下病毒文件的写顺序:
1.0x1320000 原文件加密内存
2.0x140000 “GandCrabGandCrabGandCrabGandCrab”随机数加密内存
3.0x1A0000 ”GandCrabGandCrab”随机数加密内存
4.0x1C0000 标志位
最终加密文件1.txt.CRAB
思考总结
这个病毒分析起来挺有意思的,但很磨时间,掺杂了很多的代码混淆、花指令,shellcode部分无法F5分析。
一些想法:
1.分析病毒时若导出表和代码中API很少,有理由怀疑会释放shellcode或PE文件。
2.合理选择F7进CALL的时机,寻找关键循环或CALL,不要掉入病毒的混淆陷阱。
3.内存中的释放文件要及时DUMP出来,先IDA静态分析,再OD动态调试。
4.耐心耐心再耐心,和病毒大哥拼毅力。
5.对于加解密部分,V1版本的解密是服务器泄露造成的,V2版本对防止逆向分析做了很多处理,但加解密手段没有太大改变。
6.最后友情提示,谨慎留意钓鱼邮件、漏洞工具包以及不明网站的字体下载! 字体下载!
能力有限,有误的地方请大家指出~谢谢