Phân tích thành phần rootkit VideoAti0.sys của mẫu Nailuj(Allinone)

Malware

Wh------
08/01/2015
41
56 bài viết
Phân tích thành phần rootkit VideoAti0.sys của mẫu Nailuj(Allinone)

Mở đầu: Tiếp tục với loạt bài phân tích mã độc ở mức kernel, hôm nay chúng ta sẽ phân tích một mẫu rootkit khá nổi tiếng là thành phần của nailuj hay allinone. Nailuj là một file thực thi có đuôi exe (còn gọi là dropper-cài đặt rootkit), khi thực thi, nó sẽ thực hiện cài đặt và khởi động rootkit, có 3 file quan trong được cài vào là VideoAti0.sys, VideoAti0.dll, VideoAti0.exe. Sau khi thực hiện cài đặt, file exe này sẽ tự xóa. Chúng ta sẽ phân tích thành phần kernel VideoAti0.sys này để xem hành vi và các kỹ thuật mà malware này thực hiện.
File cần phân tích: VideoAti0.sys.
MD5: 7A9691D46BB010CB533C6D7FB26E92D5
Công cụ sử dụng: IDA, WinDbg.

Yêu cầu bạn đọc:
  • Có kiến thức cơ bản về kernel windows, Windows Drivers, Rootkit, Assembly
  • Có kiến thức cơ bản về sử dụng tool IDA, WinDbg

1489939945FINDROOTKIT.jpg


Đầu tiên, rootkit lấy được danh sách các driver đã được tải lên trong hệ thống, để làm điều này, nó sẽ lấy trường DriverSection trong DriverObject của rootkit. Mỗi một DriverObject có một trường là DriverSection, trường này lại trỏ tới một danh sách các driver đã được tải lên, mỗi phần tử trong danh sách có cấu trúc:
Mã:
[B]typedef[/B] struct _MODULE_ENTRY   
[B]{[/B] 
    LIST_ENTRY le_mod[B];[/B] // +00  
    BYTE unknown[B][[/B]16[B]];[/B] // +08  
    DWORD base[B];[/B] // +18  
    DWORD driver_start[B];[/B] // +1C  
    DWORD unknown_1[B];[/B] // +20  
    UNICODE_STRING driver_Path[B];[/B] // +24  
    UNICODE_STRING driver_Name[B];[/B] // +28  
    // ...  
[B]}[/B] MODULE_ENTRY[B],[/B] [B]*[/B]PMODULE_ENTRY[B];[/B]


Sau đó nó sẽ tìm kiếm module Nt trong hệ thống, rootkit sẽ duyệt toàn bộ danh sách các driver được tải lên nói trên, sau đó tìm kiếm. Nếu tên của module có chứa xâu “krnl” thì rootkit xác định đó là Nt module. Đoạn mã thể hiện việc duyệt danh sách như sau:
Mã:
[B]while[/B] [B]([/B] 1 [B])[/B]
[B]{[/B]
    [B]if[/B] [B]([/B] [B]*(([/B]_DWORD [B]*)[/B]v1 [B]+[/B] 8[B])[/B] [B])[/B]
    [B]{[/B]
        [B]if[/B] [B]([/B] MmIsAddressValid[B](*(([/B]PVOID [B]*)[/B]v1 [B]+[/B] 10[B]))[/B] [B])[/B]
        [B]{[/B]
            v2 [B]=[/B] [B]([/B]const wchar_t [B]*)*(([/B]_DWORD [B]*)[/B]v1 [B]+[/B] 10[B]);[/B]
            [B]if[/B] [B]([/B] v2 [B])[/B]
            [B]{[/B]
                wcsncpy[B](&[/B]v5[B],[/B] v2[B],[/B] [B]([/B]unsigned int[B])*(([/B]_WORD [B]*)[/B]v1 [B]+[/B] 18[B])[/B] [B]>>[/B] 1[B]);[/B]
                wcslwr[B](&[/B]v5[B]);[/B]
                [B]if[/B] [B]([/B] wcsstr[B](&[/B]v5[B],[/B] [B]&[/B]word_FAEC55AA[B])[/B] [B])[/B]
                    [B]break[/B][B];[/B]
            [B]}[/B]
        [B]}[/B]
    [B]}[/B]
   
    v1 [B]=[/B] [B]*([/B]PVOID [B]*)[/B]v1[B];[/B]
    [B]if[/B] [B]([/B] v1 [B]==[/B] v0 [B])[/B]
        [B]return[/B] 0xC0000001[B];[/B]
[B]}[/B]

