JavaScript Obfuscation và Deobfuscation: Che giấu và giải mã mã nguồn

Giới thiệu

Trong thế giới lập trình web, đặc biệt là JavaScript, mã nguồn thường dễ dàng bị xem và sao chép. Để bảo vệ bản quyền hoặc giấu đi các thuật toán quan trọng, người ta sử dụng obfuscation (làm rối mã). Nhưng đi cùng đó, các chuyên gia bảo mật cũng cần deobfuscation (gỡ rối mã) để phân tích và hiểu code.

Thông thường, khi bị làm rối, mã sẽ biến thành một tập hợp các hàm và dòng vô nghĩa khó đọc, nhưng vẫn chạy chính xác như mã nguồn ban đầu.

Obfuscation là gì?

Obfuscation là quá trình biến đổi mã nguồn thành dạng khó đọc đối với con người, nhưng vẫn chạy đúng trên máy.

Kỹ thuật này được dùng bởi:

  • Nhà phát triển: để che giấu mã, bảo vệ ý tưởng không bị sao chép.

  • Hacker/malware author: để làm quá trình phân tích trở nên khó khăn hơn.

Ví dụ:

// Code gốc function add(x, y) { return x + y; } console.log(add(2, 3));

Sau khi obfuscate:

(function(_0x1a2b,_0x3c4d){return _0x1a2b+_0x3c4d;})(2,3);

Deobfuscation là gì?

Deobfuscation là việc áp dụng các phương pháp, công cụ để đưa đoạn mã đã bị làm rối trở lại gần dạng gốc, hoặc ít nhất là dễ đọc và dễ hiểu hơn.

Vì có nhiều phương pháp obfuscation, nên cũng có nhiều cách và công cụ deobfuscation với mức độ hiệu quả khác nhau.

Deobfuscation thường được sử dụng trong:

  • Phân tích mã độc: hiểu hành vi thực sự của đoạn script độc hại.

  • Thử nghiệm thâm nhập (pentest): tìm hiểu logic hoạt động của trang web và phát hiện lỗ hổng.

Ví dụ, từ đoạn mã obfuscate ở trên, sau khi deobfuscate ta có thể khôi phục:

function add(a, b) { return a + b; } console.log(add(2, 3));

Vì sao JavaScript thường bị obfuscate?

Một trong những ngôn ngữ dễ bắt gặp obfuscation nhất chính là JavaScript.
Nguyên nhân:

  • JavaScript được trình duyệt tải trực tiếp, dễ dàng truy cập và xem code.

  • Code thường chứa logic quan trọng, API call, key tạm thời.

Obfuscation giúp che giấu hoặc giảm rủi ro bị sao chép.

Ngoài ra, một số kỹ thuật (như loại bỏ khoảng trắng, comment, kết hợp chuỗi) còn giúp giảm dung lượng file, tăng tốc độ tải — tức vừa để làm rối, vừa tối ưu hiệu năng.

Các kỹ thuật Obfuscation phổ biến

1. Đổi tên biến và hàm

// Gốc let password = "1234"; // Obfuscate let _0x1a2b = "1234";

2. Nén code (minify)

// Gốc function greet(name) { return "Hello " + name; } console.log(greet("Alice")); // Sau khi nén function greet(n){return"Hello "+n}console.log(greet("Alice"));

3. Mã hóa chuỗi

// Gốc alert("Hello"); // Obfuscate eval(String.fromCharCode(97,108,101,114,116,40,34,72,101,108,108,111,34,41));

4. Chèn code thừa / điều kiện giả

if (true) { console.log("Run this"); } else { // đoạn này không bao giờ chạy console.log("Fake branch"); }

Công cụ Obfuscation phổ biến

Các kỹ thuật Deobfuscation

  1. Beautify code: format lại cho dễ đọc (Prettier, JSBeautifier).

  2. Đổi tên biến thành có ý nghĩa.

  3. Evaluate dần các hàm eval(), atob().

  4. Debug console để xem giá trị runtime.

Công cụ Deobfuscation phổ biến

Ví dụ thực tế

Code gốc

function greet(name) { return "Hello " + name; } console.log(greet("Alice"));

Sau khi Obfuscate (dùng javascript-obfuscator)

(function(_0x3b2d,_0x4c71){var _0x1e29=function(_0x1c5e){while(--_0x1c5e){_0x3b2d['push'](_0x3b2d['shift']());}};_0x1e29(++_0x4c71);}(_0x4c71,0x1f4));var _0x1e29=function(_0x3b2d,_0x4c71){_0x3b2d=_0x3b2d-0x0;var _0x1e29=_0x4c71[_0x3b2d];return _0x1e29;};function greet(_0xabc1){return 'Hello '+_0xabc1;}console['log'](greet('Alice'));

Sau khi Deobfuscate

function greet(name) { return "Hello " + name; } console.log(greet("Alice"));

Lưu ý quan trọng

  • Obfuscation không phải bảo mật tuyệt đối: nó chỉ tăng độ khó phân tích.

  • Không nên lưu thông tin nhạy cảm (password, secret key) trong code, ngay cả khi đã obfuscate.