的加密结果看jsjiami,一个简单的console.log("James"),加密后的结果居然是3K,可见加密已经转了。如果要手动解密一段真实的业务代码,应该会比较累,但本文不研究工作量问题,只是尝试手动解密,并向读者介绍分析方法和工具应用。同一句话在jsjiami中加密可能会有不同的结果。我相信这个工具中添加了随机因素。但是为了节省篇幅,这里就不贴出我实验用的加密结果了。一些代码片段将在分析期间发布。1.毫无疑问,第一步是可读性。如果要手动识别,首先需要对句子进行切分。幸运的是,美化(格式化)JS的工具还是很多的,随便找两个试试看哪个效果好。我这里使用的是浏览器插件FeHelper。然后我注意到所有的变量都改了名字,数字和字母读起来不舒服。所以你需要使用“重命名”重构工具来更改名称。这让VSCode可以毫无压力地去做。2.然后,分析2.1。看前两行var_0xodm="jsjiami.com.v6",_0x47c5=[_0xodm,"wrvCucKGS1U=","CGdK","jsQHMujiLamiSP.Vcom.lrtZMLzvQ6=="];这句话声明了两个变量,一个是明显是jsjiami的版本;另一个是一个数组,除了版本信息,内容估计是Base64的,我在网上试过用Base64解码,解决的是乱码,先放着吧,以后看看是什么。为了方便识别,可以重命名重构,顺便按照规范拆分声明:vartoolVersion="jsjiami.com.v6";varconstArray=[toolVersion,"wrvCucKGS1U=","CGdK","jsQHMujiLamiSP.Vcom.lrtZMLzvQ6=="];2.2.接下来是一个IIFE,IIFE的三个形参,顺便改个名字:p1,p2,p3。在IIFE中定义了一个本地函数,并将其重命名为localFunc1。函数定义好后,直接调用。经过检查,没有递归,所以相当于又一个IIFE。同样,改变它的5个参数也没有意义,但是名字很好认,结果:(function(p1,p2,p3){varlocalFunc1=function(lp1,lp2,lp3,p14,lp5){lp2=lp2>>0x8,lp5="po";var_0x1e174c="shift",_0x5428fe="push";if(lp2>p2^p3;}(constArray,0x1c7,0x1c700));2.2.1.杀死其中一个参数是一个注意事项。外层IIFE的p1是上面改名为constArray的数组。反正在范围之内。:将p1重命名为constArray,与外层数组同名,并删除外层IIFE2.2.2的第一个形参和实参。后面更改数据左右的操作既然我们已经知道constArray是一个数组,那么它作用于上面的所有属性应该都和数组有关。看看这几行代码,不难发现:lp5只参与了一个表达式,结果是"pop"var_0x1e174c="shift",_0x5428fe="push"这两个变量只作为常量使用,把var改成const让小编帮忙检查是否有写操作——结果当然是没有。不幸的是,VSCode没有提供内联重构工具,所以只能手动完成,直接用常量替换这两个变量。以_0x1e174c="shift"为例,先将"shift"(包括引号)复制到剪贴板,然后在_0x1e174c中多次使用Ctrl+D全选_0x1e174c,然后按Ctrl+V。以同样的方式处理_0x5428fe="push"。然后删除这两个声明。2.2.3.简化代码,越简单越好理解。然而,constArray["shift"]()似乎很不习惯。最好将其更改为constArray.shift()-这需要ESLint的帮助。将当前目录初始化为npm模块项目,安装并初始化eslint,然后在配置中添加一条规则:"dot-notation":"error"这时候VSCode会提示["shift"]isbetterwrittenindot符号。将鼠标移过去,使用快捷修复自动将所有[]调用更改为.电话。2.2.4.分析参数的作用接下来就很有意思了。再看localFunc1(++p2,p3)的调用,只传入了两个参数,所以除了刚才去掉的lp5外,形参lp3和lp4没有任何作用。以参数的作用,而是作为一个局部变量来使用。在这里你可以将它们从参数列表中删除,并使用let将它们定义为局部变量——当然,你做不做这一步并不重要。p2和p3的值是从外部IIFE传入的:(function(p2,p3){...}(0x1c7,0x1c700));乍一看像是变量,但仔细一看,都是以0x为前缀,显然是一个整数。p3后面比p2多了两个0。看localFunc1里面第一句是lp2=lp2>>0x8(记住lp2是传入的p3),这不就是去掉0x1c700后面的两个0变成0x1c7——现在lp2和p2的值就是一样。而在++p2中传入了lp1,所以现在lp1===lp2+1。这样就满足了if条件(lp2>(-0x2*_0x1f3b8d&0x6)):0x0){_0xad5277=_0x5b626.indexOf(_0xad5277);}return_0xcb4400;});}());第一句明显是找全局对象,相当于var_0xea3c63=globalThis的第二句先忽略,第三句很明显是看globalThis上有没有atob(),没有就给一个。由于atob()在大多数环境中都存在,所以不用担心它的内容。那么,这个IIFE就是为了保证atob()可用,所以直接delete就可以了。3.4.一个看起来比较有用的函数然后定义一个函数,去掉内容,看起来像这样:var_0xbe9954=function(_0x333549,_0x3c0fbb){...};getString.LaMLHS=_0xbe9954;通过后续调用使用它,应该是一个有用的功能。为了便于识别,将两个参数分别重命名为first和second。我们也提取出来复制到一个独立的.js文件中,发现没有遗漏变量,说明可以单独取出来分析,是一个工具函数。这个函数一开始定义了5个变量,暂时忽略,等用到再找。3.4.1.使用atob下面的代码是:let_0x2591ef="";//5个变量之一first=atob(first);对于(vari=0x0,len=first.length;i