Các Headers của tập tin PE có thể cung cấp cho chúng ta thông tin đáng kể hơn là các hàm import. Định dạng của tập tin PE chứa một Header và một chuỗi các Sections. Header chứa các siêu dữ liệu (Metadata) về bản thân của tập tin này. Những phần bên dưới Header là các phần thực tế (actual sections) của tập tin, mỗi section như thế chứa các thông tin hữu dụng. Sau đây là các phần phổ biến và quan trọng nhất trong một tập tin PE:

  • Section .text chứa các hướng dẫn cho CPU thực thi. Tất cả các Section khác lưu trữ dữ liệu và thông tin hỗ trợ. Nói chung, đây là một Section duy nhất mà có thể thực thi, và nó là section duy nhất chứa mã code của chương trình.
  • Section .rdata thường chứa các thông tin về các hàm import và export, những thông tin này thường được cung cấp bởi hai công cụ Dependency Walker và Peview. Section này cũng có thể lưu trữ những dữ liệu thuộc loại read-only khác được sử dụng bởi chương trình. Đôi khi một tập tin sẽ chứa một Section tên .idata và .edata, những Section này cũng lưu trữ các thông tin về các hàm import và export (xem hình minh họa bên dưới).
  • Section .data chứa dữ liệu toàn bộ của chương trình, nó có thể truy cập từ bất cứ nơi nào trong chương trình. Dữ liệu cục bộ thì không được lưu trữ trong Section này, hoặc ở bất cứ nơi nào khác trong tập tin PE. (Chúng ta sẽ làm rõ vấn đề này hơn ở những chương sau).
  • Section .rsrc bao gồm các tài nguyên được sử dụng bởi tiến trình thực thi, những tài nguyên này như là icon, images, menus, và các strings. Các Strings có thể được lưu trữ trong Section .rsrc hoặc trong chương trình chính, tuy nhiên chúng thường được lưu trữ trong Section .rsrc để hỗ trợ đa ngôn ngữ.

2016-01-12_094630

Kiểm tra tập tin PE với công cụ PEview

Định dạng của tập tin PE lưu trữ các thông tin quan trọng trong header của chúng. Chúng ta có thể sử dụng công cụ PEview để xem các thông tin này, như các thông tin thể hiện trong hình bên dưới. Trong hộp thoại bên dưới, cửa sổ bên trái tại mục (1) hiển thị các thành phần chính trong Header của tập tin PE. Mục (entry) IMAGE_FILE_HEADER được đánh dấu bởi vì nó đang được chọn. Hai phần đầu tiên trong Header của tập tin PE, IMAGE_DOS_HEADER và MS-DOS Stub Program là phần thuộc về quá khứ và không cung cấp thông tin nhiều gì cho chúng ta.

Section kế tiếp trong Header của tập tin PE, IMAGE_NT_HEADERS, cho thấy các Header NT. Phần chữ ký (Signatures) thì luôn luôn giống nhau và ta có thể bỏ qua. IMAGE_FILE_HEADER entry, được đánh dấu và hiển thị trong cửa sổ bên phải tại mục (2), chứa các thông tin cơ bản về tập tin này. Phần Time Date Stamp trong mục Description tại mục (3) cho chúng ta biết tập tin thực thi này được biên dịch khi nào, điều này có thể rất hữu dụng trong việc phân tích mã độc và ứng phó sự cố. Ví dụ, thời điểm biên dịch cũ gợi ý rằng đây là một kiểu tấn công cũ, và các chương trình antivirus có thể chứa các Signatures cho các malware. Thời điểm trình biên dịch mới thì lại cho thấy điều ngược lại.

z1

Điều này cho thấy rằng, thời gian biên dịch một chương trình là có một chút vấn đề. Tất cả các chương trình Delphi đều được biên dịch vào thời gian 19/06/1992. Nếu bạn nhìn vào thời điểm biên dịch đó, có lẽ bạn đang tìm kiếm thông tin biên dịch của một chương trình Delphi nào đó, và bạn sẽ không thực sự biết được chính xác nó được biên dịch khi nào. Ngoài ra, một người viết mã độc cao tay có thể dễ dàng làm giả thời điểm biên dịch. Nếu bạn nhìn vào thời điểm biên dịch mà cảm thấy “hơi sai sai”, điều này có nghĩa là nó đã bị giả mạo.

