Reverse engineering là gì?
Reverse engineering (dịch ngược) là quá trình phân tích một chương trình đã được biên dịch, đóng gói hoặc triển khai để hiểu cách nó hoạt động bên trong. Thay vì đi theo chiều thuận từ mã nguồn (source code) đến chương trình thực thi (executable program), reverse engineering đi theo chiều ngược lại, từ tệp nhị phân (binary file), hành vi chạy thực tế hoặc dữ liệu bộ nhớ để suy luận ra cấu trúc, thuật toán, luồng xử lý và ý đồ thiết kế của chương trình.
Trong phát triển phần mềm thông thường, lập trình viên viết mã nguồn bằng các ngôn ngữ như C, C++, C#, Java hoặc Go. Sau đó, mã nguồn được biên dịch hoặc thông dịch để trở thành chương trình có thể chạy trên hệ điều hành. Với các chương trình C và C++ trên Windows, kết quả cuối cùng thường là tệp .exe hoặc .dll. Người dùng bình thường chỉ nhìn thấy tệp thực thi này, còn reverse engineer (kỹ sư dịch ngược) sẽ phân tích tệp đó để hiểu bên trong chương trình có gì.
Reverse engineering không đồng nghĩa với bẻ khóa phần mềm (software cracking) hay tấn công hệ thống. Trong môi trường hợp pháp, nó là một kỹ năng quan trọng trong phân tích mã độc (malware analysis), điều tra số (digital forensics), kiểm thử bảo mật phần mềm (software security assessment), phát hiện lỗ hổng (vulnerability research), khôi phục hệ thống cũ không còn mã nguồn, đánh giá rủi ro chuỗi cung ứng phần mềm và hiểu cách hoạt động của các phần mềm đóng.
Để hiểu reverse engineering, trước hết cần hiểu chương trình được tạo ra như thế nào. Xét một ví dụ đơn giản bằng ngôn ngữ C trên Windows.
#include <stdio.h>
int add(int a, int b) {
int result = a + b;
return result;
}
int main() {
int x = 10;
int y = 20;
int z = add(x, y);
printf("Result = %d\n", z);
return 0;
}Đây là một chương trình rất đơn giản. Hàm add nhận hai số nguyên, cộng chúng lại và trả về kết quả. Hàm main tạo hai biến x và y, gọi hàm add, sau đó in kết quả ra màn hình bằng hàm printf.
Khi lập trình viên biên dịch chương trình này trên Windows, ví dụ bằng Microsoft Visual C Compiler (MSVC compiler), có thể dùng lệnh:
cl /Od /Zi hello.c /Fe:hello.exeTrong đó, cl là trình biên dịch C/C++ của Microsoft, /Od yêu cầu tắt tối ưu hóa để mã máy dễ quan sát hơn, /Zi tạo thông tin debug để phục vụ gỡ lỗi, hello.c là tệp mã nguồn đầu vào và hello.exe là tệp thực thi đầu ra.
Quá trình tạo chương trình thường đi qua các bước chính sau:
Bước 1. Tiền xử lý (preprocessing)
Ở bước này, trình tiền xử lý xử lý các chỉ thị như #include, #define, #ifdef. Dòng #include <stdio.h> làm cho các khai báo liên quan đến thư viện nhập xuất chuẩn được đưa vào chương trình. Sau bước này, mã nguồn ban đầu được mở rộng thành một dạng mã lớn hơn, có đầy đủ khai báo cần thiết cho quá trình biên dịch.
Bước 2. Biên dịch (compilation)
Trình biên dịch chuyển mã C thành mã cấp thấp hơn, có thể là mã trung gian (intermediate representation) hoặc mã hợp ngữ (assembly code). Ở mức này, các câu lệnh C như a + b, gọi hàm add, gọi printf sẽ được chuyển thành các lệnh gần với kiến trúc CPU hơn.
Ví dụ, hàm add ở mức C là:
int add(int a, int b) {
int result = a + b;
return result;
}Khi chuyển xuống hợp ngữ x64 theo quy ước gọi hàm trên Windows, hai tham số đầu tiên thường được truyền qua thanh ghi RCX và RDX. Nếu là số nguyên 32 bit, phần thấp tương ứng là ECX và EDX. Hàm add có thể được biểu diễn gần như sau:
add:
mov eax, ecx
add eax, edx
retĐoạn hợp ngữ này có thể hiểu như sau. Lệnh mov eax, ecx đưa tham số thứ nhất vào thanh ghi EAX. Lệnh add eax, edx cộng tham số thứ hai vào EAX. Theo quy ước, EAX là nơi chứa giá trị trả về của hàm kiểu int. Lệnh ret trả quyền điều khiển về hàm gọi.
Bước 3. Hợp dịch (assembly)
Trình hợp dịch (assembler) chuyển mã hợp ngữ thành mã máy (machine code). Mã máy là dãy byte mà CPU có thể thực thi trực tiếp. Ví dụ, một lệnh hợp ngữ như add eax, edx sẽ được mã hóa thành một hoặc một vài byte cụ thể trong tệp nhị phân.
Bước 4. Liên kết (linking)
Sau khi biên dịch, chương trình thường tạo ra tệp đối tượng (object file) như .obj. Trình liên kết (linker) sẽ kết hợp tệp .obj với thư viện runtime, thư viện hệ thống và các thành phần cần thiết để tạo ra tệp .exe hoàn chỉnh.
Trên Windows, tệp .exe thường có định dạng PE (Portable Executable). Một tệp PE có nhiều vùng quan trọng, ví dụ .text chứa mã máy, .rdata chứa dữ liệu chỉ đọc như chuỗi ký tự, .data chứa dữ liệu toàn cục có thể thay đổi, import table chứa danh sách các hàm được nhập từ thư viện ngoài như kernel32.dll hoặc msvcrt.dll.
Nhìn từ chiều thuận, lập trình viên viết mã C, biên dịch và tạo ra hello.exe. Nhìn từ chiều ngược, reverse engineer mở hello.exe, đọc cấu trúc PE, quan sát mã máy trong vùng .text, tìm chuỗi Result = %d trong vùng .rdata, xem chương trình gọi printf và từ đó suy luận lại logic ban đầu.
Reverse engineering thực chất nhìn thấy gì?
Khi không có mã nguồn, người phân tích không nhìn thấy tên biến x, y, z một cách rõ ràng như trong mã C. Họ có thể chỉ thấy thanh ghi, địa chỉ bộ nhớ, lệnh nhảy, lời gọi hàm và dữ liệu dạng byte. Ví dụ, thay vì thấy:
int z = add(x, y);Người phân tích có thể thấy một chuỗi lệnh kiểu:
mov edx, 20
mov ecx, 10
call addTừ đó có thể suy luận chương trình đang truyền hai giá trị 10 và 20 vào một hàm, sau đó nhận kết quả trả về. Nếu tiếp tục thấy kết quả đó được truyền vào printf cùng chuỗi Result = %d, người phân tích có thể khôi phục ý nghĩa logic của đoạn chương trình.
Điểm quan trọng là reverse engineering hiếm khi khôi phục lại được mã nguồn gốc một cách hoàn hảo. Nó thường tạo ra một bản hiểu gần đúng. Tên biến, comment, cấu trúc ban đầu, phong cách lập trình và nhiều thông tin ngữ nghĩa có thể đã mất sau khi biên dịch. Công việc của người phân tích là kết hợp nhiều dấu hiệu để tái dựng lại ý nghĩa chương trình.
Các công cụ dịch ngược
Công cụ dịch ngược không chỉ có một loại. Mỗi nhóm công cụ nhìn chương trình từ một góc khác nhau.
Disassembler (trình rã hợp ngữ)
Disassembler là công cụ chuyển mã máy thành mã hợp ngữ. Nó không tạo lại mã C gốc, mà chỉ giúp con người đọc được các lệnh CPU.
Ví dụ, một đoạn byte trong tệp binary có thể được disassembler chuyển thành:
mov eax, ecx
add eax, edx
retCác công cụ thường gặp trong nhóm này gồm IDA, Ghidra, Binary Ninja, radare2 và objdump. Disassembler rất quan trọng vì mã máy là dạng gần nhất với những gì CPU thực sự chạy.
Decompiler (trình dịch ngược cấp cao)
Decompiler cố gắng chuyển mã máy hoặc mã trung gian thành mã giả gần giống C. Ví dụ, từ hợp ngữ:
mov eax, ecx
add eax, edx
retDecompiler có thể suy luận thành:
int function(int param1, int param2) {
return param1 + param2;
}Kết quả này dễ đọc hơn assembly, nhưng không nên xem là mã nguồn thật. Tên hàm, tên biến và kiểu dữ liệu có thể bị đoán sai. Người phân tích vẫn phải kiểm tra lại bằng assembly, hành vi runtime và ngữ cảnh chương trình.
Ghidra, IDA Pro, Binary Ninja và RetDec là các ví dụ về công cụ có khả năng decompile.
Debugger (trình gỡ lỗi)
Debugger cho phép chạy chương trình từng bước, đặt breakpoint (điểm dừng), xem thanh ghi, bộ nhớ, stack, tham số hàm và luồng thực thi thực tế. Nếu disassembler giúp đọc chương trình khi nó đứng yên, debugger giúp quan sát chương trình khi nó đang chạy.
Ví dụ, khi đặt breakpoint tại hàm add, người phân tích có thể thấy ECX đang chứa 10, EDX đang chứa 20, sau khi chạy lệnh add eax, edx thì EAX chứa 30. Điều này xác nhận suy luận rằng hàm này thực hiện phép cộng.
Trên Windows, các debugger phổ biến gồm x64dbg, WinDbg và Visual Studio Debugger.
Hex editor (trình soạn thảo byte)
Hex editor cho phép xem và chỉnh sửa trực tiếp nội dung byte của tệp. Công cụ này thường dùng để kiểm tra magic number, header, chuỗi ký tự, vùng dữ liệu hoặc các byte bất thường trong binary.
Ví dụ, một tệp PE trên Windows thường bắt đầu bằng hai byte MZ. Ở phần sau của tệp có chữ PE thể hiện định dạng Portable Executable. Khi mở bằng hex editor, người phân tích có thể xác nhận tệp có đúng là PE hay không.
PE analyzer (công cụ phân tích PE)
PE analyzer giúp đọc cấu trúc tệp .exe hoặc .dll trên Windows. Nó cho biết chương trình có những section nào, import những thư viện nào, export những hàm nào, entry point ở đâu, có dấu hiệu bị pack hay không.
Ví dụ, nếu một chương trình import CreateFileW, WriteFile, RegSetValueExW và InternetOpenW, người phân tích có thể đặt giả thuyết rằng chương trình có thao tác với tệp, registry và mạng. Đây mới chỉ là giả thuyết ban đầu, cần được kiểm chứng bằng phân tích sâu hơn.
Các công cụ thường dùng gồm PEStudio, CFF Explorer, Detect It Easy và dumpbin.
Strings tool (công cụ trích chuỗi)
Công cụ strings tìm các chuỗi ký tự có thể đọc được trong binary. Trong ví dụ hello.exe, người phân tích có thể thấy chuỗi:
Result = %dTừ chuỗi này, có thể suy luận chương trình có thao tác in kết quả ra màn hình. Trong phân tích thực tế, chuỗi ký tự có thể tiết lộ đường dẫn tệp, thông báo lỗi, tên miền, khóa cấu hình, tên hàm hoặc thông tin phiên bản.
Công cụ quan sát hành vi
Bên cạnh phân tích tĩnh (static analysis), reverse engineering còn dùng phân tích động (dynamic analysis). Các công cụ như Process Monitor, Process Explorer, Wireshark, API Monitor hoặc sandbox nội bộ giúp quan sát chương trình khi chạy. Người phân tích có thể xem chương trình tạo tệp nào, kết nối mạng tới đâu, gọi API nào, tạo process con nào và thay đổi registry ra sao.
Lợi ích và ứng dụng của reverse engineering
Reverse engineering có nhiều ứng dụng hợp pháp và quan trọng.
Thứ nhất, nó phục vụ phân tích mã độc. Khi một mẫu mã độc được phát hiện, chuyên gia cần biết mã độc làm gì, lây lan thế nào, kết nối máy chủ nào, duy trì tồn tại ra sao và có thể gỡ bỏ bằng cách nào. Mã độc thường không đi kèm mã nguồn, vì vậy reverse engineering là kỹ năng cốt lõi.
Thứ hai, nó hỗ trợ tìm lỗ hổng phần mềm. Nhiều hệ thống thương mại không công bố mã nguồn. Khi cần đánh giá an toàn, chuyên gia có thể phân tích binary để phát hiện lỗi tràn bộ đệm (buffer overflow), lỗi định dạng chuỗi (format string bug), lỗi logic xác thực hoặc lỗi xử lý dữ liệu đầu vào.
Thứ ba, nó giúp điều tra số. Trong một sự cố an ninh mạng, chuyên gia có thể cần phân tích một tệp đáng ngờ, một thư viện lạ, một script đã bị đóng gói hoặc một chương trình tự khởi động cùng hệ thống để xác định nguyên nhân xâm nhập.
Thứ tư, nó hỗ trợ tương thích và khôi phục hệ thống cũ. Nhiều tổ chức vẫn vận hành phần mềm cũ nhưng không còn mã nguồn hoặc nhà cung cấp. Reverse engineering giúp hiểu định dạng dữ liệu, giao thức truyền thông hoặc logic nghiệp vụ để có thể di trú hệ thống.
Thứ năm, nó giúp kiểm tra chuỗi cung ứng phần mềm. Khi sử dụng phần mềm bên thứ ba, tổ chức có thể cần đánh giá xem binary có chứa hành vi bất thường, thư viện lỗi thời, đoạn mã nguy hiểm hoặc kết nối không mong muốn hay không.
- Thứ sáu, nó phục vụ giáo dục kỹ thuật. Khi học hệ điều hành, kiến trúc máy tính, trình biên dịch và bảo mật phần mềm, reverse engineering giúp sinh viên hiểu rõ hơn mối quan hệ giữa mã nguồn, assembly, bộ nhớ, stack, heap, thanh ghi và hệ điều hành.
Các kỹ thuật reverse engineering cơ bản
Phân tích tĩnh
Phân tích tĩnh là phân tích chương trình mà không chạy nó. Người phân tích mở binary bằng các công cụ như Ghidra, IDA, PEStudio hoặc strings để xem cấu trúc, mã máy, import table, chuỗi, section và control flow graph.
Ví dụ, với chương trình C ở trên, phân tích tĩnh có thể phát hiện:
Chuỗi: Result = %d
Import: printf
Hàm: main
Hàm phụ: add
Logic: truyền 10 và 20 vào add, sau đó in kết quảƯu điểm của phân tích tĩnh là an toàn hơn vì không cần chạy chương trình. Nhược điểm là khó hiểu với chương trình bị obfuscate (làm rối mã), pack (đóng gói) hoặc có hành vi chỉ xuất hiện khi chạy.
Phân tích động
Phân tích động là chạy chương trình trong môi trường kiểm soát để quan sát hành vi. Với x64dbg, người phân tích có thể đặt breakpoint tại printf hoặc tại hàm add. Khi chương trình dừng, họ xem giá trị thanh ghi, stack và bộ nhớ.
Ví dụ, tại thời điểm gọi add:
ECX = 10
EDX = 20
Sau khi thực thi hàm add, EAX = 30Điều này xác nhận hàm add trả về tổng của hai tham số. Trong phân tích mã độc, phân tích động cần được thực hiện trong máy ảo, sandbox hoặc môi trường cô lập, tuyệt đối không chạy trực tiếp trên máy thật đang sử dụng cho công việc.
Phân tích chuỗi
Chuỗi ký tự là một trong những dấu hiệu dễ tiếp cận nhất. Một chương trình có thể chứa thông báo lỗi, đường dẫn, URL, tên tệp, tên registry key hoặc câu lệnh hệ thống. Với chương trình ví dụ, chuỗi Result = %d cho biết chương trình có in một kết quả số nguyên.
Trong phần mềm thực tế, nếu thấy các chuỗi như api/login, config.json, error connecting server hoặc C:\Users\Public, người phân tích có thể dùng chúng làm điểm bắt đầu để tìm các hàm liên quan.
Phân tích import table
Import table cho biết chương trình gọi hàm nào từ thư viện ngoài. Ví dụ, nếu một chương trình Windows import CreateFileW, ReadFile và WriteFile, nó có khả năng thao tác với tệp. Nếu import RegOpenKeyExW và RegSetValueExW, nó có khả năng thao tác registry. Nếu import WinHttpSendRequest hoặc InternetConnectW, nó có khả năng giao tiếp mạng.
Tuy nhiên, import table chỉ là dấu hiệu ban đầu. Một chương trình có thể import hàm nhưng không dùng, hoặc có thể tải hàm động bằng LoadLibrary và GetProcAddress để che giấu hành vi.
Khôi phục control flow (luồng điều khiển)
Control flow là cách chương trình di chuyển qua các nhánh if, vòng lặp, lời gọi hàm và lệnh nhảy. Disassembler thường hiển thị control flow graph để người phân tích thấy khối lệnh nào dẫn tới khối lệnh nào.
Ví dụ, một đoạn C:
if (z > 20) {
printf("Large\n");
} else {
printf("Small\n");
}Sau khi biên dịch có thể trở thành một chuỗi lệnh so sánh và nhảy có điều kiện:
cmp eax, 20
jle small_branchNgười phân tích phải hiểu rằng cmp so sánh giá trị, còn jle chuyển hướng nếu giá trị nhỏ hơn hoặc bằng. Từ đó có thể phục dựng lại cấu trúc if else.
Nhận diện thuật toán
Một số thuật toán có dấu hiệu đặc trưng. Ví dụ, chương trình mã hóa có thể có bảng hằng số, thao tác XOR, rotate, shift hoặc vòng lặp xử lý từng byte. Chương trình nén có thể có cấu trúc bảng mã, cửa sổ trượt hoặc mẫu entropy cao. Chương trình kiểm tra mật khẩu có thể có hàm so sánh, hash hoặc kiểm tra độ dài.
Với ví dụ đơn giản, thuật toán là phép cộng hai số nguyên. Với phần mềm thực tế, việc nhận diện thuật toán thường cần kết hợp decompiler, debugger, dữ liệu đầu vào thử nghiệm và quan sát đầu ra.
Các kỹ thuật anti reverse
Anti reverse engineering (chống dịch ngược) là tập hợp kỹ thuật làm cho việc phân tích chương trình khó hơn. Trong phần mềm hợp pháp, anti reverse có thể dùng để bảo vệ sở hữu trí tuệ, chống sao chép trái phép hoặc bảo vệ thuật toán nhạy cảm. Trong mã độc, anti reverse thường được dùng để né tránh phân tích. Vì vậy, khi học chủ đề này, cần đặt trong phạm vi nghiên cứu phòng thủ, phân tích mẫu và xây dựng năng lực hiểu biết kỹ thuật.
Strip symbol (loại bỏ ký hiệu)
Khi biên dịch ở chế độ debug, binary có thể chứa tên hàm, tên biến, thông tin dòng mã nguồn và thông tin kiểu dữ liệu. Nếu loại bỏ symbol, người phân tích sẽ không thấy tên hàm rõ ràng nữa.
Ví dụ, thay vì thấy hàm add, công cụ dịch ngược có thể chỉ hiển thị một tên tự sinh như function_140001000. Khi đó, người phân tích phải dựa vào hành vi của hàm để đặt lại tên. Nếu thấy hàm nhận hai số và trả về tổng, có thể đổi tên nó thành add_numbers để dễ phân tích tiếp.
Obfuscation (làm rối mã)
Obfuscation làm cho mã khó đọc hơn nhưng vẫn giữ nguyên hành vi. Một biểu thức đơn giản như:
return a + b;có thể bị biến đổi thành dạng phức tạp hơn, ví dụ dùng nhiều biến trung gian, phép toán dư thừa hoặc nhánh điều kiện không cần thiết. Mục tiêu là làm cho decompiler tạo ra mã giả khó hiểu.
Ví dụ ý tưởng:
int temp1 = a ^ b;
int temp2 = a & b;
int result = temp1 + 2 * temp2;
return result;Biểu thức trên vẫn tương đương với phép cộng a + b đối với số nguyên trong nhiều ngữ cảnh, nhưng khó đọc hơn so với return a + b. Người phân tích phải đơn giản hóa biểu thức để hiểu logic thật.
Control flow flattening (làm phẳng luồng điều khiển)
Thông thường, chương trình có cấu trúc rõ ràng gồm if, else, for, while và call. Control flow flattening biến cấu trúc này thành một vòng lặp lớn điều khiển bằng biến trạng thái.
Ví dụ, thay vì có luồng:
Bước 1 → Bước 2 → Bước 3Chương trình có thể bị biến thành:
while (running) {
switch (state) {
case 1:
state = 2;
break;
case 2:
state = 3;
break;
case 3:
running = 0;
break;
}
}Cách này làm control flow graph phức tạp hơn. Người phân tích phải theo dõi biến state để hiểu thứ tự thực thi thật.
Packing (đóng gói binary)
Packing là kỹ thuật nén hoặc mã hóa phần thân chương trình, sau đó thêm một đoạn unpacker nhỏ ở đầu. Khi chạy, unpacker giải mã phần chương trình thật vào bộ nhớ rồi chuyển quyền điều khiển sang đó.
Khi mở tệp bằng disassembler, người phân tích ban đầu chỉ thấy đoạn unpacker, không thấy logic thật. Dấu hiệu thường gặp là section có entropy cao, import table rất ít, entry point nằm trong vùng bất thường hoặc mã máy khó đọc.
Trong phân tích phòng thủ, người phân tích cần xác định chương trình có bị pack hay không, sau đó quan sát bộ nhớ sau khi unpack để phân tích phần mã thật. Việc này phải thực hiện trong môi trường lab cô lập.
Anti debugging (chống gỡ lỗi)
Anti debugging là kỹ thuật phát hiện chương trình có đang bị chạy dưới debugger hay không. Trên Windows, một chương trình có thể kiểm tra trạng thái debug bằng một số API hoặc thông tin trong process environment block.
Ví dụ minh họa ở mức khái niệm:
#include <windows.h>
#include <stdio.h>
int main() {
if (IsDebuggerPresent()) {
printf("Debugger detected\n");
return 1;
}
printf("Normal execution\n");
return 0;
}Đoạn chương trình này kiểm tra xem có debugger đang gắn vào process hay không. Nếu có, nó in ra Debugger detected và kết thúc. Trong phần mềm bảo vệ bản quyền hoặc trong mã độc, kỹ thuật tương tự có thể được dùng để làm khó quá trình phân tích động.
Người học reverse engineering cần hiểu kỹ thuật này để nhận diện dấu hiệu anti debugging, không nên sử dụng nó để che giấu hành vi gây hại.
Anti virtual machine (chống máy ảo)
Một số chương trình kiểm tra xem chúng có đang chạy trong máy ảo hay sandbox không. Chúng có thể tìm tên driver, thiết bị, process, registry key hoặc đặc điểm phần cứng đặc trưng của VMware, VirtualBox, Hyper V hoặc môi trường sandbox.
Trong phân tích mã độc, nếu mẫu phát hiện đang chạy trong lab, nó có thể không thực hiện hành vi thật. Điều này khiến người phân tích kết luận sai rằng chương trình vô hại. Vì vậy, cần hiểu anti virtual machine để xây dựng môi trường phân tích phù hợp và đọc đúng hành vi.
String encryption (mã hóa chuỗi)
Thay vì để lộ chuỗi trực tiếp trong binary, chương trình có thể mã hóa chuỗi và chỉ giải mã khi chạy. Khi dùng công cụ strings, người phân tích sẽ không thấy URL, đường dẫn hoặc thông báo quan trọng.
Ví dụ, thay vì lưu trực tiếp chuỗi Result = %d, chương trình có thể lưu các byte đã XOR với một khóa đơn giản. Khi chạy, nó giải mã ra chuỗi thật rồi mới dùng. Trong phân tích, người học cần tìm hàm giải mã chuỗi và quan sát kết quả sau khi chương trình chạy.
Yêu cầu kỹ năng đối với nghề reverse engineering
Nghề reverse engineering yêu cầu nền tảng rộng. Người học cần hiểu kiến trúc máy tính (computer architecture), thanh ghi, stack, heap, con trỏ, gọi hàm, quản lý bộ nhớ và định dạng tệp thực thi. Cần có kiến thức về hệ điều hành, đặc biệt là Windows API nếu phân tích phần mềm Windows. Cần biết đọc assembly x86, x64 hoặc ARM tùy nền tảng. Cần hiểu lập trình C/C++ vì rất nhiều binary hệ thống và phần mềm hiệu năng cao được viết bằng các ngôn ngữ này.
Ngoài kỹ năng kỹ thuật, người làm reverse engineering cần có tư duy điều tra. Một binary lớn có thể có hàng nghìn hàm. Không thể đọc tuần tự từ đầu đến cuối. Người phân tích phải biết chọn điểm bắt đầu, ưu tiên vùng quan trọng, đánh dấu giả thuyết, đổi tên hàm, ghi chú hành vi và xây dựng bức tranh tổng thể từng bước.
Reverse engineering là một lĩnh vực nằm ở giao điểm giữa lập trình hệ thống, kiến trúc máy tính, hệ điều hành và an toàn thông tin. Nó giúp con người hiểu chương trình khi mã nguồn không còn tồn tại, không được cung cấp hoặc không đáng tin cậy. Từ một tệp binary, người phân tích có thể lần ngược lại cấu trúc chương trình, xác định hàm quan trọng, hiểu thuật toán, quan sát hành vi và đánh giá rủi ro bảo mật.
Trong ví dụ chương trình C trên Windows, ta thấy mã nguồn được chuyển qua các bước tiền xử lý, biên dịch, hợp dịch và liên kết để tạo thành tệp .exe. Khi reverse engineering, người phân tích đi theo chiều ngược lại, từ tệp .exe, đọc cấu trúc PE, trích chuỗi, xem assembly, dùng decompiler, chạy debugger và suy luận lại logic ban đầu.
Các kỹ thuật reverse như phân tích tĩnh, phân tích động, phân tích chuỗi, phân tích import table, khôi phục control flow và nhận diện thuật toán là nền tảng của nghề. Ngược lại, các kỹ thuật anti reverse như strip symbol, obfuscation, packing, anti debugging, anti virtual machine và mã hóa chuỗi làm cho quá trình phân tích khó hơn. Việc học cả reverse và anti reverse giúp người học hiểu sâu hơn về cách phần mềm vận hành, cách mã độc che giấu hành vi và cách xây dựng năng lực phân tích phòng thủ trong thực tế.
Vì vậy, reverse engineering không chỉ là một kỹ thuật phụ trợ, mà là một năng lực cốt lõi trong an toàn thông tin hiện đại. Nó giúp người học vượt ra khỏi việc sử dụng công cụ bề mặt, tiến tới hiểu bản chất của chương trình ở tầng mã máy, bộ nhớ, hệ điều hành và hành vi thực thi.


