Làm thế nào để khóa các lớp Java đã biên dịch để ngăn chặn việc dịch ngược?


96

Làm cách nào để khóa các lớp Java đã biên dịch để ngăn dịch ngược?

Tôi biết đây phải là chủ đề được thảo luận rất kỹ trên Internet, nhưng tôi không thể đưa ra kết luận nào sau khi tham khảo chúng.

Nhiều người đề xuất obfuscator, nhưng họ chỉ đổi tên các lớp, phương thức và trường với chuỗi ký tự khó nhớ, nhưng còn các giá trị hằng số nhạy cảm thì sao?

Ví dụ: bạn đã phát triển thành phần mã hóa và giải mã dựa trên kỹ thuật mã hóa dựa trên mật khẩu. Bây giờ trong trường hợp này, bất kỳ người Java trung bình nào cũng có thể sử dụng JAD để dịch ngược tệp lớp và dễ dàng truy xuất giá trị mật khẩu (được định nghĩa là hằng số) cũng như muối và đến lượt nó có thể giải mã dữ liệu bằng cách viết chương trình độc lập nhỏ!

Hay các thành phần nhạy cảm như vậy nên được xây dựng trong mã gốc (ví dụ: VC ++) và gọi chúng qua JNI ?


Ngay cả mã gốc đã được tháo rời cũng khá dễ đọc đối với một số người, bạn có thể phải sử dụng một số obfuscator hoặc lắp ráp làm bằng tay để làm cho nó trở nên không rõ ràng (C ++ phổ biến được biên dịch với tối ưu hóa là đủ để đọc). Bất kỳ mã nào chạy trên thiết bị của người dùng, đều có thể bị chặn. Mặc dù yêu cầu về chi phí / kỹ năng của việc đánh chặn như vậy có thể khá cao, ví dụ như đột nhập vào mã chip "chống giả mạo" của thẻ thông minh không hề tầm thường, chỉ có thể làm được với thiết bị và kỹ năng hàng đầu. Với các lớp Java ... Tôi sẽ không bận tâm nhiều, bạn có thể mã hóa chúng đủ để loại bỏ những đứa trẻ tập lệnh, chứ không phải nhiều hơn.
Ped7g 22/09/2016

Câu trả lời:


96

Một số trình obfuscator bytecode của Java nâng cao hơn làm được nhiều việc hơn là chỉ quản lý tên lớp. Ví dụ: Zelix KlassMaster cũng có thể xáo trộn luồng mã của bạn theo cách khiến bạn thực sự khó theo dõi và hoạt động như một trình tối ưu hóa mã tuyệt vời ...

Ngoài ra, nhiều trình làm xáo trộn cũng có thể xáo trộn các hằng số chuỗi của bạn và xóa mã không sử dụng.

Một giải pháp khả thi khác (không nhất thiết phải loại trừ sự xáo trộn) là sử dụng các tệp JAR được mã hóa và một trình tải lớp tùy chỉnh thực hiện việc giải mã (tốt nhất là sử dụng thư viện thời gian chạy gốc).

Thứ ba (và có thể cung cấp biện pháp bảo vệ mạnh nhất) là sử dụng các trình biên dịch gốc trước thời hạn như GCC hoặc Excelsior JET , chẳng hạn, để biên dịch mã Java của bạn trực tiếp sang một nền tảng nhị phân gốc cụ thể.

Trong mọi trường hợp Bạn phải nhớ rằng như câu nói trong tiếng Estonia "Ổ khóa dành cho động vật". Có nghĩa là mọi bit mã đều có sẵn (được tải vào bộ nhớ) trong thời gian chạy và được cung cấp đủ kỹ năng, quyết tâm và động lực, mọi người có thể và sẽ dịch ngược, giải mã và hack mã của bạn ... Công việc của bạn chỉ đơn giản là làm cho quá trình trở nên khó chịu như bạn có thể và vẫn giữ cho mọi thứ hoạt động ...


13
+1 cho "Ổ khóa dành cho động vật". Tôi đoán thuật ngữ thích hợp ở đây sẽ là những đứa trẻ kịch bản.
Antimony

Ý bạn là GCJ, và nó đã chết.
Marquis of Lorne

1
Mã hóa tệp jar Componio cũng đã chết. Sử dụng JarProtector để thay thế.
J.Profi 21/07/17

16

