Lucky是一种超强传播能力的恶意代码软件家族。其功能复杂,模块较多,能够利用多种漏洞组合和进行攻击传播。
含有Windows和Linux双平台攻击模块,加密算法使用RSA+AES算法,攻击完成最后利用中毒计算机进行挖矿,勒索等。
本文只分析其中的加密勒索模块部分,主要实现其加密后文件的解密,至于其他攻击模块,可参考文章后边提供的其他文章。
判断条件部分:勒索病毒会遍历全盘文件,加密固定扩展名的文件。
判断为加密的文件扩展名为:
指定目录文件不加密,排除的一些特定的目录如下:
病毒会联网检查病毒更新,尝试关闭一些数据库服务和进程以解除文件占用,方便对文件进行加密。
操作文件部分:首先重命名被加密文件
然后打开文件句柄,以每次16字节读取文件,判断文件大小和真实读取的数据大小,加密数据后再次写入文件。最后在文件末尾写入之前加密过的512字节Hex数据。
生成Key部分:计算key一共分为三部分。1,生成一个200大小的随机字符串;2,解密使用一个40大小的固定字符串;
3,然后拼接这两部分字符串,计算出AES 256 KEY。
优化过后代码就是
最后在C盘根目录下生成提示勒索的文本文档
提供三种方案的思路:
(1)如果勒索病毒进程还在运行,则直接从0x610A30地址处提取Key用于解密。
(2)如果勒索病毒进程不存在了,或者没有提取到Key,则尝试碰撞Key。
如果已知①某文件加密前的部分数据,②这个文件被加密后的那部分数据,③勒索病毒大概的爆发时间
(3)同上,没有提取到Key,尝试碰撞。如果未知加密前文件数据。则尝试用RAR,DOC等文件开始必须的数据作对比。
详细说下第二种:
我这里准备的数据是,1.源文件 BOOTSECT.BAK ;2.被加密的文件 [[email protected]]BOOTSECT.BAK.kDeLBN1WSg5DKZQjw7OhSOcmumYeDnN11eIAiIc1.lucky。
具体碰撞方法就是,生成随机字符串+固定字符串,计算出KEY,尝试去解密[[email protected]]BOOTSECT.BAK.kDeLBN1WSg5DKZQjw7OhSOcmumYeDnN11eIAiIc1.lucky文件中的前16个字节,如果解密的内容与源文件BOOTSECT.BAK中前16个字节中的内容相同,则判断为有效Key,可以去尝试解密其他文件。
提一下第三种:
第三种实际与第二种思路一样,只不过是对比源文件数据与加密文件数据的时候,源文件如果是RAR,DOC等文件,其开始处的源数据直接已知,不许要再有被加密的前的源文件。
比如RAR压缩文件,开始必有RAR!...的字符串可作为对比源。
生成Key的思路如图:
部分测试代码:
其中尝试创建Key的函数TryCreateKey(),使用了较复杂的算法,整理出代码如下:
// 创建一个随机字符串,返回随机字符串地址
int R_CreateRandKey(_In_ int vSeed, _In_ bool* IsCreate)
{
int v1;
int v6 = (int)malloc(201);
char* v3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+}{:<>?";
int v0 = time(NULL);//当前时间大于2018年12月17日则继续
if (v0 - vSeed >= gTime)
*IsCreate = true;
else
*IsCreate = false;
srand(v0 - vSeed);
for (int i = 0; i <= 199; ++i)
{
v1 = rand() % 80;
*(BYTE *)(v6 + i) = *((BYTE *)(v3 + v1));
}
*(BYTE *)(v6 + 200) = 0;
return v6;
}
#define BYTE1(x) (((BYTE*)&x)[1])
//byte_406A80
//------------------------------------------------------------
//----------- Created with 010 Editor -----------
//------ www.sweetscape.com/010editor/ ------
//
// File : C:\Users\xxxx\Desktop\D??¨??±???μμ.txt
// Address : 0 (0x0)
// Size : 256 (0x100)
//------------------------------------------------------------
unsigned char byte_406A80[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
//byte_406E00
//------------------------------------------------------------
//----------- Created with 010 Editor -----------
//------ www.sweetscape.com/010editor/ ------
//
// File : C:\Users\xxxx\Desktop\D??¨??±???μμ.txt
// Address : 0 (0x0)
// Size : 168 (0xA8)
//------------------------------------------------------------
unsigned char byte_406E00[168] = {
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00
};
// a2源(gSrcStr),a4目标(gAESKey),a3位数(256),a1没用到
signed int __cdecl R_FillKeyAddress(int a2, int a3, int a4)
{
int v4; // edi@1
signed int result; // eax@6
int v6; // eax@7
int v7; // ebx@7
int v8; // ecx@7
unsigned int v9; // edx@7
signed int v10; // ecx@7
int v11; // eax@9
int v12; // ebx@9
unsigned int v13; // edx@9
int v14; // eax@9
int v15; // eax@9
int v16; // eax@9
int v17; // eax@11
int v18; // ebx@11
int v19; // ecx@11
int v20; // edx@11
unsigned int v21; // edx@11
int v22; // ecx@11
int v23; // eax@12
int v24; // ebx@12
unsigned int v25; // edx@12
int v26; // eax@12
int v27; // eax@12
int v28; // eax@12
int v29; // eax@12
int v30; // eax@13
int v31; // ebx@15
int v32; // ecx@15
int v33; // edx@15
int v34; // ebx@15
int v35; // ecx@15
unsigned int v36; // edx@15
int v37; // ecx@15
int v38; // eax@16
int v39; // ebx@16
unsigned int v40; // edx@16
int v41; // eax@16
int v42; // eax@16
int v43; // eax@16
unsigned int v44; // eax@16
unsigned int v45; // edx@17
int v46; // eax@17
int v47; // eax@17
int v48; // eax@17
v4 = a4;
if (a2 && a4)
{
switch (a3)
{
case 256:
v31 = *(DWORD *)(a2 + 4);
v32 = *(DWORD *)(a2 + 8);
v33 = *(DWORD *)(a2 + 12);
*(DWORD *)a4 = *(DWORD *)a2;
*(DWORD *)(a4 + 4) = v31;
*(DWORD *)(a4 + 8) = v32;
*(DWORD *)(a4 + 12) = v33;
v34 = *(DWORD *)(a2 + 20);
v35 = *(DWORD *)(a2 + 24);
v36 = *(DWORD *)(a2 + 28);
*(DWORD *)(a4 + 16) = *(DWORD *)(a2 + 16);
*(DWORD *)(a4 + 20) = v34;
*(DWORD *)(a4 + 24) = v35;
*(DWORD *)(a4 + 28) = v36;
v37 = 0;
while (1)
{
v38 = (byte_406A80[(unsigned __int8)v36] << 24) ^ *(DWORD *)v4;
v39 = byte_406A80[BYTE1(v36)];
v40 = v36 >> 16;
v41 = *(DWORD *)&byte_406E00[4 * v37 + 128] ^ (byte_406A80[BYTE1(v40)] << 16) ^ (byte_406A80[(unsigned __int8)v40] << 8) ^ v39 ^ v38;
*(DWORD *)(v4 + 32) = v41;
v42 = *(DWORD *)(v4 + 4) ^ v41;
*(DWORD *)(v4 + 36) = v42;
v43 = *(DWORD *)(v4 + 8) ^ v42;
*(DWORD *)(v4 + 40) = v43;
v44 = *(DWORD *)(v4 + 12) ^ v43;
*(DWORD *)(v4 + 44) = v44;
if (v37 == 6)
break;
++v37;
v45 = v44 >> 16;
v46 = (byte_406A80[BYTE1(v45)] << 24) ^ (byte_406A80[(unsigned __int8)(v44 >> 16)] << 16) ^ (byte_406A80[BYTE1(v44)] << 8) ^ byte_406A80[(unsigned __int8)v44] ^ *(DWORD *)(v4 + 16);
*(DWORD *)(v4 + 48) = v46;
v47 = *(DWORD *)(v4 + 20) ^ v46;
*(DWORD*)(v4 + 52) = v47;
v48 = *(DWORD *)(v4 + 24) ^ v47;
*(DWORD *)(v4 + 56) = v48;
*(DWORD *)(v4 + 60) = *(DWORD *)(v4 + 28) ^ v48;
v4 += 32;
v36 = *(DWORD *)(v4 + 28);
}
*(DWORD *)(v4 + 48) = 14;
result = 0;
break;
default:
result = -2;
break;
}
}
else
{
result = -1;
}
return result;
}
// 尝试创建key
bool TryCreateKey()
{
// 创建第一个随机字符串
bool vIsCreate;
char* vFirstStr = (char*)R_CreateRandKey(gSeed, &vIsCreate);
if (vIsCreate == false)
{
// 不能创建返回
PrintHades("错误:不能创建随机字符串,请检查时间");
free(vFirstStr);
return false;
}
// 定义第二个字符串
char* vSecondStr = "qtaFLzYxCdockbV4audB0TUofxXTurDlGcfuNfLK";
// 拼接出源字符串
memset(gSrcStr, 0, 257);
memcpy(gSrcStr, vFirstStr, 200);
memcpy(gSrcStr + 200, vSecondStr, 40);
free(vFirstStr);
// 计算出AES的Key
memset(gAESKey, 0, 257);
if (R_FillKeyAddress((int)gSrcStr, 256, (int)gAESKey) != 0)
{
return false;
}
return true;
}
解密实现测试效果如图:
结语
Lucky很多模块名称和代码框架与Satan有较多相似之处,有理由相信作者是同一个人或组织或有关联,并根据排除的文件路径猜测其作者可能为国人。面对各种新的变种勒索,再次提醒用户及时更新杀毒软件,打好最新的系统补丁以防止中招儿才是上上策,文件被加密勒索后再去解密实在是下策。
注:
安全客链接
本文只介绍了Lucky家族加密模块部分,其他可参考:
《Lucky双平台勒索者样本技术分析 》
https://www.freebuf.com/column/190779.html