Section IMAGE_OPTIONAL_HEADER bao gồm một số thông tin quan trọng. Các mô tả của hệ thống con (Subsystems) chỉ ra cho dù đây là một cổng console hay là một giao diện đồ họa của chương trình. Các chương trình điều khiển kiểu console có giá trị IMAGE_SUBSYSTEM_WINDOWS_CUI và chạy bên trong một cửa sổ lệnh Windows. Các chương trình điều khiển kiểu GUI có giá trị IMAGE_ SUBSYSTEM_WINDOWS_GUI và chạy trong hệ thống Windows. Những hệ thống con ít phổ biến hơn như là Native hay Xbox cũng được sử dụng.

Các thông tin bổ ích nhất đến từ các Section Headers, trong đó là IMAGE_SECTION_HEADER, như trong hình bên dưới. Những Header này được sử dụng để mô tả từng Sections của một tập tin PE. Trình biên dịch thường tạo ra và đặt tên các Sections của một tập tin thực thi, và người dùng có ít cơ hội để kiểm soát các tên này. Kết quả là, các Sections thường thống nhất tên (xem hình minh họa Table 1-4), chính vì vậy bất kỳ sự sai lệch thông tin nào cũng là đáng nghi ngờ.

Ví dụ, trong hình minh họa 1-8 bên dưới, Virtual Size tại mục (1) cho chúng ta biết không gian lưu trữ cho một Section khi nạp lên là bao nhiêu. Mục Size of Raw Data tại mục (2) cho thấy một Section lớn như thế nào trên ổ đĩa cứng. Hai giá trị này thường được xem như nhau, bởi vì dữ liệu cần được sử dụng nhiều không gian đĩa như nó làm trong bộ nhớ. Những sự khác biệt nhỏ là bình thường, và đó là do sự khác nhau giữa các liên kết trong bộ nhớ và ổ cứng.

Kích thước của các Section có thể hữu dụng trong việc phát hiện ra các tập tin thực thi đã được đóng gói. Ví dụ, nếu Virtual Size lớn hơn nhiều so với Size of Raw Data, bạn biết rằng Section này chiếm không gian trong bộ nhớ nhiều hơn là trên ổ cứng. Điều này thường là sự biểu thị của các mã code được đóng gói, đặc biệt là Section .text trong bộ nhớ lớn hơn trên ổ cứng.

z1

Hình 1-5 cho thấy các Sections từ tập tin PotentialKeylogger.exe. Như bạn có thể thấy, các Section .text, .rdata, và .rsrc đều có giá trị Virtual Size và Size of Raw Data là như nhau. Section .data có vẻ đáng ngờ bởi vì nó có kích thước trong bộ Virtual Size lớn hơn trong Size of Raw Data là rất nhiều, tuy nhiên điều này là bình thường cho Section .data trong trong các chương trình của Windows. Tuy nhiên lưu ý rằng thông tin đơn lẻ này không thể nói cho chúng ta biết đó không phải là một phần mềm mã độc, nó chỉ đơn giản cho ta thấy nó rất có thể không bị đóng gói và Header của tập tin PE được tạo ra bởi một trình biên dịch.

2016-01-12_111258

Bảng Table 1-6 cho thấy các Sections từ tập tin PackedProgram.exe. Những Sections trong tập tin này có một số là bất thường. Các Sections tên Dijfpds, .sdfuok, và Kijijl là không ý nghĩa, và các Sections .text, .data, và .rdata là rất đáng nghi ngờ. Section .text có giá trị Size of Raw Data là 0, điều này có nghĩa nó không có chiếm không gian trên ổ cứng, và giá trị Virtual Size là A000, điều này có nghĩa là không gian lưu trữ được phân bổ cho các segments của Section .text. Điều này cho chúng ta biết được rằng người đóng gói sẽ giải nén code thực thi vào vùng lưu trữ của Section .text.