18/09/2018, 14:52

Kỹ thuật phân tích tĩnh cơ bản (Phần 2) – Liên kết động, runtime…

Tiếp tục chuyên đề kỹ thuật phân tích tĩnh cơ bản ở bài viết này thì chuyên gia an ninh mạng Bùi Đình Cường sẽ gửi đến bạn đọc các thư viện và hàm liên kết, cách phân biệt liên kết tĩnh, liên kết runtime và liên kết động, đồng thời cũng nhận biết được thế nào là các hàm được import các hàm được ...

Tiếp tục chuyên đề kỹ thuật phân tích tĩnh cơ bản ở bài viết này thì chuyên gia an ninh mạng Bùi Đình Cường sẽ gửi đến bạn đọc các thư viện và hàm liên kết, cách phân biệt liên kết tĩnh, liên kết runtime và liên kết động, đồng thời cũng nhận biết được thế nào là các hàm được import các hàm được export.

Các thư viện và hàm liên kết

Một trong những thông tin quan trọng nhất mà ta có thể thu thập được ở bước ban đầu là danh sách các hàm mà một file thực thi sử dụng (imports). Imports là tập danh sách các hàm được sử dụng bởi một chương trình nhưng lại được định nghĩa trong một chương trình khác. Các thư viện có thể liên kết với chương trình thực thi chính thông qua việc liên kết – linking.

Các lập trình viên liên kết các hàm cần sử dụng tới chương trình của mình để không phải viết lại hàm mới trong nhiều chương trình. Các thư viện có thể được liên kết tĩnh, liên kết khi thực thi (runtime) và liên kết động. Biết được thư viện được liên kết như thế nào giúp ta hiểu rõ hơn về mã độc vì các thông tin mà ta tìm thấy trong PE header phụ thuộc vào việc một thư viện được liên kết như thế nào.

XEM THÊM: Nguyên lý giải mã mật khẩu

Liên kết tĩnh, liên kết runtime và liên kết động

Liên kết tĩnh là hình thức liên kết ít phổ biến nhất, mặc dù hình thức này hay gặp trong

các chương trình của UNIX/Linux. Khi một thư viện được liên kết tĩnh tới một chương trình, tất cả mã nguồn trong thư viện đó được chép sang chương trình đó, điều này khiến chương trình tăng kích thước. Khi phân tích mã nguồn, ta gặp khó khăn trong việc phân biệt đâu là mã nguồn từ thư viện được liên kết tĩnh tới, đâu là mã nguồn của chính chương trình vì không có thông tin nào trong PE header cho thấy một file chứa các code liên kết.

Không phổ biến lắm trong các phần mềm sạch nhưng liên kết runtime lại được sử dụng nhiều trong mã độc, đặc biệt là mã độc được đóng gói và làm rối. Trình thực thi sử dụng liên kết runtime sẽ kết nối tới các thư viện chỉ khi một hàm cụ thể được yêu cầu chứ không phải khi nó khởi chạy như liên kết động.

Một vài hàm của Windows cho phép ta gọi các hàm được liên kết mà không được liệt kê trong header của chương trình thực thi. Hai hàm được sử dụng phổ biến nhất là LoadLibrary GetProcAddress. LdrGetProcAddressLdrLoadDLL cũng hay được dùng. LoadLibraryGetProcAddress cho phép chương trình truy cập tới mọi hàm và thư viện có trong hoặc đã được nạp lên hệ thống. Như vậy, khi 2 hàm này được sử dụng, ta không thể biết rõ được những hàm nào sẽ được liên kết tới chương trình nghi ngờ.

Trong 3 phương pháp liên kết thì liên kết động là phổ biến nhất và thú vị nhất khi phân tích mã độc. Một khi các thư viện được liên kết động, hệ điều hành sẽ tìm kiếm các thư viện đó khi chương trình thực thi được tải vào bộ nhớ. Khi chương trình gọi tới các hàm thư viện liên kết động, các hàm đó sẽ được thực thi ngay trong thư viện của mình.

PE header chứa các thông tin về tất cả các thư viện được tải và tất cả các hàm được sử dụng bởi chương trình. Các thư viện được sử dụng và các hàm được gọi thường là những phần quan trọng nhất của chương trình và việc xác định chúng là cực kì quan trọng vì ta có thể đoán được chương trình sẽ làm những gì. Ví dụ, một chương trình gọi hàm URLDownloadToFile, ta đoán nó sẽ kết nối Internet và tải về một vài nội dung và lưu chúng vào một file nào đó trên bộ nhớ nằm trong hệ thống.

