Có những câu chuyện, nếu kể lại theo kiểu thành tích, thì nghe như một hành trình chinh phục công nghệ. Nhưng nếu kể đúng bản chất, nó giống một lời thú nhận, một lời thú nhận muộn màng sau hơn 30 năm, về một thời mà ranh giới giữa học hỏi, sinh tồn và vi phạm đạo đức gần như bị xóa nhòa. Tôi đã từng là một phần của thời kỳ đó, vừa là người học, vừa là người “đi đường vòng”, vừa say mê kỹ thuật, vừa mang trong mình những điều đến hôm nay phải nhìn lại cho thẳng thắn.
Những ngày đầu, khi phần mềm là thứ xa xỉ
Hơn 30 năm trước, khi còn là một kỹ sư hệ thống tổng đài, công việc chính của tôi xoay quanh switching system, tín hiệu SS7, và các bài toán tính cước. Ban ngày, tôi làm việc với mạng lưới, với routing, với những bảng mạch và logic vận hành khô khan nhưng chính xác. Ban đêm, tôi viết các chương trình nhỏ bằng Visual Basic để tính cước, xây dựng bảng giá, xuất báo cáo cho các đơn vị nhỏ hơn, một cách kiếm thêm thu nhập rất thực dụng của thời đó.
Nhưng thế giới thực tế không dừng lại ở đó. Những phần mềm chuyên ngành, đặc biệt trong lĩnh vực thiết kế khuôn, CAD CAM, hay các hệ thống tổng đài nước ngoài, đều được bảo vệ bằng license và hardware dongle cắm qua cổng LPT hoặc COM. Giá của chúng vượt xa khả năng chi trả, đôi khi bằng cả năm thu nhập. Khi không thể mua, người ta bắt đầu tìm cách khác. Không ai nói ra, nhưng ai cũng hiểu.

