Bài 2: Executable File Format

Mục lục

  • Compiler, Linker và Loader
  • Định dạng ELF
  • Định dạng PE
  • Dead Space và Virus

1. Compiler, Linker và Loader

1.1 Tổng quan quy trình build

graph LR A[source1.c\nsource2.s\nsource3.cpp] -->|compiler| B[source1.o\nsource2.o\nsource3.o] B -->|linker| C[a.out] D[b.so] -->|linker| C C -->|loader| E[Process Memory] F[libc.so\nlibrt.so\nb.so] -->|loader| E

1.2 Compiler

Compiler chuyển đổi source code sang binary machine code (object code – mã máy nhị phân).

  • Đầu vào: file nguồn .c, .cpp, .s, …
  • Đầu ra: file object .o (chưa thể chạy trực tiếp)
  • Ví dụ compiler phổ biến: gcc, Clang, vc_compilerCTP.exe

1.3 Linker

Linker nhận các object fileslibrary files, rồi kết hợp chúng thành một executable file hoặc library file duy nhất.

  • Giải quyết các symbolic references (tham chiếu tên hàm, biến giữa các file object)
  • Ví dụ: GNU ld, lld, LINK.exe

1.4 Loader

Loader là một thành phần của hệ điều hành, chịu trách nhiệm nạp file thực thi và các thư viện vào bộ nhớ để khởi động một process mới.

Hai loại loader:

LoạiChức năngVí dụ
Executable loaderNạp file thực thiexecve (system call)
Dynamic linking loaderNạp thư viện độngld-linux.so

Các bước Loader thực hiện:

  1. Sao chép code (text section) và biến toàn cục (data section) từ file vào bộ nhớ
  2. Sao chép argumentsenvironment variables vào bộ nhớ
  3. Khởi tạo registers
  4. Nhảy đến điểm bắt đầu chương trình (_start function)
  5. Nạp dynamic libraries (map code của thư viện động vào bộ nhớ)

1.5 Tại sao cần định dạng file chuẩn?

Để compiler, linker và loader hoạt động đúng với nhau, chúng phải thống nhất về định dạng của object file, executable file và library file.

Các định dạng phổ biến:

Định dạngHệ điều hành
ELF (Executable and Linkable Format)Linux/Unix (*nix)
PE (Portable Executable)Windows
Mach-OmacOS (OS X)

2. Định dạng ELF

2.1 Tổng quan

ELF – Executable and Linkable Format là định dạng chuẩn trên các hệ thống *nix (Linux, BSD, …). ELF dùng cho:

  • Executables: file chương trình có thể chạy trực tiếp
  • Object files: đầu ra của compiler (.o)
  • Dynamic libraries / Shared libraries: thư viện dùng chung (.so)
  • Core dumps: snapshot bộ nhớ khi chương trình crash

2.2 Cấu trúc ELF

graph TD A[ELF Header] B[Program Header Table] C[Text Section .text] D[Data Sections .data .bss .rodata] E[Other Sections .dynamic .got .init ...] F[Relocation Information] G[Symbol Table] H[Debug Info] I[Section Header Table] A --> B --> C --> D --> E --> F --> G --> H --> I

Mô tả từng thành phần:

  • Thông tin nhận dạng cơ bản của file
  • Bao gồm: magic number (7f 45 4c 46), kiến trúc CPU, endianness, entry point address, vị trí của Program Header Table và Section Header Table
  • Công cụ xem: readelf -h <file>
  • Mô tả các segment (cách loader nạp file vào bộ nhớ)
  • Chứa vị trí (địa chỉ bộ nhớ) của các section .text, .data, …
  • Dùng ở runtime (loader đọc bảng này)
  • Mô tả vị trí và thông tin của từng section trong file
  • Dùng ở link time (linker đọc bảng này)
  • Công cụ xem: readelf -S <file>
  • Chứa machine code của chương trình
  • Thuộc tính: Readable + Executable (không ghi được trong điều kiện bình thường)