Khám phá các hàm liên kết động bằng Dependency Walker

Dependency Walker (http://www.dependencywalker.com/) chỉ liệt kê các hàm được liên kết động trong một chương trình. Ảnh dưới minh phân tích file LAB01-01.EXE bằng Dependency Walker.

(1) Tên file đang được phân tích.

(2) – Các DLL được liên kết: KERNEL32.DLL, MSVCRT.DLL

(3) – Click vào KERNEL32.DLL được danh sách các hàm được import. CopyFileA là hàm thực hiện copy một file sang một file mới.

(4) – Danh sách các hàm trong KERNEL32.DLL có thể được import – thông tin này không quan trọng.

Chú ý:

  • Cột Ordinal trong bảng (3) và (4): Chương trình có thể gọi một hàm theo tên hàm hoặc thứ tự hàm.
  • Nếu gọi hàm theo thứ tự, tên của hàm sẽ không xuất hiện trong trình thực thi gốc và sẽ khó khăn hơn để ta tìm ra hàm nào được gọi.
  • Khi mã độc gọi hàm theo thứ tự, ta có thể dùng bảng ordinal để tra cứu ra tên hàm.

(5) và (6): Thông tin phụ về phiên bản DLL sẽ được liên kết khi ta chạy trình thực thi và các báo lỗi.

phân tích tĩnh

Các DLL của một chương trình cho phép ta dự đoán về các chức năng của chương trình đó. Một số DLL phổ biến:

DLL Mô tả
Kernel32.dll DLL phổ biến nhất, chứa các hàm chính,i cho phép truy cập và sử dụng bộ nhớ, file, phần cứng,…
Advapi32.dll Cung cấp truy cập tới các thành phần quan trọng của hệ điều hành Windows như Service Manager và Registry.
User32.dll Chứa các thành phần giao diện người dùng như các nút, thanh cuộn, và các thành phần điều khiển – phản hồi thao tác người dùng.
Gdi32.dll Chứa các hàm hiển thị và sử dụng đồ họa.
Ntdll.dll DLL này là giao diện của Windows kernel. Các trình thực thi thường không import file này một cách trực tiếp mà import gián tiếp qua Kernel32.dll. Ntdll.dll được import tức là người viết chương trình có chủ đích sử dụng những hàm không phổ biến với một chương trình Windows bình thường. Một số tác vụ như chức năng ẩn hoặc quản lý tiến trình sử dụng giao diện này.
WSock32.dll và Ws2_32.dll Là các DLL dùng trong xử lí kết nối mạng. Một chương trình gọi 1 trong 2 DLL này có thể có hành vi kết nối một mạng hoặc thực hiện các thao tác liên quan đến mạng.
Wininet.dll Chứa các hàm networking mức cao hơn, triển khai các giao thức như HTTP, FTP, NTP,…

Các hàm được import

PE header chứa thông tin về các hàm cụ thể được sử dụng bởi chương trình. Tên của các hàm này gợi ý về hành vi của chương trình. Microsoft thực hiện làm tài liệu rất chi tiết về WinAPI trên MSDN.

Các hàm được export

Các DLL và EXE export các hàm để tương tác với các chương trình khác. Chẳng hạn một DLL triển khai một hoặc một vài hàm và export chúng để các hàm này có thể được import và sử dụng bởi một trình thực thi.

Các file PE chứa thông tin về các hàm được được một file nào đó export. Vì DLL được thiết kế chuyên để cung cấp hàm cho EXE nên các hàm export phổ biến nhất ở DLL. EXE không được thiết kế để chia sẻ hàm với các EXE khác nên các hàm export hiếm gặp trong EXE. Nếu bắt gặp một hàm export trong EXE, đây có thể là một manh mối hữu ích về sau.

Trong nhiều trường hợp, tác giả phần mềm đặt tên các hàm export một cách khoa học để cung cấp được nhiều thông tin. Nhưng nếu mã độc dùng các hàm export, tác giả mã độc có thể đặt tên hàm khó hiểu, rối hoặc gây hiểu nhầm để đánh lừa người phân tích. Có thể dùng Dependency Walker để tìm kiếm các hàm export trong file.

Cấu trúc PE Headers và PE Sections

PE header có thể cung cấp nhiều thông tin hơn là các Imports. Ngay sau header là các Section của file. Các section phổ biến nhất là:

.text Chứa các tập lệnh CPU. Tất cả các section khác đều để lưu trữ dữ liệu và thông tin hỗ trợ khác. Nhìn chung, đây là section duy nhất có thể thực thi, do đó .text nên là section duy nhất chứa code.
.rdata Chứa các thông tin import và export như những gì ta thấy trong Dependency Walker. Section này cũng có thể lưu trữ dữ liệu read-only dùng bởi chương trình. Thỉnh thoảng, một file có thể chứa section .idata .edata, các section này dùng riêng để chứa thông tin import và export.
.data Chứa dữ liệu toàn cục của chương trình, dữ liệu này có thể truy cập từ bất kì đâu trong chương trình. Dữ liệu cục bộ không được lưu trong section này hay bất kì đâu trong PE file.
.rsrc Chứa các tài nguyên không được coi là thành phần của chương trình nhưng được dùng bởi chương trình, chẳng hạn các icon, image, menu, string,… String có thể được lưu trữ trong section .rsrc hoặc trong chương trình chính nhưng thường thì chúng được đặt ở .rsrc vì được hỗ trợ đa ngôn ngữ.

Tên section thường không đổi trong một trình biên dịch nhưng có thể thay đổi đối với mỗi trình biên dịch khác nhau. Chẳng hạn Visual Studio dùng .text cho section chứa code thực thi nhưng Borland Delphi dùng tên CODE. Windows không quan tâm tên thực sự của section vì nó dùng các thông tin khác trong PE header để xác định các các section được sử dụng. Tuy nhiên, tên section có thể được làm rối để khó bị phân tích hơn, thông thường thì tên mặc định vẫn được dùng chủ yếu.

Xem PE file với PEview: PEview là công cụ đơn giản cho phép xem thông tin trong PE header.

  1. Các phần chính trong PE header. IMAGE_DOS_HEADER và MS-DOS Stub Program hay IMAGE_NT_HEADERS Signature là những thông tin của Windows, có thể bỏ qua.
  2. Bảng bên phải là thông tin cơ bản về IMAGE_FILE_HEADER như kiến trúc bộ xử lý, thời điểm chương trình được biên dịch (3),… Nếu một mã độc đã được biên dịch từ lâu, có thể các Antivirus đã có chữ ký của nó rồi. Việc mã độc mới được biên dịch gần đây sẽ gợi ý ta phải dịch ngược nó để tìm hiểu thêm.

Thời điểm biên dịch cũng có một vấn đề cần nhớ. Tất cả các chương trình Delphi sử dụng giá trị thời điểm biên dịch là ngày 19/6/1992. Nếu thấy thời điểm biên dịch có giá trị này, rất có thể ta đang xử lý một chương trình Delphi và không thể biết được thời điểm biên dịch thật sự. Thực ra thì hacker hoàn toàn có thể làm giả thời điểm biên dịch.

IMAGE_OPTIONAL_HEADER chứa một vài thông tin quan trọng. Mô tả trong Subsystem có thể chỉ ra chương trình là console hay có giao diện GUI. Chương trình console có giá trị IMAGE_SUBSYSTEM_WINDOWS_CUI, giá trị IMAGE_SUBSYSTEM_WINDOWS_GUI ứng với chương trình GUI.

Xem nội dung và cấu trúc file PE bằng PEview

Xem nội dung và cấu trúc file PE bằng PEview

Thông tin thú vị nhất nằm trong IMAGE_SECTION_HEADER. Header này dùng để mô tả mỗi section trong PE file.Trình biên dịch thường tạo và tự động đặt tên cho các section trong file thực thi, người dùng có ít quyền kiểm soát các tên này. Do đó, tên section thường quen thuộc và bất kì sự sai lệch nào đều đáng nghi ngờ.

Trong ảnh dưới, Virtual Size (1) cho thấy cần bao nhiêu không gian nhớ cho section khi tải tiến trình. Size of Raw Data (2) chỉ ra kích thước của section trong ổ lưu trữ. Hai giá trị này thường nên bằng nhau. Sai lệch nhỏ trong hai giá trị này có thể coi là bình thường do sự khác nhau trong việc sắp xếp của bộ nhớ và đĩa cứng.

Kích thước section có thể hữu ích để phát hiện một chương trình đã được pack. Nếu Virtual Size lớn hơn nhiều so với Size of Raw Data, đặc biệt đối với .text section, rất có thể ta đang phân tích một chương trình đã được pack!

Xem thông tin trong Section header

Xem thông tin trong Section header

Xem Resource Section với Resource Hacker: Resource section là section duy nhất ta có thể xem xét mà không cần hiểu biết những kiến thức sẽ được đề cập ở các phần sau. Ta có thể dùng công cụ Resource Hacker (http://www.angusj.com/resourcehacker/) để duyệt section .rsrc. Resource Hacker cho phép ta xem các string, icon, menu,…, là các dữ liệu ngoài của trình thực thi. Sử dụng Resource Hacker là rất dễ dàng, không cần giải thích gì thêm.

Trong ảnh là ví dụ về các resource sử dụng bởi chương trình calc.exe của Windows.

Xem thông tin các tài nguyên sử dụng bằng Resource Hacker

Xem thông tin các tài nguyên sử dụng bằng Resource Hacker

Mã độc, và thỉnh thoảng một số phần mềm sạch, thường lưu trữ một chương trình nhúng hoặc driver trong section này và trước khi chương trình chính chạy, nó sẽ giải nén trình thực thi nhúng hoặc driver đó. Resource Hacker cho phép ta giải nén các file này để phân tích riêng.

Tổng kết PE Header: PE header chứa rất nhiều thông tin hữu ích cho việc phân tích mã độc, tôi  sẽ dành 1 bài nghiên cứu cụ thể từng thông tin đó ở các phần sau. Bảng dưới thống kê lại các thông tin mấu chốt ta có thể tìm thấy trong PE header.

Trường Thông tin có thể khai thác
Imports Các hàm từ những thư viện khác được sử dụng bởi chương trình chính.
Exports Các hàm trong chương trình chính cho phép gọi bởi chương trình hoặc thư viện khác.
Time Date Stamp Thời điểm chương trình được biên dịch.
Sections Tên các section có trong file thực thi và kích thước của chúng trên đĩa cứng/bộ nhớ trong.
Subsystem Cho biết chương trình là một ứng dụng console hay có giao diện người dùng.
Resources Các string, icon, menu và các thông tin khác trong file.

Như vậy, trong bài này tôi đã trình bày cho các bạn một số kĩ thuật phân tích tĩnh cơ bản, các bạn có thể áp dụng vào thực tế quá trình phân tích mã độc để thu thập các thông tin tương ứng mình cần:

  • Quét mã độc bằng các antivirus: Phát hiện nhanh chóng mã độc nếu mã độc đã từng bị phát hiện bởi các antivirus.
  • Sử dụng mã băm trong quá trình phân tích tĩnh: Cách thức lấy mã băm và sử dụng mã băm khi phân tích mã độc.
  • Tìm kiếm các chuỗi String nghi ngờ: Ý nghĩa từ các chuỗi có sẵn trong các ứng dụng trong việc phân tích mã độc.
  • Các mã độc được packed và obfuscated: Ý nghĩa việc packed, unpacked và một số mẹo phát hiện mã độc.
  • Định dạng PE file: Cấu trúc PE file và cách thức hệ điều hành thực thi một file.
  • Các thư viện và hàm liên kết: Các phương thức gọi hàm trên hệ điều hành.
  • Cấu trúc PE headers và PE sections: Cấu trúc chi tiết hơn về PE file, có ý nghĩa đặc biệt quan trọng trong quá trình phân tích, viết hàm diệt mã độc.

Trong bài tiếp theo, tôi sẽ giới thiệu tới các bạn phương pháp phân tích mã độc, vẫn ở mức cơ bản nhưng cách thức phân tích động thay vi phân tích tĩnh như bài này.

XEM NHIỀU NHẤT: Mã độc tống tiền mang tên “Bad Rabbit” đang lây lan hết sức mạnh mẽ

Securitybox_Giải pháp an ninh mạng toàn diện giúp đánh giá mạng trước sự cố, cung cấp dịch vụ ứng cứu sự cố và dịch vụ phản ứng nhanh khi có sự cố xảy ra.

Thông tin liên hệ:

Công ty cổ phần An toàn thông tin MVS – SecurityBox

Địa chỉ: Tầng 9, Tòa nhà Bạch Dương, Số 459 Đội Cấn, Ba Đình, Hà Nội

Hotline: (+84)982.593.866 (Mr.Cường)

Email: info@securitybox.vn

0