菜鸟学Python编程AST抽象语法树-真要学ast

  工作中碰到一个网站需要过极验验证码,去年11月左右,当时一点js不会就妄想破解极验,结果当然是输的很惨。最后选择selenium。到了今年4月份左右js正则匹配多个字符串,因为破解的去哪儿的web的js,感觉懂了很多js逆向的知识,有点小膨胀,想重新挑战极验。竟然还真挑战成功了。

  多亏了蔡老板的AST教程让我事半功倍。看我也就图一乐,真要学ast还得看蔡老板。附上公众号名:菜鸟学Python编程

  AST抽象语法树,听这个名字觉得很牛皮,高端,其实也就那么回事,把他理解成一个json就行了,没有那么可怕。很多混淆、反混淆的工作都是通过AST来完成的。

  下面进入正题,我当时破解的时候,极验的fullpage版本还是8.9.3,今天打开网站一看,有8.9.5了,那我就直接搞最新的吧(有些网站应该还没上,不过都一样,猜测都应该是基于geetest6.0.9.js来的)

  正则表达式匹配多个任意字符_js正则匹配多个字符串_正则表达式匹配字符串中的字符

  直接开搞,把这串js格式化后,我们先找一下eval这个关键词(因为我一开始没找,后面反混淆完后发现还有eval里面的没反混淆,又要回过头来反混淆。所以最好是一开始先找出来,一起反混淆掉)

  正则表达式匹配字符串中的字符_js正则匹配多个字符串_正则表达式匹配多个任意字符

  很多这种类型的我们先去浏览器调试看下这是什么

  js正则匹配多个字符串_正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符

  都是一些代码,说明我们可以直接把得出的代码格式化后替换到js中。

  然后看到有很多unicode格式的编码,这种用ast一键去除。

  随便选中一个unicode编码,运行一下可以发现他的真实。

  在ast在线编辑网站上()可以看到unicode编码就是因为有extra这个属性,我们只需把这个属性删掉,就能展示原来的值了(16进制同理)

  正则表达式匹配字符串中的字符_正则表达式匹配多个任意字符_js正则匹配多个字符串

  导入依赖

  <pre class="code-snippet__js" data-lang="javascript">const parser = require("@babel/parser");//将JS源码转换成语法树的函数`const traverse = require("@babel/traverse").default;//遍历AST的函数const types = require("@babel/types");//操作节点的函数,比如判断节点类型,生成新的节点等:const generator = require("@babel/generator").default;//将语法树转换为源代码的函数`const fs = require('fs');//const fs = require('fs')</pre>

  <pre class="code-snippet__js" data-lang="typescript"> `const visitor = { StringLiteral: { enter: [replace_unicode]//遍历所有StringLiteral属性 }}; function replace_unicode(path){ delete path.node.extra;}var jscode = fs.readFileSync("fullpage8.9.5.js", { encoding: "utf-8"});let ast = parser.parse(jscode);traverse(ast,visitor);let {code} = generator(ast); fs.writeFile('fullpage8.9.5_1.js', code, (err)=>{});`</pre>

  删除raw属性,然后保存,验证一下unicode编码是否都被还原了

  正则表达式匹配字符串中的字符_js正则匹配多个字符串_正则表达式匹配多个任意字符

  只剩这些正则的pattern无法还原了。第一步反混淆就成功了。

  (这里AST替换unicode编码有点小问题,就是不能把中文的unicode编码转回去,这点我也还没搞清楚,碰到中文的unicode的话还是找个网站转码吧。)

  接下来通过调试可以发现出现了很多这种东西

  正则表达式匹配字符串中的字符_js正则匹配多个字符串_正则表达式匹配多个任意字符

  DAi其实就是个类似数组的东西,传入索引就返回值,

  EMf对代码功能上来说一点用没有,就是用来制造平坦化控制流的东西。

  我们现对DAI进行反混淆。

  把所有这种格式的还原成字符串

  <pre class="code-snippet__js" data-lang="css">AJgjJ.DAi(36)</pre>

  在AST网站上解析

  正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符_js正则匹配多个字符串

  思路就是这样。

  <pre class="code-snippet__js" data-lang="cs">function replace_DAi(path){` var node = path.node; if(node.callee == undefined || node.callee.property ==undefined ) return; if (node.callee.property.name == "DAi"){ let arg = node.arguments[0].value; let value = AJgjJ.DAi(arg); PathToLiteral(path,value) }}function PathToLiteral(path,value){ switch (typeof value) { case 'boolean': path.replaceWith(types.booleanLiteral(value)); break; case 'string': path.replaceWith(types.stringLiteral(value)); break; case 'number': path.replaceWith(types.numericLiteral(value)); break; default: console.log("出现其他类型" + value + "类型:" +typeof value); console.log(value); break }`}</pre>

  这里替换的时候需要类型判断,写了个通用的方法,如果出现其他类型,打印出来然后自行判断后写替换代码。

  DAi()类型的都成功替换了

  但是极验这里为了防止一键替换所有数组,这里做了个小处理。

  正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符_js正则匹配多个字符串

  出现很多这种代码

  给很多随机名称的变量赋值后,在通过这个变量去拿数组中的真实值。

  通过观察代码可以得出DVmS 和 EKsN 这两个位置的变量 就是用来赋值的功能。

  只需把这两个位置的所有变量的名字取出js正则匹配多个字符串,存到一个数组中,然后判断所有类似SQxP(1598)类型里面是否存在这个数组中的名字即可,如果存在着直接取出value后执行DAi赋值。

  <pre class="code-snippet__js" data-lang="javascript">function get_name_Array(path){` var node = path.node; if (node.declarations == undefined || node.declarations.length !=3 || node.declarations[0].init == undefined || node.declarations[0].init.property == undefined ) return; if (node.declarations[0].init.property.name != "DAi") return; let name1 = node.declarations[0].id.name; let name2 = node.declarations[2].id.name; name_Array.push(name1,name2);`}</pre>

  获取所有name 存入Array

  然后就是替换了

  正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符_js正则匹配多个字符串

  <pre class="code-snippet__js" data-lang="javascript">function replace_name_Array(path) {` var node = path.node; if(node.callee == undefined || node.callee.name ==undefined ) return; if (name_Array.indexOf(node.callee.name) == -1) return; let arg = node.arguments[0].value; let value = AJgjJ.DAi(arg); PathToLiteral(path,value)}`</pre>

  这就把所有和DAi相关的数组替换了

  我们用ctrl+F正则匹配搜索括号里面带数字类型的

  直接少了5000多个,剩下的都是别的类型的。

  现在其实差不多把极验js的关键代码反混淆了。

  已经可以去调试了。

  但是追求极致的我觉得还不够。

  正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符_js正则匹配多个字符串

  还有这么多无用的代码,需要删除,不然看的真的难受。

  继续干!

  继续在AST网站上分析

  先把上面那种删除吧。

  js正则匹配多个字符串_正则表达式匹配多个任意字符_正则表达式匹配字符串中的字符

<p><pre class="code-snippet__js" data-lang="javascript">function check_DAi(declaration) {` if (declaration.init == undefined || declaration.init.property == undefined) return ; if (declaration.init.property.name == "DAi") return true;}function del_DAi(path) { var node = path.node; var arrNode = node.declarations;` for(var i=0; i

文章由官网发布,如若转载,请注明出处:https://www.veimoz.com/1815
0 评论
727

发表评论

!