APT32 (Ocean Lotus) là nhóm APT nổi tiếng với mục tiêu tấn công vào các tổ chức trong và ngoài nước ta. Đây là nhóm APT được ghi nhận là đã tấn công vào nhiều công ty, tổ chức tư nhân trải dài với nhiều lĩnh vực công nghiệp khác nhau. Chuỗi tấn công của nhóm APT32 có nhiều giai đoạn, với các lớp bảo vệ lẫn nhau, khiến cho mã độc của APT32 có nét đặc sắc riêng và gây nhiều khó khăn cho việc đọc hiểu code.

Kho công cụ của APT32 phong phú và đa dạng, từ các phần mềm thương mại như Cobalt Strike, phầm mềm mã nguồn mở như Mimikatz, hay các mã độc đặc trưng của APT32  như Denis, KerrDown và các loại mã độc chưa được đặt tên khác...

Dù cho sử dụng các công cụ sẵn có, hay các loại mã độc được thiết kế riêng, một đặc điểm chung là các mã độc này đều được làm rối (obfuscated) và được đóng gói qua nhiều lớp (packed) trước khi phát tán đến nạn nhân

Ở đây ta thấy sự khác nhau giữa packer và obfuscator. Packer đóng gói file thực thi ban đầu qua một hoặc nhiều lớp, các lớp này có thể dưới dạng shellcode hoặc là một file thực thi khác. Quá trình unpack để lấy được file thực thi ban đầu thường được thực hiện thông qua trình Debugger như Ollydbg hay x64dbg. Ngược lại trình Obfuscator biến đổi file ban đầu về dạng khó đọc hơn bằng cách chèn thêm các kỹ thuật anti-Disassembly. Obfuscator thường nhắm đến các trình Disassembler như IDA, Ghidra.

Nhóm nghiên cứu Viettel Threat Intelligence (VTI) chúng tôi đã quan sát thấy có ít nhất 2 loại obfuscator đặc trưng được sử dụng bởi APT32.  Hai loại được sử dụng cho mỗi loại mã độc riêng và sử dụng cơ chế obfuscation khác nhau cho mỗi loại.

Trong bài viết này sẽ trình bày về cơ chế obfuscation của từng loại và sử dụng các công cụ Capstone, Keystone, và IDAPython để deobfuscate mã độc về dạng có thể dễ dàng đọc bằng các công cụ như IDA hoặc Hex-ray Decompiler.

Trước khi đi vào từng loại obfuscate, ta so sánh các đặc điểm của 2 loại này. (Chúng tôi tạm gọi là Type 1 và Type 2 cho mỗi loại).

1.    Type 1 Deobfuscator

Type 1 obfuscator được sử dụng cho mã độc như Denis malware. Một ví dụ về loại mã độc này được nhắc đến trong báo cáo của ESET năm 2018 hoặc trong bài viết của Fireeye về chiến dịch tấn công của APT32 vào Vũ Hán năm 2020 với tên krpt.dll  (MD5: d739f10933c11bd6bd9677f91893986c - Metajack).  Hoặc mẫu mã độc mà chúng tôi ghi nhận gần đây vào dịp hội nghị ASEAN lần thứ 36 ngày 26-6-2020 ( Filename: 36 ASEAN Summit 26-06-2020 Conference.doc.exe, MD5: 7579aede6a223c96231ad30472a060db)

Hình 1: Type 1-obfuscator

Ở Type 1, mỗi basic block là một đơn vị để thực hiện obfuscate

Junk code

Hình 2: Junk code

Đoạn junk code được chèn thêm vào mỗi basic block. Đoạn junk code này không thay đổi trạng thái thanh ghi và ngăn xếp của chương trình. Để làm điều đó, ta thấy rằng các thanh ghi được cất vào ngăn xếp bằng lệnh push và trả về các thanh ghi bằng lệnh pop khi kết thúc đoạn junk code. Chỉ có các thanh ghi eax, ebx, ecx, edx và thanh ghi cờ được sử dụng trong junk code.

Các vị trí chèn junk code

a.    Push r32 / Pop r32

Hình 3: Push eax
Hình 4: Pop esi

Ta thấy cách junk code được chèn thêm như sau:

b.    Thêm toàn bộ basic block là junk code

Hình 5: Trường hợp cả basic block là junk code

Ta thấy trong trường hợp này toàn bộ basic block là junk code. Các cặp lệnh rẽ nhánh JO/JNO, JZ/JNZ, JB/JNB, … đều nhảy về một địa chỉ

c.    Biến đổi lệnh call

Mục đích của sự biến đổi này là làm rối luồng thực thi của chương trình. IDA sẽ không nhận ra lời gọi hàm và lệnh tiếp theo được thực thi. Ta thấy có hai cách biến đổi lệnh call như sau:

Cách 1:

Hình 6: Control-Flow Obfuscation

Cách 2:

Hình 7: Control-Flow Obfuscation

Một vài biến thể khác

Ở một số mẫu khác xuất hiện gần đây, chúng tôi thấy một vài cải tiến của APT32 ở Type 1

Hình 8: Push esi obfuscation

Lệnh Push được làm rối bằng một đoạn junk code có chức năng tương đương

Hình 9: Mov eax, 09 obfuscation

Lệnh mov reg, imm được thực hiện gián tiếp qua các phép or, xor, …

Deobfuscating

Ở trên ta đã thấy cách APT32 chèn các junk code vào từng basic block. Ta cần xóa đi các junk code này và điều chỉnh các lệnh assembly về dạng ban đầu. Để làm điều này, chúng tôi sử dụng các công cụ Capstone – Disassembler Framework, Keystone-Assembler Framework, kết hợp với các API của IDA Python. Đơn vị để giải mã cũng là basic block. Ta sẽ tận dụng các API của IDA để duyệt qua các basic block, với mỗi basic block, bằng Capstone ta sẽ tìm các đoạn junk code phù hợp với các tiêu chí trên. Cụ thể ta cần tìm các đoạn push/pop r32, các cặp lệnh rẽ nhánh cùng nhảy về một địa chỉ, các biến thể của lệnh call được sử dụng cho mục đích control-flow obfuscation. Khi tìm được đoạn code phù hợp, ta sẽ sử dụng Keystone để chuyển các lệnh về dạng ban đầu. Ta thấy các đoạn junk code có đặc điểm là không thay đổi trạng thái thanh ghi và trạng thái ngăn xếp của chương trình, nghĩa là giá trị thanh ghi esp trước và sau khi thực thi junk code sẽ không thay đổi. Nhờ vào đặc điểm này ta có thể sử dụng hàm get_spd(ea) trong IDA như là một cách để nhận diện các đoạn junk code.

Ta có kết quả trước và sau khi deobfuscate:

Hình 10 So sánh kết quả trước và sau Deobfuscating

Chúng ta có thể tham khảo phần code và sample tại: Github

(Còn tiếp)

Author: VuongLVM