SectionNội dung
.dataBiến toàn cục đã khởi tạo (initialized global variables)
.bssBiến toàn cục chưa khởi tạo (uninitialized global variables)
.rodataDữ liệu read-only (hằng số, string literals)
SectionNội dung
.dynamicThông tin dynamic linking
.gotGlobal Offset Table – hỗ trợ dynamic linking
.initCode khởi tạo process (chạy trước main())
  • Thông tin để linker/loader điều chỉnh địa chỉ khi ghép các file object hoặc nạp vào bộ nhớ tại địa chỉ khác nhau
  • Chứa tên và địa chỉ của các symbolic definitions (hàm exported, biến toàn cục…)
  • Ví dụ: tên hàm main, printf, …
  • Không được copy vào bộ nhớ khi chạy
  • Thông tin phục vụ debug (mapping giữa machine code và source code)
  • Không được copy vào bộ nhớ khi chạy

2.3 ELF File → Process Memory

Không phải tất cả các section trong file ELF đều được nạp vào bộ nhớ:

graph LR subgraph ELF File T[.text] D[.data] I[.init] DY[.dynamic] SYM[Symbol Table] DBG[Debug Info] end subgraph Process Memory KM[Kernel Memory] STK[Stack] HP[Heap] DS[Data Section] TS[Text Section] end T --> TS D --> DS I --> DS DY --> DS SYM -.->|KHÔNG copy| KM DBG -.->|KHÔNG copy| KM

2.4 Section Flags – Cờ thuộc tính Section

Mỗi section có một tập flag bits xác định quyền truy cập:

FlagÝ nghĩa
A (Alloc)Section được cấp phát bộ nhớ khi chạy
X (Execute)Section chứa code có thể thực thi
W (Write)Section có thể ghi

2.5 Công cụ phân tích ELF

# Xem ELF Header
readelf -h <executable>

# Xem thông tin các section
readelf -S <executable>

# Disassemble (dịch ngược machine code sang assembly)
objdump -d <executable>

# Dump hex thô
hexdump -C <executable>

# Xác định loại file
file <executable>

Ví dụ output readelf -h:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 ...
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Entry point address:               0x8048330

3. Định dạng PE

3.1 Tổng quan

PE – Portable Executable là định dạng file thực thi chuẩn trên Windows.

  • PE32: dành cho code 32-bit
  • PE32+: dành cho code 64-bit
  • Các định dạng cũ hơn tồn tại cho 16-bit DOS và Windows 3.1

3.2 Cấu trúc PE

graph TD A[DOS Header] B[PE Header] C[Section Table] D[.text Section] E[.data Section] F[.rdata Section] G[.reloc Section] H[Other Sections] A --> B --> C --> D --> E --> F --> G --> H

Các section phổ biến trong PE:

SectionNội dung
.textMachine code (code thực thi)
.dataDữ liệu read/write (biến toàn cục)
.rdataDữ liệu read-only (hằng số, import table)
.relocRelocation data – dùng để xây dựng IAT (Import Address Table)

3.3 DOS Header

DOS Header là phần đầu của file PE, có từ thời DOS.

  • Nếu file PE được chạy trong DOS command prompt: chương trình nhỏ trong DOS Header sẽ được thực thi
  • Với hầu hết file PE32 hiện đại: DOS header chứa một đoạn code nhỏ chỉ in ra thông báo:
This application must be run from Windows

rồi thoát. Đây chỉ là thông báo tương thích ngược, không có chức năng thực sự.


4. Dead Space và Mối liên hệ với Virus

4.1 Dead Space là gì?

Dead space (không gian chết) là các vùng trống hoặc không sử dụng có mặt trong executable file.

Nguồn gốc của dead space:

  • Phần đầu file ELF (padding bytes)
  • Khoảng trống giữa các hàm (function padding)
  • Khoảng trống giữa các section (section padding)
  • Các lệnh NOP (no-operation) được chèn vào hàm để alignment
  • Linker thường align các section theo page boundary (4KB hoặc 4096 bytes) để đơn giản hóa công việc của loader → sinh ra nhiều padding

4.2 Tại sao cần hiểu PE format khi học malware?

Câu hỏi: Tại sao chúng ta quan tâm đến chi tiết của PE file format?

Trả lời:virus writer sẽ cố gắng lây nhiễm file PE theo cách khiến code của virus được thực thi, trong khi file PE trông vẫn bình thường từ bên ngoài. Nhiệm vụ của phần mềm diệt virus là phát hiện các virus được ngụy trang tinh vi này.

Dead space là nơi lý tưởng để giấu virus vì:

  • Nằm trong file hợp lệ
  • Không ảnh hưởng đến chức năng bình thường của chương trình
  • Khó phát hiện nếu không phân tích kỹ cấu trúc file