Miễn là họ có quyền truy cập vào cả dữ liệu được mã hóa và phần mềm giải mã nó, về cơ bản thì không có cách nào bạn có thể thực hiện điều này hoàn toàn an toàn. Cách này đã được giải quyết trước đây là sử dụng một số hình thức hộp đen bên ngoài để xử lý mã hóa / giải mã, như khóa, máy chủ xác thực từ xa, v.v. Nhưng ngay cả khi người dùng có toàn quyền truy cập vào hệ thống của riêng họ, điều này chỉ làm khó, không phải là không thể - trừ khi bạn có thể liên kết trực tiếp sản phẩm của mình với chức năng được lưu trữ trong "hộp đen", chẳng hạn như máy chủ trò chơi trực tuyến.


13

Tuyên bố từ chối trách nhiệm: Tôi không phải là chuyên gia bảo mật.

Điều này nghe có vẻ là một ý tưởng tồi: Bạn đang để ai đó mã hóa nội dung bằng một khóa 'ẩn' mà bạn đưa cho anh ta. Tôi không nghĩ điều này có thể được bảo mật.

Có thể các khóa không đối xứng có thể hoạt động:

  • triển khai giấy phép được mã hóa với khóa công khai để giải mã
  • cho phép khách hàng tạo một giấy phép mới và gửi cho bạn để mã hóa
  • gửi lại giấy phép mới cho khách hàng.

Tôi không chắc, nhưng tôi tin rằng khách hàng thực sự có thể mã hóa khóa cấp phép bằng khóa công khai mà bạn đã cung cấp cho anh ta. Sau đó, bạn có thể giải mã nó bằng khóa riêng của mình và mã hóa lại.

Bạn có thể giữ một cặp khóa công khai / riêng tư riêng biệt cho mỗi khách hàng để đảm bảo rằng bạn thực sự đang nhận được nội dung từ đúng khách hàng - bây giờ bạn chịu trách nhiệm về các khóa ...


2
Tôi đã sử dụng kỹ thuật này trước đây và nó hoạt động tốt. Tuy nhiên, từ góc độ tấn công, cách tiếp cận đầu tiên sẽ là chỉ sửa đổi mã thực hiện kiểm tra giấy phép và xóa nó. Có những điều bạn có thể làm để làm cho vectơ tấn công này khó khăn hơn, nhưng nếu bạn cho kẻ tấn công quyền kiểm soát phần cứng, số phận của bạn sẽ thất bại trước một kẻ tấn công có động cơ và kỹ năng phù hợp. Trong thực tế, mục tiêu chỉ là giữ những người trung thực, trung thực.
Jim Rush

12

Bất kể bạn làm gì, nó đều có thể bị 'dịch ngược'. Heck, bạn chỉ có thể tháo rời nó. Hoặc nhìn vào kết xuất bộ nhớ để tìm hằng số của bạn. Bạn thấy đấy, máy tính cần biết chúng, vì vậy mã của bạn cũng sẽ cần.

Phải làm gì về điều này?

Cố gắng không gửi khóa dưới dạng hằng số được mã hóa cứng trong mã của bạn: Giữ khóa dưới dạng cài đặt cho mỗi người dùng. Làm cho người dùng có trách nhiệm chăm sóc khóa đó.


6

@jatanp: hoặc tốt hơn, họ có thể dịch ngược, xóa mã cấp phép và biên dịch lại. Với Java, tôi không thực sự nghĩ rằng có một giải pháp chống hack thích hợp cho vấn đề này. Ngay cả một dongle nhỏ độc ác cũng không thể ngăn chặn điều này với Java.

Các nhà quản lý biz của riêng tôi lo lắng về điều này và tôi đã nghĩ quá nhiều. Nhưng một lần nữa, chúng tôi bán ứng dụng của mình cho các công ty lớn, những người có xu hướng tuân thủ các điều kiện cấp phép - nói chung là một môi trường an toàn nhờ các quầy đậu và luật sư. Hành động dịch ngược bản thân có thể là bất hợp pháp nếu giấy phép của bạn được viết đúng.

Vì vậy, tôi phải hỏi, bạn có thực sự cần sự bảo vệ cứng rắn như bạn đang tìm kiếm cho ứng dụng của mình không? Cơ sở khách hàng của bạn trông như thế nào? (Các công ty? Hay số lượng game thủ tuổi teen, nơi đây sẽ là một vấn đề nhiều hơn?)


Trên thực tế, có một giải pháp chống hack thích hợp mà btw trông giống như một dongle: excelsior-usa.com/blog/excelsior-jet/…
Dmitry Leskov

@DmitryLeskov 'chống hack', có thể. Nhưng nó chỉ đơn thuần là một cú hích tốc độ cho bất kỳ ai muốn mã. Vào cuối ngày, mã byte phải chạy trên nền tảng máy chủ lưu trữ không được mã hóa. Dấu chấm.
Stu Thompson

