13
Theo dõi tiến trình Người viết: Phí Văn Ngc Ngày: 30/3/2007 1. Đặt vn đề Vi các sn phm phn mm bo mt như Personal Firewall thì vic giám sát vic to, hy tiến trình là rt quan trng trong vic phát hin và ngăn chn các tiến trình “độc” thc thi mã ca chúng. Tuy nhiên, các tiến trình được khi to và qun lý bi hđiu hành. Chương trình ca người sdng tng User-mode không thcan thip vào quá trình này. Do vy, để có thđạt được mt kết qukhquan, cn phi có nhng cơ chế tt cho phép can thip vào nhân hđiu hành và đón bt được cách thc hđiu hành to ra cũng như qun lý các tiến trình. 2. Các nhim vchính cn gii quyết Báo cáo này schtp trung gii quyết các vn đề chyếu sau: Đón bt vic to và hy tiến trình, tiu trình, np thư vin DLL mt cách Real-time Đón bt vic mt tiến trình chun bđược to ra và can thip được vào quá trình này. 3. Đón bt vic to, hy tiến trình Trên Windows, các ng dng tng User mode thường sdng hàm API CreateProcess() để to và thc thi mt tiến trình mi. Hàm API này thc cht chlà mt hàm trung gian chuyn li gi tUser mode đến hàm thc sto tiến trình trong Kernel mode. Trong Kernel mode, tn ti các hàm API có tên dng tương tnhư các hàm API trong User mode. Các hàm này được gi là các hàm native API – NT. Ví d, hàm NT tương ng ca CreateProcess() là NtCreateProcess(). Windows NT trgiúp nhiu hthng con (subsystem) bao gm :Win32, POSIX và OS2. Mi subsystem bao gm mt tp các hàm API mà người dùng User mode có thgi để thc hin các tác vmong mun. Chng hn, vi Win32 subsystem, thư vin Kernel32.dll cung cp rt nhiu các hàm để thao tác vi tiến trình, bnh, vào ra…Tuy nhiên, Kernel32.dll thc cht không phi là nhân ca hđiu hành. Nó chlà mt lp trung gian làm nhim vgiao tiếp gia li gi tUser mode vào Kernel mode. Vic chuyn li gi hàm này cui cùng sđược thc hin bi các hàm trong thư vin Ntdll.dll. Hình vsau minh ha quá trình route mt li gi hàm tUser mode vào Kernel mode: 1

Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Theo dõi tiến trình Người viết: Phí Văn Ngọc

Ngày: 30/3/2007

1. Đặt vấn đề Với các sản phẩm phần mềm bảo mật như Personal Firewall thì việc giám sát việc tạo,

hủy tiến trình là rất quan trọng trong việc phát hiện và ngăn chặn các tiến trình “độc” thực thi mã của chúng. Tuy nhiên, các tiến trình được khởi tạo và quản lý bởi hệ điều hành. Chương trình của người sử dụng ở tầng User-mode không thể can thiệp vào quá trình này. Do vậy, để có thể đạt được một kết quả khả quan, cần phải có những cơ chế tốt cho phép can thiệp vào nhân hệ điều hành và đón bắt được cách thức hệ điều hành tạo ra cũng như quản lý các tiến trình.

2. Các nhiệm vụ chính cần giải quyết Báo cáo này sẽ chỉ tập trung giải quyết các vấn đề chủ yếu sau:

• Đón bắt việc tạo và hủy tiến trình, tiểu trình, nạp thư viện DLL một cách Real-time

• Đón bắt việc một tiến trình chuẩn bị được tạo ra và can thiệp được vào quá trình này.

3. Đón bắt việc tạo, hủy tiến trình Trên Windows, các ứng dụng ở tầng User mode thường sử dụng hàm API

CreateProcess() để tạo và thực thi một tiến trình mới. Hàm API này thực chất chỉ là một hàm trung gian chuyển lời gọi từ User mode đến hàm thực sự tạo tiến trình trong Kernel mode. Trong Kernel mode, tồn tại các hàm API có tên dạng tương tự như các hàm API trong User mode. Các hàm này được gọi là các hàm native API – NT. Ví dụ, hàm NT tương ứng của CreateProcess() là NtCreateProcess().