Câu hỏi & Đáp án Trắc Nghiệm

Câu 1. Thứ tự đúng của quá trình build một chương trình C là?

  • A. Linker → Compiler → Loader
  • B. Compiler → Loader → Linker
  • C. Compiler → Linker → Loader
  • D. Loader → Compiler → Linker

Câu 2. Compiler tạo ra loại file nào?

  • A. Executable file (.exe hoặc a.out)
  • B. Object file (.o)
  • C. Shared library (.so)
  • D. Script file

Câu 3. Nhiệm vụ chính của Linker là gì?

  • A. Chuyển source code sang machine code
  • B. Nạp file thực thi vào bộ nhớ
  • C. Kết hợp các object file và library file thành một file thực thi
  • D. Khởi tạo registers trước khi chạy chương trình

Câu 4. ld-linux.so là ví dụ của loại loader nào?

  • A. Executable loader
  • B. Dynamic linking loader
  • C. Static linker
  • D. Kernel loader

Câu 5. execve là ví dụ của?

  • A. Compiler
  • B. Linker
  • C. Executable loader (system call)
  • D. Dynamic library

Câu 6. Loader thực hiện bước nào SAU KHI khởi tạo registers?

  • A. Copy text section vào bộ nhớ
  • B. Copy arguments vào bộ nhớ
  • C. Nhảy đến hàm _start để bắt đầu thực thi
  • D. Load dynamic libraries

Câu 7. Định dạng ELF được dùng trên hệ điều hành nào?

  • A. Windows
  • B. macOS
  • C. Linux/Unix (*nix)
  • D. Android

Câu 8. ELF format được dùng cho loại file nào? (chọn tất cả đúng)

  • A. Executable files
  • B. Object files
  • C. Dynamic libraries
  • D. Core dumps
  • E. Tất cả các loại trên

Câu 9. Magic number của file ELF là gì?

  • A. FF FE
  • B. 4D 5A (MZ)
  • C. 7F 45 4C 46
  • D. CA FE BA BE

Câu 10. Section .bss trong ELF chứa gì?

  • A. Machine code
  • B. Biến toàn cục đã khởi tạo
  • C. Biến toàn cục chưa khởi tạo
  • D. Dữ liệu read-only

Câu 11. Section .rodata trong ELF chứa gì?

  • A. Code thực thi
  • B. Dữ liệu read-only (hằng số, string literals)
  • C. Biến toàn cục có thể ghi
  • D. Thông tin relocation

Câu 12. Section .data trong ELF chứa gì?

  • A. Code thực thi
  • B. Biến toàn cục đã được khởi tạo
  • C. Biến toàn cục chưa khởi tạo
  • D. Thông tin debug

Câu 13. Section .got trong ELF có chức năng gì?

  • A. Lưu machine code
  • B. Hỗ trợ dynamic linking thông qua Global Offset Table
  • C. Lưu thông tin debug
  • D. Chứa biến toàn cục chưa khởi tạo

Câu 14. Section .init trong ELF chứa gì?

  • A. Code khởi tạo process, chạy trước main()
  • B. Dữ liệu khởi tạo biến
  • C. Thông tin để linker khởi tạo symbol table
  • D. Code dọn dẹp khi process kết thúc

Câu 15. Khi nạp ELF vào bộ nhớ, section nào KHÔNG được copy?

  • A. .text
  • B. .data
  • C. Symbol table
  • D. .dynamic

Câu 16. Program Header Table trong ELF được đọc bởi ai?

  • A. Compiler
  • B. Linker
  • C. Loader
  • D. Assembler

Câu 17. Section Header Table trong ELF được đọc bởi ai?

  • A. Loader
  • B. Linker
  • C. CPU
  • D. OS kernel

Câu 18. Lệnh nào dùng để xem ELF header?

  • A. objdump -d <file>
  • B. readelf -h <file>
  • C. hexdump -C <file>
  • D. file <file>

Câu 19. Lệnh nào dùng để disassemble (dịch ngược) một file ELF?

  • A. readelf -h
  • B. hexdump -C
  • C. objdump -d
  • D. file

Câu 20. Flag AX trên một section ELF có nghĩa là gì?

  • A. Section chỉ có thể đọc
  • B. Section được cấp phát bộ nhớ và có thể thực thi
  • C. Section có thể ghi và thực thi
  • D. Section chứa thông tin archive