Sau đây là một số hành vi chính của rootkit:

1. Ẩn giấu registry
Để có thể ẩn giấu được khóa registry của rootkit, nhằm không cho người dùng phát hiện ra, rootkit thực hiện hook (móc vào) một hàm dùng để duyệt registry của hệ thống, ở đây là hàm CmEnumerateKey nằm ở module Nt, hàm CmEnumerateKey có chữ kí như sau:
Sử dụng lệnh u Nt!CmEnumerateKey trong WinDbg ta được kết quả:
Mã:
80627c40 68d43295f8         push    offset VideoAti0[B]+[/B]0x12d4 [B]([/B]f89532d4[B])[/B]
80627c45 c3                 ret
80627c46 80e8c4             sub     al[B],[/B]0C4h
80627c49 02f1               add     dh[B],[/B]cl

Ta thấy 2 lệnh push và ret, lệnh push thực hiện đẩy tham số trong lệnh vào stack, còn lệnh ret sẽ lấy giá trị đỉnh của stack và thực hiện lệnh có địa chỉ là giá trị đỉnh của stack. Khi thực hiện lênh trên, số phần tử trong stack giảm đi 1. Tham số trong lệnh push là offset VideoAti0+0x12d4,là một địa chỉ bên trong module VideoAti0, là module của rootkit, như vậy ta thấy rằng hàm CmEnumerateKey đã được chuyển hướng để gọi tới hàm của rootkit, kĩ thuật này là kĩ thuật Inline Hook. Theo kĩ thuật này, 6 byte đầu tiên của hàm sẽ bị ghi đè, trong đó byte đầu tiên là 68h là mã hexa của lệnh push, 4 byte tiếp theo là địa chỉ của hàm sẽ chuyển tới, byte cuối cùng là C3 là mã hexa của lệnh ret. Để có thể chuyển hướng hàm bằng kĩ thuật này, rootkit tắt chức năng Write Protection của windows, bằng cách xóa cờ WP của thanh ghi CR0. Đoạn mã xóa cờ WP như sau:
Mã:
_disable[B]();[/B]
result [B]=[/B] __readcr0[B]()[/B] [B]&[/B] 0xFFFEFFFF[B];[/B]
__writecr0[B]([/B]result[B]);[/B]

Một số hành vi trong hàm được chuyển hướng từ hàm CmEnumerateKey:
- Che giấu với các tiến trình fhs.exe và knlsc13.exe, nếu tiến trình gọi hàm có tên là một trong 2 chuỗi “fhs.exe” và “knlsc13.exe” thì hàm.
- Che giấu key, rootkit che giấu 2 key là LEGACY_VIDEOATI0 và VideoAti0.
Trước khi quay về hàm ban đầu của windows, rootkit sẽ khôi phục lại 6 byte như cũ để đảm bảo không nảy sinh vòng lặp gọi hàm vô hạn.

2. Thay đổi một số hàm majorfunction của file system
Mục đích: ẩn giấu file của rootkit cùng một số file khác.
Thứ tự thực hiện hành vi của rootkit:
- Lấy địa chỉ của NTFS, FastFat.
- Hook IRP_MJ_CREATE.
- Hook IRP_MJ_DIRECTORY_CONTROL.
Ví dụ một đoạn mã hook các hàm của NTFS và FastFat:

Mã:
v7 [B]=[/B] a2[B]->[/B]MajorFunction[B][[/B]a1[B]];[/B]
[B]if[/B] [B]([/B] v7 [B]!=[/B] a3 [B])[/B]
[B]{[/B]
    [B]*[/B]a4 [B]=[/B] v7[B];[/B]
    a2[B]->[/B]MajorFunction[B][[/B]a1[B]][/B] [B]=[/B] a3[B];[/B]
[B]}[/B]