Windows NT trợ giúp nhiều hệ thống con (subsystem) bao gồm :Win32, POSIX và OS2. Mỗi subsystem bao gồm một tập các hàm API mà người dùng ở User mode có thể gọi để thực hiện các tác vụ mong muốn. Chẳng hạn, với Win32 subsystem, thư viện Kernel32.dll cung cấp rất nhiều các hàm để thao tác với tiến trình, bộ nhớ, vào ra…Tuy nhiên, Kernel32.dll thực chất không phải là nhân của hệ điều hành. Nó chỉ là một lớp trung gian làm nhiệm vụ giao tiếp giữa lời gọi từ User mode vào Kernel mode. Việc chuyển lời gọi hàm này cuối cùng sẽ được thực hiện bởi các hàm trong thư viện Ntdll.dll. Hình vẽ sau minh họa quá trình route một lời gọi hàm từ User mode vào Kernel mode:

1

Page 2: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Thư viện Ntdll.dll có thể được coi là “lá chắn” cuối cùng của tầng User mode tiếp giáp với Kernel mode. Các đoạn mã thực sự thi hành các dịch vụ của hệ điều hành nằm trong file ntoskrnl.exe. Ntdll.dll chỉ làm nhiệm vụ phơi bày một số hàm API mà ntoskrnl.exe cung cấp để cho Kernel32.dll, User32.dll, Gdi32.dll…gọi chúng.

Hiểu được cơ chế ở trên, để có thể đón bắt việc tạo và hủy tiến trình một cách real-time, ta đề xuất một số giải pháp sau:

3.1. Giải pháp 1: sử dụng API hooking trong User mode

API hooking cho phép hook một hàm API mà một thư viện nào đó đã export. Để có thể hook, cần phải đặt mã của hàm hook vào trong một file DLL. Sau đó, nạp file DLL này vào tiến trình cần hook. Tiến trình cần hook chính là tiến trình đã nạp thư viện dll đã export hàm API trên. Có nhiều cách thực hiện việc hook API ở tầng user mode mà điển hình nhất là sử dụng Trampoline function (thư viện Detours đã sử dụng kĩ thuật này).

Với mục đích đã đặt ra, các hàm cần hook bao gồm: CreateProcess(),WinExec(), ShellExecute(), Yield(), TerminateProcess(), ExitProcess(). Hơn nữa, cần phải hook mọi tiến trình đang chạy nhằm phát hiện việc tạo, hủy tiến trình từ mọi tiến trình này. Điều này là không tối ưu nếu xét về góc độ hiệu năng và tính hiệu quả. Thứ nhất, việc sử dụng API hook cho toàn bộ tiến trình sẽ làm suy giảm hiệu năng hệ thống. Thứ hai, có thể tồn tại các hàm API khác dạng undocumented cũng có chức năng tạo tiến trình. Khi đó, việc hook này sẽ không thành công.

2

Page 3: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

3.2. Giải pháp 2: Sử dụng Polling kết hợp với các hàm API liệt kê tiến trình

Theo phương pháp này, một Thread ngầm sẽ được tạo ra. Nhiệm vụ của Thread này là liên tục capture các tiến trình của hệ điều hành nhằm phát hiện việc tạo và hủy tiến trình mới.

Để capture thông tin về tiến trình, có thể sử dụng các hàm API do các thư viện psapi.dll, thư viện Tool help 32 như : EnumProcess(), CreateToolhelp32Snapshot()… Ưu điểm của phương pháp này là dễ cài đặt. Tuy nhiên, không tối ưu về hiệu năng cũng như tính real-time.

3.3. Giải pháp 3: Sử dụng API hooking trong Kernel mode