Câu 21. Virus có thể làm gì với flag bits của section ELF để lây nhiễm hiệu quả hơn?

  • A. Xóa toàn bộ flag bits
  • B. Sửa flag bits để biến section .text thành writable, từ đó ghi code độc hại vào
  • C. Thêm flag bits để tăng kích thước section
  • D. Copy flag bits sang section khác

Câu 22. Điều gì thực sự xác định quyền truy cập (read/write/execute) của một section ELF?

  • A. Tên của section (.text, .data, …)
  • B. Vị trí section trong file
  • C. Flag bits của section
  • D. Kích thước của section

Câu 23. PE format là định dạng file thực thi của hệ điều hành nào?

  • A. Linux
  • B. macOS
  • C. Windows
  • D. FreeBSD

Câu 24. PE32+ dùng cho loại code nào?

  • A. 16-bit
  • B. 32-bit
  • C. 64-bit
  • D. 128-bit

Câu 25. Magic number của file PE (Windows executable) là gì?

  • A. 7F 45 4C 46
  • B. 4D 5A (MZ)
  • C. CA FE BA BE
  • D. FF D8 FF

Câu 26. DOS Header trong file PE có chức năng gì khi chạy trên DOS?

  • A. Không làm gì cả
  • B. Thực thi một đoạn code nhỏ (thường in thông báo lỗi)
  • C. Load Windows kernel
  • D. Khởi tạo registry

Câu 27. Section .rdata trong PE chứa gì?

  • A. Code thực thi
  • B. Dữ liệu read/write
  • C. Dữ liệu read-only (hằng số, import table)
  • D. Relocation data

Câu 28. Section .reloc trong PE dùng để làm gì?

  • A. Lưu code thực thi
  • B. Chứa relocation data để xây dựng IAT (Import Address Table)
  • C. Lưu debug symbols
  • D. Chứa thông tin về version của file

Câu 29. Dead space trong executable file bao gồm những gì?

  • A. Chỉ khoảng trống giữa các section
  • B. Chỉ NOP instructions
  • C. Khoảng trống đầu file, giữa các hàm, giữa các section, NOP instructions, và padding do alignment
  • D. Chỉ padding do page alignment

Câu 30. Tại sao linker align các section theo page boundary?

  • A. Để giảm kích thước file
  • B. Để đơn giản hóa công việc của loader
  • C. Để tăng tốc độ compiler
  • D. Để tương thích với các hệ điều hành cũ

Câu 31. CIH virus (Chernobyl) sử dụng kỹ thuật nào để lây nhiễm và khó bị phát hiện?

  • A. Mã hóa toàn bộ file
  • B. Thêm section mới vào PE file
  • C. Chia nhỏ bản thân và giấu trong dead space giữa các PE section
  • D. Thay thế hoàn toàn file gốc

Câu 32. Tại sao dead space là vị trí lý tưởng để giấu virus?

  • A. Vì nó dễ dàng bị phát hiện
  • B. Vì nó nằm trong file hợp lệ, không ảnh hưởng chức năng bình thường, khó phát hiện
  • C. Vì nó luôn được thực thi khi chương trình chạy
  • D. Vì nó có nhiều không gian lưu trữ

Câu 33. Mach-O là định dạng file thực thi của hệ điều hành nào?

  • A. Linux
  • B. Windows
  • C. macOS (OS X)
  • D. Android

Câu 34. Trong ELF, PIC/PIE là gì và tại sao liên quan đến địa chỉ bộ nhớ?

  • A. PIC/PIE là loại virus đặc biệt
  • B. PIC (Position Independent Code) / PIE (Position Independent Executable) cho phép code chạy ở bất kỳ địa chỉ nào, thường kết hợp với ASLR
  • C. PIC/PIE là loại section đặc biệt trong ELF
  • D. PIC/PIE là công cụ phân tích ELF

Câu 35. ASLR có liên hệ gì đến địa chỉ của các section trong ELF?

  • A. ASLR cố định địa chỉ các section
  • B. ASLR ngẫu nhiên hóa địa chỉ bộ nhớ mỗi lần chạy, làm cho địa chỉ trong ELF không còn chính xác tuyệt đối
  • C. ASLR xóa section header table
  • D. ASLR mã hóa nội dung các section

