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")
可以发现,其实没有做什么什么修改,只是做了一些变量替换。想还原也比较简单的。这里就不拿它来做代表,也没有什么人用。
通过javascript-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/crack.js/blob/master/crack.js
还原后,如何重构代码,那么你还得知道代码生成之前是通过什么工具打包的webpack? 还是?
如webpack 的各种封装头和尾
https://webpack.js.org/configuration/output/#expose-a-variable
(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抽象语法树的功能如下:
或者可以阅读《编程语言实现模式》,涉及到 antlr4。
当然也可以通过esprima等工具来做解混淆,只是工作量大一点,值不值的问题。
对于未来,JS商业源码加密的方向可能webassembly,先在服务端编译成wasm,源码就能真正的闭源。
有人的地方就有路,有混淆的地方就有解混淆,目前机器学习编程响应的解混淆工具也做的相当出色,比如
Machine Learning for Programming 产品
nice2predict,jsnice …
查看 https://www.sri.inf.ethz.ch/research/plml
拓展参考
AST抽象语法树
为什么额外说一下AST抽象语法树,因为你可以 input-> ast -> output Anything。
比如你jsx转换小程序模版语法,这样你就可以用react语法来写小程序,如Taro。
mpvue, wepy, postcss …… 这些都是通过AST进行构建转换的工具,es6 -> es5, babel 都是使用AST。
AST抽象语法树大致流程:
Input 生成 AST tree
然后通过AST类型断言进行相应的转换
反编译工具全集
小程序
https://github.com/qwerty472123/wxappUnpacker
推荐.Net、C# 逆向反编译四大工具利器
https://www.cnblogs.com/ldc218/p/8945892.html
2018年支持java8的Java反编译工具汇总
https://blog.csdn.net/yannqi/article/details/80847354
Javascript混淆与解混淆的那些事儿的更多相关文章
- apk反编译(6)ProGuard 工具 android studio版官方教程[作用,配置,解混淆,优化示例]
ProGuard In this document Enabling ProGuard (Gradle Builds) Configuring ProGuard Examples Decoding O ...
- 技术分享:几种常见的JavaScript混淆和反混淆工具分析实战【转】
信息安全常被描述成一场军备竞赛,白帽与黑帽,渗透测试者与黑客,善与恶,本文将聚焦这场永无止境决斗中的一个小点. HTML5 & JS 应用中充满着对输入进行验证/注入的问题,需要开发人员始终保 ...
- Android APK代码混淆与资源混淆详解,你确定不看?
APK的混淆分为资源混淆与代码混淆.一般大部分都使用两者结合.尤其是目前主流的应用. 其中的优点: 防止被恶意破解逆向分析 减少apk体积,也是瘦身的方法 代码可阅读性降低 其中的缺点: 调试不方便( ...
- 几种常见的JavaScript混淆和反混淆工具分析实战
几种常见的JavaScript混淆和反混淆工具分析实战 xiaix2016-03-05+8共1195751人围观 ,发现 5 个不明物体WEB安全 信息安全常被描述成一场军备竞赛,白帽与黑帽,渗透测试 ...
- javascript反混淆之packed混淆(二)
上次我们简单的入门下怎么使用html破解packed的混淆,下面看一个综合案例. 上次内容javascript反混淆之packed混淆(一) function getKey() { var aaaaf ...
- javascript反混淆之packed混淆(一)
javascript反混淆之packed混淆(一) 什么是JavaScript反混淆,在理解这个概念前我们先来看下什么是代码混淆,代码混淆,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理 ...
- JavaScript事件详解-jQuery的事件实现(三)
正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...
- JavaScript事件详解-Zepto的事件实现(二)【新增fastclick阅读笔记】
正文 作者打字速度实在不咋地,源码部分就用图片代替了,都是截图,本文讲解的Zepto版本是1.2.0,在该版本中的event模块与1.1.6基本一致.此文的fastclick理解上在看过博客园各个大神 ...
- JavaScript正则表达式详解(一)正则表达式入门
JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaScript正则表达式的用法进行了列表,希望 ...
随机推荐
- 洛谷P2196 挖地雷(dp)
题意 题目链接 Sol 早年NOIP的题锅好多啊.. 这题连有向边还是无向边都没说(害的我wa了一遍) 直接\(f[i]\)表示到第\(i\)个点的贡献 转移的时候枚举从哪个点转移而来 然后我就用一个 ...
- Linux下C语言操作MySQL数据库
MySQL是Linux系统下广泛使用的开源免费数据库,是Linux应用程序数据存储的首选. Ubuntu下安装 […]
- 寒假来了,阿里游戏云6000、20000元新春大礼,游戏开发的骚年们r u ready?
寒假来了,游戏开发的骚年们,r u ready? 亿元云计算基金.游戏云计算解决方案.尊享VIP服务,为你“三羊开泰”! 现在参与游戏云认证,即享6000元.2万元… 最高100万云基金!走你> ...
- ES6入门——函数的扩展
1.函数参数的默认值 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法.现在ES6可以为函数的参数添加默认值,简洁了许多. ES5 function show(a,b){ b = b ...
- jdk1.8 对数组及arrays类对数组的操作与增强
数组的初始化有两种方式 静态初始化: 初始化时由程序员显示置顶每个数组的初始值,由系统决定数组长度.如: int[] a1 = new int[] {1,2,3,4}; 动态初始化:初始化时由程序员只 ...
- [翻译]Elasticsearch重要文章之二:堆内存的大小和swapping
Elasticsearch默认安装后设置的内存是1GB,对于任何一个业务部署来说,这个都太小了.如果你正在使用这些默认堆内存配置,你的集群配置可能有点问题. 这里有两种方式修改Elasticsearc ...
- January 19 2017 Week 3 Thursday
What a man needs most is appreciated. 人性最深切的需求就是渴望别人的赞赏. Being appreciated by others is very importa ...
- 使用nodejs代码在SAP C4C里创建Individual customer
需求:使用nodejs代码在SAP Cloud for Customer里创建Individual customer实例. 代码: var createAndBind = require('../je ...
- Python模块(进阶3)
转载请标明出处: http://www.cnblogs.com/why168888/p/6411917.html 本文出自:[Edwin博客园] Python模块(进阶3) 1. python中模块和 ...
- HashMap 和 ConcurrentHashMap,Java1.8版本
1. HashMap Entry,一对kv就是一个Entry,还包括一些next指针,用来解决散列冲突. table,内部用来存储Entry的数组,resize时候table会成倍扩容. 容量,tab ...