首頁  >  文章  >  web前端  >  Javascript混淆與解混淆的詳細介紹(附程式碼)

Javascript混淆與解混淆的詳細介紹(附程式碼)

不言
不言轉載
2019-04-02 10:28:0310290瀏覽

這篇文章帶給大家的內容是關於Javascript混淆與解混淆的詳細介紹(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

就像軟體加密與解密一樣,javascript的混淆與解混淆同屬於同一個範疇。道高一尺,魔高一丈。沒有永恆的黑,也沒有永恆的白。一切都是資本市場驅動行為,現在都流行你能為人解決什麼問題,這個概念。那麼市場究竟能容納多少個能解決這種問題的利益者。 JS沒有秘密。

其實本人不贊成javascript進行hash混淆處理,一拖慢運行時速度,二體積大。 JS程式碼前端可獲取,天生賦予「開源」屬性,都可以在chrome devTools下查看。 JS非壓縮性混淆完全違法前端最佳化準則。

目前網路上可以搜尋的JS混淆工具不外乎以下幾種:

eval混淆,也是最早JS出現的混淆加密,據說第一天就被破解,修改一下程式碼,alert一下就可以破解了。這種方法從出生的那天就失去了意義。其實JS加密(混淆)是相對於可讀性而言的,其實真正有意義的就是壓縮型混淆uglify這一類,即可減少體重,也可減少可讀性。

但是,也不能排除部分商業原始碼使用hash類型混淆原始碼,例如 miniui 使用的JSA加密, fundebug使用的javascript-obfuscator。

下面透過程式碼來說明JSA加密和javascript-obfuscator 的差異:

#要混淆的程式碼:

function logG(message) {
  console.log('\x1b[32m%s\x1b[0m', message); 
}
function logR(message) {
  console.log('\x1b[41m%s\x1b[0m', message); 
}
logG('logR');
logR('logG');

透過JSA加密混淆後產生的程式碼

function o00($){console.log("\x1b[32m%s\x1b[0m",$)}function o01($){console.log("\x1b[41m%s\x1b[0m",$)}o00("logR");o01("logG")

然後再beautifier一下:

function o00($) {
  console.log("\x1b[32m%s\x1b[0m", $)
}

function o01($) {
  console.log("\x1b[41m%s\x1b[0m", $)
}
o00("logR");
o01("logG")

可以發現,其實沒有做什麼什麼修改,只是做了一些變數替換。想還原也比較簡單的。這裡就不拿它來做代表,也沒有什麼人用。

透過ja​​vascript-obfuscator混淆後產生的程式碼

var _0xd6ac=['[41m%s[0m','logG','log'];(function(_0x203a66,_0x6dd4f4){var _0x3c5c81=function(_0x4f427c){while(--_0x4f427c){_0x203a66['push'](_0x203a66['shift']());}};_0x3c5c81(++_0x6dd4f4);}(_0xd6ac,0x6e));var _0x5b26=function(_0x2d8f05,_0x4b81bb){_0x2d8f05=_0x2d8f05-0x0;var _0x4d74cb=_0xd6ac[_0x2d8f05];return _0x4d74cb;};function logG(_0x4f1daa){console[_0x5b26('0x0')]('[32m%s[0m',_0x4f1daa);}function logR(_0x38b325){console[_0x5b26('0x0')](_0x5b26('0x1'),_0x38b325);}logG('logR');logR(_0x5b26('0x2'));

再beautifier一下:

var _0xd6ac = ['[41m%s[0m', 'logG', 'log'];
(function(_0x203a66, _0x6dd4f4) {
  var _0x3c5c81 = function(_0x4f427c) {
    while (--_0x4f427c) {
      _0x203a66['push'](_0x203a66['shift']());
    }
  };
  _0x3c5c81(++_0x6dd4f4);
}(_0xd6ac, 0x6e));
var _0x5b26 = function(_0x2d8f05, _0x4b81bb) {
  _0x2d8f05 = _0x2d8f05 - 0x0;
  var _0x4d74cb = _0xd6ac[_0x2d8f05];
  return _0x4d74cb;
};

function logG(_0x4f1daa) {
  console[_0x5b26('0x0')]('[32m%s[0m', _0x4f1daa);
}

function logR(_0x38b325) {
  console[_0x5b26('0x0')](_0x5b26('0x1'), _0x38b325);
}
logG('logR');
logR(_0x5b26('0x2'));

這個複雜得多,但是分析一下你會發現,其實多了一個字典,所有方法變量,都有可能存在字典中,調用時先調用字典還原方法名變量再執行。
其實入口都是變數的規則。

字典函數:

var _0xd6ac = ['[41m%s[0m', 'logG', 'log'];
(function(_0x203a66, _0x6dd4f4) {
  var _0x3c5c81 = function(_0x4f427c) {
    while (--_0x4f427c) {
      _0x203a66['push'](_0x203a66['shift']());
    }
  };
  _0x3c5c81(++_0x6dd4f4);
}(_0xd6ac, 0x6e));
var _0x5b26 = function(_0x2d8f05, _0x4b81bb) {
  _0x2d8f05 = _0x2d8f05 - 0x0;
  var _0x4d74cb = _0xd6ac[_0x2d8f05];
  return _0x4d74cb;
};

透過以上發現,我們可以把JS混淆歸結為三類,分別是 eval類型,hash類型,壓縮類型。而壓縮類型,是目前前端效能最佳化的常用工具,以uglify為代表。

常用的前端壓縮最佳化工具:

JavaScript:

  • babel-minify
  • terser
  • uglify-js
  • uglify-es
  • Google Closure Compiler
  • YUI Compressor

CSS:

    ##PostCSS
  • clean-css
  • CSSO
  • YUI Compressor
#HTML:

##html-minifier

從工具流(workflow) 來看,不論是webpack 還是gulp ,目前javascript最受歡迎工具還是uglify。

對應的解混淆工具:
  • eval對應的解混淆工具, 隨便百度都可以搜尋到,如jspacker
  • JSA對應的解混淆工具unjsa
  • javascript-obfuscator對應的解混淆工具crack.js
  • 壓縮類型uglify對應的工具UnuglifyJS,線上版jsnice

解混淆策略其實是依據生成程式碼規律編寫,不外乎觀察特徵分析,再觀察特徵分析,不斷調整。都是手辦眼見功夫。


都沒有什麼難度可言,有的就是耐性。例如javascript-obfuscator對應的解混淆工具可以

分解為N因子問題:


如何查詢function的作用域?
預執行變數替換可能存在類型?

...

如:

var _0xd6ac = ['[41m%s[0m', 'logG', 'log'];
(function(_0x203a66, _0x6dd4f4) {
  var _0x3c5c81 = function(_0x4f427c) {
    while (--_0x4f427c) {
      _0x203a66['push'](_0x203a66['shift']());
    }
  };
  _0x3c5c81(++_0x6dd4f4);
}(_0xd6ac, 0x6e));
var _0x5b26 = function(_0x2d8f05, _0x4b81bb) {
  _0x2d8f05 = _0x2d8f05 - 0x0;
  var _0x4d74cb = _0xd6ac[_0x2d8f05];
  return _0x4d74cb;
};

function logG(_0x4f1daa) {
  console[_0x5b26('0x0')]('[32m%s[0m', _0x4f1daa);
}

function logR(_0x38b325) {
  console[_0x5b26('0x0')](_0x5b26('0x1'), _0x38b325);
}
logG('logR');
logR(_0x5b26('0x2'));
要還原成

function logG(message) {
  console.log('\x1b[32m%s\x1b[0m', message); 
}
function logR(message) {
  console.log('\x1b[41m%s\x1b[0m', message); 
}
logG('logR');
logR('logG');
第一步你總得知道字典函數,然後執行字典函數_0x5b26(' 0x0') 還原成log.


那麼就好辦了,寫程式的事。

如 https://github.com/jscck/crac...

還原後,如何重構程式碼,那麼你還得知道程式碼產生之前是透過什麼工具打包的webpack? 還是?


如webpack 的各種封裝頭和尾

https://webpack.js.org/config...

(function webpackUniversalModuleDefinition(root, factory) {
  if(typeof exports === 'object' && typeof module === 'object')
    module.exports = factory();
  else if(typeof define === 'function' && define.amd)
    define([], factory);
  else if(typeof exports === 'object')
    exports['MyLibrary'] = factory();
  else
    root['MyLibrary'] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
  return _entry_return_;
});
假如再深入一點,可能會涉及JS語法解釋器, AST抽象語法樹

目前涉及JS語法解釋器, AST抽象語法樹的功能如下:

prepack, esprima, babel

或可以閱讀《程式語言實作模式》,涉及antlr4。

當然也可以透過esprima等工具來做解混淆,只是工作量大一點,值不值的問題。

對於未來,JS商業原始碼加密的方向可能webassembly,先在服務端編譯成wasm,原始碼就能真正的閉源。

有人的地方就有路,有混淆的地方就有解混淆,目前機器學習程式設計回應的解混淆工具也做的相當出色,例如

Secure, Reliable, and Intelligent Systems Lab


Machine Learning for Programming 產品
nice2predict,jsnice ...

查看https://www.sri.inf.ethz.ch/r...###

拓展參考

AST抽象語法樹

為什麼要額外說AST抽象語法樹,因為你可以 input-> ast -> output Anything。

例如你jsx轉換小程式模版語法,這樣你就可以用react語法來寫小程序,如Taro。
mpvue, wepy, postcss … 這些都是透過AST進行建置轉換的工具,es6 -> es5, babel 都是使用AST。

AST抽象語法樹大致流程:

Input 產生AST tree

#然後透過AST類型斷言進行對應的轉換

##【相關推薦:

JavaScript影片教學

以上是Javascript混淆與解混淆的詳細介紹(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除