H: Nếu tôi mã hóa các tệp .class của mình và sử dụng trình tải lớp tùy chỉnh để tải và giải mã chúng một cách nhanh chóng, điều này có ngăn chặn quá trình dịch ngược không?
Đáp: Vấn đề ngăn chặn dịch ngược mã byte Java gần như là ngôn ngữ cũ. Mặc dù có một loạt các công cụ làm xáo trộn có sẵn trên thị trường, các lập trình viên Java mới làm quen vẫn tiếp tục nghĩ ra những cách mới và thông minh để bảo vệ tài sản trí tuệ của họ. Trong phần Hỏi & Đáp Java này, tôi xóa tan một số lầm tưởng xung quanh một ý tưởng thường được nhắc lại trong các diễn đàn thảo luận.
Việc các tệp .class Java có thể được tái tạo lại thành các nguồn Java gần giống với các bản gốc cực kỳ dễ dàng có liên quan rất nhiều đến các mục tiêu thiết kế mã byte Java và sự cân bằng. Trong số những thứ khác, mã byte Java được thiết kế cho tính nhỏ gọn, tính độc lập của nền tảng, tính di động của mạng và dễ dàng phân tích bởi trình thông dịch mã byte và trình biên dịch động JIT (just-in-time) / HotSpot. Có thể cho rằng, các tệp .class đã được biên dịch thể hiện ý định của lập trình viên nên rõ ràng chúng có thể dễ phân tích hơn so với mã nguồn ban đầu.
Một số việc có thể được thực hiện, nếu không muốn ngăn chặn hoàn toàn quá trình dịch ngược, ít nhất là làm cho nó khó khăn hơn. Ví dụ, ở bước sau biên dịch, bạn có thể xoa bóp dữ liệu .class để làm cho mã byte khó đọc hơn khi dịch ngược hoặc khó dịch ngược thành mã Java hợp lệ (hoặc cả hai). Các kỹ thuật như thực hiện quá tải tên phương thức cực đoan hoạt động tốt đối với phương thức trước đây và thao tác luồng điều khiển để tạo cấu trúc điều khiển không thể biểu diễn thông qua cú pháp Java hoạt động tốt đối với phương thức sau. Các trình xử lý obfuscators thương mại thành công hơn sử dụng kết hợp các kỹ thuật này và các kỹ thuật khác.
Thật không may, cả hai cách tiếp cận phải thực sự thay đổi mã mà JVM sẽ chạy và nhiều người dùng sợ (đúng là như vậy) rằng sự chuyển đổi này có thể thêm lỗi mới vào ứng dụng của họ. Hơn nữa, việc đổi tên phương thức và trường có thể khiến các lệnh gọi phản chiếu ngừng hoạt động. Thay đổi tên gói và lớp thực tế có thể phá vỡ một số API Java khác (JNDI (Giao diện thư mục và đặt tên Java), nhà cung cấp URL, v.v.). Ngoài tên đã thay đổi, nếu mối liên kết giữa hiệu số byte-mã lớp và số dòng nguồn bị thay đổi, việc khôi phục dấu vết ngăn xếp ngoại lệ ban đầu có thể trở nên khó khăn.
Sau đó, có tùy chọn làm xáo trộn mã nguồn Java ban đầu. Nhưng về cơ bản điều này gây ra một loạt vấn đề tương tự. Mã hóa, không làm xáo trộn?
Có lẽ điều ở trên đã khiến bạn nghĩ, "Chà, điều gì sẽ xảy ra nếu thay vì thao tác mã byte, tôi mã hóa tất cả các lớp của mình sau khi biên dịch và giải mã chúng ngay lập tức bên trong JVM (có thể được thực hiện với một trình nạp lớp tùy chỉnh)? Sau đó, JVM thực thi mã byte gốc và không có gì để dịch ngược hoặc thiết kế ngược, phải không? "
Thật không may, bạn sẽ sai, cả khi nghĩ rằng bạn là người đầu tiên đưa ra ý tưởng này và nghĩ rằng nó thực sự hoạt động. Và lý do không liên quan gì đến sức mạnh của chương trình mã hóa của bạn.