Kỹ thuật inject dll từ kernel của rootkit
Chào các bạn , trong bài viết trước mình đã giới thiệu với các bạn Kỹ thuật ẩn giấu hook SSDT của rootkit. Hôm nay mình sẽ tiếp tục phân tích thêm một kỹ thuật nữa mà rootkit sử dụng - Kỹ thuật inject dll ở kernel của rootkit.
Nội dung bài viết
- Giới thiệu kỹ thuật inject dll ở kernel của rootkit.
- Ứng dụng kỹ thuật này đối với rootkit thực tế.
Yêu cầu người đọ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 WinDbg.
1. Giới thiệu kỹ thuật inject dll ở kernel của rootkit
Như các bạn đã biết, malware thường sử dụng các kỹ thuật để mã độc có thể thực thi trên các process khác. Các kỹ thuật như là “windows hook”, ” CreateRemoteThread&LoadLibrary”, “CreateRemoteThread & WriteProcessMemory” … song các kỹ thuật đó đều thực hiện trên usermode. Các kỹ thuật này quá quen thuộc đối với những người có kiến thức về malware và hiện tại các AV(AntiVirus) trên thị trường đều bắt chặt chẽ hành vi này. Các bạn có thể tìm hiểu thêm về các kỹ thuật inject code trên usermode ở đây: http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces.
Một kỹ thuật để inject dll khác đã xuất hiện lâu rồi, nhưng nó được thực hiện ở mức kernel bởi rootkit đó là kỹ thuật sử dụng APC.
APC là Asynchronous Procedure Calls – là một hàm được thực thi không đồng bộ trong hoàn cảnh (context) của thread nào đó. Mỗi thread đều có APC queue. Khi APC được chèn vào một thread nào đó thì hệ điều hành sẽ tạo ra software interupt để bắt buộc hàm APC được thực hiện. Một APC có thể được tạo ra từ usermode hoặc kernel mode, ở đây ta chỉ xét APC tạo ra từ kernel mode.
Các bạn có thể tham khảo thêm về APC tại trang chủ của MSDN. Hoặc xem thêm APC Internal và undocumented về APC tại đây: http://www.opening-windows.com/techart_windows_vista_apc_internals.htm.
Các bước thực hiện inject dll từ kernel mode như sau:
1) Lấy địa chỉ của KdVersionBlock từ KPCR. (sủ dụng hàm __readfsdword)
2) Lấy địa chỉ của hàm MmLoadedUserImageList từ KdVersionBlock.
3) Lấy base address của ntdll từ MmLoadedUserImageList.
4) Tìm trong bảng export của ntdll xác định hàm LdrLoadDll.
5) Tìm thread mà chúng ta cần inject. ( sử dụng hàm ZwQuerySystemInformation)
6) Open process mà ta cần inject. ( sử dụng hàm PsLookupProcessByProcessId)
7) Open thread mà ta cần inject. (sử dụng hàm PsLookupThreadByThreadId)
8) Attach tới vùng địa chỉ của process cần inject. (sử dụng hàm KeAttachProcess)
9) Cấp phát vùng nhớ trong vùng địa chỉ của process cần inject. (sử dụng hàm ZwAllocateVirtualMemory)
10) Copy đường dẫn DLL và hàm APC vào vùng địa chỉ của process cần inject. ( sử dụng hàm memcpy,RtlInitUnicodeString)
11) Set APCState.UserAPCPending bằng TRUE để bắt buôc hàm APC thực thi.
12) Cấp phát một APC object từ nonpaged pool. (sử dụng hàmExAllocatePool)
13) Khởi tạo APC objec sau đó chèn APC object này vào thread target mà ta cần inject. (sử dụng hàm KeInitializeAPC,KeInsertQueueAPC)
14) Khi target thread mà ta cần inject thực thi hàm APC thì hàm APC này sẽ gọi hàm LdrLoadDll để load dll của chúng ta.
15) Chờ hàm APC hoàn thành.
16) Giải phóng vùng nhớ đã cấp phát. (sử dụng hàm ZwFreeVirtualMemory,ExFreePool)
17) Detach target process's mà ta đã attach trước đó. (sử dụng hàm KeDetachProcess)
18) Dereference target process và target thread. (sử dụng hàm ObDereferenceObject).
Có thể tóm tắt lại các bước trên đơn giản: từ bước 1 đến 4 mục đích của ta là tìm được hàm LdrLoadDll trong thư viện ntdll, các bước còn lại mục đích là chèn APC của ta vào tiến trình đích cần inject. Sau khi APC được chèn vào thì hàm APC của ta sẽ được thực thi trong process của tiến trình đích. Và hàm APC sẽ thực thi load dll của ta vào process đích. Công việc inject thành công và kết thúc!
Để các bạn rõ hơn về cài đặt code thực tế, tôi có đính kèm code cùng comment rõ ràng trong bài viết này.
2. Ứng dụng kỹ thuật này đối với rootkit thực tế
Bây giờ chúng ta cùng xem lại kỹ thuật này được rootkit thực tế sử dụng như thế nào:
- TDL 3 Là rootkit được cho là "Rootkit of all Evil". Là rootkit nổi tiếng thế giới, đáng sợ trong lịch sử, trong đó có rất nhiều kỹ thuật lần đầu tiên được áp dụng. TDL 3 đã inject dll của nó (tdlcmd.dll và tdlswp.dll) vào các tiến trình khác sử dụng kỹ thuật đã đề cập trong bài này: insert APC ở mức kernel!
Cụ thể là TDL 3 đăng ký hàm notify khi image được load, vì thế mỗi khi thư viện "kernel32.dll" được load lên thì hàm notify này sẽ insert một APC và hàm APC này sẽ được thực thi trong tiến trình target. Chính hàm APC này thực hiện việc load 2 dll kia.
Hình 1: TDL3 inject dll bằng hàm insert APC
- Zero access rootkit hay còn được biết đến là Smiscer or Max++ rootkit. Cũng là một “hàng khủng” trong các loại rootkit. Kỹ thuật inject dll mà zero acces rootkit này sử dụng cũng là insert APC để inject max++.00.x86 vào process của tiến trình victim.
Hình 2: Zero access inject dll bằng hàm insert APC
Lời kết
Trên đây là bài viết sơ lược về kỹ thuật inject dll ở kernel mode mà rootkit sử dụng. Hi vọng bài viết sẽ có ích đối với những ai quan tâm, làm việc với kernel windows, phân tích các mã độc ở mức kernel… khi gặp các dấu hiệu như trên sẽ nhận biết ngay kỹ thuật này.
Rất mong nhận sự góp ý từ bạn đọc .
Nội dung bài viết
- Giới thiệu kỹ thuật inject dll ở kernel của rootkit.
- Ứng dụng kỹ thuật này đối với rootkit thực tế.
Yêu cầu người đọ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 WinDbg.
1. Giới thiệu kỹ thuật inject dll ở kernel của rootkit
Như các bạn đã biết, malware thường sử dụng các kỹ thuật để mã độc có thể thực thi trên các process khác. Các kỹ thuật như là “windows hook”, ” CreateRemoteThread&LoadLibrary”, “CreateRemoteThread & WriteProcessMemory” … song các kỹ thuật đó đều thực hiện trên usermode. Các kỹ thuật này quá quen thuộc đối với những người có kiến thức về malware và hiện tại các AV(AntiVirus) trên thị trường đều bắt chặt chẽ hành vi này. Các bạn có thể tìm hiểu thêm về các kỹ thuật inject code trên usermode ở đây: http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces.
Một kỹ thuật để inject dll khác đã xuất hiện lâu rồi, nhưng nó được thực hiện ở mức kernel bởi rootkit đó là kỹ thuật sử dụng APC.
APC là Asynchronous Procedure Calls – là một hàm được thực thi không đồng bộ trong hoàn cảnh (context) của thread nào đó. Mỗi thread đều có APC queue. Khi APC được chèn vào một thread nào đó thì hệ điều hành sẽ tạo ra software interupt để bắt buộc hàm APC được thực hiện. Một APC có thể được tạo ra từ usermode hoặc kernel mode, ở đây ta chỉ xét APC tạo ra từ kernel mode.
Các bạn có thể tham khảo thêm về APC tại trang chủ của MSDN. Hoặc xem thêm APC Internal và undocumented về APC tại đây: http://www.opening-windows.com/techart_windows_vista_apc_internals.htm.
Các bước thực hiện inject dll từ kernel mode như sau:
1) Lấy địa chỉ của KdVersionBlock từ KPCR. (sủ dụng hàm __readfsdword)
2) Lấy địa chỉ của hàm MmLoadedUserImageList từ KdVersionBlock.
3) Lấy base address của ntdll từ MmLoadedUserImageList.
4) Tìm trong bảng export của ntdll xác định hàm LdrLoadDll.
5) Tìm thread mà chúng ta cần inject. ( sử dụng hàm ZwQuerySystemInformation)
6) Open process mà ta cần inject. ( sử dụng hàm PsLookupProcessByProcessId)
7) Open thread mà ta cần inject. (sử dụng hàm PsLookupThreadByThreadId)
8) Attach tới vùng địa chỉ của process cần inject. (sử dụng hàm KeAttachProcess)
9) Cấp phát vùng nhớ trong vùng địa chỉ của process cần inject. (sử dụng hàm ZwAllocateVirtualMemory)
10) Copy đường dẫn DLL và hàm APC vào vùng địa chỉ của process cần inject. ( sử dụng hàm memcpy,RtlInitUnicodeString)
11) Set APCState.UserAPCPending bằng TRUE để bắt buôc hàm APC thực thi.
12) Cấp phát một APC object từ nonpaged pool. (sử dụng hàmExAllocatePool)
13) Khởi tạo APC objec sau đó chèn APC object này vào thread target mà ta cần inject. (sử dụng hàm KeInitializeAPC,KeInsertQueueAPC)
14) Khi target thread mà ta cần inject thực thi hàm APC thì hàm APC này sẽ gọi hàm LdrLoadDll để load dll của chúng ta.
15) Chờ hàm APC hoàn thành.
16) Giải phóng vùng nhớ đã cấp phát. (sử dụng hàm ZwFreeVirtualMemory,ExFreePool)
17) Detach target process's mà ta đã attach trước đó. (sử dụng hàm KeDetachProcess)
18) Dereference target process và target thread. (sử dụng hàm ObDereferenceObject).
Có thể tóm tắt lại các bước trên đơn giản: từ bước 1 đến 4 mục đích của ta là tìm được hàm LdrLoadDll trong thư viện ntdll, các bước còn lại mục đích là chèn APC của ta vào tiến trình đích cần inject. Sau khi APC được chèn vào thì hàm APC của ta sẽ được thực thi trong process của tiến trình đích. Và hàm APC sẽ thực thi load dll của ta vào process đích. Công việc inject thành công và kết thúc!
Để các bạn rõ hơn về cài đặt code thực tế, tôi có đính kèm code cùng comment rõ ràng trong bài viết này.
2. Ứng dụng kỹ thuật này đối với rootkit thực tế
Bây giờ chúng ta cùng xem lại kỹ thuật này được rootkit thực tế sử dụng như thế nào:
- TDL 3 Là rootkit được cho là "Rootkit of all Evil". Là rootkit nổi tiếng thế giới, đáng sợ trong lịch sử, trong đó có rất nhiều kỹ thuật lần đầu tiên được áp dụng. TDL 3 đã inject dll của nó (tdlcmd.dll và tdlswp.dll) vào các tiến trình khác sử dụng kỹ thuật đã đề cập trong bài này: insert APC ở mức kernel!
Cụ thể là TDL 3 đăng ký hàm notify khi image được load, vì thế mỗi khi thư viện "kernel32.dll" được load lên thì hàm notify này sẽ insert một APC và hàm APC này sẽ được thực thi trong tiến trình target. Chính hàm APC này thực hiện việc load 2 dll kia.
Hình 1: TDL3 inject dll bằng hàm insert APC
- Zero access rootkit hay còn được biết đến là Smiscer or Max++ rootkit. Cũng là một “hàng khủng” trong các loại rootkit. Kỹ thuật inject dll mà zero acces rootkit này sử dụng cũng là insert APC để inject max++.00.x86 vào process của tiến trình victim.
Hình 2: Zero access inject dll bằng hàm insert APC
Lời kết
Trên đây là bài viết sơ lược về kỹ thuật inject dll ở kernel mode mà rootkit sử dụng. Hi vọng bài viết sẽ có ích đối với những ai quan tâm, làm việc với kernel windows, phân tích các mã độc ở mức kernel… khi gặp các dấu hiệu như trên sẽ nhận biết ngay kỹ thuật này.
Rất mong nhận sự góp ý từ bạn đọc .