Định dạng cơ sở dữ liệu của Windows Defender

Windows defender (WD) là 1 sản phẩm phòng chống mã độc được tích hợp sẵn trên windows 10 và 11. Trải qua quá trình phát triển cùng với windows, càng ngày WD càng cho thấy sự hiệu quả của nó trong việc phát hiện và ngăn chặn các loại mã độc khác nhau trên máy tính cá nhân. Trong bài này, ta sẽ cùng tìm hiểu về cơ sở dữ liệu (CSDL) mà WD sử dụng, tiến hành trích xuất các dữ liệu trong đó để tìm hiểu thêm về định dạng của CSDL này và một vài kiểu dấu hiệu nhận biết (signature) trong CSDL.

1. Cấu trúc tập tin cơ sở dữ liệu của Windows Defender

Thông thường, các bản WD trên máy tính cá nhân sẽ có 4 tập tin CSDL có đuôi .VDM và 1 tập tin dll có nhiệm vụ nạp và sử dụng các CSDL này. Các tập tin sẽ được lưu trữ tại đường dẫn %ProgramData%\Microsoft\Windows Defender\Definition Updates\[GUID]. Trong đó

  • mpasbase.vdm: cơ sở dữ liệu cho module AntiSpyware
  • mpasdlta.vdm: bản cập nhật cho cơ sở dữ liệu AntiSpyware
  • mpavbase.vdm: cơ sở dữ liệu cho module AntiVirus
  • mpavdlta.vdm: bản cập nhật cho cơ sở dữ liệu AntiVirus

Các tập tin VDM thực chất là các tập tin DLL chỉ chứa resouce, một dạng DLL đặc biệt, mà Microsoft sử dụng để chi sẻ các nguồn dữ liệu giữa các chương trình khác nhau. Các DLL này không chứa đoạn mã thực thi nào mà chỉ bao gồm phần header của tập tin PE và phần dữ liệu trong resource. Nội dung chính của CSDL mà WD sử dụng nằm trong resource có tên RT_RCDATA.

Resouce này là một đoạn dữ liệu có cấu trúc, trong đó, một phần của header có thể bao gồm các trường như sau:

typedef struct _RMDX_HEADER {
    ULONG Signature; //0
    ULONG Timestamp; //4
    ULONG Unknown1; //8
    ULONG Options; //12 (0C)
    ULONG Unknown2; //16
    ULONG Unknown3; //20
    ULONG DataOffset; //24 (18)
    ULONG DataSize; //28 (1C)
    //incomplete, irrelevant
} RMDX_HEADER, *PRMDX_HEADER;

Một số trường đã biết trong cấu trúc:

  •  Signature là 4 byte ‘RMDX;
  •  Options: chứa các thuộc tính của CSDL, hiện tại việc trích xuất CSDL chỉ hỗ trợ các file vdm có thuộc tính nén
  • DataOffset: Offset trỏ tới phần dữ liệu được nén bằng zlib
  • DataSize: kích thước của đoạn dữ liệu nén

Dữ liệu trỏ tới bới DataOffset có cấu trúc gồm thông tin về kích thước dữ liệu nén và dữ liệu nén. Dựa vào 2 thông tin này ta có thể giải nén CSDL trong VDM để bắt đầu tìm hiểu những gì bên trong nó.

typedef struct _CDATA_HEADER {
    ULONG Length; //0
    ULONG Unknown1; //4
    union { //8
        BYTE Data[1];
        ULONG Unknown2;
    } u1;
} CDATA_HEADER, *PCDATA_HEADER;

Dữ liệu sau khi giải nén có thể được đọc theo một mảng dữ liệu chứa các phần tử signature có cấu trúc:

struct {
    uint8_t sig_type;
    uint8_t size_low;
    uint16_t size_high;
    uint8_t value[size_low | size_high << 8];
} sig_entry;

Trong đó, sig_type là kiểu dữ liệu của phần tử signature này, kết hợp size_low và size_high, ta sẽ thu được kích thước đoạn dữ liệu chứa signature, chính là kích thước dữ liệu còn lại trong phần tử. Có thể thấy, kích thước của từng signature không cố định, cần dựa vào kích thước của phần tử hiện tại để xác định phần tử tiếp theo. Ví dụ đối với dữ liệu VDM vừa giải nén:

signature đầu tiên:

  • Signature type: 0x5c
  • Kích thước: 0x1e
  • Dữ liệu của signature: Mảng có kích thước 0x1e: 45060000…..24000400

