【软件逆向-【病毒分析】888勒索家族再出手!幕后加密器深度剖析】此文章归类为:软件逆向。
2025年3月,Solar应急响应团队成功捕获了888勒索家族的加密器样本。实际上,我们最早接触该家族是在2024年10月,彼时888家族活跃度极高,频繁针对医疗行业发起攻击,受害对象以药店、医院等医疗机构为主。
在攻击方式上,888家族主要通过MSSQL数据库弱口令爆破实现初始入侵,成功获取权限后,将自制的加密器投放至服务器路径中的Music\misc目录,以隐藏其恶意文件,随后迅速对服务器内的重要数据实施加密勒索。
该勒索家族较为狡猾,通过ping空地址绕过本地安全机制监测最终实现自删除。
加密器启动后运行的命令行指令
在成功加密后,桌面上会生成名为“!RESTORE_FILES!.txt”的勒索信,要求受害者将信内ID发到下方的邮箱中,以取得初步联系获得赎金报价。
勒索信
被加密后的目录
888勒索家族惯用的手段是通过数据库对外暴露入口弱口令入侵数据库,并在数据执行提权操作,获取高权限账户或将木马加载到受害者设备,随后再进行加密器的加载运行。
详细信息 | 类型 | 关联文件/主机/备注 |
---|---|---|
d15ab1e89fc94d9b4dff7cb5b8d392eca74a0a65 | Sha1 | netpass64.exe |
7ab128659ad586761ea68009d59a1ccf1547a039 | Sha1 | netpass64.exe |
8b0e4650f1a7080b78066a61152e571ca8b6816b | Sha1 | svchost.exe |
86803bbc26ed08e863ab17c765577a74637afaa7 | Sha1 | svchost.exe |
a0bdfac3ce1880b32ff9b696458327ce352e3b1d | Sha1 | processhacker.exe |
729fd507a1118b2d9008a097b7330c52760ceb9e | Sha1 | processhacker.exe |
31.43.176.57 | IP | 波兰 |
36.152.235.38 | IP | 中国 江苏省 徐州市 |
185.132.176.32 | IP | 荷兰 南荷兰省 纳尔德韦克 |
58.211.56.222 | IP | 中国 江苏省 苏州市 |
nemesis@888recover.4wrd.cc | Mail_addr | 勒索邮箱 |
nemesissupport@firemail.cc | Mail_addr | 勒索邮箱 |
!RESTORE_FILES!.txt | File | 勒索信文件名 |
.888 | Suffix | 勒索后缀名 |
文件名 | svchost.exe |
---|---|
编译器 | Microsoft Visual C/C++(19.36.33923)[C++] |
大小 | 2.43 MB |
操作系统 | Windows(Vista)[AMD64, 64位, GUI] |
模式 | 64 位 |
类型 | EXEC |
字节序 | LE |
MD5 | 5315bdbf85ad2b3bb13ae8ee62489f7f |
SHA1 | 8b0e4650f1a7080b78066a61152e571ca8b6816b |
SHA256 | dee0fde2d096c79e138890f958b9440e87cce38504b654a97de50bb7969a9c98 |
+----------------------------------------------------------------------------+
| !!!ALL YOUR FILES ARE ENCRYPTED, AS A RESULT OF A BREACH IN SECURITY!!! |
+----------------------------------------------------------------------------+
No worries - you can get them back!
It's impossible to decrypt without contacting us.
+----------------------------------------------------------------------------+
| !!!DON'T TRY TO CHANGE ENCRYPTED FILES!!! |
| !!!DON'T RENAME ENCRYPTED FILES!!! |
| !!!DON'T USE ADDITIONAL RECOVERY SOFTWARE!!! |
| !!!IT WILL MAKE THEM IMPOSSIBLE TO DECRYPT!!! |
+----------------------------------------------------------------------------+
How to return all your data back in safe:
1. Copy and sent us your KEY.
2. We can decrypt 2 small files, no databases (.jpg, .txt, .doc, ets.. (up to 3mb)) as your warranty.
3. After payment, you will receive a special software for decryption.
-----------------------------------------------------------------------------------------------------------------
KEY:
-----------------------------------------------------------------------------------------------------------------
EMAILS:
nemesis@888recover.4wrd.cc
nemesissupport@firemail.cc
Zero cheats, all integrity.
病毒家族 | 888 |
---|---|
首次出现时间/捕获分析时间 | 2024/10/19 || 2025/03/27 |
威胁类型 | 勒索软件,加密病毒 |
加密文件扩展名 | .888 |
勒索信文件名 | !RESTORE_FILES!.txt |
有无免费解密器? | 无 |
联系邮箱 | nemesis@888recover.4wrd.cc |
感染症状 | 无法打开存储在计算机上的文件,以前功能的文件现在具有不同的扩展名(例如,solar.docx.888)。桌面上会显示一条勒索要求消息。网络犯罪分子要求支付赎金(通常以比特币)来解锁您的文件。 |
感染方式 | 受感染的电子邮件附件(宏)、恶意广告、漏洞利用、恶意链接 |
受灾影响 | 所有文件都经过加密,如果不支付赎金就无法打开。其他密码窃取木马和恶意软件感染可以与勒索软件感染一起安装。 |
sierting.txt
加密文件名 = 原始文件名+888 ,例如:sierting.txt.888
通过随机生成的两个guid来生成key和iv
初始化了几个常量如下
5FC92AFFB28BE14BD3A8B1843E9F8E8BB394A50F7E3E599D0316E97D8B98BEDF
FC5A714EFBF1AE255D0071443A0D08FE70B2DE19F1F288115EDF3E6FA5263DBF
.888
AC11CD9E6DA7311B9804D8EB421DB7EFEC8ABB7EACC999CA64F3C7A99686E826
!RESTORE_FILES!.txt
9139F9BF04FB5ED3A8DF78E10110710C4134C2A37CBE912B6428B7FE19D22689
06FEECBAD923B75FA5B35A7A949C479AA67D838884BDA14963DC1903ACCD3E37
171C88018769B3D2B33D7065A162D3731ECEFB18A54054075A16614A468925B4
24AD21C4C3E2A430DF77EC0A190E2021976059732C696FADC61F62490E5EC202
B502B9C8546259BC27DAA82287C4ADA92A16B7A81665FAF9EFD20A4C3FD6233A
A9C3ED26735E74CC8939D5D7875BC9AEC04E5A91607BE48E6897CB7A96E1170D
45AB92864D45D54123C980CD245B31ED37A6EDDDF952A342CC5D9CB777B3942E
查找同路径下是否存在p.txt文件,如果有,则读取,并将读取到的内容进行sha256哈希计算之后再进行base64编码,然后再将此文件移动到C:\Windows\Temp\!wwwGdddf#.txt
__int64 __fastcall sub_7FF643B1AF70(__int64 a1, __int64 a2)
{
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
if ( !(unsignedint)S_P_CoreLib_System_IO_File__Exists(a1) )
{
if ( (unsignedint)S_P_CoreLib_System_IO_File__Exists(a2) )
{
if ( *(&qword_7FF643BB5520 - 1) )
sub_7FF643A11806();
v6 = read_file(a2, *(_QWORD *)(qword_7FF643CDBB28 + 8));
v7 = sha256_base64(v6);
if ( v7 )
{
if ( *(_DWORD *)(v7 + 8) )
return v7;
}
}
return0i64;
}
if ( (unsignedint)S_P_CoreLib_System_IO_File__Exists(a2) )
S_P_CoreLib_System_IO_File__Delete(a2);
move_file(a1, a2, 0);
if ( *(&qword_7FF643BB5520 - 1) )
sub_7FF643A11806();
v4 = read_file(a2, *(_QWORD *)(qword_7FF643CDBB28 + 8));
v5 = sha256_base64(v4);
if ( !v5 || !*(_DWORD *)(v5 + 8) )
return0i64;
return v5;
}
用于测试的p.txt的内容为sdjfpisjpdfajspfas[pfpasjf计算后的结果为Yatspzm25UgfTLY0KDmz8Gi6SZVhA1tIk4HTqwpOBcs=
获取mac地址信息并转换为hex字符串
char **sub_7FF643B1C6C0()
{
char **v0; // rbx
__int64 NetworkInterfaces; // rsi
int v2; // edi
int v3; // ebp
__int64 *v4; // r14
__int64 v5; // r15
__int64 v6; // rcx
__int64 v7; // rax
int v8; // edx
__int64 v9; // rax
__int64 v11; // [rsp+28h] [rbp-40h] BYREF
__int64 v12; // [rsp+30h] [rbp-38h]
v11 = 0i64;
v12 = 0i64;
v0 = &off_7FF643B92330;
NetworkInterfaces = System_Net_NetworkInformation_System_Net_NetworkInformation_SystemNetworkInterface__GetNetworkInterfaces();
v2 = 0;
v3 = *(_DWORD *)(NetworkInterfaces + 8);
if ( v3 > 0 )
{
do
{
v4 = *(__int64 **)(NetworkInterfaces + 8i64 * (unsignedint)v2 + 16);
v5 = *v4;
if ( (*(unsignedint (__fastcall **)(__int64 *))(*v4 + 64))(v4) != 24
&& (*(unsignedint (__fastcall **)(__int64 *))(v5 + 48))(v4) == 1 )
{
v6 = *(_QWORD *)((*(__int64 (__fastcall **)(__int64 *))(v5 + 56))(v4) + 8);
if ( v6 )
{
v7 = v6 + 16;
v8 = *(_DWORD *)(v6 + 8);
}
else
{
v7 = 0i64;
v8 = 0;
}
v11 = v7;
LODWORD(v12) = v8;
v9 = S_P_CoreLib_System_Convert__ToHexString_1(&v11);
v0 = (char **)String__Concat_5(v0, v9);
}
++v2;
}
while ( v3 > v2 );
}
return v0;
}
获取计算机名称,截断字符串FC5A714EFBF1AE255D0071443A0D08FE70B2DE19F1F288115EDF3E6FA5263DBF的部分字节结果如下FC5A714EFBF1AE255D0071443A0D08FE,将其进行sha256计算之后再将刚刚获得的mac信息和计算机名称进行拼接,然后再计算sha256并编码为base64。最后得到如下结果 akflLG7b++2vAPZZP62WLtO5XDpblwfcnVbR+65Y1/U=
__int64 sub_7FF643B1C0E0()
{
__int64 v0; // rbx
__int64 v1; // rsi
__int64 v2; // rax
__int64 v3; // rax
__int64 v4; // rax
v0 = get_mac();
v1 = get_computer_name();
if ( qword_7FF643BB56F0[-1] )
sub_7FF643A11BA6();
v2 = String__Substring_0(*(_QWORD *)(qword_7FF643CDBD68 + 16), 0i64, 32i64);
v3 = sha256_base64_0(v2, 16);
v4 = String__Concat_6(v0, v1, v3);
return sha256_base64_0(v4, 32);
}
首先将常量字符串FC5A714EFBF1AE255D0071443A0D08FE70B2DE19F1F288115EDF3E6FA5263DBF按照12个字符的顺序截取,首先是开头部分的FC5A714EFBF1,然后是AE255D007144,以此类推。最后再截取出末尾的字符3DBF。
接着再将前面计算得到的字符串akflLG7b++2vAPZZP62WLtO5XDpblwfcnVbR+65Y1/U=用同样的方式计算。
__int64 __fastcall key_init(__int64 a1, unsigned int a2)
{
__int64 v4; // rdi
__int64 v5; // rdx
int v6; // ebp
int v7; // r14d
char **v8; // rax
__int64 v9; // rcx
__int64 v10; // rdx
v4 = RhpNewFast(&unk_7FF643BCDCA0);
RhpAssignRefAVLocation((unsigned __int64 *)(v4 + 8), *(_QWORD *)(qword_7FF643CDBE80 + 8));
v5 = 0i64;
v6 = *(_DWORD *)(a1 + 8);
if ( v6 > 0 )
{
do
{
v7 = v5 + a2;
if ( (int)(v5 + a2) > v6 )
{
v8 = String__Substring(a1, v5);
++*(_DWORD *)(v4 + 20);
v9 = *(_QWORD *)(v4 + 8);
v10 = *(unsignedint *)(v4 + 16);
if ( *(_DWORD *)(v9 + 8) <= (unsignedint)v10 )
{
LABEL_6:
S_P_CoreLib_System_Collections_Generic_List_1_System___Canon___AddWithResize(v4, v8);
goto LABEL_7;
}
}
else
{
v8 = (char **)String__Substring_0(a1, v5, a2);
++*(_DWORD *)(v4 + 20);
v9 = *(_QWORD *)(v4 + 8);
v10 = *(unsignedint *)(v4 + 16);
if ( *(_DWORD *)(v9 + 8) <= (unsignedint)v10 )
goto LABEL_6;
}
*(_DWORD *)(v4 + 16) = v10 + 1;
RhpAssignRefAVLocation((unsigned __int64 *)(v9 + 8 * v10 + 16), (unsigned __int64)v8);
LABEL_7:
v5 = (unsignedint)v7;
}
while ( v6 > v7 );
}
return v4;
}
最后通过如下方式计算出勒索信中显示的key:++2vAPZZAE255D007144akflLG7bFC5A714EFBF1P62WLtO53A0D08FE70B2nVbR+65Y5EDF3E6FA526XDpblwfcDE19F1F288111/U=3DBF
def split_string_by_segments(input_str,segment_length):
segments = []
for i in range(0, len(input_str) - 4, segment_length):
segment = input_str[i:i + segment_length]
segments.append(segment)
last_segment = input_str[-4:]
segments.append(last_segment)
return segments
str1 = "FC5A714EFBF1AE255D0071443A0D08FE70B2DE19F1F288115EDF3E6FA5263DBF"#常量字符串
result1 = split_string_by_segments(str1,12)
list1=[]
for i, seg in enumerate(result1):
list1.append(seg)
str2 = "akflLG7b++2vAPZZP62WLtO5XDpblwfcnVbR+65Y1/U="#通过计算机信息计算出来的hash
result2 = split_string_by_segments(str2,8)
list2=[]
for i, seg in enumerate(result2):
list2.append(seg)
print(list2[1]+list1[1]+list2[0]+list1[0]+list2[2]+list1[2]+list2[4]+list1[4]+list2[3]+list1[3]+list2[5]+list1[5])
将通过mac和计算机名称计算得到的hash写入C:\Windows\Temp\!wwkdsfdsfewt.txt
__int64 __fastcall sub_7FF643AE6930(
__int64 a1,
const void *lpBuffer_1,
DWORD nNumberOfBytesToWrite_1,
DWORD *lpNumberOfBytesWritten_1,
struct _OVERLAPPED *lpOverlapped)
{
void *hFile_1; // r14
unsignedint v9; // ebx
DWORD LastError; // esi
_BYTE v12[44]; // [rsp+28h] [rbp-A0h] BYREF
LPDWORD lpNumberOfBytesWritten; // [rsp+54h] [rbp-74h]
LPCVOID lpBuffer; // [rsp+5Ch] [rbp-6Ch]
HANDLE hFile; // [rsp+64h] [rbp-64h]
DWORD nNumberOfBytesToWrite; // [rsp+6Ch] [rbp-5Ch]
DWORD *lpNumberOfBytesWritten_2; // [rsp+70h] [rbp-58h]
__int128 v18; // [rsp+78h] [rbp-50h] BYREF
v18 = 0i64;
*(_QWORD *)&v18 = a1;
S_P_CoreLib_System_Runtime_InteropServices_SafeHandle__DangerousAddRef(a1, (char *)&v18 + 8);
lpNumberOfBytesWritten_2 = lpNumberOfBytesWritten_1;
hFile_1 = *(void **)(v18 + 8);
SetLastError(0);
hFile = hFile_1;
lpBuffer = lpBuffer_1;
nNumberOfBytesToWrite = nNumberOfBytesToWrite_1;
lpNumberOfBytesWritten = lpNumberOfBytesWritten_1;
RhpPInvoke(v12);
v9 = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
RhpPInvokeReturn(v12);
LastError = GetLastError();
lpNumberOfBytesWritten_2 = 0i64;
if ( BYTE8(v18) )
S_P_CoreLib_System_Runtime_InteropServices_SafeHandle__InternalRelease(v18, 0i64);
*(_DWORD *)(_GetThreadStaticBase_S_P_CoreLib_Internal_Runtime_ThreadStatics_9() + 168) = LastError;
return v9;
}
对输入的字符串进行sha256哈希,然后根据输入的a2参数进行截断,最后将截断后的字符串进行base64编码
__int64 __fastcall sha256_base64_0(__int64 a1, unsigned int a2)
{
__int64 Bytes; // rsi
__int64 v5; // rdi
__int64 v6; // rsi
__int64 v7; // rdi
__int64 v8; // rbx
__int64 v10; // [rsp+20h] [rbp-28h]
if ( *(&qword_7FF643BB5520 - 1) )
sub_7FF643A11806();
Bytes = S_P_CoreLib_System_Text_UTF8Encoding_UTF8EncodingSealed__GetBytes(*(_QWORD *)(qword_7FF643CDBB28 + 8), a1);
v5 = RhpNewFast(&unk_7FF643BC7D88);
System_Security_Cryptography_System_Security_Cryptography_SHA256Managed___ctor(v5);
v10 = v5;
v6 = sub_7FF643AFB200(v5, Bytes);
v7 = RhpNewArray(&unk_7FF643BFE7C0, (int)a2);
S_P_CoreLib_System_Array__Copy_1(v6, v7, a2);
v8 = str_to_base64(v7);
unk_7FF643BB7AA0(v10);
return v8;
}
遍历文件,并排除以下目录
对文件名进行判断
如果包含以下文件名,就跳过
!RESTORE_FILES!.txt svchost.exe bootmgr bootmgr.efi bootmgr.efi.mui bootmgr.exe bootmgr.exe.mui img___XXX.jpg
接着判断后缀是否为.888,如果是,就跳过。
接着对进行计算并得到一个常量。
if ( v17 > 1 ) { do { if ( v15 ) { v18 = (char *)v15 + 12; v19 = *((_DWORD *)v15 + 2); } else { v18 = 0i64; v19 = 0; } LODWORD(v39) = *(unsigned __int16 *)(v14 + 2i64 * (unsignedint)v16 + 12); S_P_CoreLib_System_Globalization_CultureInfo__get_CurrentCulture(); TextInfo = S_P_CoreLib_System_Globalization_CultureInfo__get_TextInfo(); HIDWORD(v39) = S_P_CoreLib_System_Globalization_TextInfo__ToLower(TextInfo, (unsignedint)v39); *(_QWORD *)&v38 = v18; DWORD2(v38) = v19; *(_QWORD *)&v37 = (char *)&v39 + 4; DWORD2(v37) = 1; v15 = (char **)String__Concat_8(&v38, &v37); v16 += 2; } while ( v17 > v16 ); }
计算方式如下
byte[] byteArray ={ 0x32, 0x00, 0x34, 0x00, 0x41, 0x00, 0x44, 0x00, 0x32, 0x00, 0x31, 0x00, 0x43, 0x00, 0x34, 0x00, 0x43, 0x00, 0x33, 0x00, 0x45, 0x00, 0x32, 0x00, 0x41, 0x00, 0x34, 0x00, 0x33, 0x00, 0x30, 0x00, 0x44, 0x00, 0x46, 0x00, 0x37, 0x00, 0x37, 0x00, 0x45, 0x00, 0x43, 0x00, 0x30, 0x00, 0x41, 0x00, 0x31, 0x00, 0x39, 0x00, 0x30, 0x00, 0x45, 0x00, 0x32, 0x00, 0x30, 0x00, 0x32, 0x00, 0x31, 0x00, 0x39, 0x00, 0x37, 0x00, 0x36, 0x00, 0x30, 0x00, 0x35, 0x00, 0x39, 0x00, 0x37, 0x00, 0x33, 0x00, 0x32, 0x00, 0x43, 0x00, 0x36, 0x00, 0x39, 0x00, 0x36, 0x00, 0x46, 0x00, 0x41, 0x00, 0x44, 0x00, 0x43, 0x00, 0x36, 0x00, 0x31, 0x00, 0x46, 0x00, 0x36, 0x00, 0x32, 0x00, 0x34, 0x00, 0x39, 0x00, 0x30, 0x00, 0x45, 0x00, 0x35, 0x00, 0x45, 0x00, 0x43, 0x00, 0x32, 0x00, 0x30, 0x00, 0x32 }; string sum= ""; for (int i = 1; i * 2 < byteArray.Length; i += 2) { sum+= (char)byteArray[i * 2]; }
接着再根据输入的文件名进行计算
v21 = (unsigned __int64 *)RhpNewArray(&qword_7FF643BFE520, 5i64); v22 = String__Substring_0(v35, 0i64, 8i64); RhpAssignRefAVLocation(v21 + 2, v22); RhpAssignRefAVLocation(v21 + 3, name_no_ext); RhpAssignRefAVLocation(v21 + 4, v12); v23 = String__Substring(v35, (unsigned int)(*(_DWORD *)(v35 + 8) - 8)); RhpAssignRefAVLocation(v21 + 5, (unsigned __int64)v23); RhpAssignRefAVLocation(v21 + 6, a2); v24 = String__Concat_12((__int64)v21); v25 = sha256_base64_0((__int64)v24, 8); v26 = sha256_base64_0(name_no_ext, 16); v27 = (unsigned __int64 *)RhpNewArray(&qword_7FF643BFE520, 5i64); RhpAssignRefAVLocation(v27 + 2, v26); v28 = String__Substring(*(_QWORD *)(v13 + 16), 32i64); v29 = sha256_base64_0((__int64)v28, 32); RhpAssignRefAVLocation(v27 + 3, v29); RhpAssignRefAVLocation(v27 + 4, a2); v30 = String__Substring(v35, (unsigned int)(*(_DWORD *)(v35 + 8) - 10)); RhpAssignRefAVLocation(v27 + 5, (unsigned __int64)v30); RhpAssignRefAVLocation(v27 + 6, (unsigned __int64)v15); v31 = String__Concat_12((__int64)v27); v32 = sha256_base64_0((__int64)v31, 32); return String__Concat_6(v32, &off_7FF643BAFBC0, v25);
首先计算v32,计算方法如
//Program.const_str是输入的密钥文件sha256加密后再使用base64编码后的结果 string filename = Path.GetFileNameWithoutExtension(Path.GetFileName(encryptedFilePath)); string name = Path.GetFileNameWithoutExtension(filename); byte[] name_sha256 = ComputeTruncatedHash(sha256, name, 16); string base_name = Convert.ToBase64String(name_sha256); string concat_str0 = base_name + "kJxdORYN/Ls2XC9oCqio+0ZY63esndX7jYcy4GGrLrI=" + Program.const_str + "FE19D226894d143240f" + "7ca9e017093c9fd6f29ee22"; byte[] concat_str0_sha256 = ComputeTruncatedHash(sha256, concat_str0, 32); string base_concat_str0 = Convert.ToBase64String(concat_str0_sha256);
接下来计算v25,计算方法如下
string input = "9139F9BF" + name + "B33D7065A162D3731ECEFB18A540540719D22689" + Program.const_str; byte[] hash = ComputeTruncatedHash(sha256, input, 8); string input_hash = Convert.ToBase64String(hash);
然后通过||将这个两个计算出来的字符串拼接在一起
接着随机生成两个guid
guid1 = S_P_CoreLib_System_Guid__ToString_1((__int64)&v66 + 8, (__int64)&off_7FF643BAD1D0, 0i64, v16); guid2 = S_P_CoreLib_System_Guid__ToString_1((__int64)&v65, (__int64)&off_7FF643BAD1D0, 0i64, v17); v60 = sha256_base64_0(guid1, 32); v59 = sha256_base64_0(guid2, 32); v47 = sha256_base64_0(v13[11], 32); v18 = sha256_base64_0(v13[11], 32); v46 = String__Substring(v47, (unsigned int)(*(_DWORD *)(v18 + 8) - 12)); v19 = sha256_base64_0(v13[13], 32); v20 = String__Substring_0(v19, 0i64, 16i64); v58 = String__Concat_5(v46, v20); v45 = sha256_base64_0(v13[13], 32); v21 = sha256_base64_0(v13[11], 32); v44 = String__Substring(v45, (unsigned int)(*(_DWORD *)(v21 + 8) - 12)); v22 = sha256_base64_0(v13[11], 32); v23 = String__Substring_0(v22, 0i64, 16i64); v57 = String__Concat_5(v44, v23); v43 = sha256_base64_0(v13[13], 32); v24 = sha256_base64_0(v13[11], 32); v42 = String__Substring(v43, (unsigned int)(*(_DWORD *)(v24 + 8) - 16)); v41 = sha256_base64_0(FileNameFromPathBuffer, 16); v25 = sha256_base64_0(v13[11], 32); v40 = String__Substring_0(v25, 0i64, 12i64); v26 = String__Substring(v13[9], (unsigned int)(*(_DWORD *)(v13[9] + 8) - 16)); v56 = String__Concat_7(v42, v41, v40, v26); v39 = sha256_base64_0(v13[11], 32); v27 = sha256_base64_0(v13[11], 32); v38 = String__Substring(v39, (unsigned int)(*(_DWORD *)(v27 + 8) - 16)); v37 = sha256_base64_0(FileNameFromPathBuffer, 16); v28 = sha256_base64_0(v13[13], 32); v36 = String__Substring_0(v28, 0i64, 12i64); v29 = String__Substring(v13[10], (unsigned int)(*(_DWORD *)(v13[10] + 8) - 12)); v48 = String__Concat_7(v38, v37, v36, v29); v55 = sha256_base64(v58); v54 = sha256_base64(v57); v53 = sha256_base64(v56); v52 = sha256_base64(v48); v30 = String__Concat_6(*(_QWORD *)(v6 + 16), v60, v59); v31 = sha256_base64(v30);
还原后的代码如下
//随机生成的guid,这里使用固定值进行测试 string guid1 = "c6d47a10-0cf3-4d5c-a500-267db6a41545"; byte[] guid1_byte = ComputeTruncatedHash(sha256, guid1, 32); string base_guid1_byte = Convert.ToBase64String(guid1_byte); //随机生成的guid,这里使用固定值进行测试 string guid2 = "8184cff9-01c7-4f07-ac38-d80ed77d4b58"; byte[] guid2_byte = ComputeTruncatedHash(sha256, guid2, 32); string base_guid2_byte = Convert.ToBase64String(guid2_byte); byte[] hex4_byte = ComputeTruncatedHash(sha256, hex4, 32); string base_hex4_byte = Convert.ToBase64String(hex4_byte); byte[] hex5_byte = ComputeTruncatedHash(sha256, hex5, 32); string base_hex5_byte = Convert.ToBase64String(hex5_byte); string hex5_hex4_cat = hex4_cat + base_hex5_byte.Substring(0, 16); string base_hex5_cat = base_hex5_byte.Substring(base_concat_str0.Length - 12, 12); string base_hex4_cat = base_hex4_byte.Substring(0, 16); string concat5 = base_hex5_cat + base_hex4_cat; //filename为文件名 byte[] filename_byte = ComputeTruncatedHash(sha256, filename, 16); string base_filename_byte = Convert.ToBase64String(filename_byte); string concat6 = "e9+zXBNtL8ALaRk=" + base_filename_byte + "IewroqVNVUV0" + "5A16614A468925B4"; string concat7 = "D8NSVR1FARLvFrc=" + base_filename_byte + "Q9584Xb6oe9J" + "62490E5EC202"; byte[] byte7 = ComputeTruncatedHash(sha256, "VR1FARLvFrc=Q9584Xb6oe9J5Vxk", 32); string base_byte7 = Convert.ToBase64String(byte7); byte[] byte8 = ComputeTruncatedHash(sha256, "XBNtL8ALaRk=IewroqVNVUV0G/DZ", 32); string base_byte8 = Convert.ToBase64String(byte8); byte[] filename_concat_byte_sha256 = ComputeTruncatedHash(sha256, concat6, 32); string base_filename_concat_byte_sha256 = Convert.ToBase64String(filename_concat_byte_sha256); byte[] filename_concat2_byte_sha256 = ComputeTruncatedHash(sha256, concat7, 32); string base_filename_concat2_byte_sha256 = Convert.ToBase64String(filename_concat2_byte_sha256); //上文通过mac信息和计算机名称计算得到的hash string const_str = "akflLG7b++2vAPZZP62WLtO5XDpblwfcnVbR+65Y1/U="; string concat_str = const_str + base_guid1_byte + base_guid2_byte; byte[] concat_str_byte_sha256 = ComputeTruncatedHash(sha256, concat_str, 32); string base_concat_str_byte_sha256 = Convert.ToBase64String(concat_str_byte_sha256);
然后再拼接生成salt和password
string password= base_concat_str_byte_sha256 + base_concat_str0; string salt= input_hash+ base_guid2_byte;
通过salt和password生成key和iv,然后再将待加密的数据末尾添加上时间,接着使用aes对文件进行加密
v42 = String__Concat_5(file_ext, a5); sub_7FF643ACBDA0(file_ext, v42, 0); if ( *(&qword_7FF643BB5520 - 1) ) sub_7FF643A11806(); v31 = qword_7FF643CDBB28; Bytes = S_P_CoreLib_System_Text_UTF8Encoding_UTF8EncodingSealed__GetBytes(*(_QWORD *)(qword_7FF643CDBB28 + 8), a3); if ( a4 && *(_DWORD *)(a4 + 8) ) { v40 = S_P_CoreLib_System_Text_UTF8Encoding_UTF8EncodingSealed__GetBytes(*(_QWORD *)(v31 + 8), a4); } else { v16 = RhpNewArray(&unk_7FF643BFE7C0, 16i64); *(_OWORD *)(v16 + 16) = xmmword_7FF643C3FAA0; v40 = v16; } v35 = sub_7FF643A13B30(&unk_7FF643BC2078); S_P_CoreLib_System_IO_FileStream___ctor_13(v35, v42, 3, 3, 3, 4096, 0, 0i64); v32 = RhpNewFast(&unk_7FF643BC73B0); System_Security_Cryptography_System_Security_Cryptography_Aes___ctor(); (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)v32 + 112i64))(v17, 256i64); (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)v32 + 64i64))(v32, 128i64); if ( qword_7FF643BB56F0[-1] ) sub_7FF643A1132C(); v45 = qword_7FF643BB56F0[0]; v34 = RhpNewFast(&unk_7FF643BC7C70); System_Security_Cryptography_System_Security_Cryptography_Rfc2898DeriveBytes___ctor_7( v34, Bytes, v40, v45, (__int64)&off_7FF643BA93E0, 0); v18 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v32 + 104i64))(v32); v19 = System_Security_Cryptography_System_Security_Cryptography_Rfc2898DeriveBytes__GetBytes( v34, (unsignedint)(v18 / 8)); (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)v32 + 96i64))(v32, v19); v20 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v32 + 56i64))(v32); v21 = System_Security_Cryptography_System_Security_Cryptography_Rfc2898DeriveBytes__GetBytes( v34, (unsignedint)(v20 / 8)); (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)v32 + 80i64))(v32, v21); v37 = sub_7FF643AF7900(v32); v22 = S_P_CoreLib_System_IO_File__GetLastWriteTime(v42); v23 = S_P_CoreLib_System_DateTimeFormat__Format_0(v22, &off_7FF643BAD360, 0i64, 0x8000000000000000ui64); v36 = S_P_CoreLib_System_Text_UTF8Encoding_UTF8EncodingSealed__GetBytes(*(_QWORD *)(v31 + 8), v23); sub_7FF643ACCEC0(v35, 0i64, 2i64); v44 = *(_DWORD *)(v36 + 8); if ( (*(unsignedint (__fastcall **)(_QWORD))(**(_QWORD **)(v35 + 16) + 240i64))(*(_QWORD *)(v35 + 16)) ) sub_7FF643A9D1D0(); (*(void (__fastcall **)(_QWORD, __int64, _QWORD, _QWORD))(**(_QWORD **)(v35 + 16) + 216i64))( *(_QWORD *)(v35 + 16), v36, 0i64, v44); sub_7FF643ACCEC0(v35, 0i64, 0i64); v33 = RhpNewFast(&unk_7FF643BC7578); sub_7FF643AF7EA0(v33, v35, v37, 1, 0); v24 = RhpNewArray(&unk_7FF643BFE7C0, Enumerator); v48 = 0i64; while ( sub_7FF643ACCBB0(v35) > v48 ) { v47 = sub_7FF643ACCC00(v35); v43 = *(_DWORD *)(v24 + 8); if ( (*(unsignedint (__fastcall **)(_QWORD))(**(_QWORD **)(v35 + 16) + 240i64))(*(_QWORD *)(v35 + 16)) ) sub_7FF643A9D1D0(); v46 = (*(__int64 (__fastcall **)(_QWORD, __int64, _QWORD, _QWORD))(**(_QWORD **)(v35 + 16) + 200i64))( *(_QWORD *)(v35 + 16), v24, 0i64, v43); v48 += v46; sub_7FF643ACCC50(v35, v47); System_Security_Cryptography_System_Security_Cryptography_CryptoStream__Write(v33, v24, 0, v46); }
其中生成key和iv的方法如下,iterations和hashAlgorithm可以通过动态调式得到
int iterations = 50000; using (var deriveBytes = new Rfc2898DeriveBytes( password: passwordBytes, salt: saltBytes, iterations: iterations, hashAlgorithm: HashAlgorithmName.SHA256)) { byte[] key = deriveBytes.GetBytes(32); // AES-256密钥 byte[] iv = deriveBytes.GetBytes(16);
接着拼接字符串 Done||文件名
,然后使用
string salt = "Ed5w7OB07XyYegT57in85K82oHdRSx0bLKOKDCCGGKI="; string password = "+7Qvnh2QKaffTK+NQYapC6DwoJGM1StCA/9R9fCdR6o=";
生成密钥,接着对其进行aes加密,然后将生成的密文的长度转换为字符串,再用刚刚的密钥进行加密
接着再用相同的密钥对前面生成的guid1进行加密。
通过文件名生成密钥来对guid2进行加密
byte[] filename_byte = ComputeTruncatedHash(sha256, filename, 16); string base_filename = Convert.ToBase64String(filename_byte); string file_concat1 = "e9+zXBNtL8ALaRk=" + base_filename + "IewroqVNVUV0" + "5A16614A468925B4"; byte[] guid2_password_byte = ComputeTruncatedHash(sha256, file_concat1, 32); string guid2_password = Convert.ToBase64String(guid2_password_byte); string file_concat2 = "D8NSVR1FARLvFrc=" + base_filename + "Q9584Xb6oe9J" + "62490E5EC202"; byte[] guid2_salt_byte = ComputeTruncatedHash(sha256, file_concat2, 32); string guid2_salt = Convert.ToBase64String(guid2_salt_byte);
最后再加密字符串encr
,密钥跟加密文件的密钥相同
在网络位置处创建勒索信的快捷方式
__int64 __fastcall sub_7FF643B1A7D0(__int64 a1, __int64 a2, unsigned int n0xEB)
{
__int64 EnvironmentVariable_1; // rax
__int64 v7; // rbx
__int64 EnvironmentVariable; // rax
__int64 EnvironmentVariable_2; // r14
__int64 result; // rax
__int64 v11; // r15
__int64 v12; // r13
__int64 v13; // rax
__int64 v14; // rsi
__int64 v15; // rax
__int64 v16; // rax
__int64 v17; // rax
__int64 v18; // rax
__int64 v19; // rax
__int64 v20; // rax
__int64 v21; // rbx
__int64 UTF8BomThrowing; // rdi
EnvironmentVariable_1 = sub_7FF643A87F00();
v7 = sub_7FF643ACEA80(EnvironmentVariable_1, a1);
EnvironmentVariable = S_P_CoreLib_System_Environment__GetEnvironmentVariable(&off_7FF643B9C708);
EnvironmentVariable_2 = String__Concat_5(EnvironmentVariable, &off_7FF643BAC628);
result = S_P_CoreLib_System_Environment__GetEnvironmentVariable(&off_7FF643BAF580);
if ( result )
{
if ( *(_DWORD *)(result + 8) )
{
v11 = sub_7FF643ACEAC0(result, &off_7FF643BAA6C8, &off_7FF643BAEE08);
v12 = RhpNewFast(&unk_7FF643BC0858);
v13 = String__Concat_5(a2, &off_7FF643B94780);// !RESTORE_FILES!.url
v14 = sub_7FF643ACEA80(EnvironmentVariable_2, v13);
*(_DWORD *)(v12 + 32) = 0x7FFFFFFF;
v15 = RhpNewArray(&unk_7FF643BFE858, 16i64);
RhpAssignRefAVLocation(v12 + 8, v15);
S_P_CoreLib_System_Text_StringBuilder__AppendLine_0(v12, &off_7FF643BAC580);
v16 = String__Replace_1(v7, 92i64, 47i64);// C:/Windows/System32/!RESTORE_FILES!.txt
v17 = String__Concat_5(&off_7FF643BAB7A8, v16);// URL=file:///C:/Windows/System32/!RESTORE_FILES!.txt
S_P_CoreLib_System_Text_StringBuilder__AppendLine_0(v12, v17);
v18 = String__Concat_5(&off_7FF643BA4450, v11);
S_P_CoreLib_System_Text_StringBuilder__AppendLine_0(v12, v18);// IconFile=C:\Windows\System32\shell32.dll
v19 = S_P_CoreLib_System_Number__Int32ToDecStr(n0xEB);// 235
v20 = String__Concat_5(&off_7FF643BA4478, v19);
S_P_CoreLib_System_Text_StringBuilder__AppendLine_0(v12, v20);// IconIndex=235
v21 = S_P_CoreLib_System_Text_StringBuilder__ToString(v12);
UTF8BomThrowing = S_P_Xml_System_Xml_XmlTextReaderImpl__get_UTF8BomThrowing();
sub_7FF643ACBE50(v14, UTF8BomThrowing);
return sub_7FF643ACBEA0(v14, 2i64, v21, UTF8BomThrowing);
}
}
return result;
}
如下
删除如下文件
C:\Windows\Temp\!wwwGdddf#.txt //密钥文件
C:\windows\temp\!wwkdsfdsfewt.txt //通过计算机信息计算出来的hash
通过修改注册表键值来替换壁纸
解析base64编码的图片
将其写入C:\Users\Public\img___XXX.jpg
,图片如下
修改后的注册表如下
执行如下指令进行自删除
/C @echo off && ping -n 1 127.0.0.1 > nul && del /q /f "加密器路径"
根据对样本的深入逆向工程分析,得出该勒索病毒分析结果概览:
该恶意软件是一个勒索软件,主要行为总结如下:
加密方式:
使用AES-256算法,密钥基于随机GUID、MAC地址和计算机名动态生成。
排除系统目录(如System32
),跳过白名单文件(如勒索信!RESTORE_FILES!.txt
)。
生成勒索信:
桌面生成勒索信快捷方式(.url
),图标伪装为系统文件。
修改注册表键值(HKCU\Control Panel\Desktop\Wallpaper
)替换壁纸。
反分析策略:
动态拼接关键字符串,规避静态检测。
删除临时密钥文件(如C:\Windows\Temp\!wwkdsfdsfewt.txt
)。
总结:
高度组织化的勒索攻击,技术复杂且对抗性强,需结合动态行为监控与纵深防御体系阻断传播链。
针对888家族的攻击行为,Solar团队已发布专项防护与加固建议,包括数据库弱口令治理、MSSQL安全基线检查、服务器目录权限收紧、异常文件投放监测等措施,详情可参考【漏洞与预防】MSSQL数据库弱口令漏洞预防
更多【软件逆向-【病毒分析】888勒索家族再出手!幕后加密器深度剖析】相关视频教程:www.yxfzedu.com