当前位置: 首页 > 后端技术 > Node.js

关于Javascript混淆和反混淆的那些事

时间:2023-04-03 10:56:29 Node.js

和软件加解密一样,javascript混淆和反混淆属于同一类。掌握了棍子,但瞄准了院子。没有永恒的黑色,也没有永恒的白色。一切都是资本市场推动的,现在流行你能解决什么问题的概念。那么市场能容纳多少利益相关者才能解决这个问题。JS没有秘密。其实我并不认同javascript的hash混淆处理。首先,它会降低运行速度,其次,它体积庞大。前端JS代码可用,天生就被赋予了“开源”的属性,可以在chromedevTools下查看。JS不可压缩混淆完全违反了前端优化准则。目前网上能搜到的JS混淆工具无外乎以下几种:eval混淆,这也是最早的JS混淆加密,据说第一天就破解了,修改代码,并且警报可以被破解。这种方法从出生之日起就失去了意义。其实JS加密(混淆)是相对于可读性而言的。其实真正有意义的是压缩式混淆uglify,可以减轻重量和可读性。但是也不排除有一些商业源码使用hash类型来混淆源码,比如miniui使用的JSA加密,fundebug使用的javascript-obfuscator。下面的代码说明了JSA加密和javascript-obfuscator的区别:要混淆的代码:functionlogG(message){console.log('\x1b[32m%s\x1b[0m',message);}functionlogR(message){console.log('\x1b[41m%s\x1b[0m',message);}logG('logR');logR('logG');JSA加密混淆函数o00($){console.log("\x1b[32m%s\x1b[0m",$)}functiono01($){console.log("\x1b[41m%s\x1b[0m",$)}o00("logR");o01("logG")然后是美化器:functiono00($){console.log("\x1b[32m%s\x1b[0m",$)}functiono01($){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=函数(_0x2d8f05,_0x4b81bb){_0x2d8f05=_0x2d8f05-0x0;var_0x4d74cb=_0xd6ac[_0x2d8f05];返回_0x4d74cb;};函数logG(_0x4f1daa){console[_0x5b26('0x0')]('[32m%s[0m',_0x4f1daa);}函数logR(_0x38b325){console[_0x5b26('0x0')](_0x5b26('0x1'),_0x38b325);}logG('logR');logR(_0x5b26('0x2'));再美化一下:var_0xd6ac=['[41m%s[0m','logG','log'];(函数(_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];返回_0x4d74cb;};函数logG(_0x4f1daa){控制台[_0x5b26('0x0')]('[32m%s[0m',_0x4f1daa);}函数logR(_0x38b325){控制台[_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){_var0x2d8f05=_0x2d0f0;7_0xd4_0xd6ac[_0x2d8f05];返回_0x4d74cb;};通过以上发现,我们可以将JS混淆归为三类,分别是eval类型、hash类型和压缩类型。压缩类型是前端性能优化的常用工具,以uglify为代表。常用的前端压缩优化工具:JavaScript:babel-minifyterseruglify-jsuglify-esGoogleClosureCompilerYUICompressorCSS:PostCSSclean-cssCSSOYUICompressorHTML:html-minifier从工作流(workflow)来看,无论是webpack还是gulp,最流行的工具对于javascript是uglify。对应的反混淆工具:eval对应的反混淆工具可以随便百度搜索一下,比如jspackerJSA对应的反混淆工具unjsajavascript-obfuscator对应的反混淆工具crack。混淆策略其实是按照生成代码的规则写的,无非是观察特征分析,再观察特征分析,不断调整。这一切都是手工完成的。一点难度都没有,有的是耐心。比如javascript-obfuscator对应的反混淆工具,可以分解成N个因素的问题:如何查询函数作用域?预执行变量替换可能的类型?...喜欢:var_0xd6ac=['[41m%s[0m','logG','log'];(function(_0x203a66,_0x6dd4f4){var_0x3c5c81=function(_0x4f427c){while(--_0x4f427c){-;var_0x4d74cb=_0xd6ac[_0x2d8f05];return_0x4d74cb;};functionlogG(_0x4f1daa){console[_0x5b26('0x0')]('[32m%s[0m',_0x4f1daolea);}bcon函数logR(3_0x38)[_0x5b26('0x0')](_0x5b26('0x1'),_0x38b325);}logG('logR');logR(_0x5b26('0x2'));恢复到函数logG(message){console.log('\x1b[32m%s\x1b[0m',消息);}functionlogR(消息){console.log('\x1b[41m%s\x1b[0m',消息);}logG('logR');logR('logG');第一步要知道字典函数,然后执行字典函数_0x5b26('0x0')恢复log,就好办了,就是写代码。比如https://github.com/jscck/crack.js/blob/master/crack.js恢复后如何重构代码,那你就得知道生成代码之前用什么工具打包webpack?或者?比如webpack的各种包头包尾https://webpack.js.org/config...(functionwebpackUniversalModuleDefinition(root,factory){if(typeofexports==='object'&&typeofmodule==='object')module.exports=factory();elseif(typeofdefine==='function'&&define.amd)define([],factory);elseif(typeofexports==='object')exports['MyLibrary']=factory();elseroot['MyLibrary']=factory();})(typeofself!=='undefined'?self:this,function(){return_entry_return_;});可能会涉及到JS语法解释器,AST抽象语法树目前涉及到JS语法解释器,AST抽象语法树的功能有:prepack、esprima、babel或者你可以阅读《编程语言实现模式》,其中涉及到antlr4。当然也可以使用esprima等工具来做反混淆,只是工作量大了点,值不值得的问题。对于未来JS商业源码加密的方向可能是webassembly,先在服务端编译成wasm,源码可以真正闭源。有人的地方就有方法,混乱的地方就有解惑。目前机器学习编程响应的去混淆工具也做得相当不错,比如MachineLearningforProgramming产品nice2predict,jsnice...查看https://www.sri.inf.ethz.ch/r...扩展参考AST抽象语法树为什么要讲AST抽象语法树,因为你可以input->ast->outputAnything。比如你jsx把小程序的模板语法进行了转换,这样就可以使用react语法来写小程序了,比如太郎。mpvue、wepy、postcss……这些都是通过AST构建改造的工具,es6->es5,babel都使用了AST。AST抽象语法树的大致流程:输入生成AST树,然后通过AST类型断言进行相应的转换http://esprima.org/demo/parse...反编译工具全集小程序https://github.com/qwerty4721...推荐.Net、C#四大反编译工具https://www.cnblogs.com/ldc21...2018年支持java8的Java反编译工具汇总https://blog.csdn.net/yannqi/...原创文本:http://blog.w3cub.com/blog/20...