Bạn chưa đọc bài đăng mà tôi đã liên kết. Bytecode được chuyển đổi thành mã CPU của dongle và được mã hóa. Khi người dùng cuối chạy ứng dụng được bảo vệ, mã được mã hóa đó sẽ được chuyển đến "dongle". Dongle giải mã và chạy nó trên CPU của nó.
Dmitry Leskov

2
Công ty game thủ tuổi teen.
odiszapc

3

Nếu bạn đang tìm kiếm giải pháp cấp phép, bạn có thể xem API TrueLicense . Nó dựa trên việc sử dụng các phím không đối xứng. Tuy nhiên, nó không có nghĩa là ứng dụng của bạn không thể bị bẻ khóa. Mọi ứng dụng đều có thể bị bẻ khóa với đủ nỗ lực. Như Stu đã trả lời , điều thực sự quan trọng là tìm ra mức độ bảo vệ mạnh mẽ mà bạn cần.


2

Tôi không nghĩ rằng có tồn tại bất kỳ phương pháp chống vi phạm bản quyền ngoại tuyến hiệu quả nào. Ngành công nghiệp trò chơi điện tử đã cố gắng tìm ra điều đó nhiều lần và các chương trình của họ luôn bị bẻ khóa. Giải pháp duy nhất là chương trình phải được chạy trực tuyến được kết nối với máy chủ của bạn để bạn có thể xác minh khóa lincense và tại một thời điểm chỉ có một liên kết hoạt động bởi người được cấp phép. Đây là cách hoạt động của World of Warcraft hoặc Diablo . Thậm chí khó có những máy chủ riêng được phát triển để chúng vượt qua bảo mật.

Phải nói rằng, tôi không tin rằng các tập đoàn tầm trung / lớn sử dụng phần mềm sao chép bất hợp pháp, bởi vì chi phí giấy phép cho họ là rất nhỏ (có lẽ, tôi không biết bạn phải tính bao nhiêu cho chương trình của mình) so với chi phí của một phiên bản dùng thử.


2

Bạn có thể sử dụng mã hóa mã byte mà không cần lo lắng.

Thực tế là bài báo được trích dẫn ở trên “Bẻ khóa mã hóa mã byte Java” chứa một lỗi ngụy biện logic. Yêu cầu chính của bài báo là trước khi chạy tất cả các lớp phải được giải mã và chuyển cho ClassLoader.defineClass(...)phương thức . Nhưng điều này là không đúng sự thật.

Giả định bị bỏ qua ở đây được cung cấp là chúng đang chạy trong môi trường thời gian chạy java đích thực hoặc tiêu chuẩn . Không gì có thể bắt buộc ứng dụng java được bảo vệ không chỉ khởi chạy các lớp này mà còn giải mã và chuyển chúng sang ClassLoader. Nói cách khác, nếu bạn đang ở trong JRE tiêu chuẩn, bạn không thể chặn defineClass(...)phương pháp này vì java tiêu chuẩn không có API cho mục đích này và nếu bạn sử dụng JRE đã sửa đổi với bản vá ClassLoaderhoặc bất kỳ "thủ thuật hacker" nào khác, bạn không thể làm điều đó vì đã được bảo vệ ứng dụng java sẽ hoàn toàn không hoạt động, và do đó bạn sẽ không có gì để ngăn chặn. Và hoàn toàn không quan trọng "công cụ tìm bản vá" nào được sử dụng hoặc thủ thuật nào được sử dụng bởi tin tặc. Những chi tiết kỹ thuật này là một câu chuyện hoàn toàn khác.


Chính xác thì bạn định phát hiện một JVM đã được vá như thế nào? Dù sao, tất cả những điều này làm mọi thứ khó hơn một chút.
Antimony

Bạn không thể tìm thấy lệnh gọi đến defineClass () trong trình khởi chạy ứng dụng của mình? Khi bạn thực hiện cuộc gọi đó, bạn phải đưa vào một mảng các byte đã được giải mã. Đó không phải là một điểm khác mà nguồn gốc có thể bị rò rỉ?
Thăng thiên

4
Tôi không thực sự đồng ý với câu trả lời này. Đối với tôi, điều này giống như, "Câu hỏi: Cách dễ nhất để tìm số Pi là gì? Câu trả lời: Lấy 2 * Pi và chia cho hai." Tôi không đồng ý với ý kiến ​​này, nhưng bạn có thể nêu thêm chi tiết không? Ví dụ, bạn có mong đợi chương trình chính được viết bằng java thuần túy không? Điều đó có bao gồm mã đang tìm kiếm sửa đổi không?
Patrick M

-1

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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.