Theo sau là signature thứ 2:

  • Signature type: 0x40
  • Kích thước: 0x45
  • Dữ liệu của signature: Mảng có kích thước 0x45: 04000103…..fe00000000

.

Các kiểu signature được xác định dựa vào một hàm nằm trong trong mpengine.dll. Hàm này nhận đầu vào là giá trị sig_type, sau đó trả về chuỗi ứng với sig_type nhận được.

Trường sig_type có kiểu dữ liệu là uint8, do đó sẽ giá trị từ 0 đến 0xff. Tuy nhiên, không phải giá trị nào cũng ứng với một kiểu signature, một vài giá trị sẽ được gán với kiểu “SIGNATURE_TYPE_UNKNOWN”. Có khoảng 158 kiểu signature hợp lệ, nhưng hầu như các cơ sở dữ liệu không chứa tất tất cả các loại signature này mà chỉ chứa từ 50 đến 100 loại signature.

2. Tìm hiểu một số kiểu signature trong CSDL VDM

Ở phần này ta sẽ `mò` xem 1 số loại sig được lưu trữ như thế nào trong file VDM. Trước khi đọc file VDM, mpengine sẽ khởi tạo các module thông qua hàm AutoInitModules::AutoInitModules.

Biến module_list là một mảng các cấu trúc về module, bao gồm mô tả, hàm khởi tạo, hàm cleanup và 1 QWORD chứa flag là 0 hoặc 1 (??).

Ở bản hiện tại, có tất cả 399 module khác nhau, trong đó có 159 module có flag là 1, còn lại là các module có flag = 0. Các hàm khởi tạo của từng module này có thể thiết lập các callback để xử lí từng loại signature tương ứng.

2.1 SIGNATURE_TYPE_THREAT_BEGIN

Dạng signature SIGNATURE_TYPE_THREAT_BEGIN sẽ được xử lí bởi module threatmgr.

Mỗi phần thử SIGNATURE_TYPE_THREAT_BEGIN bao gồm các mô tả về một threat nhất định. Cấu trúc dữ liệu của phần tử này ở dạng struct như sau:

struct THREAT_BEGIN
{
    char unknow_metadata[0xa];
    unsigned __int16 nameSize;
    char name[name_size];
    // unknow data
}

Các phần tử sign tiếp theo sau mỗi SIGNATURE_TYPE_THREAT_BEGIN sẽ là một hoặc nhiều loại sign khác thuộc threat này. Phạm vi các phần tử sign nằm trong threat sẽ được xác định khi gặp một phần tử sig có dạng SIGNATURE_TYPE_THREAT_END.

Ví dụ có thể hiểu 1 phần dữ liệu trong file vdm dưới đây mổ tả 1 threat có tên MonitoringTool:Win32/ActiveKeylogger bao gồm 2 sign dạng PEHSTR_EXT.

2.2 SIGNATURE_TYPE_PEHSTR

Dạng signature PEHSTR và một vài dạng khác được xử lí bởi module cksig.

Hàm cksig_init_module sẽ gọi tới pattsearch_init sau đó sẽ thực hiện đăng kí các callback (hstr_push, hstr_pushend_common) để gọi tới hàm xử lí dạng sign này khi chúng bắt đầu được load và sau khi load từ file vdm.

Có thể tạm coi mỗi phần tử PEHSTR là một dữ liệu có cấu trúc như sau

struct string_data
{
    WORD reversed0;
    char string_size;
    char str[1];
} string_data;

typedef struct PEHSTR
{
    WORD count_1;
    WORD count_2;
    WORD count_3;
    char reversed_0;
    string_data s_data[1];
} PEHSTR, *PPEHSTR; 

Khi đó, mỗi sig dạng PEHSTR có thể được tạm hiểu bao gồm nhiều string khác nhau như ví dụ dưới đây:

Với các threat chỉ sử dụng pattern PEHSTR trong việc nhận dạng mã độc, ta có thể biết được dấu hiệu nhận dạng mã độc của windefender để có thể bổ sung vào các rule phát hiện hay tìm cách che dấu đi các chuỗi này để tránh bị windefender phát hiện khi chỉ quét tĩnh theo signature.

Còn rất nhiều loại sign khác có cấu trúc phức tạp hơn để tìm hiểu, đây là script để trích xuất dữ liệu từ file vdm (mpengine version 1.1.20200.4, db version 1.387.0.0 sau khải đã giải nén bằng WDExtract) ra dữ liệu dạng csv để mọi người tham khảo.

Tài liệu tham khảo:

490 lượt xem