Câu 36. Lệnh file <executable> có tác dụng gì?

  • A. Liệt kê các file trong thư mục
  • B. Xác định loại file (ELF, PE, script, …)
  • C. Hiển thị nội dung file dưới dạng hex
  • D. Disassemble file

Câu 37. Trong quá trình dynamic linking, thư viện (.so) được nạp vào bộ nhớ khi nào?

  • A. Khi compile
  • B. Khi link
  • C. Khi loader khởi động process
  • D. Thư viện không bao giờ nạp vào bộ nhớ

Câu 38. Điểm vào (entry point) của chương trình ELF thường là hàm gì?

  • A. main()
  • B. _start
  • C. init()
  • D. entry()

Câu 39. Symbol table trong ELF chứa thông tin gì?

  • A. Machine code của chương trình
  • B. Tên và địa chỉ của các symbolic definitions như tên hàm, biến toàn cục
  • C. Thông tin về dynamic libraries cần nạp
  • D. Dữ liệu runtime của chương trình

Câu 40. Core dump file trong ELF chứa gì?

  • A. Chỉ chứa source code
  • B. Snapshot của bộ nhớ process tại thời điểm crash
  • C. Log của toàn bộ quá trình thực thi
  • D. Thông tin về cấu hình hệ thống

Câu 41. Sự khác biệt chính giữa static linking và dynamic linking là gì?

  • A. Static linking nhanh hơn dynamic linking
  • B. Static linking nhúng toàn bộ thư viện vào executable; dynamic linking chỉ tham chiếu, thư viện nạp lúc runtime
  • C. Static linking chỉ dùng trên Linux; dynamic linking chỉ dùng trên Windows
  • D. Không có sự khác biệt

Câu 42. Trong phân tích malware, tại sao cần biết chi tiết về PE/ELF format?

  • A. Để viết phần mềm nhanh hơn
  • B. Vì virus lợi dụng cấu trúc file format để ẩn mình; hiểu format giúp phát hiện virus tinh vi
  • C. Để tối ưu hóa compiler
  • D. Để thiết kế CPU hiệu quả hơn

Câu 43. Khi nào địa chỉ của section trong ELF được cố định (không thay đổi giữa các lần chạy)?

  • A. Luôn luôn cố định
  • B. Khi không dùng PIC/PIE và ASLR bị tắt
  • C. Khi dùng ASLR
  • D. Khi dùng dynamic linking

Câu 44. Trong ELF, sự khác biệt giữa “section” và “segment” là gì?

  • A. Không có sự khác biệt
  • B. Section là góc nhìn của linker (link time); segment là góc nhìn của loader (runtime)
  • C. Section lớn hơn segment
  • D. Segment chỉ tồn tại trong PE, không có trong ELF

Câu 45. IAT (Import Address Table) trong PE dùng để làm gì?

  • A. Lưu danh sách các function exported của file PE
  • B. Lưu địa chỉ thực tế của các hàm được import từ DLL khi chạy
  • C. Quản lý bộ nhớ heap
  • D. Lưu thông tin debug

Câu 46. Lệnh readelf -S <file> hiển thị thông tin gì?

  • A. ELF header
  • B. Thông tin từng section (tên, địa chỉ, kích thước, flags)
  • C. Disassembly code
  • D. Dynamic linking dependencies

Câu 47. Kích thước của file PE bị nhiễm CIH virus so với file gốc như thế nào?

  • A. Lớn hơn đáng kể
  • B. Nhỏ hơn
  • C. Gần như không thay đổi
  • D. Gấp đôi

Câu 48. Trong ELF, entry point address trong ELF header chỉ đến đâu?

  • A. Hàm main()
  • B. Địa chỉ đầu tiên của section .text
  • C. Địa chỉ của hàm _start (điểm bắt đầu thực thi)
  • D. Địa chỉ của dynamic linker

Câu 49. Tại sao antivirus không thể chỉ dựa vào tên section để xác định quyền của nó?

  • A. Tên section quá dài
  • B. Vì virus có thể sửa flag bits mà không đổi tên section, quyền thực sự do flag bits quyết định
  • C. Vì ELF không có tên section
  • D. Vì tên section bị mã hóa

Câu 50. Bộ ba công cụ cơ bản để phân tích file ELF trên Linux là?

  • A. gcc, ld, execve
  • B. readelf, objdump, hexdump
  • C. vim, nano, gedit
  • D. ps, top, htop