Tools

Reverse Engineering (1/5): nền tảng — từ mã nguồn đến binary và assembly

Tóm tắt

Dịch ngược là biên dịch chạy ngược. Nắm quy trình biên dịch, bảng import, chuỗi ký tự, khoảng 30 lệnh assembly và quy ước gọi hàm là đủ để bắt đầu đọc binary.

Bạn nhận một file thực thi không có mã nguồn: thư viện của bên thứ ba bị lỗi, một thiết bị cũ không có tài liệu, hay một mẫu nghi là mã độc. Muốn hiểu nó, bạn phải đi ngược quá trình biên dịch. Đây là bài 1 trong loạt 5 bài Reverse Engineering cho lập trình viên: nền tảng để đọc được binary — quy trình biên dịch, định dạng file, assembly tối thiểu và quy ước gọi hàm.

Biên dịch xoá mất gì?

Dịch ngược thực chất là biên dịch chạy ngược. Mỗi bước biên dịch xoá một lớp thông tin mà sau này bạn phải tự dựng lại:

  1. Tiền xử lý (gcc -E): macro và #include được mở rộng — tên macro biến mất.
  2. Biên dịch (gcc -S): C thành assembly — mất tên biến, kiểu dữ liệu, cấu trúc vòng lặp; chỉ còn thanh ghi và offset trên stack.
  3. Hợp dịch (as): assembly thành object file kèm relocation.
  4. Liên kết (ld): ghép object và thư viện. Liên kết tĩnh kéo theo hàng nghìn hàm thư viện bạn phải học cách bỏ qua.

Thử ngay với một chương trình nhỏ và so sánh mức tối ưu:

gcc -O0 -g -o hello_O0 hello.c
gcc -O2 -s -o hello_O2 hello.c      # -s: xoá symbol
objdump -d -M intel hello_O0 | less

Ở -O2, hàm bị inline, vòng lặp bị unroll, biến chỉ sống trong thanh ghi. Khoảng cách giữa hai bản này chính là thứ khiến binary thực tế khó đọc.

Định dạng file thực thi

Định dạngNền tảngCấu trúc đáng chú ýCông cụ xem
ELFLinux, Android, thiết bị nhúngSegment, section .text/.rodata, .plt/.gotreadelf -a, objdump, nm
PE / PE32+WindowsBảng Import (IAT), bảng Export, sectionPE-bear, CFF Explorer, dumpbin
Mach-OmacOS, iOSLoad command, segment __TEXT/__DATA, chữ ký codeotool -l, nm

Hai "bản đồ" đầu tiên trước khi đọc lệnh nào: bảng import (binary gọi connect, CryptEncrypt đã kể một câu chuyện) và chuỗi ký tự (strings -n 8 file): thông báo lỗi, URL, format string chỉ thẳng tới hàm đáng chú ý.

Assembly tối thiểu cần biết

Không cần thuộc tài liệu Intel. Khoảng ba chục lệnh đã đủ đọc phần lớn code do trình biên dịch sinh ra:

  • Dữ liệu: mov, lea, push, pop, movzx, movsx
  • Tính toán: add, sub, imul, xor, and, or, shl, shr, sar
  • Điều khiển: cmp, test, jmp, je/jne, jl/jg (có dấu), jb/ja (không dấu), call, ret

Mẫu cần nhận ra ngay: xor eax, eax là gán 0; lea rax, [rbx+rbx*4] thường là nhân 5 chứ không phải đọc bộ nhớ; nhảy có dấu hay không dấu tiết lộ kiểu gốc của biến.

Quy ước gọi hàm

Quy ướcNền tảngTham số nguyênTrả về
System V AMD64Linux, macOS x86-64rdi, rsi, rdx, rcx, r8, r9rax
Microsoft x64Windows x86-64rcx, rdx, r8, r9 + 32 byte shadow spacerax
AAPCS64ARM64 (Android, Apple Silicon)x0–x7x0

Nhận diện cấu trúc C trong assembly

  • if/else: cmp + nhảy có điều kiện bỏ qua một khối.
  • for/while: lệnh nhảy ngược về nhãn phía trên.
  • switch: kiểm tra biên rồi jmp [table + rax*8] (bảng nhảy).
  • struct: cùng thanh ghi cơ sở với offset cố định [rdi+0x8], [rdi+0x10].
  • hàm ảo C++: mov rax, [rdi] (lấy vtable) rồi call [rax+0x18].

Lưu ý

  • Pháp lý: chỉ phân tích phần mềm bạn sở hữu, được phép kiểm thử, hoặc phát hành để luyện tập (crackme, CTF). Chỉ thị EU 2009/24/EC (Điều 6) và DMCA §1201(f) cho phép dịch ngược vì mục đích tương thích, nhưng EULA và luật địa phương vẫn áp dụng.
  • Lab riêng: dùng máy ảo Linux có snapshot; không chạy mẫu lạ trên máy làm việc.

Áp dụng thế nào?

  • Dev: viết 5 hàm C nhỏ (if, loop, switch, struct, virtual), dán vào Compiler Explorer, so sánh -O0 và -O2 cho tới khi đoán được assembly trước khi nhìn.
  • Tech Lead: đưa "đọc crash dump/disassembly" vào kỹ năng debug của team — nhiều lỗi production chỉ lộ ra ở mức binary.
  • PM: khi tích hợp thiết bị/hệ thống cũ không có tài liệu, dịch ngược định dạng là phương án hợp lệ; tính thời gian và rà soát pháp lý vào kế hoạch.

Nguồn & tham khảo

  1. Reverse Engineering for Beginners — Dennis Yurichev
  2. Compiler Explorer — Matt Godbolt
  3. ELF specification (Tool Interface Standard) — Linux Foundation Refspecs
  4. PE Format — Microsoft Learn
  5. x64 calling convention — Microsoft Learn
  6. Directive 2009/24/EC on the legal protection of computer programs — EUR-Lex
  7. 17 U.S. Code § 1201 — Cornell LII