Như đã đề cập ở trên, các hàm API trong User mode chỉ thực sự là trung gian chuyển lời gọi từ User mode vào Kernel mode. Chẳng hạn, CreateProcess() thực chất sẽ gọi vào NtCreateProcess(). Do vậy, để tăng tính triệt để và thu hẹp phạm vi kiểm soát, có thể sử dụng phương pháp Hook các hàm native API.

Theo phương pháp này, hàm hook sẽ được đặt trong một Device Driver. Vai trò của Device Driver trong Kernel mode cũng tương tư như các file DLL trong User mode khi sử dụng System-wide hook. Các hàm native API liên quan đến tạo, hủy tiến trình sẽ bị hook. Hàm hook sẽ đón bắt việc gọi đến các hàm này và trả về thông tin cho người dùng ở User mode đồng thời gọi hàm bị hook (e.g, NtCreateProcess) để tiến trình có thể tạo và hủy một cách hợp lệ.

Ưu điểm của phương pháp này là có thể thu hẹp phạm vi giám sát các hàm API. Thay vì phải giám sát một số lượng lớn các hàm API tạo, hủy tiến trình ở User mode, phương pháp này chỉ giám sát một số hàm native API ở Kernel mode. Do vậy, sẽ có thể đón bắt tốt hơn việc tạo, hủy tiến trình cũng như tăng tính Real-time.

Nhược điểm của phương pháp này là nếu cài đặt không tốt, có thể gây ra sự phụ thuộc qúa nhiều vào các hàm native API vốn có thể bị thay đổi bởi Microsoft trong các phiên bản khác nhau của Windows.

3.4. Giải pháp 4: Sử dụng native API tiện ích của hệ điều hành

Trong tất cả các giải pháp đưa ra, có lẽ giải pháp này sẽ mang lại hiệu quả hơn cả. Nguyên lý của giải pháp này dựa trên cơ chế sau: Windows cung cấp một số hàm API ở tầng Kernel mode hỗ trợ việc đăng ký một hàm Callback nhằm thông báo việc tạo và hủy tiến trình. Mỗi khi có một tiến trình được tạo hoặc hủy, Windows sẽ gọi hàm Callback này. Hàm

3

Page 4: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Callback cần phải được đặt trong một Device Driver vì cơ chế này chỉ làm việc ở Kernel mode.

Hàm mà ta vừa nêu có dạng như sau:

Tham số Remove sẽ thiết lập cơ chế Callback (FALSE) hoặc loại bỏ hàm Callback(TRUE).

Hàm Callback có dạng sau:

Trong hàm Callback này, các ham số bao gồm:

NTSTATUS PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE Callback,IN BOOLEAN Remove);

VOID ProcessCallback(IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create);

• ParentId: ID của Process cha đã tạo hoặc hủy tiến trình

• ProcessId: ID của Process được tạo hoặc hủy

• Create: TRUE nếu Process được tạo, FALSE nếu bị hủy

Trong hàm Callback, các thông tin về tiến trình vừa tạo hoặc hủy sẽ được thông báo cho chương trình người sử dụng ở User mode biết và xử lý. Ở đây, ta sử dụng cơ chế giao tiếp sự kiện. Một đối tượng đồng bộ kiểu Event được tạo ra trong DriverEntry. Chương trình User mode sẽ lắng nghe Event này. Khi hàm Callback được gọi, Event được thiết lập trạng thái thành Signaled và chương trình User mode sẽ được thông báo để có thể gửi lệnh IOCTL vào Driver và lấy thông tin cần thiết. Thông tin về tiến trình sẽ được lưu tạm thời trong một cấu trúc PROCESS_CALLBACK_INFO của DEVICE_EXTENSION.

4

Page 5: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

