bảo vệ mã nguôn chương trình java

42 770 1
bảo vệ mã nguôn chương trình java

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

LỜI MỞ ĐẦU Hiện lĩnh vực công nghệ phần mềm phát triển mạnh mẽ, sản phẩm phần mềm xuất ngành nghề từ y tế bệnh viện, tài ngân hàng đến giáo dục hay quan nhà nước Mỗi sản phẩm phần mềm chứa đựng thuật toán cốt yếu, liệu nhạy cảm tối quan trọng phản ảnh giá trị phần mềm đó, đem lại cạnh tranh tốt so với sản phẩm phần mềm tương tự Ví dụ phần mềm kế toán Misa, quy trình nghiệp vụ tích hợp với thuật toán xử lý liệu cách nhanh ổn định nhất, hay máy tìm kiếm google với thuật toán tìm kiếm liệu nhanh nhất, … Mỗi sản phẩm khẳng định vị vượt trội lĩnh vực tương ứng nhờ thuật toán cốt lõi cài đặt Các công ty đối thủ cạnh tranh trực tiếp tìm cách đánh cắp mã nguồn, lấy thuật toán liệu quan trọng để cài tiến, xây dựng sản phẩm riêng họ vượt trội Chính vấn đề bảo vệ mã nguồn ứng dụng tránh đánh cắp, dịch ngược thu mã nguồn liệu quan trọng toán cấp thiết có ý nghĩa thực tiễn cao thời đại bùng nổ công nghệ thông tin Trong phát triển phầm mềm nay, Java môi trường mạnh mẽ công ty, nhà phát triển phần mềm Tuy nhiên, với ngôn ngữ lập trình java ứng dụng dễ bị công dịch ngược mã nguồn java ngôn ngữ có tính cấu trúc rõ ràng, định dạng bytecode ứng dụng hàm chứa nhiều thông tin quan trọng phục vụ cho trình thông dịch máy ảo java Trong báo cáo này, đưa hai giải pháp nhằm ngăn chặn trình công đánh cắp mã nguồn ứng dụng java Ở giải pháp thứ nhất, cài đặt thuật toán liệu nhạy cảm đặt server chia sẻ cho ứng dụng phía người dùng dạng dịch vụ Phần mềm ứng dụng phía người dùng thực tính toán thông qua việc gọi đến dịch vụ máy server Khi đó, thành phần liệu nhạy cảm thuật toán cốt lõi ứng dụng quản lý tập trung server nên ứng dụng bị dịch ngược mã nguồn không bị lỗ thuật toán, liệu quan trọng Trong giải pháp thứ hai, thực xáo trộn mã nguồn ứng dụng với kỹ thuật Obfuscation Khi đó, có bị dịch ngược kẻ công thu mã nguồn hỗn độn, khó đọc khác biệt với mã nguồn gốc nên thuật toán hay liệu ứng dụng che giấu Trong báo cáo này, trình bày nội dung nghiên cứu kết đạt nhóm đề tài chương: Chương 1: Nguy bị lộ mã nguồn chương trình java Trong chương này, trình phát triển ứng dụng java từ viết code đến biên dịch thông dịch chương trình Sau phân tích nguy khiến ứng dụng java bị lộ mã nguồn Chương 2: Kỹ thuật dịch ngược mã nguồn Chương trình bày rõ sở việc dịch ngược chương trình java cách thức thực để dịch ngược chương trình từ mã bytecode ứng dụng thông qua công cụ dịch ngược Chương 3: Nghiên cứu kỹ thuật bảo vệ mã nguồn ứng dụng Java Trong đó, nhóm đề tài trình bày hai giải pháp thực việc bảo vệ chống bị lộ mã nguồn Trong trình thực đề tài, nhóm cố gắng làm việc nghiêm túc khoa học Tuy nhiên, hạn chế thời gian kiến thức vấn đề với phát triển mạnh mẽ công nghệ nên không tránh khỏi thiếu sót, hạn chế Chúng mong nhận đóng góp nhà khoa học, cấp quản lý đồng nghiệp để chỉnh sửa bổ sung hoàn thiện Chúng xin chân thành cảm ơn Ban giám đốc, phòng Quản lý NCKH, khoa Công nghệ thông tin, phòng chức – Học viện Kỹ thuật Mật mã bạn đồng nghiệp tạo điều kiện thuận lợi cho việc nghiên cứu hoàn thiện đề tài Hà Nội, tháng 11/2013 CHƯƠNG 1: NGUY CƠ BỊ LỘ MÃ NGUỒN CHƯƠNG TRÌNH JAVA Môi trường trình biên dịch chương trình Java Java ngôn ngữ lập trình hướng đối tượng đưa Sun MicroSysem Mỗi chương trình viết ngôn ngữ java chạy hệ thống có cài máy ảo Java (Java Virtual Machine) Tất chương trình muốn thực thi phải biên dịch mã máy Mã máy kiến trúc CPU máy tính khác (tập lệnh mã máy CPU Intel, CPU Solarix, CPU Macintosh … khác nhau), trước chương trình sau biên dịch xong chạy kiến trúc CPU cụ thể Đối với CPU Intel chạy hệ điều hành Microsoft Windows, Unix, Linux, OS/2, … Chương trình thực thi Windows biên dịch dạng file có đuôi EXE Linux biên dịch dạng file có đuôi ELF, trước chương trình chạy Windows muốn chạy hệ điều hành khác Linux chẳng hạn phải chỉnh sửa biên dịch lại Ngôn ngữ lập trình Java đời, nhờ vào máy ảo Java mà khó khăn nêu khắc phục Một chương trình viết ngôn ngữ lập trình Java biên dịch mã máy ảo java (mã java bytecode) Sau máy ảo Java chịu trách nhiệm chuyển mã java bytecode thành mã máy tương ứng Sun Microsystem chịu trách nhiệm phát triển máy ảo Java chạy hệ điều hành kiến trúc CPU khác Quá trình thông dịch: Java ngôn ngữ lập trình vừa biên dịch vừa thông dịch Chương trình nguồn viết ngôn ngữ lập trình Java có đuôi *.java Trước tiên, tập tin Java (chứa mã nguồn java) biên dịch thành tập tin có đuôi *.class (chứa mã bytecode – định dạng sau biên dịch từ mã nguồn) sau trình thông dịch thông dịch thành mã máy tương ứng với tảng cài đặt máy ảo Java Dịch chạy chương trình Java: Giả sử có đoạn mã sau: /*Viết chương trình in dòng HelloWorld lên hình Console*/ class HelloWorldApp{ public static void main(String[] args){ //In dong chu “HelloWorld” System.out.println(“Hello World!!!”); } } Lưu lại với tên HelloWorldApp.java sau tiến hành dịch chạy sau: - Mở cửa sổ Command Prompt - Chuyển đến thư mục chứa file java - Gọi lệnh javac để compile mã nguồn thành mã bytecode: HelloworldApp.java - Gọi lệnh java để thực thi chương trình: java HelloworldApp javac Nguy bị lộ mã nguồn chương trình Java Trong phát triển phần mềm, java môi trường mạnh để xây dựng ứng dụng Với ngôn ngữ java phát triển nhiều loại ứng dụng như: applet (để nhúng trang HTML), ứng dụng console (chạy dạng hình console), ứng dụng đồ họa người dùng (application GUI), applet (các chương trình web server) hay ứng dụng chạy điện thoại di động (J2ME), … Trong ứng dụng chứa nhiều thuật toán quan trọng mấu chốt, chìa khóa thành công phần mềm Khi công ty đối thủ cạnh tranh luôn mong muốn nắm bắt thuật toán cốt lõi phần mềm đó, họ tìm cách lấy mã nguồn chương trình Hơn nữa, ứng dụng thuật toán có phần liệu quan trọng (ví dụ thông tin truy cập vào server data, hay resource bên ứng dụng, …) Việc có liệu hữu ích công ty đối thủ Vậy để có thuật toán, liệu quan trọng họ phải làm nào? Một cách thức hữu hiệu dịch ngược ứng dụng để thu mã nguồn, từ họ có cần Một ứng dụng viết Java, chuyển giao ứng dụng cho khách hàng chuyển cho họ file sau biên dịch từ mã nguồn java thành mã bytecode (các file có đuôi class) Ứng dụng thông dịch thành mã máy thích hợp để thực thi thông qua máy ảo Java (Java Virtual Machine – JVM) cài đặt máy người dùng Các file class hoàn toàn che giấu người dùng, họ đọc hiểu file biên dịch Tuy nhiên, với trợ giúp công cụ dịch ngược (decompiler tools) hoàn toàn dịch ngược từ mã bytecode thành mã nguồn java ban đầu Giả sử có chương trình java đơn giản sau: import java.io.*; class Demo { public static void main(String args[]) throws Exception { int size; InputStream f = new FileInputStream("filedemo.txt"); System.out.println("Bytes available to read:"+ (size = f.available())); char str[] = new char[300]; for(int count = 0;count < size;count++) { str[count] = ((char)f.read()); System.out.print(str[count]); } System.out.println(""); f.close(); } } Lưu lại thành file Demo.java Biên dịch file Demo.java ta thu file Demo.class file chữa mã bytecode chương trình, câu lệnh sau: javac Demo.java Sử dụng công cụ dịch ngược Java decompiler ta thu kết sau: Như kỹ thuật dịch ngược ta hoàn toàn thu mã nguồn chương trình, từ nắm bắt thuật toán liệu ứng dụng Hiện có nhiều công cụ hỗ trợ việc dịch ngược mã nguồn ứng dụng từ mã bytecode Java decompiler tool dịch ngược gọn nhẹ hoàn toàn miễn phí phổ biến lĩnh vực Với công cụ thực dịch ngược ứng dụng với cấu trúc package phức tạp, kết thu gần tương đồng với mã nguồn gốc ứng dụng CHƯƠNG 2: KỸ THUẬT DỊCH NGƯỢC MÃ NGUỒN CHƯƠNG TRÌNH JAVA Cơ sở việc dịch ngược Trong môi trường lý tưởng, việc dịch ngược mã nguồn không cần thiết, nhà phát triển phần mềm ý thức làm tốt tài liệu thiết kế Tuy nhiên thực tế có số trường tình việc dịch ngược cần thiết hữu dụng:  Khôi phục lại mã nguồn chẳng may bị  Muốn học cách cài đặt thuật toán đặc trưng hay bí  Khắc phục cố, lỗi ứng dụng hay thư viện mà tài liệu thiết kế tốt  Khắc phục lỗi khẩn cấp mã nguồn bên thứ ba mà tay mã nguồn  Học cách bảo vệ mã nguồn để tránh bị đánh cắp Việc dịch ngược mang lại mã nguồn chương trình từ mã bytecode Đây trình đảo ngược trình biên dịch, trình thực mã bytecode có cấu trúc chuẩn có tài liệu đặc tả tốt Ngôn ngữ Java thiết kế với khả thực thi cách linh hoạt thông minh Mã nguồn chương trình biên dịch sang định dạng bytecode – độc lập với tảng, tức thực thi tảng nào, máy tính mà không cần viết lại mã nguồn, không cần chuyển đổi mã bytecode, mã bytecode lưu trữ class file Mã bytecode biểu diễn trung gian mã nguồn chương trình không mã hóa cho tảng xác định Tức là, trình biên dịch tối ưu hóa mã nguồn cho phần cứng xác định, mã bytecode phải thông dịch sang mã máy để thực thi thông tin mức cao phải đính kèm với mã nguồn để phục vụ cho trình thông dịch Trong Java, trình thông dịch thực máy ảo Java (Java Virtual Machine – JVM) JVM máy trừu tượng, hiểu thực thi mã bytecode máy thật JVM phải thực thi tảng mà người dùng muốn chạy chương trình Java đó, phải đặc tả cách dễ hiểu Java bytecode mã hóa cách đơn giản, không tối ưu, chứa đựng nhiều thông tin mức cao Việc lưu giữ thông tin mức cao trình thực thi mã bytecode máy tính khác nhau, tảng khác nên định dạng class file đơn giản, rõ ràng, che giấu tảng Mã bytecode không tối ưu nên biểu diễn đơn giản hơn, rõ ràng Mã bytecode độc lập kiến trúc, chứa nhiều thông tin mã nguồn Do đó, từ mã bytecode dễ dàng dịch ngược thành mã nguồn java ban đầu Dịch ngược chương trình Java Xuất phát từ tình cần có mã nguồn từ mã bytecode nêu phần 1, nhà phát triển môi trường Java cung cấp công cụ dịch ngược mã nguồn, có tên javap cài đặt sẵn JDK (Java Development Kit) Java Cú pháp: javap [options] tên_lớp Trong đó: options tùy chọn lệnh javap, ví dụ:     help: hiển thị thông báo hỗ trợ sử dụng lệnh javap public: hiển thị lớp, thành phần public protected: hiển thị lớp, thành phần protected p: hiển thị tất lớp, thành phần Giả sử có chương trình Java thực việc hiển thị dòng chữ lên hình, HelloworldApp.java sau: public class HelloWorldApp { public static void main(String[] args) { // TODO code application logic here System.out.println(" Hello world!!!"); } } Sau biên dịch ta thu file HelloworldApp.class chứa mã bytecode chương trình Đây định dạng không đọc mã nguồn thông thường, thông dịch sang mã máy máy ảo java (JVM) Sử dụng lệnh javap dịch ngược mã bytecode ta thu mã nguồn chương trình sau: 10 Việc thay định danh loại bỏ khối lượng lớn thông tin quan trọng Thực tế kỹ thuật rối mã hiệu Ví dụ, tên phương thức thường lưu giữ thông tin rõ ràng, súc tích ý nghĩa hàm getName(), getConnection(),… Khi ta thực thay tên phương thức chuỗi ngẫu nhiên rõ ràng làm che giấu ý nghĩa phương thức mà không ảnh hưởng đến hoạt động bên chúng Kỹ thuật thực việc thay tên lớp, phương thức hay thuộc tính nơi có thể, tức có ngoại lệ mà thay định danh Để không làm phá vỡ chế bên script file – thành phần sử dụng để khởi đầu chương trình định danh Main class giữ nguyên, thể phương thức run() cài đặt lớp kế thừa từ java.lang.Thread không thay đổi tên định danh Ngoài ra, chương trình giả định không sử dụng tham chiếu java cho phép tải động lớp hay gọi phương thức chạy nên việc thay tên gây lỗi Các định danh thay chuỗi sinh ngẫu nhiên Chuỗi tên thay sinh ngẫu nhiên từ ba ký tự sau: (S, 5, $), (l, 1, I) ( _ ) Các ký tự sử dụng ký tự có đặc điểm nhận diện tương đồng nhau, khó phân biệt chúng nên sinh ngẫu nhiên tên trở nên khó đọc cách tự nhiên  S, 5, $: gồm ký tự S hoa, số ký tự dollar Bộ ký tự giống cách hiển thị  l, 1, I: ký tự gồm l thường, số ký tự I hoa Bộ ký tự khó phân biệt, đặc biệt tùy loại font chúng giống  Ký tự _: ký tự gạch chân ( _ ) Việc sử dụng ký tự gạch chân giúp cho việc tạo tên trở nên khó phân biệt biến có ký tự gạch chân với biến có ký tự gạch chân Đặc biệt có nhiều font chữ ký tự gạch chân liên tiếp nhìn giống đường kẻ liền nên khó phân biệt 28 Giải thuật sinh chuỗi tên ngẫu nhiên: Giải thuật: createNewName(int length, int n, set chars) Input: số nguyên length giá trị độ dài cho trước để sinh tên ngẫu nhiên, n số lần lặp sinh tên chars tập ký tự cho trước Output: trả chuỗi ngẫu nhiên 1: Khởi tạo: string name = “”; 2: Lặp 3: For i=1 to n 4: name = “”; 5: For j= to length 6: 7: name += random(chars); if( name is not exist) return name; 8: End for 9: length++; GiảiKết thuật thực hiệnlặp sinh ngẫu nhiên chuỗi với độ dài cho trước length Nếu 10: thúc vòng sau n lần thử mà chưa tìm chuỗi tên thực tăng độ dài lên tiếp tục lặp lại trình sinh chuỗi ngẫu nhiên với độ dài Quá trình lặp dừng lại tìm chuỗi tên thay Trong hầu hết trường hợp, tên sinh ngắn tên ban đầu Mỗi lập trình viên thường có xu hướng đặt tên lớp, phương thức hay thuộc tính có ý nghĩa, phản ánh súc tích chức lớp, phương thức nên tên ban đầu thường dài tên sinh thay Chính kích thước mã nguồn ứng dụng giảm đáng kể trình biên dịch hay thực thi hiệu 2.2 Kỹ thuật xáo trộn liệu (data obfuscation) 2.2.1 Thay giá trị trường tĩnh (static fields) 29 Các liệu xuất trực tiếp mã nguồn chương trình, nơi mà chúng sử dụng, gọi hard code mã nguồn Điều phản ánh rõ ràng sử dụng nào, đâu chương trình Do dễ để khai thác ý nghĩa suy đoán ý nghĩa mã nguồn chương trình Trong java, giá trị xuất trực tiếp mã nguồn chương trình thực chúng lại lưu trữ tách biệt mã bytecode Mỗi class file mà sử dụng liệu liệu lưu constant pool, tách biệt với mã nguồn Các truy cập thông qua index constant pool thông qua lệnh ldc Các giá trị khác thuộc tính lớp (class fields) dùng để lưu trữ giá trị (được gán khởi tạo lớp), truy cập thông qua tên trường không truy cập trực tiếp qua index Phương pháp xáo trộn liệu làm để che dấu không xuất trực tiếp nơi chúng sử dụng mã nguồn chương trình chương trình bị dịch ngược Một kỹ thuật đơn giản dễ dàng để làm việc lưu trữ liệu trường tĩnh lớp Khi đó, thể số bên mã nguồn thay tham chiếu đến trường tĩnh lưu giá trị số tương ứng 2.2.2 Thay biểu thức toán học phép dịch bit Các biểu thức số học sử dụng để thực tính toán phần mềm, chúng phần quan trọng thuật toán chứa đựng nhiệu thông tin cốt yếu thuật toán Mỗi biểu thức số học cách biểu diễn thông thường chúng biểu diễn thông qua phép toán dịch bit Cách biểu diễn làm tăng hiệu suất chương trình thực thi mà ẩn biểu diễn biểu thức số học chúng trở nên rắc rối hơn, khó đọc Cụ thể thay phép toán nhân chia phép toán dịch bit trái phải tương ứng Giả sử cần tìm biểu diễn phép dịch bit biểu thức v*C (tương tự tình v/C), v biến C số Bước 1: Chúng ta phân tích C thành số nguyên i lớn cho thỏa mãn: i < C i lũy thừa 2, tức i = 2s, với s = floor(log2C) Bước 2: Tính phần dư r = C – i Khi đó, biểu thức v*C = v*2s + v*r = v[...]... đề bảo vệ mã nguồn chống việc lấy cắp mã nguồn hay thay đổi mã nguồn là điều rất có ý nghĩa Việc dịch ngược đối với chương trình Java là không thể ngăn cản, tuy nhiên chúng ta có thể sử dụng kỹ thuật rối mã để sau khi dịch ngược cũng không thể có được mã nguồn gốc Chương 3 sẽ trình bày chi tiết về kỹ thuật rối mã (Obfuscation techniques) 14 CHƯƠNG 3: NGHIÊN CỨU KỸ THUẬT BẢO VỆ MÃ NGUỒN ỨNG DỤNG JAVA. .. nhằm bảo vệ mã nguồn quan trọng của ứng dụng – kỹ thuật xáo trộn mã nguồn chương trình (Java Obfuscation) 25 2 Sử dụng kỹ thuật Obfuscation Như chúng ta đã biết, một chương trình java sau khi được cài đặt thì mã nguồn ứng dụng sẽ được lưu trong các tập tin java Các tập tin này sẽ được biên dịch thành mã bytecode được lưu trữ trong các tập tin class trước khi chúng được thông dịch từ mã bytecode sang mã. .. hiểu được ý nghĩa của mã nguồn chương trình Như mô hình được chỉ ra dưới đây, mã nguồn gốc của chương trình sẽ được thực hiện obfuscation trước khi được biên dịch ra mã bytecode Như vậy, nếu có bị dịch ngược thì hacker cũng chỉ thu được mã nguồn đã bị xáo trộn, đây là mã nguồn rất khó hiểu so với mã nguồn gốc Từ đó làm giảm nguy cơ bị lộ mã nguồn chương trình 26 Các kỹ thuật làm rối mã nguồn (Obfuscation)... việc bảo vệ mã nguồn chống sự đánh cắp trở nên hết sức cấp thiết đối với mỗi công ty sản xuất phần mềm Mỗi ứng dụng Java sẽ được biên dịch sang mã bytecode (được chứa trong các file class) trước khi chúng được thông dịch sang mã máy để thực thi Như đã đề cập trong chương 2, ứng dụng java ở dạng mã bytecode rất dễ dàng để dịch ngược để thu được mã nguồn Chính vì vậy, trong chương này chúng tôi sẽ trình. .. điều khiển chương trình 2.3.1 Chèn thêm mã Kỹ thuật obfuscation nhằm mục đích làm cho mã nguồn chương trình trở nên rối ren hơn, khó đọc hiểu hơn khi nó bị dịch ngược Với kỹ thuật chèn thêm mã, từ một khối mã nguồn S = S1; S2; …; Sn chúng ta sẽ chèn thêm vào đâu đó phù hợp một đoạn mã nhằm mục đích làm thay đổi cấu trúc chương trình sao cho không làm ảnh hưởng đến luồng logic thực hiện của khối mã ban... khi nào, ở đâu trong chương trình Do đó rất dễ để khai thác ý nghĩa của hằng và suy đoán được ý nghĩa của mã nguồn chương trình Trong java, các hằng giá trị xuất hiện trực tiếp trong mã nguồn chương trình nhưng thực sự chúng lại được lưu trữ tách biệt trong mã bytecode Mỗi class file mà sử dụng các hằng dữ liệu thì các hằng dữ liệu đó được lưu trong một constant pool, tách biệt với mã nguồn Các hằng đó... tượng đang tồn tại trên một máy ảo Java khác (JVM) 1.2.1 Kiến trúc RMI Kiến trúc của chương trình RMI được mô tả qua hình vẽ sau: Chương trình Server Đường logic Chương trình Client Skeleton Stub Tầng tham chiếu từ xa Tầng tham chiếu từ xa Tầng giao vận Network Tầng giao vận Trong đó:  Server: là chương trình cung cấp các đối tượng có thể gọi từ xa  Client: là chương trình có tham chiếu đến các phương... cụ này chính là sự phát triển từ công cụ cơ sở javap như đã trình bày ở trên bằng cách phân tích thông tin từ mã bytecode để dựng ngược mã nguồn hoàn chỉnh của chương trình Giả sử chúng ta có một ứng dụng java J2ME thực hiện tính toán và hiển thị lịch âm – dương, trong đó có phương thức convertSolar2Lunar chuyển đổi ngày dương lịch sang ngày âm lịch, có mã nguồn gốc như sau: public static int[] convertSolar2Lunar(int.. .Mã nguồn thu được ở trên về cơ bản đã phản ánh được các thành phần trong một lớp và một phần mã bytecode các câu lệnh của từng phương thức Từ mã bytecode ở trên người ta có thể dựng lại được mã nguồn hoàn chỉnh của chương trình java gốc Hiện nay có rất nhiều công cụ thương mại cũng như miễn phí, cho phép dịch ngược mã nguồn hoàn chỉnh Tiêu biểu là hai công... thông tin quan trọng Khi biên dịch chương trình, mã nguồn được biên dịch ra mã bytecode và sau đó thông dịch ra mã máy để thực thi Trong quá trình đó, Java đã lưu giữ một lược đồ định danh (trong mã bytecode) để phục vụ cho việc debug, báo cáo ngữ nghĩa của ngoại lệ khi nó xảy ra hay một số định danh được yêu cầu để thực thi chương trình 27 Việc thay thế các định danh có thể loại bỏ được một khối lượng

Ngày đăng: 22/09/2016, 22:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan