Xin chào mọi người, lần đầu tiên mình viết blog trên VNPT Cyber Immunity, lúc đầu nhận làm thì nghĩ cũng dễ thôi mà, mình vốn cũng là người hay viết lách. Nhưng khi bắt tay vào làm thì lại cảm thấy bí ý tưởng ☹ . Cả tuần phân vân mà không biết nên chọn chủ đề gì. Mình đã thử vài chủ đề nhưng cảm thấy chưa được ưng ý lắm, deadline dí tới mông rồi may mà nghĩ ra được chủ đề mình thấy khá thú vị mà phù hợp với phong cách của mình 😀

Mình dự định sẽ làm một loạt bài khám phá về format của các loại file cả trên Windows, linux hay mobile. Cố gắng mỗi loại file sẽ làm 1 bài lý thuyết và một bài thực hành (code C++, python, hoặc ngôn ngữ gì đó tùy hứng 😀). Với kế hoạch như vậy thì  có thể seri này có thể lên tới chục hoặc vài chục bài, miễn là ae còn ủng hộ thì mình sẽ còn nghiên cứu và viết lách.

Nào, cùng bắt tay vào bài đầu tiên nhé!

Mình chọn bài đầu tiên sẽ viết về common object file format (COFF) vì mình thấy ít có tài liệu và ít người quan tâm tới định dạng file này, có lẽ là mọi người dung nhiều quá mà không để ý. Bắt đầu bằng một cái gì đó lạ, chắc là sẽ gây được chút ấn tượng 😅

COFF

Viết tắt của Common Object File Format, được sử dụng để lưu trữ các code đã được biên dịch. Ví dụ như output của các trình compiler hay linker.

Nếu là dân dev C, C++ thì bạn có thể dễ dàng tìm thấy các file với định dạng COFF này: nó là các lib trong windows sdk hay thư viện khác.COFF file cũng được sinh ra khi ta buid các code trong visual studio, gcc, g++, …

File COFF có thể chứa code của các hàm (code này đã được biên dịch sang mã máy nhé), các symbol, một phần hay toàn bộ code của một thư viện hoặc 1 file thực thi.

Thoạt nhìn cấu trúc COFF có nhiều nét tương đồng với PE file (Microsoft’s Portable Executable – một định dạng file rất phổ biến mà chúng ta sẽ phân tích nó ở bài nào đó sau này). Tuy nhiên COFF được đánh giá là phức tạp hơn. COFF trong nhiều trường hợp được thay thế bằng ELF và một số định dạng file thực thi khác.

Bắt đầu bằng một thứ cổ điển như COFF thì sau này chúng ta  mở rộng ra một số định dạng khác sẽ dễ hơn rất nhiều 😋

COFF file structure

 

Structure

Chức năng Vị trí

Kích thước

File header Lưu trữ các thông tin cơ bản về file và các con trỏ đến các bảng cấu trúc khác Nằm ở đầu file 20 byte
Optional Header Lưu trữ thông tin bổ sung về việc thực thi file Cấu trúc này có thể có hoặc không có trong file tùy thuộc vào thông tin trong file header. Nếu có, nó sẽ nằm ngay sau File header 0 hoặc 28 byte
Section header Lưu trữ thông tin về các section trong file Nằm ngay tiếp sau Optional header Có 2 version của COFF: COFF1 kích thước section header 40 byte, COFF2 là 48 byte. Như vậy khối section header có tổng kích thước là số section * kích thước section.
Section Relocation table Cung cấp thông tin về những địa chỉ cần thay đổi giúp tệp có thể load ở bất kỳ vùng nhớ nào. Nằm sau khối các section header. Hầu như mỗi section đều có một relocation table tương ứng, địa chỉ được trỏ đến bởi 1 trường trong section header Địa chỉ và số lượng entries được lấy từ thông tin section header tương ứng. Kích thước 1 relo entry là 10 bytes.

Tổng kích thước = Số lượng entries * 10

Section Line Number table Cung cấp thông tin debug: ánh xạ code này ở dòng nào trong file mã nguồn (.c, .cpp). Được trỏ tới từ thông tin trong section header Kích thước 1 items là 6 byte, do đó kích thước table = Số items * 6
symbol table Lưu trữ thông tin về các symbol được define hoặc định nghĩa trong code Được trỏ đến từ file header Kích thước 1 entry là 18 byte. Kích thước table = số entries * 18
String table Lưu trữ tên section hoặc tên symbol mà dài hơn 8 ký tự Được trỏ đến từ symbol table hoặc section header 4 byte đầu tiên là kích thước của string table , tiếp đó là nội dung các string phân cách bằng. Do đó kích thước này không cố định và >= 4

 

Mục đích của chúng ta là tìm hiểu để code được một chương trình view được cấu trúc của một file COFF bất kỳ, do đó cần tiếp tục đi sâu vào chi tiết các table.

File header

 

Vị trí

Kiểu dữ liệu

Ý nghĩa