typedef struct tagProcessCallbackInfo { HANDLE hParentID; HANDLE hProcessID; BOOLEAN bCreated; }PROCESS_CALLBACK_INFO,*PPROCESS_CALLBACK_INFO; //.................... /***********************************************/ void ProcessCallback(IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create) { PDEVICE_EXTENSION pDevExtension; // Lấy về đối tượng Device Extension từ biến toàn cục g_pDeviceObject. pDevExtension=(PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension; // Gán thông tin tiến trình vào cấu trúc ProcessInfo trong Device Extension pDevExtension->ProcessInfo.hParentID=ParentId; pDevExtension->ProcessInfo.hProcessID=ProcessId; pDevExtension->ProcessInfo.bCreated=Create; // Thiết lập Event để thông báo cho User mode KeSetEvent( pDevExtension->KeProcessEvent, 0, FALSE); KeClearEvent(pDevExtension->KeProcessEvent); }

5

Page 6: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

// Lấy về thông tin tiến trình qua IOCTL NTSTATUS DispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { //................. switch(pIoStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_GET_PROCESS_INFO: { if(pIoStack->Parameters.DeviceIoControl.OutputBufferLength>= sizeof(PROCESS_CALLBACK_INFO)) { // Set user-supplied buffer pProcessInfo=(PPROCESS_CALLBACK_INFO)Irp->AssociatedIrp.SystemBuffer; // Lấy thông tin tiến trình đã lưu trong Device Extension và gán vào bộ đệm trả về cho User mode pProcessInfo->hParentID=pDevExtension->ProcessInfo.hParentID; pProcessInfo->hProcessID=pDevExtension->ProcessInfo.hProcessID; pProcessInfo->bCreated=pDevExtension->ProcessInfo.bCreated; } break; }

4. Đón bắt việc tạo, hủy tiểu trình và các module Cơ chế tương tự cũng được sử dụng để đón bắt việc tạo, hủy các tiểu trình (Thread) và

nạp, hủy nạp các module DLL. Các hàm sử dụng cho việc này như sau:

6

NTSTATUS PsSetCreateThreadNotifyRoutine(PCREATE_THREAD_NOTIFY_ROUTINE Callback; NTSTATUS PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE Callback); VOID ThreadCallback( IN HANDLE ProcessId, IN HANDLE ThreadId, IN BOOLEAN Create); VOID ImageCallback( IN PUNICODE_STRING FullImageName, IN HANDLE ProcessId, IN PIMAGE_INFO ImageInfo);

Page 7: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

5. Đón bắt và can thiệp quá trình tạo tiến trình Như đã phân tích ở trên, kĩ thuật hook các hàm native API tỏ ra có lợi thế trong các

trường hợp này. Để đón bắt việc tạo một tiến trình và có thể can thiệp nó (hủy không cho tạo hoặc cho tiếp tục tạo tiến trình), cần phải có cơ chế hook các hàm native API có khả năng tạo tiến trình. Một ứng cử viên tiềm tàng là hàm NtCreateProcess(). Tuy nhiên, không có điều gì đảm bảo rằng có hay không một hàm khác cũng có thể tạo tiến trình. Vì vậy, cần phải hook ở mức độ hẹp hơn. Cơ chế tạo tiến trình có thể được minh họa bởi dãy các hàm sau:

Do vậy, để có thể đón bắt ở mức hẹp hơn, ta nên hook hàm NtCreateSection(). Hàm này sẽ được gọi trước khi hàm NtCreateProcess() được gọi. Việc hook hàm NtCreateSection() được thực hiện bằng cách can thiệp vào bảng System Service Dispatch Table (bảng chứa vector đến địa chỉ các hàm thực sự cung cấp dịch vụ của hệ điều hành) và sửa đổi địa chỉ của hàm NtCreateSection() thành địa chỉ của hàm hook đặt trong Driver. Cấu trúc của bảng SSDT như sau:

Để tiện lợi, ta định nghĩa một macro dùng cho việc lấy về địa chỉ của một hàm native API bất kỳ như sau:

NtCreateSection() NtCreateProcess() NtCreateThread() NtCreateFile()

7

Page 8: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Macro trên sẽ lấy về địa chỉ hàm _function.

Các thủ tục Hook và UnHook đơn giản là thay thế địa chỉ hàm thực bởi hàm hook và ngược lại:

RealZwCreateSection là một con trỏ hàm đến hàm NtCreateSection.

