【病毒分析】独家揭秘LIVE勒索病毒家族之2.0(全版本可解密)
1.1 来源
公司从客户现场提取出来了该勒索样本,通过分析发现该样本存在LIVE家族的特征,但与LIVE1.0的加密特征略有不同,故称为LIVE2.0版本。该文我们会对LIVE2.0加密流程进行分析,并在接下来的文章发布LIVE2.0勒索病毒的解密器。
1.2 介绍
LIVE2.0勒索病毒是LIVE家族的第二代恶意软件,该恶意软件会加密受害者的文件,并且将受害者的ID、文件名称和文件名称的长度写入到加密文件的末尾,最后会将文件名重命名成带.LIVE的文件 ,尤其是针对较重要的文本类文件会采用全部数据加密的方式。此外,它还会提供给受害者一封“FILE RECOVERY_ID_+受害者ID.txt”的勒索信。
加密前:

加密后:

2.文件分析
2.1 文件结构
与LIVE1.0版本不同的地方是密钥的长度从16byte变到了8byte,勒索壁纸换成了png格式的新图片。

2.2 程序配置信息

2.3 勒索信

2.4 勒索壁纸

2.5 密钥

2.6 加密文件结构
其中原始文件名长度和progarm_id都是以小端序的方式存储的。

2.7 加密文件样式
加密文件名特征:随机数+.LIVE
加密文件目录样式:
勒索信+加密文件

解密后:

3.程序运行分析
初步来看加密器并未使用保护措施,并且没有移除符号表,入口点为main。

首先因虑到LIVE1.0版本和LIVE2.0版本有过多相似的地方,所以2.0的伪C代码就不再重复加注释了,注释可以参考上篇LIVE1.0版本内容。
3.1 Main函数
从Main函数中可以知道主要逻辑在progarm_main函数中,跟LIVE1.0版本一致。

3.2 Progarm_main函数
首先程序会获取程序运行中的命令行,并且根据其参数内容进行其他功能的使用。

3.3 program_print_help函数(打印使用说明)
具体实现在函数program_print_help函数中有所说明,如:指定加密的目录、删除系统还原点、停止服务等,使用方法是--参数 true/false,跟LIVE1.0版本一致。
Progarm_main函数逻辑分析,最开始仅仅只检测cmd命令行的第一个参数是不是--self,如果是需要将第二个参数即程序本身路径作为cmdline的第一个参数,以防止后续读取自身文件时,使用第一个参数不是文件本身路径而是--self参数,导致后续读取密钥与程序配置内容失败。
接下来进行了读取系统时间,以用作后续的日期判断,来对程序状态进行设置。
再往下是初始化,初始化主要分为两部分,密钥初始化和程序初始化。这里再次提一下文件的结构组成:
其中初始化和LIVE1.0版本一样,都是两个初始化由encryption_Initialize函数和program_Initialize函数来实现。
3.4 encryption_Initialize函数(密钥初始化)
密钥初始化核心为两部分,一个是从程序文件本身读取KEY,另外是从将硬编码的IV赋值。
读取KEY
原理和LIVE1.0版本一样,先从末尾读取4字节长度,再用fseek来不断的移动文件指针到key处。

赋值IV

整体的密钥初始化结束。
3.5 program_Initialize函数(程序初始化)
其功能是读取勒索信前面部分程序配置信息,并且将其转换为key:value的形式,以便于后续功能的使用。
读取配置项
原理和LIVE1.0版本一样,先读取末尾的勒索信长度,再依次移动文件指针到配置信息的开头

转化为key:value的形式

文件内配置信息

整体的程序初始化结束。
接下来是一个死循环,主要针对于文件本身的第一个参数以后的其他参数进行遍历,并且判断其功能是否开启等操作,具体功能介绍在program_print_help函数有介绍,如果参数未在其中,会触发program_print_help函数。

参数遍历完毕后,就是针对于时间的比较,从文件配置信息中可以得到一个最大与最小的日期信息,是个时间戳,转换一下可以得到其具体时间。


逻辑实现
原理与LIVE1.0版本一样,都是根据Unix时间戳的形式来进行的判断,作用就是来判断软件是否在2023-01-01 08:00:00 ~ 2024-02-15 08:00:00 之间,不在则不能够运行。

接下来会从配置文件中读取勒索信的文件名称,并且从文件名中以‘_’字符进行分割包含的ID,给到progarms_id变量以便后续的使用,最后获取更换壁纸功能的状态,如果是true的话就会进入到progarm_ChangeWallpaper函数进行勒索壁纸的更换。
配置中的变量内容