Bước vào thế giới reverse engineering
Mọi thứ bắt đầu từ những file .exe, nơi không có source code, không có tài liệu, không có bất kỳ gợi ý nào về ý định của người viết. Chỉ có binary. Từ đó, chúng tôi sử dụng debugger và disassembler để “dịch ngược” chương trình về dạng có thể đọc được, chủ yếu là assembly x86. Trên màn hình, mọi thứ hiện ra dưới dạng instruction stream, các lệnh mov, cmp, jmp, call, các thanh ghi eax, ebx, esp, và một control flow gần như trần trụi.
Không có biến, không có tên hàm, không có comment. Chỉ có control flow graph (CFG) mà bạn phải tự hình dung trong đầu, và data flow mà bạn phải lần theo từng thanh ghi, từng stack frame. Reverse engineering thời đó thực chất là quá trình tái dựng lại logic từ những mảnh vỡ của execution.
Những đêm dò từng dòng lệnh
Công việc khi đó mang tính thủ công đến cực đoan. Đặt breakpoint, step into từng instruction, theo dõi từng thay đổi của register, từng byte trong memory. Bạn không “đọc code”, bạn quan sát hành vi của chương trình khi nó chạy, rồi suy luận ngược lại. Có những đêm kéo dài đến 2, 3 giờ sáng chỉ để hiểu một đoạn hàm verify license.
Những đoạn kiểm tra thường có pattern quen thuộc, một chuỗi so sánh key, một lời gọi đến hàm tương tác với dongle, và sau đó là một conditional branch, ví dụ cmp eax, valid_key rồi jne invalid. Chỉ cần xác định đúng decision point trong control flow graph, bạn có thể can thiệp bằng opcode patching, đổi một lệnh nhảy có điều kiện thành nhảy vô điều kiện, từ jne thành jmp. Một byte thay đổi, toàn bộ cơ chế bảo vệ bị vô hiệu. Đó là thứ mà sau này chúng tôi gọi một cách rất “kỹ thuật” là bypass, nhưng thực chất ai cũng hiểu nó là gì.
Khi mọi thứ không còn đơn giản
Không phải lúc nào logic cũng lộ ra rõ ràng như vậy. Nhiều phần mềm sử dụng packer, obfuscation, thậm chí self modifying code để làm rối control flow. Khi đó, static analysis gần như vô dụng, bạn buộc phải chuyển sang dynamic analysis, chạy chương trình, dump memory sau khi unpack, rebuild import table, rồi disassemble lại từ trạng thái runtime. Việc này đòi hỏi hiểu rõ cả control flow lẫn data flow, biết lúc nào chương trình “lộ diện” logic thật.
Trong những trường hợp phức tạp hơn, chúng tôi phải hook vào API call, giả lập phản hồi từ hardware dongle, hoặc viết một layer trung gian để đánh lừa chương trình rằng license hợp lệ. Đó không còn là việc đọc code, mà là một dạng đối thoại gián tiếp với hệ thống, nơi bạn đặt câu hỏi bằng breakpoint và nhận câu trả lời qua register.
Lời thú nhận muộn màng
Nhìn lại, tôi không thể gọi tất cả những việc đó là học hỏi. Một phần đúng là như vậy, nó rèn luyện tư duy hệ thống, khả năng phân tích và sự kiên nhẫn. Nhưng một phần khác, rõ ràng, là crack phần mềm, sử dụng trái phép, và đôi khi còn chia sẻ lại cho người khác. Trong bối cảnh của một thời kỳ khó khăn, người ta dễ tự cho mình lý do, rằng đó là để làm việc, để tồn tại, để phát triển kỹ năng.
Nhưng lý do không làm cho hành động trở nên đúng. Và nếu phải nói thẳng, đó là những việc tôi không tự hào. Sự “thanh niên sôi nổi” của thời đó có thể giải thích, nhưng không thể biện minh.
Nếu có một điều tôi muốn nói với những người trẻ hôm nay, đặc biệt là những ai bước vào thế giới AI và hệ thống phức tạp, thì đó là: năng lực reverse engineering là con dao hai lưỡi. Nó cho bạn khả năng hiểu sâu một hệ thống mà người khác không thấy, nhưng đồng thời cũng mở ra những cám dỗ rất thực tế.
Ngày hôm nay, việc phân tích một hệ thống không còn cần phải “dò từng byte” như trước. Với AI, bạn có thể dựng lại control flow, suy luận data flow, thậm chí tái tạo cả logic ở mức pseudocode chỉ trong vài phút. Nhưng chính vì dễ hơn, nên ranh giới đạo đức càng cần rõ ràng hơn. Không phải cái gì hiểu được cũng nên khai thác, không phải cái gì có thể bypass cũng nên bypass.
Từ assembler đến AI
Ngày hôm nay, khi làm việc với các hệ thống AI, tôi nhận ra bản chất không thay đổi, chỉ có công cụ thay đổi. Ngày xưa, chúng tôi đọc assembler, reconstruct control flow graph trong đầu, patch opcode trực tiếp vào binary. Ngày nay, chúng ta đọc system prompt, phân tích tool chain, hiểu cách một agent quản lý state, và “patch” hành vi thông qua prompt, config và workflow.
Reverse engineering không biến mất. Nó tiến hóa từ mức instruction sang mức system intent. Từ việc hiểu một hàm verify license sang việc hiểu cách một hệ thống ra quyết định.
Kết, một ẩn dụ
Marcus Aurelius từng viết rằng, con người không bị tổn hại bởi những gì xảy ra bên ngoài, mà bởi cách họ diễn giải nó. Tôi nghĩ reverse engineering cũng vậy. Bản thân kỹ thuật không có đạo đức, nó chỉ là công cụ để hiểu. Nhưng cách ta sử dụng sự hiểu đó mới là điều định nghĩa chúng ta.
Ba mươi năm trước, tôi dùng nó để đi đường tắt. Hôm nay, tôi dùng nó để đọc hiểu hệ thống, để tư vấn, để xây dựng những thứ minh bạch hơn. Khoảng cách giữa hai điều đó không nằm ở công nghệ, mà nằm ở lựa chọn.
Và có lẽ, sau tất cả, reverse engineering không chỉ là việc đọc một chương trình. Nó là việc đọc chính mình, xem ta sẽ đi theo nhánh nào trong control flow của cuộc đời, nhánh dễ hơn, hay nhánh đúng hơn.