trong đó a1 là chỉ số của hàm trong bảng majorfunction, a1 có thể là IRP_MJ_CREATE hoặc IRP_MJ_DIRECTORY_CONTROL, a3 là địa chỉ hàm của rootkit để thay vào.
Với hàm bị chuyển hướng ở vị trí IRP_MJ_CREATE: hàm của rootkit sẽ trả lại STATUS_ACCESS_DENIED khi mở một trong các file: FastFat.sys, Ntfs.sys, Ntfs.sys, tmp.hiv. Đoạn mã thực hiện hành vi này của rootkit như sau:

Mã:
qmemcpy[B]([/B]v3[B],[/B] [B]*([/B]const void [B]**)([/B]v2 [B]+[/B] 52[B]),[/B] [B]*([/B]_WORD [B]*)([/B]v2 [B]+[/B] 48[B]));[/B]
[B]if[/B] [B]([/B] [B]![/B]wcsstr[B](([/B]const wchar_t [B]*)[/B]v3[B],[/B] L"Fastfat.sys"[B])[/B]
    [B]&&[/B] [B]![/B]wcsstr[B](([/B]const wchar_t [B]*)[/B]v3[B],[/B] L"Ntfs.sys"[B])[/B]
    [B]&&[/B] [B]![/B]wcsstr[B](([/B]const wchar_t [B]*)[/B]v3[B],[/B] L"fastfat.sys"[B])[/B]
    [B]&&[/B] [B]![/B]wcsstr[B](([/B]const wchar_t [B]*)[/B]v3[B],[/B] L"ntfs.sys"[B])[/B]
    [B]&&[/B] [B]![/B]wcsstr[B](([/B]const wchar_t [B]*)[/B]v3[B],[/B] L"tmp.hiv"[B])[/B] [B])[/B]
    [B]{[/B]
        ExFreePool[B]([/B]v3[B]);[/B]
        [B]return[/B] v5[B]([/B]a1[B],[/B] Irp[B]);[/B]
    [B]}[/B]
ExFreePool[B]([/B]v3[B]);[/B]
Irp[B]->[/B]IoStatus[B].[/B]Information [B]=[/B] 0[B];[/B]
Irp[B]->[/B]IoStatus[B].[/B]Status [B]=[/B] 0xC0000022[B];[/B]
IofCompleteRequest[B]([/B]Irp[B],[/B] 0[B]);[/B]
[B]return[/B] 0xC0000022[B];[/B]


Với hàm bị chuyển hướng ở vị trí IRP_MJ_DIRECTORY_CONTROL: hàm mới của rootkit thực hiện hành vi ẩn giấu file VideoAti.sys, VideoAti.dll, VideoAti.exe. Mỗi khi hàm ở ở vị trí IRP_MJ_DIRECTORY_CONTROL của Ntfs và FastFat được gọi, ta sẽ lấy được một danh sách liên kết các cấu trúc định nghĩa như sau:
Mã:
[B]typedef[/B] struct _FILE_BOTH_DIRECTORY_INFORMATION [B]{[/B]
    ULONG NextEntryOffset[B];[/B]
    ULONG Unknown[B];[/B]
    LARGE_INTEGER CreationTime[B];[/B]
    LARGE_INTEGER LastAccessTime[B];[/B]
    LARGE_INTEGER LastWriteTime[B];[/B]
    LARGE_INTEGER ChangeTime[B];[/B]
    LARGE_INTEGER EndOfFile[B];[/B]
    LARGE_INTEGER AllocationSize[B];[/B]
    ULONG FileAttributes[B];[/B]
    ULONG FileNameLength[B];[/B]
    ULONG EaInformationLength[B];[/B]
    UCHAR AlternateNameLength[B];[/B]
    WCHAR AlternateName[B][[/B]12[B]];[/B]
    WCHAR FileName[B][[/B]1[B]];[/B]
[B]}[/B] FILE_BOTH_DIRECTORY_INFORMATION[B],[/B] [B]*[/B]PFILE_BOTH_DIRECTORY_INFORMATION[B];[/B]