0-1 Unsigned short magic number, COFF có 2 version nên sẽ có một số giá trị magic number khác nhau. Trong giới hạn code tool thì mình muốn đọc các file Microsoft COFF nên sẽ sử dụng version 1.
2-3 Unsigned short Số lượng section
4-7 long Time và date stamp, thời điểm mà file được tạo
8-11 long File pointer đến Symbol table
12-15 long số lượng entries trong symbol table
16-17 unsigned short kích thước optional header, chỉ có 2 giá trị là 0 hoặc 28. Nếu là 0 thì không có optional header.
18-19 unsigned short cờ, có rất nhiều thông tin của tệp được thể hiện trong đây, nhưng mình thực sự cũng chưa hiểu hết, có lẽ khi code tool chúng ta sẽ cố gắng tìm thể hiện thêm cái này.

 

Optional File Header

Chỉ những file COFF có khả năng thực thi mới có optional header vì những thông tin trong này chủ yếu là phục vụ cho runtime.

 

Vị trí

Kiểu dữ liệu

Ý nghĩa

0-1 unsigned short magic number
2-3 unsigned short version stamp
4-7 unsigned long kích thước của section code
8-11 unsigned long kích thước dữ liệu đã được khởi tạo
12-15 unsigned long kích thước dữ liệu chưa được khởi tạo
16-19 unsigned long Entry point – vị trí bắt đầu thực thi
20-23 unsigned long Địa chỉ bắt đầu của code thực thi
24-27 unsigned long Địa chỉ bắt đầu của dữ liệu đã được khởi tạo

 

Section Header

 

Vị trí

Kiểu dữ liệu

Ý nghĩa

0-7 char[] Tên section. Nếu tên section < 8 ký tự, thì sẽ nằm luôn trọng trương này. Nếu không, trường này sẽ chứa con trỏ tới string table nơi chứa tên section
8-11 long section physical address
12-15 long section virtual address
16-19 long kích thước section
20-23 long Con trỏ tới section data
24-27 long Con trỏ tới relocation table của section
28-31 long Con trỏ tới line number table của section
32-33 unsigned short số relocation entries
34-35 unsigned short Số line number entries
36-39 long cờ

 

Ở đây có 2 trường Address là physical và virtual: physical là địa chỉ khi file nằm trên ổ cứng vật lý, virtual là địa chỉ khi file nằm trên không gian nhớ ảo, có thể hiểu và hình dung khi file được load lên ram. Với COFF file thì thường 2 trường này có giá trị giống nhau. Sau này với PE file thì nó sẽ khác nhau.

Relocation Entries

Relocation có ý nghĩa gì?

Khi trình biên dịch biến mã nguồn thành mã máy thì thường code sẽ nằm ở 1 section và các biến sẽ nằm ở 1 section khác, toàn bộ việc sử dụng biến sẽ quy về thao tác với các địa chỉ vùng nhớ. Lúc này khi load các section này lên thì việc tham chiếu đến các vùng nhớ này sẽ bị thay đổi và không thể chắc chắn rằng vùng nhớ cần thao tác sẽ có địa chỉ bao nhiêu.

bảng Relocation sẽ đánh dấu những vị trí nhạy cảm đó trong code để khi trình loader load các section lên vùng nhớ nào, nó sẽ đi fix lại các vị trí được đánh dấu đó phù hợp với vùng nhớ tương ứng. Như vậy file hay các section có thể được load một cách rất linh động và thoải mái, loader sẽ dùng bảng relocation để đi tinh chỉnh lại địa chỉ để mọi thứ chạy được.

 

Vị trí

Kiểu dữ liệu

Ý nghĩa

0-3 long physical address tham chiếu
4-7 long Tham chiếu đến symbol table index
8-9 unsigned short phần này khá phức tạp, nó cho biết cách mà địa chỉ này được cập nhật

 

Line Number Entries

Ý nghĩa có lẽ mình đã mô tả ở phần đầu, chứa thông tin dòng code trong file mã nguồn gốc.

 

Vị trí

Kiểu dữ liệu

Ý nghĩa

0-3 long symbol index hoặc physical address
4-5 unsigned short dòng bao nhiêu

 

Symbol Table

 

 

Vị trí Kiểu dữ liệu Ý nghĩa
0-7 char[] Nếu symbol name < 8 ký tự, nó sẽ nằm luôn ở đây. Ngược lại, vị trí này sẽ là con trỏ đến string table chứa symbol name.
8-11 long Giá trị của symbol
12-13 short section number
14-15 unsigned short Loại symbol
16 char storage class
17 char auxiliary class

 

Chi tiết rõ hơn về symbol table mình sẽ trình bày thêm khi demo tool 😀

Như vậy là chúng ta đã cấu trúc hóa các thành phần quan trọng nhất của COFF file. Lý thuyết thì mình cũng tham khảo từ 3 nguồn:

  1. https://wiki.osdev.org/COFF
  2. https://www.ti.com/lit/an/spraao8/spraao8.pdf?ts=1653923070006&ref_url=https%253A%252F%252Fwww.google.com%252F#:~:text=COFF%20is%20an%20implementation%20of,segments%20and%20target%20system%20memory.
  3. https://docs.microsoft.com/en-us/windows/win32/debug/pe-format

Nếu lý thuyết suông thì chắc mình cũng chỉ là người Việt hóa và phân tích tài liệu thôi, do đó bài thực hành sẽ là điều mình muốn làm và hy vọng sẽ có ích cho cộng đồng.

Cảm ơn mọi người đã đọc và hẹn gặp lại ở bài tiếp theo.

 

1.050 lượt xem