Trong bài viết này, mình sẽ giải đáp câu hỏi tại sao bạn lại có thể khôi phục được các file do một vài loại virus tống tiền gây ra. Đồng thời, mình cũng sẽ demo quá trình viết một trình giải mã file dựa trên mã nguồn và key được fix cứng vào trong source code của virus nhé

0. Trước khi bắt đầu…

Trước khi bắt đầu với bài viết này,

  • Mình sẽ không cung cấp sample đã được sử dụng để viết trình decompile, hãy nhớ rằng virus máy tính thực sự không phải một trò đùa ;). Bài viết này được viết với mục đích giáo dục về lập trình cũng như sử dụng kỹ thuật dịch ngược trong lập trình
  • Nếu muốn thực hiện những hành động như mình, hãy chuẩn bị một môi trường thử nghiệm an toàn (chạy trong sandbox hoặc máy ảo, ngắt hoàn toàn kết nối mạng, …)

Nếu bạn đã sẵn sàng, thì chúng ta cùng bắt đầu nhé 😊

1. Phân tích mẫu của file executable

Trong bài viết này, mình sẽ tập trung vào phân tích ransomware Jigsaw (2016, loại A, được viết bằng .NET/C#). Nhưng trước khi bắt tay vào việc chính, chúng ta hãy liệt kê ra những thứ cần được thực hiện nhé.

  • Tại sao? (Phần mềm đã được tải, được khởi chạy ở đâu)
    • Nó đến từ đâu?
    • Tại sao nó lại ở đó?
  • Loại malware
    • Downloader
    • Launcher
    • Backdoor
      • RAT
      • Botnet
      • Shell
    • Credential stealer
      • Keylogger
    • Mã hoá file
    • etc..

(checklist còn khá nhiều, nhưng để không làm ảnh hưởng đến chất lượng bài viết, mình sẽ chỉ đi qua 2 phần chính ở trên)

Sau khi đã nắm được hết những thứ chúng ta cần phải tìm hiểu, thì hãy cùng mình bước vào quá trình phân tích và nghiên cứu mẫu ransomware này nhé.

  • “Tại sao?”:

    • Ransowmare Jigsaw phần lớn đến từ một trang lưu trữ đám mây có tên miền 1fichier[.]com
      • Tên miền này cũng đã được biết đến qua nhiều lần host các malware như Fareit (đánh cắp thông tin), coinstealer (đào và trộm bitcoin)
    • Jigsaw còn đến từ một tên miền với tên hxxp://waldortrust[.]com , hầu như ransomware này được đính kèm với một phần mềm đào tiền ảo.

    Cả hai trường hợp trên đều là do những người dùng trên mạng upload nội dung chứa mã độc lên các trang dùng để host file miễn phí, từ đó những người dùng sẽ tải về và bị lây nhiễm

  • Loại malware:

    • Jigsaw được xác định là một ransomware ⇒ Jigsaw sẽ mã hoá các tệp tin trên máy tính và bắt người dùng trả một khoản tiền chuộc để có thể lấy được lại tệp tin đã bị mã hoá.

Bây giờ mình sẽ bắt tay vào việc phân tích file thực thi của ransomware này, hệ điều hành Host trong trường hợp để tìm kiếm thông tin của file mình đang dùng là macOS (arm). Đầu tiên, chúng ta sẽ tìm thông tin của loại file được cho là mẫu của ransomware:

$ file Jigsaw.Ransom.A.bin
Jigsaw.Ransom.A.bin: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

Như các bạn có thể thấy ở trên, kết quả, dữ liệu của file Jigsaw.Ransom.A.bin được xác định là một ứng dụng dành cho Windows (for MS Windows) và được viết bằng ngôn ngữ C#/.NET, tập trung vào nền tảng các chip x86_64.

Đồng thời, mình cũng sẽ lấy hash MD5 và SHA256 để tiện cho việc tìm các mẫu ransomware sử dụng base của Jigsaw (đổi tên):

$ md5 Jigsaw.Ransom.A.bin
MD5 (Jigsaw.Ransom.A.bin) = 5a9bd3d7f1534431a396a033d16ca496
 
$ openssl dgst -sha256 Jigsaw.Ransom.A.bin
SHA2-256(Jigsaw.Ransom.A.bin)= bc83ef30422eb7b0c8903d3b4f1d4258e25cf78e9357a30dac773f8d2c17aa28

Như vậy, chúng ta đã nắm được các thông tin cơ bản về file (nghi) chứa mã độc như sau:

  • Được xây dựng cho nền tảng x86_64, viết bằng ngôn ngữ C#/.NET, chạy trên nền tảng Windows
  • Mã MD5: 5a9bd3d7f1534431a396a033d16ca496
  • Mã SHA256: bc83ef30422eb7b0c8903d3b4f1d4258e25cf78e9357a30dac773f8d2c17aa28

2. Setup môi trường thử nghiệm

2.1: Mạng

Việc thử nghiệm các loại Malware luôn phải diễn ra trong môi trường nghiêm ngặt, để không làm ảnh hưởng đến các máy tính khác trong hệ thống mạng (như WannaCry tận dụng EternalBlue của Windows để phát tán). Trong trường hợp này, mình đang sử dụng máy ảo như sau:

C:\Users\kirbee> systeminfo
 
Host Name:                 DESKTOP-9J9GFFB
OS Name:                   Microsoft Windows 11 Pro
OS Version:                10.0.22631 N/A Build 22631
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Workstation
OS Build Type:             Multiprocessor Free
Registered Owner:          kirbee
 
...
 
Network Card(s):           1 NIC(s) Installed.
                           [01]: vmxnet3 Ethernet Adapter
                                 Connection Name: Ethernet
                                 DHCP Enabled:    Yes
                                 DHCP Server:     172.16.4.254
                                 IP address(es)
                                 [01]: 172.16.4.129
                                 [02]: fe80::5fd6:d2:58f4:9649

Nếu như các bạn để ý, thì môi trường mạng mình setup cho máy ảo này đang chạy ở chế độ NAT. Đối với NAT, môi trường máy ảo và máy chính sẽ dùng chung một dải địa chỉ, nhưng máy ảo sẽ không thể giao tiếp được với các địa chỉ IP nội bộ trong hệ thống. Để đảm bảo an toàn, chúng ta có thể kiểm tra lại ở trên máy tính host máy ảo:

$ ifconfig
...
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
	ether 60:3e:5f:79:a5:a7
	inet6 fe80::8ab:7de5:10d5:575d%en0 prefixlen 64 secured scopeid 0x10
	inet 10.0.0.174 netmask 0xffffff00 broadcast 10.0.0.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active
...

Như các bạn có thể thấy, máy ảo và máy host của mình đang ở hai dải địa chỉ IP khác nhau (10.0.x.x và 172.16.x.x). Điều này cũng đồng nghĩa với việc chúng ta sẽ an toàn khi chạy file được cho là chữa mã độc.

Đến đây, chắc sẽ có nhiều bạn thắc mắc tại sao mình không ngắt hẳn kết nối mạng với máy ảo. Đơn giản là vì một số loại mã độc sẽ cần truyền các gói tin qua các server bên ngoài, từ đó nếu không có mạng, chúng ta có thể sẽ không chạy được mã độc.

2.2: Các tập tin mẫu

Đối với ransomware, chúng sẽ nhắm vào những file tài liệu, với phần mở rộng như (.zip, .pdf, .docx, … ).

Để tiện cho quá trình tìm hiểu cách hoạt động, mình sẽ tạo ra một số file mẫu và để ngoài màn hình chính

C:\Users\kirbee\Desktop\Samples>dir /w
 Directory of C:\Users\kirbee\Desktop\Samples
 
[.]            [..]           Document.rtf   pic.png        siuuu.txt      siuuu.zip

2.3: Các ứng dụng hỗ trợ theo dõi

Trong bài viết này, mình sẽ sử dụng ứng dụng Process Monitor của Sysinternals, bạn có thể tải phần mềm đó tại đây:

Process Monitor - Sysinternals

2.4: Tắt trình quét virus

Để quá trình nghiên cứu và kiểm thử được diễn ra mượt mà và không bị gián đoạn với các phần mềm diệt virus, chúng ta sẽ tắt tính năng Real-time protection để phần mềm không dừng các hoạt động / tác vụ của virus. (Không làm trên máy chính)

2.5: Chuẩn bị sẵn sàng

Sau khi đã thực hiện xong việc setup 4 mục ở trên, chúng ta sẽ bắt đầu chạy chương trình malware, và theo dõi các tiến trình xuất hiện trong Process Monitor tại phần 2.3.

Lưu ý với một số loại sample, phần mở rộng của file sẽ không kết thúc bằng .exe để tránh phần mềm diệt virus quét được, nếu thiếu hoặc chưa có phần mở rộng này, chúng ta có thể tự thêm vào trong file.

3. Thực thi file chứa mã độc

Sau khi thực thi file chứa mã nguồn, mình nhận được một thông báo như trên

Nhận định: Bảng thông báo trên là giả, nhằm đánh lạc hướng chúng ta trong quá trình mã hoá file.

Sau một hồi chờ đợi, mình nhận được bảng thông báo như sau:

Và toàn bộ các file trong hệ thống của mình đã bị mã hoá

C:\Users\kirbee\Desktop\Samples>dir/w
 Directory of C:\Users\kirbee\Desktop\Samples
 
[.]                [..]               Document.rtf.fun   pic.png.fun        siuuu.txt.fun      siuuu.zip
               4 File(s)        150,130 bytes
               2 Dir(s)  19,868,893,184 bytes free

4. Phân tích hành vi

Quay lại với ProcessMonitor, chúng ta cần phải thêm các filter như sau để nắm được các hoạt động của file thực thi này.

If Process Name == “Jigsaw.Ransom.A.exe” then Include

Và chúng ta nhận được kết quả như sau:

Đây là những lần file này (từ khi thực thi) thực hiện việc gọi API của Windows, kết hợp với process mình tìm được trong Task Manager, thì file gốc này không còn được thực thi nữa, thay vì đó, một file tên drpbx.exe đang được chạy trên hệ thống tương ứng với bảng thông báo được hiện trên màn hình.

Điều này cũng tương ứng với việc chương trình được thực thi chỉ là dropper, với mục đích di chuyển một file khác để giấu trong hệ thống:

Tuy nhiên, việc cần thiết bây giờ chính là xác định đâu đã là file mã hoá hệ thống của chúng ta (file lúc ban đầu hay file được drop vào %localappdata%).

Lưu ý parameter thứ 3

Chúng ta có thể thêm rule sau để xác định file thực thi có tác động đến các thư mục chứa file có đuôi mở rộng là .fun hay không.

Và kết quả là không có gì, chúng ta sẽ kiểm tra đến process đã được drop trong quá trình thực thi chương trình, tiến hành thêm filter sau, và tắt filter với Process Name cũ đi:

Sau khi filter, đây sẽ là kết quả chúng ta nhận được, như mọi người có thể thấy, các file trong thư mục sample của mình đã được mã hoá, và phần mềm này dùng API IRP_* và FASTIO_* để thực hiện việc mã hoá file.

Từ đó, chúng ta có thể xây dựng được một graph behavior cơ bản như sau:

Đồng thời kiểm tra phần startup item, thì jigsaw cũng đã tự drop mình vào thư mục startup để tự khởi chạy khi hệ thống được khởi động.

Với registry trong hệ thống, Jigsaw có thực hiện một số thay đổi trong Internet Setting và tự thêm mình vào Run :

4: Thử nghiệm việc decompile mã nguồn

Theo như dữ liệu của việc phân tích loại file ở trên, chúng ta có thể thấy chương trình Jigsaw được viết bằng ngôn ngữ C#/.NET, nên việc phân tích cũng sẽ không khó khăn (nếu chương trình không được obfuscate)

Trước hết, chúng ta sẽ dùng dotPeek để trích xuất dữ liệu mã nguồn được dịch ngược từ file thực thi.

Duyệt qua phần metadata, chúng ta có thể nhận thấy không có dấu hiệu của việc đã được một phần mềm obfuscate can thiệp ở đây, mình sẽ đi qua các file trong mã nguồn và chỉ ra những entry “nghe hấp dẫn” trong chương trình nhé.

Khi đến hàm Main.FormGame, mình có đọc được một hàm như sau:

private void buttonCheckPayment_Click(object sender, EventArgs e)
    {
      try
      {
        double price = Blockr.GetPrice();
        int num1 = (int) (Blockr.GetBalanceBtc(FormGame.GetBitcoinAddess()) * price);
        if (num1 > Config.RansomUsd)
        {
          this.timerCountDown.Stop();
          this.buttonCheckPayment.Enabled = false;
          this.buttonCheckPayment.BackColor = Color.Lime;
          this.buttonCheckPayment.Text = "Great job, I'm decrypting your files...";
          int num2 = (int) MessageBox.Show((IWin32Window) 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 (num1 > 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)
      {
        int num = (int) MessageBox.Show(ex.ToString());
        this.buttonCheckPayment.Text = "Are you connected to the internet? Try again!";
        this.buttonCheckPayment.BackColor = Color.Tomato;
      }
    }

Nếu như để ý kỹ, thì bạn sẽ nhận ra ngay, đây là hàm dùng để kiểm tra nếu bạn đã thanh toán thành công vào địa chỉ bitcoin được hiện trên màn hình, mình sẽ không đi sâu vào cách kiểm tra thanh toán như thế nào, chúng ta sẽ sử dụng các hàm được cung cấp sẵn trong mã nguồn được dịch ngược để viết một trình giải mã file.

Duyệt qua thêm các biến của class Locker, mình còn tìm được các thông tin sau

private const string EncryptionFileExtension = ".fun";
private const string EncryptionPassword = "OoIsAwwF23cICQoLDA0ODe==";

Mọi việc liên quan đến giải mã file đều được thực hiện trong hàm Locker .

Đào sâu thêm một chút tới class Hacking, mình tìm được function sau:

internal static void RemoveItself()
    {
      if (Config.StartMode == Config.StartModeType.Debug)
        Environment.Exit(0);
      try
      {
        Main.Tools.Windows.RemoveStartupRegistry(Config.FinalExePath);
        foreach (string path in new HashSet<string>()
        {
          Path.GetDirectoryName(Config.FinalExePath),
          Path.GetDirectoryName(Config.TempExePath),
          Config.WorkFolderPath
        })
        {
          try
          {
            if (Directory.Exists(path))
              Directory.Delete(path, true);
          }
          catch (Exception ex)
          {
          }
        }
        string str = Path.GetDirectoryName(Application.ExecutablePath) + "\\DeleteItself.bat";
        using (StreamWriter streamWriter = new StreamWriter(str, false, Encoding.Default))
          streamWriter.Write(":del\r\n del \"{0}\"\r\nif exist \"{0}\" goto del\r\ndel %0\r\n", (object) Application.ExecutablePath);
        int num = (int) Hacking.WinExec(str, 0U);
      }
      catch
      {
      }
      finally
      {
        try
        {
          Environment.Exit(0);
        }
        catch
        {
          Application.Exit();
        }
      }
    }

Theo nhận định của mình, thì với 2 class Locker và Hacking, chúng ta có thể tận dụng để viết một trình giải mã file, cùng với việc loại bỏ malware này ra khỏi máy tính.

5: Viết trình giải mã file

Trước hết, mình sẽ bắt đầu với một project Console đơn giản bằng C# trong Visual Studio, nội dung mình sử dụng để build up chương trình hiện như sau:

using System;
 
namespace Jigsaw_decryptor
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Decrypting files...");
 
            Console.WriteLine("All done. Press any key to continue");
            Console.ReadKey();
 
        }
    }
}

Trên lý thuyết, tất cả những gì chúng ta cần dùng để giải mã file chỉ là Locker.DecryptFiles(".fun"); , mình sẽ thực hiện việc copy hết nội dung của class Locker qua quá trình decompile diễn ra ở trên:

Locker.cs (overview)

6. Moment of truth

Sau khi đã viết xong phần code ở trên để thực hiện việc giải mã file và thực thi, mọi tệp tin trong các thư mục đã bị mã hoá trong máy của mình đã được khôi phục (giải mã?) thành công.

7. Kết luận

7.1. Làm sao để không bị dính mã độc (virus)

Để hạn chế tối đa việc dính mã độc, mình khuyên mọi người nên làm theo những outline sau đây

  • Cài đặt và duy trì phần mềm diệt virus
  • Cài đặt tường lửa cho máy tính
  • Luôn cập nhật các phiên bản phần mềm mới nhất, đặc biệt là các bàn cập nhật cải thiện bảo mật
  • Không mở các file, phần mềm lạ.

7.2. Sau khi thực hiện xong quá trình decryption ở trên, chúng ta có thể rút ra được kết luận gì?

  • Trước hết, sample Jigsaw mình sử dụng ở đây là một ransomware “tệ”. Nếu thực sự muốn người dùng không thể dễ dàng giải mã được file, các malware sẽ cần giấu được cách mình đã sử dụng để mã hoá file (bằng việc đưa secret key lên máy chủ, hoặc obfuscate phần mềm trước khi release).
  • Windows Defender cũng đã thực hiện khá tốt việc ngăn mình mở phần mềm chứa mã độc này trong khi thực hiện, vậy nên, Windows Defender cũng đã đủ tốt để phát hiện được (hầu hết) các loại mã độc.

Cảm ơn mọi người đã đọc qua bài viết của mình, nếu có vấn đề gì không hiểu, mọi người hãy comment phía dưới để nhận được sự giải đáp của mình, mình xin cảm ơn ạ 😽