获取progarm_id

读取壁纸更换功能状态,并且判断是否更换壁纸

读取勒索壁纸文件名称,并且进行壁纸更换的操作。
3.6 progarm_ChangeWallpaper函数(更改壁纸):
先移动FILE指针到程序文件中的勒索壁纸的开头,读入到临时变量中,跟LIVE1.0版本相比,除了图片的类型和内容长度发生了变化,其余的实现逻辑一样。

获取程序文件的目录,进行勒索壁纸的保存。

写入一个更换壁纸的Powershell脚本wallpaper.ps1,并且使用system函数执行,完成更换壁纸的操作。

更换壁纸powershell脚本wallpaper.ps1内容:

获取勒索信的内容分析,将勒索信内容赋值到了NoteBytes变量中,以便后续的使用。

对IncludeExtensions配置项的状态进行获取,来判断是否启动包含扩展的功能,这里配置中IncludeExtensions是False,所以他将获取NoneSet的配置项内容,即不加密的文件后缀。

IncludeExtensions配置项的状态也决定了程序使用那个加密函数,这里加密函数有两个一个是_lambda4program_encrypt,另外一个是_lambda5program_encrypt,根据IncludeExtensions配置项的内容为false的缘故,所以progarm_encrypt将使用这个加密_lambda5program_encrypt作为其执行函数。

程序为了保证写入勒索信和对文件进行加密顺利,将利用system函数来执行相应的cmd命令对系统进行恢复选项的禁用并且对操作系统的引导状态策略设置为忽略所有故障。

之后就是对程序指定的服务和进程的停止操作.
对进程
原理和LIVE1.0版本一样,先是判断其功能的开关状态,再进行执行

对服务
原理和LIVE1.0版本一样,先是判断其功能的开关状态,再进行执行

在对指定的服务和进程进行关闭后,将开始最为关键的对文件操作的流程了。
首先是比较明显的目录下进行勒索信的写入.

因为DropNoteInSpecificDirectories配置项内容为true的缘故,所以勒索信会在DirectoriesToDropNoteIn配置项内容下的两个目录中写入名为NoteFilename配置项内容的勒索信文件。勒索信写入完毕后,将开始对磁盘文件的遍历与加密。
到了这部分原本的1.0在接下来的代磁盘遍历前,将进行多线程的操作,以此种方式来加快加密的速度,但是因为LIVE1.0版本的BUG问题,所以会导致出现非预期的文件,这里就是与LIVE1.0版本最不一样的地方。
黑客发现bug后开始做修复,直接去掉了多线程的方式,采用单线程的方式进行磁盘的遍历与加密。

获取IncludeDirectories指定目录的功能开关状态,开始判断。
如果开则获取DirectorySet的目录并且向下遍历。

程序因为并未开启该功能,所以跳过,准备对所有磁盘进行遍历操作。
首先是对A-Z字符做了拷贝,以供后续作为磁盘的盘符。

对其进行遍历路径的拼接,不断的迭代,类似树的DFS,具体由progarm_Iterate函数实现。

3.7 progarm_Iterate函数(遍历文件路径,过滤文件,加密文件)
其参数有四个,分别为:(文件路径,配置信息,勒索信内容,勒索信长度,多线程对象)
因为LIVE2.0版本取消了多线程的操作,直接去掉了多线程对象的这个参数。
首先该函数会打开文件路径下的目录,并且获得该目录下的所有文件的同时进行路径拼接,对其路径所指文件或目录进行判断是文件还是目录。
打开目录

获取该目录下的文件并做判断

如果是普通文件的话,先对其中的隐藏文件进行判断,根据EncryptHiddenFiles配置项来决定是否加密隐藏文件,EncryptHiddenFiles内容为true,所以对隐藏文件也进行加密。
考虑到存在NAS的缘故,所有判断了‘.‘开头的文件。

当满足了上述条件后,将最后做一次文件过滤,判断其加密文件后缀是否在Noset配置项内容中,所有过程过程由program_Filter函数实现,与LIVE1.0版本一样。
3.7.1 program_Filter函数(文件过滤)
其参数有七个,分别为(文件名称,IncludeFiles配置项内容,FileSet配置项内容,FileSet配置项内容长度,IncludeExtension配置项内容,IncludeExtension配置项内容长度)
首先是获取文件的后缀,并且转换为小写
判断该文件后缀是否在Noset配置项内容中,Noset配置项内容:['exe', 'dll', 'ink', 'ini', 'lnk', 'ico', 'sys', 'desktop', 'mui', 'live'],若是不在则通过,若是在则不通过。
(这里考虑到判断较多,不美观,所以选用LIVE1.0版本的图,实现是一致的)