Trong hàm hook, một đối tượng Event sẽ được thiết lập trạng thái signaled để thông báo cho người sử dụng và đợi ý kiến của người dùng (cho phép hoặc cấm) tiến trình thực hiện. Tùy theô kết quả trả về mà hàm hook sẽ gọi hàm gốc (cho phép) hoặc trả về STATUS_ACCESS_DENIED để báo rằng việc tạo tiến trình không được thực hiện.

#define SYSCALL(_function) ServiceTable->ServiceTable[ *(PULONG)((PUCHAR)_function+1)]

NTSTATUS (*RealZwCreateSection) ( OUT PHANDLE, IN ULONG, IN POBJECT_ATTRIBUTES, IN PLARGE_INTEGER, IN ULONG, IN ULONG, IN HANDLE ); void SetHook(){ // Lưu hàm gốc RealZwCreateSection=SYSCALL(ZwCreateSection); // Thay hàm gốc bằng hàm hook SYSCALL(ZwCreateSection)=(PVOID)HookZwCreateSection; } void UnsetHook(){ // Khôi phục hàm gốc SYSCALL(ZwCreateSection)=(PVOID)RealZwCreateSection; }

8

Page 9: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

NTSTATUS HookZwCreateSection(OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL ) { //........................ // Set event so that user can be notified

KeSetEvent(pDevExt->KeHookEvent, 0, FALSE); KeClearEvent(pDevExt->KeHookEvent); DbgPrint("Waiting for user response...\n"); // Đợi trả lời của người dùng UserResponse.bResponsed=FALSE; while(1) { KeDelayExecutionThread(KernelMode,0,&li); if(UserResponse.bResponsed) break; } // Nếu người dùng cho phép thì gọi hàm gốc if(UserResponse.bAllowed) { DbgPrint("ProcMan: User responsed allow\n"); RETURN_ORG; }

// Nếu không thi trả về lỗi và hủy việc tạo tiến trình else { DbgPrint("ProcMan: User responsed disallow\n"); return STATUS_ACCESS_DENIED; } return STATUS_SUCCESS;

6. Chương trình Demo Chương trình demo được xây dựng nhằm sử dụng Driver đã tạo và minh họa kết quả.

Chương trình được viết bằng Visual C++ 6.0, sử dụng MFC. Một số kết quả demo như hình chụp dưới đây:

9

Page 10: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Hình 1: Giao diện chính

Hình 2: Thông báo tiến trình vừa được tạo Hình 3:Thông báo tiến tình bị hủy

10

Page 11: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Hình 4: Hỏi người dùng quyết định việc có tạo tiến tình hay không

Hình 5: Không cho phép tạo tiến trình

11

Page 12: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

Hình 6: Ứng dụng xây dựng chức năng lọc chương trình dựa trên tập luật

Hình 7: Tạo luật lọc tiến trình

12

Page 13: Theo dõi tiến trình - WordPress.com...Theo dõi tiến trình Người viết: Phí Văn Ngọc Ngày: 30/3/2007 1. Đặt vấn đề Với các sản phẩm phần mềm bảo

7. Đánh giá kết quả Chương trình đã được thử nghiệm trên Windows XP SP2, Windows Server 2003

tandard Edition và cho kết quả tốt. Có thể bắt được việc tạo tiến trình của bất kỳ tiến trình ào kể cả explorer.exe, task manager… Hiệu năng của hệ thống hầu như ổn định.

ướng phát triển tiếp

Hướng phát triển tiếp theo sẽ bao gồm việc theo dõi các hành vi khác của tiến trình ư: truy cập file, truy cập Registry, truy cập network…

. Tài liệu tham khảo 1] - [Addison Wesley] Undocumented Windows 2000 Secrets - The Programmers Cookbook

] – www.CodeProject.Com

Sn

8. H

nh

9[

[2

[3] - MSDN

] - Wi

] – www.Rootkit.com

[4 ndows 2000 Device Driver Book A Guide For Programmers

[5

13