Reverse Engineering (2/5): phân tích tĩnh với Ghidra, IDA, Binary Ninja
Tóm tắt
Phân tích tĩnh không phải đọc hết mọi hàm mà là tìm điểm neo qua strings/xref rồi đổi tên, gán kiểu lặp lại. Ghidra miễn phí là lựa chọn mặc định để bắt đầu.
Mở một binary trong decompiler lần đầu, bạn sẽ thấy hàng nghìn hàm tên FUN_00401a30 và biến local_28. Đọc hết là không thể. Bài 2 trong loạt Reverse Engineering cho lập trình viên nói về phân tích tĩnh — hiểu chương trình mà không chạy nó: chọn công cụ, quy trình 15 phút đầu, và cách biến output decompiler thành thứ đọc như mã nguồn thật.
Chọn công cụ
| Công cụ | Chi phí | Điểm mạnh | Hợp với |
|---|---|---|---|
| Ghidra (NSA) | Miễn phí, mã nguồn mở | Decompiler tốt, nhiều kiến trúc, script Java/Python | Lựa chọn mặc định cho người học và team |
| IDA Pro / IDA Free | Thương mại; bản Free giới hạn | Chuẩn công nghiệp, chữ ký thư viện FLIRT, nhiều plugin | Phân tích mã độc, lỗ hổng chuyên nghiệp |
| Binary Ninja | Thương mại | Các tầng IL rõ ràng, Python API mạnh | Tự động hoá, phân tích tuỳ biến |
| radare2 / Rizin / Cutter | Miễn phí | CLI script được, chạy mọi nơi | Phân loại nhanh trên server |
Chọn một công cụ và đào sâu; khái niệm dùng lại được giữa các công cụ.
Quy trình 15 phút đầu
- Nhận diện:
file,checksec, Detect It Easy — kiến trúc, trình biên dịch, packer, cơ chế bảo vệ (PIE, NX, canary, RELRO). - Strings và imports: đánh dấu URL, tên thuật toán mã hoá, thông báo lỗi, khoá registry.
- Tìm điểm neo: từ
main(trên Linux là tham số đầu của__libc_start_main) hoặc từ xref tới một chuỗi/hàm import đáng chú ý, ví dụ chuỗi "invalid license". - Mở rộng dần: đi theo hàm gọi và hàm được gọi; bỏ qua code thư viện.
Biến decompiler thành mã đọc được
Công việc thật sự là đổi tên và gán kiểu lặp đi lặp lại:
- Đổi tên ngay khi có phỏng đoán (phím
Ltrong Ghidra,Ntrong IDA). Tên sai sửa sau vẫn tốt hơn không tên. - Đặt chữ ký hàm: khi
param_1được gán kiểuConfig *, kiểu lan sang mọi nơi gọi hàm. - Tạo struct: thấy
*(int *)(param_1 + 0x18)lặp lại → chuột phải, Auto Create Structure, đặt tên từng trường. - Áp chữ ký thư viện: FLIRT (IDA), Function ID (Ghidra) nhận diện libc, OpenSSL, zlib liên kết tĩnh — loại bỏ rất nhiều hàm khỏi tầm nhìn.
- Nhận diện mã hoá qua hằng số:
0x67452301(MD5/SHA-1),0x6A09E667(SHA-256), S-box AES bắt đầu63 7C 77 7B. - Ghi chú và bookmark mọi phát hiện; đây là một cuộc điều tra dài.
Lưu ý theo ngôn ngữ
- C++: tìm RTTI và vtable để khôi phục cây kế thừa; giải tên bằng
c++filt. - Go: binary vẫn giữ bảng
pclntabchứa tên hàm kể cả khi đã strip. - Rust: inline nhiều, tên mangled dài; chuỗi panic lộ đường dẫn file nguồn.
- .NET / Java: là bytecode — dùng ILSpy/dnSpyEx hoặc jadx/CFR để nhận mã gần như gốc.
Tự động hoá
Ghidra có chế độ headless để phân tích hàng loạt binary bằng script:
$GHIDRA_HOME/support/analyzeHeadless /tmp/proj MyProj \
-import ./target.bin -postScript MyScript.py
Rủi ro và lưu ý
- Decompiler có thể sai: output là phỏng đoán; khi nghi ngờ hãy kiểm tra lại assembly hoặc xác nhận bằng phân tích động (bài 3).
- Đừng sa đà: đặt câu hỏi cụ thể trước ("key được tạo ở đâu?") để không đọc lan man code không liên quan.
- Phạm vi pháp lý: chỉ phân tích phần mềm bạn có quyền.
Áp dụng thế nào?
- Dev: tải một crackme dễ trên crackmes.one, mở bằng Ghidra, tìm hàm kiểm tra mật khẩu, đổi tên mọi biến và viết ra input đúng — không chạy chương trình.
- Tech Lead: dùng Ghidra để kiểm tra thư viện closed-source trước khi đưa vào sản phẩm: nó gọi mạng không, có hardcode gì không.
- PM: Ghidra miễn phí giúp team bắt đầu mà không tốn license; chỉ mua IDA/Binary Ninja khi khối lượng công việc thực sự cần.
Nguồn & tham khảo
- Ghidra Software Reverse Engineering Framework — NSA
- NationalSecurityAgency/ghidra — GitHub
- crackmes.one — crackmes.one
- Reverse Engineering for Beginners — Dennis Yurichev