最后会多加一个判断,判断其文件是否是勒索信文件。
在完成文件过滤后,如果该文件符合上述所有条件,原本的LIVE1.0版本操作则会采用:需要将其普通文件丢入到线程池中,进行最后的加密了,然后还会将勒索信文件可写标志设置成true。
而在LIVE2.0版本中去掉了多线程的操作后,将直接执行progarm_encrypt函数,进行文件的加密操作,紧接着写入加密的标志性内容和重命名操作。
程序加密

对不是普通文件的进行一个判断,如果是目录的话就会继续往下遍历,执行与上面一样的操作。

3.7.2 progarm_encrypt函数(文件加密)
文件加密的progarm_encrypt函数的实现在程序中有两个:
_lambda4program_encrypt函数
_lambda5program_encrypt函数(此程序选择该函数作为加密函数)
而这两个函数的实现基本一致。
在LIVE1.0版本中,采用的核心加密函数为两个,但也可以算作是一个,只是加密的部分有所区别,而区分标准则是根据后缀类型:
'txt', 'log', 'doc', 'docx', 'msg', 'rtf', 'dat', 'ppt', 'pptx', 'xml', 'csv', 'xls', 'xlsx'后缀的文件采用encryption_Full函数加密,会对其文件的全部数据进行加密
除了'exe', 'dll', 'ink', 'ini', 'lnk', 'ico', 'sys', 'desktop', 'mui', 'live'后缀的文件,都采用encryption_Fast函数加密,会对其文件的部分数据进行加密,也就是文件数据的前0x2000字节大小的数据进行加密。
3.7.3 encryption_Full函数(全加密)
这里和LIVE1.0版本的一样,就完全采用LIVE1.0版本的内容
该函数整体其实主要做的是文件的分快读写操作,一次读0x1000大小的数据,然后交给加密算法进行加密,最后写入原文件,直到加密完全部的文件数据为止,而加密部分主要是由encryption_OFB_Encrypt实现。
注意:2.0的全加密的算法中,并未采用8字节对齐的操作,最后一块加密内容若是少于8字节就不加密了。
采用读写的模式打开文件流;

采用分块加密,一次加密0x1000大小的数据,直到加密完所有数据为止;

采用了OFB的加密方式,由函数encryption_OFB_Encrypt实现;

最后依次将其加密数据写入到原文件中。
3.7.4 encryption_Fast函数(部分加密)
这里和LIVE1.0版本的一样,就完全采用LIVE1.0版本的内容
该函数整体其实主要做的是文件的读写操作,一次性读取0x2000大小的文件数据交给加密函数进行加密,而加密部分主要是也是由encryption_OFB_Encrypt实现。
采用读写的模式打开文件流;

采用一次性读取0x2000大小数据进行加密;

加密算法采用了OFB的加密方式,由函数encryption_OFB_Encrypt实现;

最后将加密数据写入到原文件中。

3.7.5 encryption_OFB_Encrypt函数(核心加密函数)
这里和LIVE1.0版本的不一样,LIVE1.0版本采用的是encryption_Treyfer128函数对IV和Key进行处理**6**
该函数核心是异或加密,首先程序会处理一下iv,这里变成了通过encryption_Xor函数进行处理,最后将处理过的IV和原文件进行异或运算,8个字符为一组,将结果作为加密后的结果,最后再处理一次IV。

3.7.6 encryption_Xor函数(IV处理)
整体的处理呢大致分为两步:
将key和iv的值进行异或操作
将对应得到的iv加13
这里反而与LIVE1.0版本相比变的更加简单

当文件全部加密结束后,将回到progarm_lterate函数,然后继续执行写入加密标志内容与文件重命名操作。
写入加密的标志性内容:
这里与LIVE1.0版本不同,LIVE1.0版本标志性内容只有progarm_id
加密的标志性内容组成:
原始文件名;
原始文件名长度;
8字节的progarm_id。

重命名
这里也与LIVE1.0版本有所不同,LIVE1.0版本仅仅是在原始文件名后加.LIVE,而LIVE2.0版本则会采用随机数作为文件名。

在该加密文件的目录下写入勒索信文件。

下面会发现磁盘中的文件变成下图。

最后,在所有磁盘加密完成后将执行:
清空应用程序日志、安全日志和系统日志;
获取当前的UTC时间;
计算当前时间和另一个时间(v401)之间的差值,并将结果输出为字符串;
释放内存并清理变量。


