鐵人賽 Day 12 什麼是混淆?揭開程式碼迷霧的資安技術

本系列文章所討論的 JavaScript 資安與逆向工程技術,旨在分享知識、探討防禦之道,並促進技術交流。
所有內容僅供學術研究與學習,請勿用於任何非法或不道德的行為。
讀者應對自己的行為負完全責任。尊重法律與道德規範是所有技術人員應共同遵守的準則。
在資安逆向工程領域,除了需要面對加密演算法、驗證機制之外,「混淆」也是一道重要的障礙。
它的目的不是讓程式無法執行,而是讓程式碼對人類分析者與自動化工具更難以理解。
什麼是混淆?
在現代的資安攻防戰中,程式碼混淆用開發者用來保護智慧財產權和核心業務的重要手段之一。
混淆是透過多種技術,將原本可讀的程式碼轉換成,令人難以理解或是各種繞路,但是電腦執行卻正常且與未混淆時的功能相同。
是一種將原始程式碼轉換為功能相同但難以理解的形式的技術。
對於開發者,它是一種「保護智慧財產」或「提高逆向成本」的方法;對於攻擊者,它則是一道必須破解的迷霧。
為什麼需要混淆?
為了降低程式碼被逆向工程、竊取或未經授權修改的風險,必須採取防護措施。
這些保護不僅能守住商業邏輯與核心演算法,還能避免 API 金鑰等敏感資訊外洩。
特別是在 JavaScript 的中這點更顯重要,因為前端程式碼會完整暴露在使用者端安全挑戰更高。
混淆與加密的差異
混淆後的程式碼依然能執行但程式被刻意設計得難以理解。
但加密的程式碼在未解密前無法直接執行。
常見的混淆手法
變數與函式名稱混淆
將有意義的變數或函式庫變成毫無意義的文字、零寬字體、拉丁文、阿拉伯文...等,結合而成的奇怪文字。
控制流程扭曲
透過 if/else、switch 結構讓程式流程難以追蹤。
字串編碼與解碼
將程式裡的敏感字串用 Base64、Hex 或自定義編碼的方式隱藏。
死程式碼插入
故意放入永遠不會執行到的程式片段。
混淆的局限性
混淆能帶來一定的保護效果但並不能真正的防止攻擊,只能延緩攻擊者理解程式邏輯的時間。
對於解混淆技術純熟的人來說,最終仍能還原出程式的核心運作方式,然而混淆後的程式往往體積增大,會導致執行效能下降。
即便程式碼經過混淆,攻擊者仍能透過前幾篇介紹的方法動態觀察分析最終還原出原始邏輯。
程式碼混淆示意
變數與函式名稱混淆
原始程式碼
function add(a, b) {
return a + b;
}
let result = add(3, 5);
console.log(result);
混淆程式碼
function _0x1a2b(_0x3c4d, _0x5e6f) {
return _0x3c4d + _0x5e6f;
}
let _0x9f8e = _0x1a2b(3, 5);
console.log(_0x9f8e);
控制流程扭曲
原始程式碼
function isEven(num) {
if (num % 2 === 0) {
return true;
}
return false;
}
混淆程式碼
function isEven(_0x1a2b) {
switch (_0x1a2b % 2) {
case 0:
return true;
default:
return false;
}
}
字串編碼與解碼
原始程式碼
let message = "Hello World";
console.log(message);
混淆程式碼
let _0x2a3b = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
let msg = String.fromCharCode(..._0x2a3b);
console.log(msg);
死程式碼插入
原始程式碼
function multiply(a, b) {
return a * b;
}
混淆程式碼
function multiply(_0x1a2b, _0x3c4d) {
let useless = 12345 * 67890; // 無用計算
if (false) {
console.log("This will never run");
}
return _0x1a2b * _0x3c4d;
}
混淆是一種「拖延戰術」,對開發者而言是延緩程式被破解的手段,對分析者而言則是必須穿透的煙霧。
掌握混淆與去混淆的技巧,才能在資安逆向工程中更進一步。