trong đó trường NextEntryOffset là vị trí của phần tử tiếp theo trong danh sách liên kết. Với danh sách này, rootkit thực hiện duyệt từng phần tử để kiểm tra, nếu gặp phần tử chưa tên file cần ẩn giấu thì rootkit thực hiện loại bỏ nó khỏi danh sách bằng cách gán giá trị trường NextEntryOffset của phần tử đứng trước nó thành giá trị trường NextEntryOffset của trường cần loại bỏ.

3. Tự ẩn giấu
Rootkit sẽ tự ẩn mình khỏi hệ thống, nghĩa là người dùng sẽ không thể thấy được rootkit đang hoạt động. Như ở trên, rootkit đã lấy được PsLoadedModuleList, là danh sách các driver được tải lên. Một phần tử trong danh sách có cấu trúc:

Mã:
[B]typedef[/B] struct _MODULE_ENTRY 
[B]{[/B]
    LIST_ENTRY le_mod[B];[/B] // +00
    BYTE unknown[B][[/B]16[B]];[/B] // +08
    DWORD base[B];[/B] // +18
    DWORD driver_start[B];[/B] // +1C
    DWORD unknown_1[B];[/B] // +20
    UNICODE_STRING driver_Path[B];[/B] // +24
    UNICODE_STRING driver_Name[B];[/B] // +28
    // ...
[B]}[/B] MODULE_ENTRY[B],[/B] [B]*[/B]PMODULE_ENTRY[B];[/B]

trong đó trường le_mod có kiểu được định nghĩa:
Mã:
[B]typedef[/B] struct _LIST_ENTRY [B]{[/B]
    struct _LIST_ENTRY  [B]*[/B]Flink[B];[/B]
    struct _LIST_ENTRY  [B]*[/B]Blink[B];[/B]
[B]}[/B] LIST_ENTRY[B],[/B] [B]*[/B]PLIST_ENTRY[B];[/B]

Trường Flink trỏ tới phần tử kế tiếp trong danh sách, còn trường Blink trỏ tới phần tử đứng ngay trước trong danh sách. Rootkit duyệt danh sách PsLoadedModuleList này, nếu gặp phần tử có trường driver_Name chứa xâu “VideoAti0” thì thực hiện loại bỏ phần tử này khỏi danh sách. Việc loại bỏ này giống như việc loại bỏ một phần tử khỏi danh sách liên kết đôi.

4. Tự khởi động cùng windows
Rootkit thực hiện đăng kí một hàm callback bằng cách gọi hàm PsSetCreateProcessNotifyRoutine().
v7 = PsSetCreateProcessNotifyRoutine(NotifyRoutine, 0);
Bằng cách gọi hàm này, thì hàm callback của rootkit sẽ được gọi mỗi khi một tiến trình được tạo hay bị xóa. Bên trong hàm callback này, lại có một hàm con nữa, hàm sẽ được gọi khi tiến trình có tên là “userinit.exe” được tạo ra. Hàm con này thực hiện ghi key khởi động của rootkit, key này có đường dẫn:
HKLMSOFTWAREMicrosoftWindowsCurrentVersionRun. Bên trong key, rootkit tạo ra một khóa tên AtiCardInit với giá trị khóa là VideoAti0.exe.

Mã:
RtlInitUnicodeString[B](&[/B]ValueName[B],[/B] a2[B]);[/B]
RtlInitUnicodeString[B](&[/B]v8[B],[/B] a3[B]);[/B]
ZwSetValueKey[B](([/B]HANDLE[B])[/B]SourceString[B],[/B] [B]&[/B]ValueName[B],[/B] 0[B],[/B] 1u[B],[/B] v8[B].[/B]Buffer[B],[/B] v8[B].[/B]Length[B]);[/B]
ZwClose[B](([/B]HANDLE[B])[/B]SourceString[B]);[/B]
result [B]=[/B] 0[B];[/B]

Trên đây là bài viết phân tích mẫu rootkit VideoAti0.sys thành phần kernel của Nailuj. Mong nhận được góp ý, đóng góp từ bạn đọc ./. :eek:
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Anh @Malware ơi anh có mở lớp dạy malware không ạ? Đọc bài viết của anh mà thấy ngưỡng mộ quá :) Cảm ơn anh đã dành thời gian viết bài, chia sẻ kiến thức tới mọi người ạ.
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
VideoAti0.sys --> Ring0 rootkit :-"
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Bên trên