病毒分析之Lucky勒索病毒解密分析

病毒分析之Lucky勒索病毒解密分析

0x0概况

Lucky是一种超强传播能力的恶意代码软件家族。其功能复杂,模块较多,能够利用多种漏洞组合和进行攻击传播。

含有Windows和Linux双平台攻击模块,加密算法使用RSA+AES算法,攻击完成最后利用中毒计算机进行挖矿,勒索等。

本文只分析其中的加密勒索模块部分,主要实现其加密后文件的解密,至于其他攻击模块,可参考文章后边提供的其他文章。

0x1加密分析

判断条件部分:勒索病毒会遍历全盘文件,加密固定扩展名的文件。

病毒分析之Lucky勒索病毒解密分析_第1张图片病毒分析之Lucky勒索病毒解密分析_第2张图片

病毒分析之Lucky勒索病毒解密分析_第3张图片

判断为加密的文件扩展名为:

病毒分析之Lucky勒索病毒解密分析_第4张图片

指定目录文件不加密,排除的一些特定的目录如下:

病毒分析之Lucky勒索病毒解密分析_第5张图片

病毒会联网检查病毒更新,尝试关闭一些数据库服务和进程以解除文件占用,方便对文件进行加密。

病毒分析之Lucky勒索病毒解密分析_第6张图片

操作文件部分:首先重命名被加密文件

病毒分析之Lucky勒索病毒解密分析_第7张图片

病毒分析之Lucky勒索病毒解密分析_第8张图片

然后打开文件句柄,以每次16字节读取文件,判断文件大小和真实读取的数据大小,加密数据后再次写入文件。最后在文件末尾写入之前加密过的512字节Hex数据。

病毒分析之Lucky勒索病毒解密分析_第9张图片

生成Key部分:计算key一共分为三部分。1,生成一个200大小的随机字符串;2,解密使用一个40大小的固定字符串;

3,然后拼接这两部分字符串,计算出AES 256 KEY。

病毒分析之Lucky勒索病毒解密分析_第10张图片

优化过后代码就是

病毒分析之Lucky勒索病毒解密分析_第11张图片

最后在C盘根目录下生成提示勒索的文本文档

病毒分析之Lucky勒索病毒解密分析_第12张图片

病毒分析之Lucky勒索病毒解密分析_第13张图片

0x2解密思路

提供三种方案的思路:

(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!...的字符串可作为对比源。

病毒分析之Lucky勒索病毒解密分析_第14张图片

生成Key的思路如图:

病毒分析之Lucky勒索病毒解密分析_第15张图片

部分测试代码:

病毒分析之Lucky勒索病毒解密分析_第16张图片病毒分析之Lucky勒索病毒解密分析_第17张图片病毒分析之Lucky勒索病毒解密分析_第18张图片

其中尝试创建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;
}

0x3解密实现

解密实现测试效果如图:

病毒分析之Lucky勒索病毒解密分析_第19张图片

病毒分析之Lucky勒索病毒解密分析_第20张图片

结语

Lucky很多模块名称和代码框架与Satan有较多相似之处,有理由相信作者是同一个人或组织或有关联,并根据排除的文件路径猜测其作者可能为国人。面对各种新的变种勒索,再次提醒用户及时更新杀毒软件,打好最新的系统补丁以防止中招儿才是上上策,文件被加密勒索后再去解密实在是下策。

注:

安全客链接

本文只介绍了Lucky家族加密模块部分,其他可参考:

《Lucky双平台勒索者样本技术分析 》

https://www.freebuf.com/column/190779.html

你可能感兴趣的:(系统安全,软件安全,逆向分析,C/C++,ASM)